mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-10-15 18:53:09 +08:00
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.
183 lines
6.1 KiB
Python
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')
|