Files
rt-thread/components/rust/examples/modules/SConscript
T
yan hu 30af7388a4 [rust][tools] Fix Rust build example configuration handling
Improve the Rust build integration across core, applications, components, and module examples. Fix build failure propagation, target and feature handling, linker flags, example configuration semantics, and add STM32 CI attach coverage.
2026-08-21 11:17:57 +08:00

183 lines
6.1 KiB
Python

import os
import sys
import subprocess
import toml
from building import *
cwd = GetCurrentDir()
RUSTC_FLAGS = {
"linker": "-C linker=ld.lld",
"panic": "-C panic=abort",
}
CARGO_CMD = {
"base": "cargo build",
"build_std": "-Z build-std=core,alloc,panic_abort",
"target_flag": "--target",
"target_arch": "%s",
"release_profile": "--release",
"debug_profile": "", # No additional flag for debug mode
}
tools_dir = os.path.join(cwd, '..', '..', 'tools')
sys.path.insert(0, tools_dir)
from build_support import detect_rust_target, ensure_rust_target_installed, clean_rust_build
def _has(sym: str) -> bool:
"""Helper function to check if a configuration symbol is enabled"""
try:
return bool(GetDepend([sym]))
except Exception:
return bool(GetDepend(sym))
MODULE_CONFIG_MAP = {
'example_lib': 'RT_RUST_MODULE_SIMPLE_MODULE',
}
def should_build_module(module_dir: str) -> bool:
if _has('RT_RUST_BUILD_ALL_EXAMPLES'):
return True
config = MODULE_CONFIG_MAP.get(os.path.basename(module_dir))
return bool(config and _has(config))
def detect_target_for_dynamic_modules():
"""
Detect the appropriate Rust target for dynamic modules.
For dynamic modules, we need Linux targets instead of bare-metal targets.
"""
if detect_rust_target is not None:
try:
import rtconfig
bare_metal_target = detect_rust_target(_has, rtconfig)
if bare_metal_target:
if "riscv64" in bare_metal_target:
return "riscv64gc-unknown-linux-gnu"
elif "riscv32" in bare_metal_target:
return "riscv32gc-unknown-linux-gnu"
elif "aarch64" in bare_metal_target:
return "aarch64-unknown-linux-gnu"
elif "arm" in bare_metal_target or "thumb" in bare_metal_target:
return "armv7-unknown-linux-gnueabihf"
except Exception as e:
print(f"Error: Target detection failed: {e}")
raise RuntimeError(f"Failed to detect Rust target for dynamic modules: {e}")
print("Error: Unable to detect appropriate Rust target for dynamic modules")
raise RuntimeError("Target detection failed - no valid target found")
def build_rust_module(module_dir, build_root):
"""Build a Rust dynamic module with automatic target detection"""
cargo_toml_path = os.path.join(module_dir, 'Cargo.toml')
if not os.path.exists(cargo_toml_path):
return [], [], ""
with open(cargo_toml_path, 'r') as f:
cargo_config = toml.load(f)
module_name = cargo_config['package']['name']
# Detect target automatically based on the current configuration
target = detect_target_for_dynamic_modules()
print(f"Building Rust module '{module_name}' for target: {target}")
# Detect debug mode from rtconfig (same as main rust/SConscript)
debug = bool(_has('RUST_DEBUG_BUILD'))
build_mode = "debug" if debug else "release"
print(f"Building in {build_mode} mode")
# Use global RUSTFLAGS configuration for dynamic modules
rustflags = " ".join(RUSTC_FLAGS.values())
# Verify that the target is installed
if ensure_rust_target_installed is not None:
if not ensure_rust_target_installed(target):
print(f"Error: Rust target '{target}' is not installed")
print(f"Please install it with: rustup target add {target}")
return [], [], ""
else:
print(f"Warning: Cannot verify if target '{target}' is installed")
# Set up build environment
env = os.environ.copy()
env['RUSTFLAGS'] = rustflags
env['CARGO_TARGET_DIR'] = build_root
# Build the module with configurable parameters using dictionary configuration
build_cmd = [
CARGO_CMD["base"].split()[0], # 'cargo'
CARGO_CMD["base"].split()[1], # 'build'
CARGO_CMD["target_flag"], # '--target'
target, # actual target architecture
]
# Add profile flag based on debug mode
profile_flag = CARGO_CMD["debug_profile"] if debug else CARGO_CMD["release_profile"]
if profile_flag:
build_cmd.append(profile_flag)
# Add build-std flag if specified
if CARGO_CMD["build_std"]:
build_std_parts = CARGO_CMD["build_std"].split()
build_cmd.extend(build_std_parts)
try:
subprocess.run(build_cmd, cwd=module_dir, env=env, check=True, capture_output=True)
lib_dir = os.path.join(build_root, target, build_mode)
return [module_name], [lib_dir], ""
except subprocess.CalledProcessError:
return [], [], ""
# Check dependencies
if not _has('RT_USING_MODULE') and not GetOption('clean'):
Return([])
if not (
_has('RT_RUST_BUILD_MODULES') or _has('RT_RUST_BUILD_ALL_EXAMPLES')
) and not GetOption('clean'):
Return([])
build_root = os.path.join(Dir('#').abspath, "build", "rust_modules")
# Handle clean operation
if GetOption('clean'):
if clean_rust_build is not None:
modules_build_dir = clean_rust_build(Dir('#').abspath, "rust_modules")
if os.path.exists(modules_build_dir):
print(f'Registering {modules_build_dir} for cleanup')
Clean('.', modules_build_dir)
else:
print('No rust_modules build artifacts to clean')
else:
print('Warning: clean_rust_build function not available')
else:
# Build all Rust modules in subdirectories
modules_built = []
for item in os.listdir(cwd):
item_path = os.path.join(cwd, item)
if (
os.path.isdir(item_path)
and os.path.exists(os.path.join(item_path, 'Cargo.toml'))
and should_build_module(item_path)
):
result = build_rust_module(item_path, build_root)
if result[0]:
modules_built.extend(result[0])
if modules_built:
print(f"Successfully built {len(modules_built)} Rust dynamic module(s): {', '.join(modules_built)}")
group = DefineGroup(
'rust_modules',
[],
depend=['RT_USING_RUST']
)
Return('group')