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)' ], } ],