SConscript 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import os
  2. import sys
  3. import subprocess
  4. import toml
  5. from building import *
  6. cwd = GetCurrentDir()
  7. RUSTC_FLAGS = {
  8. "linker": "-C linker=ld.lld",
  9. "panic": "-C panic=abort",
  10. }
  11. CARGO_CMD = {
  12. "base": "cargo build",
  13. "build_std": "-Z build-std=core,alloc,panic_abort",
  14. "target_flag": "--target",
  15. "target_arch": "%s",
  16. "release_profile": "--release",
  17. "debug_profile": "", # No additional flag for debug mode
  18. }
  19. tools_dir = os.path.join(cwd, '..', '..', 'tools')
  20. sys.path.insert(0, tools_dir)
  21. from build_support import detect_rust_target, ensure_rust_target_installed, clean_rust_build
  22. def _has(sym: str) -> bool:
  23. """Helper function to check if a configuration symbol is enabled"""
  24. try:
  25. return bool(GetDepend([sym]))
  26. except Exception:
  27. return bool(GetDepend(sym))
  28. def detect_target_for_dynamic_modules():
  29. """
  30. Detect the appropriate Rust target for dynamic modules.
  31. For dynamic modules, we need Linux targets instead of bare-metal targets.
  32. """
  33. if detect_rust_target is not None:
  34. try:
  35. import rtconfig
  36. bare_metal_target = detect_rust_target(_has, rtconfig)
  37. if bare_metal_target:
  38. if "riscv64" in bare_metal_target:
  39. return "riscv64gc-unknown-linux-gnu"
  40. elif "riscv32" in bare_metal_target:
  41. return "riscv32gc-unknown-linux-gnu"
  42. elif "aarch64" in bare_metal_target:
  43. return "aarch64-unknown-linux-gnu"
  44. elif "arm" in bare_metal_target or "thumb" in bare_metal_target:
  45. return "armv7-unknown-linux-gnueabihf"
  46. except Exception as e:
  47. print(f"Error: Target detection failed: {e}")
  48. raise RuntimeError(f"Failed to detect Rust target for dynamic modules: {e}")
  49. print("Error: Unable to detect appropriate Rust target for dynamic modules")
  50. raise RuntimeError("Target detection failed - no valid target found")
  51. def build_rust_module(module_dir, build_root):
  52. """Build a Rust dynamic module with automatic target detection"""
  53. cargo_toml_path = os.path.join(module_dir, 'Cargo.toml')
  54. if not os.path.exists(cargo_toml_path):
  55. return [], [], ""
  56. with open(cargo_toml_path, 'r') as f:
  57. cargo_config = toml.load(f)
  58. module_name = cargo_config['package']['name']
  59. # Detect target automatically based on the current configuration
  60. target = detect_target_for_dynamic_modules()
  61. print(f"Building Rust module '{module_name}' for target: {target}")
  62. # Detect debug mode from rtconfig (same as main rust/SConscript)
  63. debug = bool(_has('RUST_DEBUG_BUILD'))
  64. build_mode = "debug" if debug else "release"
  65. print(f"Building in {build_mode} mode")
  66. # Use global RUSTFLAGS configuration for dynamic modules
  67. rustflags = " ".join(RUSTC_FLAGS.values())
  68. # Verify that the target is installed
  69. if ensure_rust_target_installed is not None:
  70. if not ensure_rust_target_installed(target):
  71. print(f"Error: Rust target '{target}' is not installed")
  72. print(f"Please install it with: rustup target add {target}")
  73. return [], [], ""
  74. else:
  75. print(f"Warning: Cannot verify if target '{target}' is installed")
  76. # Set up build environment
  77. env = os.environ.copy()
  78. env['RUSTFLAGS'] = rustflags
  79. env['CARGO_TARGET_DIR'] = build_root
  80. # Build the module with configurable parameters using dictionary configuration
  81. build_cmd = [
  82. CARGO_CMD["base"].split()[0], # 'cargo'
  83. CARGO_CMD["base"].split()[1], # 'build'
  84. CARGO_CMD["target_flag"], # '--target'
  85. target, # actual target architecture
  86. ]
  87. # Add profile flag based on debug mode
  88. profile_flag = CARGO_CMD["debug_profile"] if debug else CARGO_CMD["release_profile"]
  89. if profile_flag:
  90. build_cmd.append(profile_flag)
  91. # Add build-std flag if specified
  92. if CARGO_CMD["build_std"]:
  93. build_std_parts = CARGO_CMD["build_std"].split()
  94. build_cmd.extend(build_std_parts)
  95. try:
  96. subprocess.run(build_cmd, cwd=module_dir, env=env, check=True, capture_output=True)
  97. lib_dir = os.path.join(build_root, target, build_mode)
  98. return [module_name], [lib_dir], ""
  99. except subprocess.CalledProcessError:
  100. return [], [], ""
  101. # Check dependencies
  102. if not _has('RT_RUST_BUILD_MODULES'):
  103. Return([])
  104. build_root = os.path.join(Dir('#').abspath, "build", "rust_modules")
  105. # Handle clean operation
  106. if GetOption('clean'):
  107. if clean_rust_build is not None:
  108. modules_build_dir = clean_rust_build(Dir('#').abspath, "rust_modules")
  109. if os.path.exists(modules_build_dir):
  110. print(f'Registering {modules_build_dir} for cleanup')
  111. Clean('.', modules_build_dir)
  112. else:
  113. print('No rust_modules build artifacts to clean')
  114. else:
  115. print('Warning: clean_rust_build function not available')
  116. else:
  117. # Build all Rust modules in subdirectories
  118. modules_built = []
  119. for item in os.listdir(cwd):
  120. item_path = os.path.join(cwd, item)
  121. if os.path.isdir(item_path) and os.path.exists(os.path.join(item_path, 'Cargo.toml')):
  122. result = build_rust_module(item_path, build_root)
  123. if result[0]:
  124. modules_built.extend(result[0])
  125. if modules_built:
  126. print(f"Successfully built {len(modules_built)} Rust dynamic module(s): {', '.join(modules_built)}")
  127. group = DefineGroup(
  128. 'rust_modules',
  129. [],
  130. depend=['RT_RUST_BUILD_MODULES']
  131. )
  132. Return('group')