| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- import os
- import subprocess
- # Configuration to feature mapping table for components
- # This table defines which RT-Thread configurations should enable which component features
- # All feature configurations are now defined in feature_config_component.py
- CONFIG_COMPONENT_FEATURE_MAP = {}
- class ComponentBuildError(Exception):
- pass
- def check_component_dependencies(component_dir, required_dependencies):
- """
- Check if a component has the required dependencies
-
- Args:
- component_dir: Component directory path
- required_dependencies: List of dependency names to check
-
- Returns:
- bool: True if all required dependencies are present
- """
- if not component_dir or not required_dependencies:
- return True
-
- cargo_toml_path = os.path.join(component_dir, 'Cargo.toml')
- if not os.path.exists(cargo_toml_path):
- return False
-
- try:
- import toml
- with open(cargo_toml_path, 'r') as f:
- cargo_data = toml.load(f)
-
- dependencies = cargo_data.get('dependencies', {})
-
- # Check if all required dependencies are present
- for dep in required_dependencies:
- if dep not in dependencies:
- return False
-
- return True
-
- except Exception as e:
- print(f"Warning: Failed to parse {cargo_toml_path}: {e}")
- return False
- def collect_component_features(has_func, component_dir=None):
- """
- Collect component features based on RT-Thread configuration using extensible mapping table
-
- Args:
- has_func: Function to check if a configuration is enabled
- component_dir: Component directory to check dependencies (optional)
-
- Returns:
- list: List of features to enable
- """
- features = []
-
- # Iterate through all configured mappings
- for config_name, config_info in CONFIG_COMPONENT_FEATURE_MAP.items():
- # Check if this RT-Thread configuration is enabled
- if has_func(config_name):
- feature_name = config_info['feature']
- required_deps = config_info.get('dependencies', [])
-
- # If component_dir is provided, check dependencies
- if component_dir:
- if check_component_dependencies(component_dir, required_deps):
- features.append(feature_name)
- print(f"Enabling component feature '{feature_name}' for {config_name} in {os.path.basename(component_dir)}")
- else:
- # If no component_dir provided, enable for all (backward compatibility)
- features.append(feature_name)
- print(f"Enabling component feature '{feature_name}' for {config_name}")
-
- return features
- def cargo_build_component_staticlib(rust_dir, target, features, debug, rustflags=None, build_root=None):
- """
- Build a Rust component as a static library using Cargo.
-
- Args:
- rust_dir: Directory containing the Rust component
- target: Rust target architecture
- features: List of features to enable
- debug: Whether this is a debug build
- rustflags: Additional Rust compilation flags
- build_root: Build root directory (if not provided, will raise error)
-
- Returns:
- str: Path to the built library file, or None if build failed
- """
- if not build_root:
- raise ComponentBuildError("build_root parameter is required")
-
- build_root = os.path.abspath(build_root)
- 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"] = build_root
- 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 example component log (cargo)…")
- res = subprocess.run(cmd, cwd=rust_dir, env=env, capture_output=True, text=True)
-
- if res.returncode != 0:
- print("Warning: Example component build failed")
- if res.stderr:
- print(res.stderr)
- return None
- mode = "debug" if debug else "release"
-
- # Try target-specific path first, then fallback to direct path
- lib_path = os.path.join(build_root, target, mode, "libem_component_registry.a")
- if os.path.exists(lib_path):
- print("Example component log built successfully")
- return lib_path
-
- print("Warning: Library not found at expected location")
- print(f"Expected: {lib_path}")
- return None
- def build_example_component(cwd, has_func, rtconfig, build_root=None):
- """
- Build the example component.
-
- Args:
- cwd: Current working directory (component directory)
- has_func: Function to check if a configuration is enabled
- rtconfig: RT-Thread configuration module
- build_root: Optional build root directory
-
- Returns:
- tuple: (LIBS, LIBPATH, LINKFLAGS) for SCons
- """
- LIBS = []
- LIBPATH = []
- LINKFLAGS = ""
-
- # Import build support functions
- import sys
- sys.path.append(os.path.join(cwd, '../rust/tools'))
- from build_support import (
- detect_rust_target,
- make_rustflags,
- )
-
- target = detect_rust_target(has_func, rtconfig)
-
- # Build mode and features
- debug = bool(has_func('RUST_DEBUG_BUILD'))
-
- # Build the component registry
- registry_dir = os.path.join(cwd, 'component_registry')
- features = collect_component_features(has_func, registry_dir)
-
- rustflags = make_rustflags(rtconfig, target)
-
- rust_lib = cargo_build_component_staticlib(
- rust_dir=registry_dir,
- target=target,
- features=features,
- debug=debug,
- rustflags=rustflags,
- build_root=build_root
- )
-
- if rust_lib:
- LIBS = ['em_component_registry']
- LIBPATH = [os.path.dirname(rust_lib)]
- # Add LINKFLAGS to ensure component is linked into final binary
- LINKFLAGS += " -Wl,--whole-archive -lem_component_registry -Wl,--no-whole-archive"
- LINKFLAGS += " -Wl,--allow-multiple-definition"
- print('Example component registry library linked successfully')
- else:
- print('Warning: Failed to build example component registry library')
-
- return LIBS, LIBPATH, LINKFLAGS
|