Skip to content

macOS: gyp omits -isysroot when binding.gyp doesn't set SDKROOT, causing clang to resolve SDK via a path that ignores DEVELOPER_DIR/xcode-select #3344

Description

@solarispika

Environment

  • node-gyp version: 9.4.1
  • Node.js version: v20.18.1
  • OS: macOS 26 (Tahoe) 26.5.1
  • Xcode: 16.2.0 (Apple clang 16.0.0), xcode-select -p -> /Applications/Xcode-16.2.0.app/Contents/Developer
  • Command Line Tools: 26.6 (installed via Software Update, independent of Xcode.app)

Bug description

On macOS, node-gyp rebuild invokes clang++ without either -isysroot or --sdk. This makes the clang driver fall back to its own internal call to xcrun --show-sdk-path (with no --sdk argument). Verified via xcrun -v that this specific call variant resolves via a cache key hard-coded to /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -- independent of xcode-select/DEVELOPER_DIR, and independent of whichever Xcode toolchain actually supplies the invoked clang++ binary. (By contrast, xcrun --sdk macosx --show-sdk-path -- i.e. with an explicit SDK name -- does respect DEVELOPER_DIR/xcode-select.)

On systems where the OS has been updated (bumping the standalone CommandLineTools SDK) but the selected Xcode.app has not, this pairs a newer SDK's libc++ headers (which reference builtins like __builtin_ctzg/__builtin_clzg, requiring Clang >= 19) with an older embedded clang (16.0.0 from Xcode 16.2), producing:

error: use of undeclared identifier '__builtin_ctzg'

Root cause in gyp's own code

gyp/pylib/gyp/xcode_emulation.py already contains logic that avoids this, by explicitly naming the SDK when querying xcrun, and by passing -isysroot:

# GetSDKVersionInfoItem
return GetStdoutQuiet(["xcrun", "--sdk", sdk, infoitem])   # explicit --sdk, respects DEVELOPER_DIR

# GetCflags
if "SDKROOT" in self._Settings() and sdk_root:
    cflags.append("-isysroot %s" % sdk_root)               # only appended if SDKROOT is explicitly set in xcode_settings

(Line numbers 525 / 581-582 in the 9.4.1 tag I actually hit this on; confirmed the exact same structure -- same gating -- is still present at line 522 / 578-579 in the current latest release, v13.0.1, published 2026-07-02. Also checked that release's CHANGELOG for any macOS SDK/clang-related fix; found none.)

This mirrors what CMake does (Modules/Platform/Darwin-Initialize.cmake: xcrun --sdk macosx --show-sdk-path), which correctly resolves the SDK paired with the active developer directory, and does not hit this issue on the same machine/OS update.

However, -isysroot is only emitted if the target's binding.gyp (or a shared .gypi) sets SDKROOT under xcode_settings. Neither node-gyp's own addon.gypi, node's cached common.gypi, nor common third-party native modules (checked diskusage, better-sqlite3, node-pty) set SDKROOT. As a result, no -isysroot is passed for ordinary builds, and clang falls through to the SDK-resolution path described above.

Steps to reproduce

  1. On a Mac where the standalone CommandLineTools SDK has been updated (via Software Update) to a version requiring Clang >= 19 builtins, while xcode-select still points at an older Xcode with an older embedded clang.
  2. npm install / yarn install any package with a native addon (e.g. diskusage, better-sqlite3, node-pty).
  3. node-gyp rebuild fails with __builtin_ctzg/__builtin_clzg undeclared identifier errors, even though xcodebuild/CMake-based builds on the same machine succeed.

Expected behavior

The SDK-resolution path gyp uses by default (when SDKROOT is not explicitly configured) should pair the SDK with the actual compiler in use -- e.g. by always querying xcrun --sdk macosx --show-sdk-path instead of the no---sdk variant -- rather than relying on a system-wide default that can silently drift out of sync with the selected Xcode/CLT compiler.

Workaround (confirmed working)

Pin toolchain and SDK together, either direction:

DEVELOPER_DIR=/Library/Developer/CommandLineTools npm install   # newer clang + newer SDK, paired
SDKROOT=/Applications/Xcode-16.2.0.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.2.sdk npm install   # older clang + older SDK, paired

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions