| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- 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))
- 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_RUST_BUILD_MODULES'):
- 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')):
- 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_RUST_BUILD_MODULES']
- )
- Return('group')
|