Export recipe Cargo config to the devtool workspace so Cargo and
rust-analyzer reuse target, linker, rustflags, and dependency settings
instead of duplicating them in settings.json and tasks.json. Other IDE
integrations can reuse the generated config too.

Update managed TOML table entries in place to preserve unrelated content.
tomllib and tomli only parse TOML; using a writer would add a dependency.

AI-Generated: Uses GitHub Copilot
Signed-off-by: Enguerrand de Ribaucourt 
<[email protected]>
---
 scripts/lib/devtool/ide_sdk.py | 84 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)

diff --git a/scripts/lib/devtool/ide_sdk.py b/scripts/lib/devtool/ide_sdk.py
index e686dbcff8..21229f5970 100755
--- a/scripts/lib/devtool/ide_sdk.py
+++ b/scripts/lib/devtool/ide_sdk.py
@@ -36,6 +36,34 @@ logger = logging.getLogger('devtool')
 ide_plugins = {}
 
 
+def set_toml_table_values(content, table, values):
+    """Update one TOML table while preserving unrelated configuration text."""
+    lines = content.splitlines()
+    header = '[%s]' % table
+    try:
+        start = next(i for i, line in enumerate(lines)
+                     if line.strip() == header)
+    except StopIteration:
+        if lines and lines[-1].strip():
+            lines.append('')
+        lines.append(header)
+        start = len(lines) - 1
+
+    end = next((i for i in range(start + 1, len(lines))
+                if lines[i].lstrip().startswith('[')
+                and lines[i].rstrip().endswith(']')), len(lines))
+    for key, value in values.items():
+        entry = '%s = %s' % (key, value)
+        for i in range(start + 1, end):
+            if '=' in lines[i] and lines[i].split('=', 1)[0].strip() == key:
+                lines[i] = entry
+                break
+        else:
+            lines.insert(end, entry)
+            end += 1
+    return '\n'.join(lines).rstrip() + '\n'
+
+
 class DevtoolIdeMode(Enum):
     """Different modes are supported by the ide-sdk plugin.
 
@@ -1122,6 +1150,62 @@ class RecipeModified:
         self.recipe_id = self.bpn + "-" + self.package_arch
         self.recipe_id_pretty = self.bpn + ": " + self.package_arch
 
+    @property
+    def cargo_config_path(self):
+        return os.path.join(self.ide_sdk_dir, 'cargo-config.toml')
+
+    def update_cargo_config(self):
+        """Export the recipe Cargo config to the devtool workspace."""
+        source_config = os.path.join(self.cargo_home, 'config.toml')
+        try:
+            with open(source_config, 'r') as config_file:
+                original = config_file.read()
+        except FileNotFoundError as exc:
+            raise DevtoolError(
+                'Cargo config not found at %s; build the recipe first' % 
source_config) from exc
+
+        content = (
+            '# Generated by devtool ide-sdk for the active build 
environment.\n'
+            '\n'
+            + original)
+        content = set_toml_table_values(content, 'build', {
+            'target': json.dumps(self.cargo_target),
+        })
+        content = set_toml_table_values(content, 'target.%s' % 
self.cargo_target, {
+            'linker': json.dumps(self.cargo_linker),
+            'rustflags': json.dumps(shlex.split(self.cargo_rustflags)),
+        })
+        env_names = (
+            'CC', 'CXX', 'CFLAGS', 'CXXFLAGS', 'AR',
+            'TARGET_CC', 'TARGET_CXX', 'TARGET_CFLAGS', 'TARGET_CXXFLAGS', 
'TARGET_AR',
+            'HOST_CC', 'HOST_CXX', 'HOST_CFLAGS', 'HOST_CXXFLAGS', 'HOST_AR',
+            'RUST_TARGET_PATH', 'RUST_BACKTRACE', 'SOURCE_DATE_EPOCH',
+            'PKG_CONFIG', 'PKG_CONFIG_FOR_BUILD', 'PKG_CONFIG_FOR_TARGET',
+            'PKG_CONFIG_SYSROOT_DIR', 'PKG_CONFIG_PATH', 'PKG_CONFIG_LIBDIR',
+            'LIBGIT2_NO_VENDOR', 'LIBSSH2_SYS_USE_PKG_CONFIG',
+            'LIBSQLITE3_SYS_USE_PKG_CONFIG', 'OPENSSL_NO_VENDOR',
+            'PKG_CONFIG_ALLOW_CROSS', 'PKG_CONFIG_ALL_DYNAMIC',
+            'SYSTEM_DEPS_BUILD_INTERNAL', 'ZSTD_SYS_USE_PKG_CONFIG',
+        )
+        env_values = {}
+        for name in env_names:
+            value = self.cargo_env.get(name)
+            if value is not None:
+                env_values[name] = '{ value = %s, force = true }' % 
json.dumps(str(value))
+        content = set_toml_table_values(content, 'env', env_values)
+
+        config_path = self.cargo_config_path
+        os.makedirs(os.path.dirname(config_path), exist_ok=True)
+        try:
+            with open(config_path, 'r') as config_file:
+                current = config_file.read()
+        except FileNotFoundError:
+            current = None
+        if current != content:
+            with open(config_path, 'w') as config_file:
+                config_file.write(content)
+        return config_path
+
     @staticmethod
     def is_valid_shell_variable(var):
         """Skip strange shell variables like systemd

-- 
2.53.0

-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#248641): 
https://lists.openembedded.org/g/openembedded-core/message/248641
Mute This Topic: https://lists.openembedded.org/mt/121938784/21656
Group Owner: [email protected]
Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to