| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- import os
- import subprocess
- def _parse_cflags(cflags: str):
- info = {
- "march": None,
- "mabi": None,
- "rv_bits": None, # 32 or 64
- "has_f": False,
- "has_d": False,
- }
- if not cflags:
- return info
- parts = cflags.split()
- for flag in parts:
- if flag.startswith("-march="):
- info["march"] = flag.split("=", 1)[1]
- if "rv32" in info["march"]:
- info["rv_bits"] = 32
- elif "rv64" in info["march"]:
- info["rv_bits"] = 64
- # crude feature detection
- m = info["march"]
- if m:
- info["has_f"] = ("f" in m)
- info["has_d"] = ("d" in m)
- elif flag.startswith("-mabi="):
- info["mabi"] = flag.split("=", 1)[1]
- if info["mabi"] in ("ilp32d", "ilp32f", "lp64d", "lp64f"):
- # floating-point ABI implies FPU availability
- info["has_f"] = True
- info["has_d"] = info["mabi"].endswith("d")
- return info
- def detect_rust_target(has, rtconfig):
- """
- Decide the Rust target triple based on RT-Thread Kconfig and rtconfig.*.
- `has` is a callable: has("SYMBOL") -> bool
- """
- # ARM Cortex-M
- if has("ARCH_ARM"):
- # FPU hints from flags/macros
- cflags = getattr(rtconfig, "CFLAGS", "")
- hard_float = "-mfloat-abi=hard" in cflags or has("ARCH_ARM_FPU") or has("ARCH_FPU_VFP")
- if has("ARCH_ARM_CORTEX_M3"):
- return "thumbv7m-none-eabi"
- if has("ARCH_ARM_CORTEX_M4") or has("ARCH_ARM_CORTEX_M7"):
- return "thumbv7em-none-eabihf" if hard_float else "thumbv7em-none-eabi"
- if has("ARCH_ARM_CORTEX_M33"):
- # v8m.main
- return "thumbv8m.main-none-eabi"
- if has("ARCH_ARM_CORTEX_A"):
- return "armv7a-none-eabi"
- # AArch64
- if has("ARCH_AARCH64") or has("ARCH_ARMV8") or has("ARCH_ARM64"):
- if has("ARCH_CPU_FLOAT_ABI_SOFT"):
- return "aarch64-unknown-none-softfloat"
- return "aarch64-unknown-none"
-
- # RISC-V
- if has("ARCH_RISCV32") or has("ARCH_RISCV64"):
- cflags = getattr(rtconfig, "CFLAGS", "")
- info = _parse_cflags(cflags)
- # fallback to Kconfig hint if march not present
- rv_bits = info["rv_bits"] or (32 if has("ARCH_RISCV32") else 64)
- # ABI must carry f/d to actually use hard-float calling convention
- abi = info["mabi"] or ""
- abi_has_fp = abi.endswith("f") or abi.endswith("d")
- if rv_bits == 32:
- # Only pick *f* target when ABI uses hard-float; otherwise use soft-float even if core has F/D
- return "riscv32imafc-unknown-none-elf" if abi_has_fp else "riscv32imac-unknown-none-elf"
- else:
- # rv64: prefer gc (includes fd) only when ABI uses hard-float
- return "riscv64gc-unknown-none-elf" if abi_has_fp else "riscv64imac-unknown-none-elf"
- # Fallback by ARCH string or CFLAGS
- arch = getattr(rtconfig, "ARCH", None)
- if arch:
- arch_l = arch.lower()
- if "aarch64" in arch_l:
- return "aarch64-unknown-none"
- if "arm" == arch_l or "armv7" in arch_l:
- return "armv7a-none-eabi"
- if "riscv32" in arch_l:
- return "riscv32imac-unknown-none-elf"
- if "riscv64" in arch_l or "risc-v" in arch_l:
- # Many BSPs use "risc-v" token; assume 64-bit for virt64
- return "riscv64imac-unknown-none-elf"
- # Parse CFLAGS for hints
- cflags = getattr(rtconfig, "CFLAGS", "")
- if "-mcpu=cortex-m3" in cflags:
- return "thumbv7m-none-eabi"
- if "-mcpu=cortex-m4" in cflags or "-mcpu=cortex-m7" in cflags:
- if "-mfpu=" in cflags and "-mfloat-abi=hard" in cflags:
- return "thumbv7em-none-eabihf"
- return "thumbv7em-none-eabi"
- if "-march=rv32" in cflags:
- march_val = None
- mabi_val = None
- for flag in cflags.split():
- if flag.startswith("-march="):
- march_val = flag[len("-march="):]
- elif flag.startswith("-mabi="):
- mabi_val = flag[len("-mabi="):]
- has_f_or_d = False
- if march_val and any(x in march_val for x in ("f", "d")):
- has_f_or_d = True
- if mabi_val and any(x in mabi_val for x in ("f", "d")):
- has_f_or_d = True
- return "riscv32imafc-unknown-none-elf" if has_f_or_d else "riscv32imac-unknown-none-elf"
- if "-march=rv64" in cflags:
- march_val = None
- mabi_val = None
- for flag in cflags.split():
- if flag.startswith("-march="):
- march_val = flag[len("-march="):]
- elif flag.startswith("-mabi="):
- mabi_val = flag[len("-mabi="):]
- has_f_or_d = False
- if mabi_val and (("lp64d" in mabi_val) or ("lp64f" in mabi_val)):
- has_f_or_d = True
- if march_val and any(x in march_val for x in ("f", "d")):
- has_f_or_d = True
- if mabi_val and any(x in mabi_val for x in ("f", "d")):
- has_f_or_d = True
- if has_f_or_d:
- return "riscv64gc-unknown-none-elf"
- return "riscv64imac-unknown-none-elf"
- return None
- def make_rustflags(rtconfig, target: str):
- rustflags = [
- "-C", "opt-level=z",
- "-C", "panic=abort",
- "-C", "relocation-model=static",
- ]
- if "riscv" in target:
- rustflags += [
- "-C", "code-model=medium",
- "-C", "link-dead-code",
- ]
- # propagate march/mabi for consistency (use link-arg for staticlib builds – harmless)
- cflags = getattr(rtconfig, "CFLAGS", "")
- for flag in cflags.split():
- if flag.startswith("-march=") or flag.startswith("-mabi="):
- rustflags += ["-C", f"link-arg={flag}"]
- if "thumb" in target or "aarch64" in target:
- rustflags += ["-C", "link-arg=-nostartfiles"]
- return " ".join(rustflags)
- def collect_features(has):
- feats = []
- if has("RT_USING_SMP"):
- feats.append("smp")
- return feats
- def verify_rust_toolchain():
- try:
- r1 = subprocess.run(["rustc", "--version"], capture_output=True, text=True)
- r2 = subprocess.run(["cargo", "--version"], capture_output=True, text=True)
- return r1.returncode == 0 and r2.returncode == 0
- except Exception:
- return False
- def ensure_rust_target_installed(target: str):
- try:
- result = subprocess.run(["rustup", "target", "list", "--installed"], capture_output=True, text=True)
- if result.returncode == 0 and target in result.stdout:
- return True
- print(f"Rust target '{target}' is not installed.")
- print(f"Please install it with: rustup target add {target}")
- except Exception:
- print("Warning: Failed to check rustup target list (rustup missing?)")
- return False
- def cargo_build_staticlib(rust_dir: str, target: str, features, debug: bool, rustflags: str = None):
- build_root = os.path.join((os.path.abspath(os.path.join(rust_dir, os.pardir, os.pardir))), "build", "rust")
- target_dir = os.path.join(build_root, "target")
- os.makedirs(build_root, exist_ok=True)
- env = os.environ.copy()
- if rustflags:
- prev = env.get("RUSTFLAGS", "").strip()
- env["RUSTFLAGS"] = (prev + " " + rustflags).strip() if prev else rustflags
- env["CARGO_TARGET_DIR"] = target_dir
- cmd = ["cargo", "build", "--target", target, "--manifest-path", os.path.join(rust_dir, "Cargo.toml")]
- if not debug:
- cmd.insert(2, "--release")
- if features:
- cmd += ["--no-default-features", "--features", ",".join(features)]
- print("Building Rust component (cargo)…")
- res = subprocess.run(cmd, cwd=rust_dir, env=env, capture_output=True, text=True)
- if res.returncode != 0:
- print("Warning: Rust build failed")
- if res.stderr:
- print(res.stderr)
- return None
- mode = "debug" if debug else "release"
- lib_path = os.path.join(target_dir, target, mode, "librt_rust.a")
- if os.path.exists(lib_path):
- print("Rust component built successfully")
- return lib_path
- print("Warning: Library not found at expected location")
- return None
- def clean_rust_build(bsp_root: str, artifact_type: str = "rust"):
- """Return the build directory path for SCons Clean operation"""
- build_dir = os.path.join(bsp_root, "build", artifact_type)
- return build_dir
|