From d1557032a396745c9d1ff7e446f71f98e6ba3f35 Mon Sep 17 00:00:00 2001 From: inoway46 Date: Fri, 6 Nov 2026 17:49:00 +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. If the triples cannot be determined, disable Temporal with a warning unless it was explicitly enabled. 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 | 6 ++++ configure.py | 66 ++++++++++++++++++++++++++++++++++++++++++ deps/crates/crates.gyp | 22 ++++++++++++-- 3 files changed, 92 insertions(+), 2 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 8c7407b96274..6c3a5e183a62 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -1067,6 +1067,12 @@ 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.py` (for example, +`aarch64-unknown-linux-gnu`). Otherwise, Temporal support is disabled with a +warning, or `configure.py` stops with an error when +`--v8-enable-temporal-support` is passed. + ## 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..03b41fceda08 100755 --- a/configure.py +++ b/configure.py @@ -1620,6 +1620,55 @@ def get_rustc_version(rustc): warn(f'Could not recognize `rustc`: {rustc_ret}') return '0.0' +# Prefixes of Rust target triple architectures for each GYP architecture. +rust_arch_prefixes = { + 'arm': ('arm', 'thumb'), + 'arm64': ('aarch64',), + 'ia32': ('i386', 'i586', 'i686'), + 'loong64': ('loongarch64',), + 'mips64el': ('mips64el',), + 'mipsel': ('mipsel',), + 'ppc64': ('powerpc64',), + 'riscv64': ('riscv64',), + 's390x': ('s390x',), + 'x64': ('x86_64',), +} + +def get_rust_cross_targets(host_arch, default_target): + """Returns (host triple, target triple, problem). problem is non-empty when + the triples for a bundled Temporal cross build cannot be determined.""" + rust_target = os.environ.get('CARGO_BUILD_TARGET', '') or default_target + if not rust_target: + return '', '', '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: + return '', '', 'Cannot determine the Rust host triple from `rustc -vV`.' + + # The host toolset follows CC_host, which may build 32-bit host tools for + # 32-bit targets (e.g. CC_host="gcc -m32") on a 64-bit Rust host. + rust_host_arch, _, rust_host_rest = rust_host_target.partition('-') + if not rust_host_arch.startswith(rust_arch_prefixes.get(host_arch, ('',))): + if host_arch == 'ia32' and rust_host_arch == 'x86_64': + rust_host_target = f'i686-{rust_host_rest}' + else: + return '', '', (f'Rust host triple {rust_host_target} does not match ' + f'the host toolset architecture {host_arch} (CC_host).') + + 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 +2006,23 @@ 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, problem = get_rust_cross_targets( + host_arch, o['variables']['cargo_rust_target']) + if problem: + # Like a missing Rust toolchain, this is only fatal when Temporal support + # was explicitly requested. + if options.v8_enable_temporal_support: + error(problem) + warn(f'{problem} Support for Temporal will be disabled.') + options.v8_disable_temporal_support = True + else: + 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)' ], } ],