From 7378d0750c06994d98a3553bec8a4c040023beed Mon Sep 17 00:00:00 2001 From: inoway46 Date: Sun, 18 Oct 2026 16:02:46 +0900 Subject: [PATCH] build: separate host and target Rust artifacts in cross builds Capture the Rust target and host triples during configure for bundled Temporal cross builds. Use explicit Cargo targets and separate output directories so host and target archives do not share a build rule. Fixes: https://github.com/nodejs/node/issues/66897 Refs: https://github.com/nodejs/node/issues/66803 Assisted-by: Codex Signed-off-by: inoway46 --- BUILDING.md | 14 ++++++++++++++ configure.py | 31 +++++++++++++++++++++++++++++++ deps/crates/crates.gyp | 22 ++++++++++++++++++++-- 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 8c7407b96274..4d7338926508 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -1067,6 +1067,20 @@ a warning is printed and Temporal support is disabled. Passing both options to `configure.py` is an error. +For non-Windows cross builds with bundled Temporal, set `CARGO_BUILD_TARGET` +to the Rust target triple when running configure, unless configure already +provides a target for the platform. For example, when targeting Linux ARM64: + +```bash +CARGO_BUILD_TARGET=aarch64-unknown-linux-gnu ./configure \ + --cross-compiling --dest-os=linux --dest-cpu=arm64 +``` + +Configure saves this target and the host triple reported by `rustc -vV`. +Install the target's Rust standard library and configure the cross linker +separately. Re-run configure when changing targets. Cargo configuration-file +targets and custom JSON targets are not supported by this detection. + ## Building Node.js with external core modules It is possible to specify one or more JavaScript text files to be bundled in diff --git a/configure.py b/configure.py index 5a30e76b1d84..571694ca5b97 100755 --- a/configure.py +++ b/configure.py @@ -1620,6 +1620,29 @@ def get_rustc_version(rustc): warn(f'Could not recognize `rustc`: {rustc_ret}') return '0.0' +def get_rust_cross_targets(default_target): + rust_target = os.environ.get('CARGO_BUILD_TARGET', '') or default_target + if not rust_target: + error('Cross compilation with bundled Temporal requires CARGO_BUILD_TARGET') + + rust_host_target = '' + rustc = os.environ.get('RUSTC', 'rustc') + try: + version = subprocess.check_output(shlex.split(rustc) + ['-vV'], + stderr=subprocess.PIPE, text=True) + except (OSError, subprocess.CalledProcessError): + version = '' + match = re.search(r'^host: (\S+)$', version, re.MULTILINE) + if match: + rust_host_target = match.group(1) + if not rust_host_target: + error('Cannot determine the Rust host triple from rustc -vV') + + for triple in (rust_host_target, rust_target): + if not re.fullmatch(r'[A-Za-z0-9_]+(?:-[A-Za-z0-9_]+)+', triple): + error('Rust targets must be target triples, not paths to target JSON files') + return rust_host_target, rust_target + # Note: Apple clang self-reports as clang 4.2.0 and gcc 4.2.1. It passes # the version check more by accident than anything else but a more rigorous # check involves checking the build number against an allowlist. I'm not @@ -1957,6 +1980,14 @@ def configure_node(o): os.environ['GYP_CROSSCOMPILE'] = "1" o['variables']['want_separate_host_toolset'] = int(cross_compiling) + o['variables']['cargo_cross_compiling'] = 0 + if (flavor != 'win' and cross_compiling and + not options.v8_disable_temporal_support and not options.shared_temporal_capi): + # Only bundled Temporal cross builds need explicit per-toolset Rust targets. + rust_host_target, rust_target = get_rust_cross_targets(o['variables']['cargo_rust_target']) + o['variables']['cargo_cross_compiling'] = 1 + o['variables']['cargo_rust_target_target'] = rust_target + o['variables']['cargo_rust_target_host'] = rust_host_target if target_arch == 'arm64': o['variables']['arm_fpu'] = options.arm_fpu or 'neon' diff --git a/deps/crates/crates.gyp b/deps/crates/crates.gyp index 216b0cff5128..3070e334244e 100644 --- a/deps/crates/crates.gyp +++ b/deps/crates/crates.gyp @@ -6,14 +6,18 @@ 'zoneinfo64_dir': 'zoneinfo64-v0_3', 'temporal_zoneinfo64_data_output': '<(SHARED_INTERMEDIATE_DIR)/src/builtins/builtins-temporal-zoneinfo64-data.cc', 'cargo_rust_target%': '', + 'cargo_cross_compiling%': 0, + 'cargo_rust_target_host%': '', + 'cargo_rust_target_target%': '', }, 'conditions': [ ['build_type == "Release"', { 'variables': { 'cargo_build_flags': ['--release'], + 'cargo_profile': 'release', }, 'conditions': [ - ['cargo_rust_target!=""', { + ['cargo_rust_target!="" and cargo_cross_compiling==0', { 'variables': { 'cargo_build_flags': ['--target', '<(cargo_rust_target)'], } @@ -31,6 +35,7 @@ }, { 'variables': { 'cargo_build_flags': [], + 'cargo_profile': 'debug', }, 'conditions': [ ['OS=="win"', { @@ -50,6 +55,18 @@ 'target_name': 'node_crates', 'type': 'none', 'toolsets': ['host', 'target'], + 'variables': { + 'cargo_output_dir': '<(SHARED_INTERMEDIATE_DIR)', + 'cargo_cross_target_flags': [], + 'conditions': [ + ['cargo_cross_compiling==1', { + 'cargo_output_dir': '<(SHARED_INTERMEDIATE_DIR)/cargo/<(_toolset)', + 'cargo_cross_target_flags': ['--target', '<(cargo_rust_target_<(_toolset))'], + # Referencing cargo_output_dir here would use its pre-condition value. + 'node_crates_libpath': '<(SHARED_INTERMEDIATE_DIR)/cargo/<(_toolset)/<(cargo_rust_target_<(_toolset))/<(cargo_profile)/<(STATIC_LIB_PREFIX)node_crates<(STATIC_LIB_SUFFIX)', + }], + ], + }, 'hard_dependency': 1, 'sources': [ 'Cargo.toml', @@ -103,10 +120,11 @@ 'action': [ '<(cargo)', 'rustc', + '<@(cargo_cross_target_flags)', '<@(cargo_build_flags)', '--frozen', '--target-dir', - '<(SHARED_INTERMEDIATE_DIR)' + '<(cargo_output_dir)' ], } ],