Skip to content

fix: override host-specific variables when reading headers config.gypi#3303

Open
iFwu wants to merge 1 commit intonodejs:mainfrom
iFwu:fix/disturl-host-vars-override
Open

fix: override host-specific variables when reading headers config.gypi#3303
iFwu wants to merge 1 commit intonodejs:mainfrom
iFwu:fix/disturl-host-vars-override

Conversation

@iFwu
Copy link
Copy Markdown

@iFwu iFwu commented Apr 20, 2026

Background

getBaseConfigGypi reads \$nodedir/include/node/config.gypi verbatim whenever --disturl, --dist-url, or --nodedir is set (and --force-process-config is not). This was introduced in #2497 to let Electron / NW.js builds pick up target build config from custom headers.

The official Node release headers tarball is, however, a single universal artifact shipped to all platforms, and its embedded config.gypi reflects the build host of the Node release-engineering machine (currently a Linux x64 / GCC box). When a consumer on a different host inherits it verbatim, host-specific fields end up wrong.

Symptom on macOS arm64

Field-by-field diff between the cached headers' config.gypi and process.config.variables on darwin/arm64 with Node v24.13.1:

field cache process.config
host_arch x64 arm64
clang 0 1
llvm_version "0.0" "16.0"
xcode_version <undef> "16.0"
arm_fpu <undef> "neon"
gas_version "2.38" <undef>
shlib_suffix "so.137" "137.dylib"

The killer is clang=0: Node's common.gypi gates -std=gnu++20 (and several other flags) on clang==1. With clang=0 those branches never fire, C++ compilation falls back to C++03, and any addon using node-addon-api immediately fails with:

```
node-addon-api/napi.h: error: a space is required between consecutive right angle brackets (use '> >')
node-addon-api/napi.h: error: no template named 'initializer_list' in namespace 'std'
node-addon-api/napi.h: error: unknown type name 'constexpr'
```

For comparison, on Linux x64 / Node v24.13.1 the same diff shows all 7 host-specific fields are identical between cache and process.config (the cache literally is a Linux x64 build farm fingerprint), so the fix in this PR is a strict no-op there.

Minimal repro (no Electron required)

```bash
mkdir /tmp/repro && cd /tmp/repro
cat > package.json <<'EOF'
{"name":"r","dependencies":{"node-addon-api":"^8.0.0"}}
EOF
cat > binding.gyp <<'EOF'
{"targets":[{"target_name":"r","sources":["r.cc"],
"include_dirs":["<!@(node -p \"require('node-addon-api').include\")"],
"dependencies":["<!(node -p \"require('node-addon-api').gyp\")"]}]}
EOF
echo '#include <napi.h>' > r.cc
npm install --ignore-scripts

Works:

npx node-gyp rebuild

Fails (anywhere disturl is set):

npm_config_disturl=https://npmmirror.com/mirrors/node npx node-gyp rebuild
```

Affected scope

Anyone with `disturl` set in `~/.npmrc`, project `.npmrc`, or as `npm_config_disturl` env var. Common cases:

Why `--force-process-config` is not a real fix

Fix

Override only the host-specific variables from process.config.variables after parsing the headers' config.gypi:

```js
const HOST_SPECIFIC_VARIABLES = [
'host_arch',
'clang',
'llvm_version',
'xcode_version',
'arm_fpu',
'gas_version',
'shlib_suffix'
]
```

PR #2497's intent is preserved — target build config (v8 features, bundled vs shared deps, node_module_version, etc.) still comes from the headers tarball; only host (build machine) fields are corrected.

Verification

  • All existing tests pass (npm test: 108 passing, 6 pending — unchanged from main).
  • Two new tests added in test/test-create-config-gypi.js covering the override behaviour and --force-process-config back-compat, with a new fixture test/fixtures/nodedir-mismatched-host/ that mimics a Linux x64 build farm headers tarball.
  • No-op verified on Linux x64 (all 7 host fields already match cache / process.config).
  • Necessary verified on macOS arm64 (all 7 fields mismatched).
  • npm run lint clean for changed files.

Open questions for maintainers

  1. Is the HOST_SPECIFIC_VARIABLES set complete? It was derived from a full diff on macOS arm64; would appreciate a sanity check on Windows arm64 / FreeBSD / AIX.
  2. Should an upstream fix in Node release engineering (ship platform-specific headers, or strip host-specific keys before packaging the universal tarball) take priority? That would fix every node-gyp version retroactively, but turnaround is much slower.

Related

Made with Cursor

The official Node release headers tarball is a single universal artifact
shipped to all platforms, but its embedded config.gypi reflects the build
host of the Node release-engineering machine (currently Linux x64 / GCC).
When a consumer on a different host inherits it verbatim via --disturl or
--nodedir (PR nodejs#2497), host-specific fields end up wrong:

  * host_arch is x64 even on arm64 hosts
  * clang is 0 even when the local toolchain is clang
  * llvm_version, xcode_version, arm_fpu, gas_version, shlib_suffix
    similarly reflect the build farm rather than the local host

The most visible symptom is on macOS arm64, where clang=0 silently
drops the `clang==1` branches in common.gypi (notably -std=gnu++20).
C++ compilation then falls back to C++03 and node-addon-api/napi.h
fails with "no template named initializer_list", "unknown type name
constexpr", etc.

Affected scope: anyone with disturl set in .npmrc or env (China mirrors
such as npmmirror/taobao, self-hosted Nexus/JFrog with disturl rewriting,
Electron projects via electron-rebuild). See electron/rebuild#1209 for
the original report.

Override only the host-specific variables from process.config after
parsing the headers' config.gypi. PR nodejs#2497's intent is preserved:
target build config (v8 features, bundled vs shared deps,
node_module_version, etc.) still comes from the headers tarball; only
host fields are corrected. Verified that the fix is a no-op on Linux
x64 (all 7 fields already match between cache and process.config) and
necessary on macOS arm64 (all 7 fields mismatched).

Refs: nodejs#2497, electron/rebuild#1209

Signed-off-by: iFwu <blanu@live.com>
Made-with: Cursor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant