Skip to content

Commit 2c28d96

Browse files
committed
fix: disable LTO/ThinLTO via gyp -D flags for Node 26 Windows builds
The previous attempt at this fix (a222989) put `enable_lto: false` and `enable_thin_lto: false` in binding.gyp's `variables` block. That didn't actually work — node-gyp's create-config-gypi.js seeds config.gypi from `process.config` of the Node binary running the build, and the resulting config.gypi lives in a separate gyp scope from binding.gyp. binding.gyp variables can't override config.gypi variables that way. The real path: set npm_config_enable_thin_lto/enable_lto in the build environment. node-gyp loops through unrecognized npm_config_* opts and forwards them as `-D<name>=<value>` gyp defines, which take precedence over both config.gypi and binding.gyp. Wire that into scripts/ci/windows/build.ps1 so the build matrix runs are fixed. The binding.gyp change is reverted since it wasn't doing anything. This still leaves end-user source installs (e.g. consumers pnpm-adding node-libcurl on Node 26 Windows with no prebuilt available) broken — those users would need to set the same env vars themselves. A follow-up should set GYP_DEFINES from our preinstall script so the workaround applies transparently for them too.
1 parent a222989 commit 2c28d96

3 files changed

Lines changed: 21 additions & 17 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
99
### Breaking Change
1010

1111
### Fixed
12-
- Fixed Windows source builds against Node.js 26 failing with `LINK : fatal error LNK1117: syntax error in option 'opt:lldltojobs=2'`. Node 26 was built with clang-cl + lld + ThinLTO and its installed `common.gypi` propagates `enable_thin_lto=true` to downstream addons, which then appends `-flto=thin` to `cl.exe` and `/opt:lldltojobs=<n>` to `link.exe` — both invalid for the regular MSVC toolchain. Force `enable_lto` and `enable_thin_lto` off in `binding.gyp` so those conditions evaluate to false. Affects every consumer building node-libcurl from source on Windows + Node 26.
12+
- Fixed Windows source builds against Node.js 26 failing with `LINK : fatal error LNK1117: syntax error in option 'opt:lldltojobs=2'`. Node 26 was built with clang-cl + lld + ThinLTO (PR [nodejs/node#63114](https://github.com/nodejs/node/pull/63114), released in v26.3.0), and node-gyp's `create-config-gypi.js` seeds the addon's `config.gypi` from `process.config` of the running Node binary — picking up `enable_thin_lto: true` and `lto_jobs: <n>` from how Node itself was built. Node's installed `common.gypi` then unconditionally appends `-flto=thin` to MSVC `cl.exe`'s `AdditionalOptions` and `/opt:lldltojobs=<n>` to `link.exe`'s. MSVC ignores `-flto=thin` (warning) but rejects `/opt:lldltojobs=<n>` because `/OPT:` only accepts `REF/ICF/NOREF/NOICF/LBR/NOLBR`. Force them off via `npm_config_enable_thin_lto=false` + `npm_config_enable_lto=false` in the Windows build script, which node-gyp forwards as `-Denable_thin_lto=false` gyp defines (top precedence — `binding.gyp` `variables` don't override `config.gypi`'s, they're a separate gyp scope).
1313

1414
### Added
1515

binding.gyp

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,7 @@
1414
'node_libcurl_debug%': 'false',
1515
'node_libcurl_asan_debug%': 'false',
1616
'node_libcurl_cpp_std%': 'c++20',
17-
'macos_universal_build%': 'false',
18-
# Node.js 26 was built with clang-cl + lld and ThinLTO enabled, and
19-
# its installed common.gypi propagates `enable_thin_lto=true` to
20-
# downstream native addons. When the addon is then built with the
21-
# regular MSVC toolchain (the overwhelmingly common case for
22-
# consumers), the conditions inside common.gypi append `-flto=thin`
23-
# to cl.exe's AdditionalOptions and `/opt:lldltojobs=<n>` to
24-
# link.exe's AdditionalOptions. cl.exe warns and ignores `-flto=thin`,
25-
# but link.exe bails with `LNK1117: syntax error in option` on the
26-
# bogus `/OPT:lldltojobs=` value (link.exe's /OPT: only takes
27-
# REF/ICF/NOREF/NOICF/LBR/NOLBR). Force these off so the conditions
28-
# evaluate false and the flags are never emitted. Affects every
29-
# consumer trying to build node-libcurl from source against Node 26
30-
# on Windows; harmless everywhere else.
31-
'enable_lto': 'false',
32-
'enable_thin_lto': 'false',
17+
'macos_universal_build%': 'false'
3318
},
3419
'targets': [
3520
{

scripts/ci/windows/build.ps1

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,30 @@ $env:npm_config_dist_url = $dist_url
162162
$env:npm_config_target = $target
163163
$env:npm_config_node_gyp = $globalNodeGypPath
164164

165+
# Disable LTO/ThinLTO for the addon build. Node 26 ships with
166+
# enable_thin_lto=true baked into process.config because the Node binary
167+
# itself was built with clang-cl + lld + ThinLTO (PR nodejs/node#63114,
168+
# released in v26.3.0). node-gyp's create-config-gypi.js seeds config.gypi
169+
# from process.config when neither --nodedir nor --dist-url is set, so
170+
# common.gypi's `enable_thin_lto=="true"` conditions fire and emit
171+
# `-flto=thin` to cl.exe and `/opt:lldltojobs=<n>` to link.exe. Those are
172+
# clang-cl/lld-link flags; MSVC's cl.exe warns and ignores `-flto=thin`,
173+
# but link.exe rejects `/opt:lldltojobs=<n>` with `LNK1117` because
174+
# /OPT: only accepts REF/ICF/NOREF/NOICF/LBR/NOLBR.
175+
#
176+
# Setting npm_config_enable_thin_lto/enable_lto here makes node-gyp
177+
# forward them as `-Denable_thin_lto=false -Denable_lto=false` gyp
178+
# defines, which take precedence over config.gypi (binding.gyp variables
179+
# don't — they're a separate scope and lose to config.gypi).
180+
$env:npm_config_enable_thin_lto = "false"
181+
$env:npm_config_enable_lto = "false"
182+
165183
Write-Host "Build configuration:" -ForegroundColor Green
166184
Write-Host " npm_config_build_from_source: $env:npm_config_build_from_source" -ForegroundColor Cyan
167185
Write-Host " npm_config_runtime: $env:npm_config_runtime" -ForegroundColor Cyan
168186
Write-Host " npm_config_dist_url: $env:npm_config_dist_url" -ForegroundColor Cyan
169187
Write-Host " npm_config_target: $env:npm_config_target" -ForegroundColor Cyan
188+
Write-Host " npm_config_enable_thin_lto: $env:npm_config_enable_thin_lto" -ForegroundColor Cyan
170189

171190
# Install dependencies and build
172191
Write-Host "Installing dependencies..." -ForegroundColor Blue

0 commit comments

Comments
 (0)