diff mbox series

[03/24] devtool: ide-sdk: VSCode IntelliSense for rootfs-dbg sources

Message ID 20260830142922.17241-4-adrian.freihofer@siemens.com
State New
Headers show
Series devtool: ide-sdk: NFS/slirp support, deploy filtering, and robustness fixes | expand

Commit Message

AdrianF Aug. 30, 2026, 2:28 p.m. UTC
From: Adrian Freihofer <adrian.freihofer@siemens.com>

Add includePath fallback entries to c_cpp_properties.json pointing at
recipe-sysroot/usr/include and rootfs-dbg/usr/src/debug, so the C/C++
extension can resolve symbols in other recipes' sources whenever they
are opened from rootfs-dbg, e.g. while stepping into them with the
debugger.

Also widen files.readonlyInclude from just the recipe's sysroots to
the whole TMPDIR: more robust, since it also covers oe-workdir, rootfs,
and other generated content reachable from the workspace. oe-logs and
oe-workdir are kept visible in the VSCode explorer instead of being
hidden via files.exclude, so build logs and temp scripts can still be
browsed, while staying out of the file watcher/indexer and read-only.

Signed-off-by: Adrian Freihofer <adrian.freihofer@siemens.com>
---
 meta/lib/oeqa/selftest/cases/devtool.py     |  8 ++--
 scripts/lib/devtool/ide_plugins/ide_code.py | 44 +++++++++++++++------
 scripts/lib/devtool/ide_sdk.py              |  2 +
 3 files changed, 38 insertions(+), 16 deletions(-)
diff mbox series

Patch

diff --git a/meta/lib/oeqa/selftest/cases/devtool.py b/meta/lib/oeqa/selftest/cases/devtool.py
index 7c989f9dc2..c0df13b718 100644
--- a/meta/lib/oeqa/selftest/cases/devtool.py
+++ b/meta/lib/oeqa/selftest/cases/devtool.py
@@ -3945,11 +3945,11 @@  class DevtoolIdeSdkKernelTests(DevtoolIdeSdkTests):
                          os.path.join(tempdir, 'Makefile'),
                          'makefilePath should point to the Makefile in the source tree')
 
-        # Verify kernel sources are set read-only
+        # Verify kernel sources (under TMPDIR) are set read-only
+        tmpdir = get_bb_var('TMPDIR', recipe_name)
         readonly_includes = settings_d.get('files.readonlyInclude', {})
-        self.assertTrue(
-            any(k for k in readonly_includes if 'staging_kernel' in k.lower() or 'linux' in k.lower()),
-            'Kernel staging dir should be set read-only in files.readonlyInclude: %s' % readonly_includes)
+        self.assertIn(os.path.realpath(tmpdir) + '/**', readonly_includes,
+                     'TMPDIR should be set read-only in files.readonlyInclude: %s' % readonly_includes)
 
         # Verify the cross-build environment is exported for the terminal
         self.assertIn('terminal.integrated.env.linux', settings_d,
diff --git a/scripts/lib/devtool/ide_plugins/ide_code.py b/scripts/lib/devtool/ide_plugins/ide_code.py
index 1a8a79f623..5abf0492e8 100644
--- a/scripts/lib/devtool/ide_plugins/ide_code.py
+++ b/scripts/lib/devtool/ide_plugins/ide_code.py
@@ -205,9 +205,6 @@  class IdeVSCode(IdeBase):
         settings_dict["files.watcherExclude"].update(files_excludes_kernel)
         settings_dict["python.analysis.exclude"] += kernel_exclude_patterns
 
-        # protect the kernel sources
-        settings_dict["files.readonlyInclude"][modified_recipe.staging_kernel_dir + '/**'] = True
-
         # Export the complete cross-build environment
         settings_dict["terminal.integrated.env.linux"] = modified_recipe.exported_vars
 
@@ -232,12 +229,15 @@  class IdeVSCode(IdeBase):
         ]
 
     def vscode_settings(self, modified_recipe, image_recipe):
-        files_excludes = {
+        files_hide = {
             "**/.git/**": True,
-            "**/oe-logs/**": True,
-            "**/oe-workdir/**": True,
             "**/source-date-epoch/**": True
         }
+        files_watcher_exclude = dict(files_hide)
+        files_watcher_exclude.update({
+            "**/oe-logs/**": True,
+            "**/oe-workdir/**": True,
+        })
         python_exclude = [
             "**/.git/**",
             "**/oe-logs/**",
@@ -245,14 +245,16 @@  class IdeVSCode(IdeBase):
             "**/source-date-epoch/**"
         ]
         files_readonly = {
-            modified_recipe.recipe_sysroot + '/**': True,
-            modified_recipe.recipe_sysroot_native + '/**': True,
+            modified_recipe.tmpdir + '/**': True,
+            "**/oe-logs/**": True,
+            "**/oe-workdir/**": True,
         }
         if image_recipe.rootfs_dbg is not None:
             files_readonly[image_recipe.rootfs_dbg + '/**'] = True
         settings_dict = {
-            "files.watcherExclude": files_excludes,
-            "files.exclude": files_excludes,
+            "files.watcherExclude": files_watcher_exclude,
+            "files.exclude": files_hide,
+            "search.exclude": dict(files_watcher_exclude),
             "files.readonlyInclude": files_readonly,
             "python.analysis.exclude": python_exclude
         }
@@ -287,7 +289,7 @@  class IdeVSCode(IdeBase):
         IdeBase.update_json_file(
             self.dot_code_dir(modified_recipe), extensions_file, {"recommendations": recommendations})
 
-    def vscode_c_cpp_properties(self, modified_recipe):
+    def vscode_c_cpp_properties(self, modified_recipe, image_recipe):
         properties_dict = {
             "name": modified_recipe.recipe_id_pretty,
         }
@@ -322,6 +324,24 @@  class IdeVSCode(IdeBase):
         else:  # no C/C++ build
             return
 
+        # configurationProvider/compileCommands only cover the recipe under
+        # development. Add includePath as a fallback so the C/C++ extension
+        # also resolves symbols in other recipes sources found in rootfs-dbg.
+        if image_recipe.rootfs_dbg is not None:
+            recipe_sysroot_include = os.path.join(modified_recipe.recipe_sysroot, "usr", "include")
+            # rootfs_dbg/usr/include is empty, target headers come from recipe-sysroot,
+            # consistent with the GDB sourceFileMap for "/usr/include".
+            rootfs_dbg_src_debug = os.path.join(image_recipe.rootfs_dbg, "usr", "src", "debug")
+            include_path = properties_dict.get("includePath", ["${workspaceFolder}/**"])
+            for path in (recipe_sysroot_include, rootfs_dbg_src_debug + "/**"):
+                if path not in include_path:
+                    include_path.append(path)
+            properties_dict["includePath"] = include_path
+            # That's the default, but make it easy to change if a big index is preferred.
+            properties_dict["browse"] = {
+                "limitSymbolsToIncludedHeaders": True
+            }
+
         properties_dicts = {
             "configurations": [
                 properties_dict
@@ -873,7 +893,7 @@  class IdeVSCode(IdeBase):
     def setup_modified_recipe(self, args, image_recipe, modified_recipe):
         self.vscode_settings(modified_recipe, image_recipe)
         self.vscode_extensions(modified_recipe)
-        self.vscode_c_cpp_properties(modified_recipe)
+        self.vscode_c_cpp_properties(modified_recipe, image_recipe)
         if args.target:
             if modified_recipe.toolchain == 'clang':
                 self.initialize_cross_debug_configs(
diff --git a/scripts/lib/devtool/ide_sdk.py b/scripts/lib/devtool/ide_sdk.py
index 6f08940c9c..d7575ec523 100755
--- a/scripts/lib/devtool/ide_sdk.py
+++ b/scripts/lib/devtool/ide_sdk.py
@@ -457,6 +457,7 @@  class RecipeModified:
         self.staging_incdir = None
         self.strip_cmd = None
         self.target_arch = None
+        self.tmpdir = None
         self.toolchain = None
         self.topdir = None
         self.workdir = None
@@ -545,6 +546,7 @@  class RecipeModified:
             recipe_d.getVar('STAGING_INCDIR'))
         self.strip_cmd = recipe_d.getVar('STRIP')
         self.target_arch = recipe_d.getVar('TARGET_ARCH')
+        self.tmpdir = os.path.realpath(recipe_d.getVar('TMPDIR'))
         self.toolchain = recipe_d.getVar('TOOLCHAIN')
         self.topdir = recipe_d.getVar('TOPDIR')
         self.workdir = os.path.realpath(recipe_d.getVar('WORKDIR'))