Repository navigation
fix(llvm): the macOS cfg asks xcrun for the SDK before a fixed CommandLineTools path - #858
Merged
Merged
Conversation
…dLineTools path
__install_macosx_cfg wrote --sysroot into clang.cfg/clang++.cfg by checking a
fixed candidate list, /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
first, whenever SDKROOT was unset. On the GitHub xcode-27 runner image
(20260912+) that SDK's .tbd files list an arm64e.x1 architecture that
ld64.lld 22.1.8 cannot parse (llvm-project#222721 lands the support, after
22.1.8), so every link against a clang++ built from this cfg failed with:
ld64.lld: error: could not load TAPI file at
.../CommandLineTools/SDKs/MacOSX.sdk/usr/lib/libSystem.tbd: malformed file
This broke even mcpp's own raw-compile CI steps, which pass a working
`-isysroot $(xcrun --show-sdk-path)` on their own command line: on Darwin
-isysroot only redirects header search, not the linker's syslibroot, so it
cannot override a --sysroot baked into the driver's cfg file. mcpp worked
around this on its own compiles (mcpp#665) but had no way to reach into a
package it does not own.
Without this change, any consumer of the llvm package's clang++.cfg on a
host that has a working Xcode.app SDK *and* a broken CommandLineTools SDK
still gets the broken one, because the CommandLineTools path was checked
unconditionally before anything asked what the active developer directory
actually is.
Query `xcrun --show-sdk-path` (the same canonical probe mcpp's own SDK
selection tries first, modules/platform/src/macos/macos.cppm sdk_path())
before falling back to the fixed candidate list, which now only matters when
xcrun itself cannot answer.
Verified: this repo's static + isolation pytest suites (tests/l/test_llvm.py
and the full tests/ -m static run) pass unchanged, and the file still parses
under lua5.4. The macOS install/config path itself could not be exercised --
this machine is Linux and __install_macosx_cfg only runs on os.host() ==
"macosx".
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The mechanism
__install_macosx_cfg()inpkgs/l/llvm.luawrites a--sysroot=<path>lineinto the installed
clang.cfg/clang++.cfg. Until now, wheneverSDKROOTwas unset it picked the first directory that exists from a fixed list, with
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdkchecked before/Applications/Xcode.app/.../MacOSX.sdk. The Command Line Tools directoryexists on a stock runner/laptop, so that is what got baked in — even on a
machine whose
xcode-selectis pointed at a working Xcode.app SDK instead.On the GitHub
xcode-27runner image (2026-09-12+), that Command Line ToolsSDK's
.tbdfiles list anarm64e.x1architecture thatld64.lld22.1.8cannot parse (upstream support lands in llvm-project#222721, after 22.1.8),
so every link against a
clang++configured by this package failed with:Why a command-line
-isysrootdid not fix it. mcpp's own CI (PRmcpp-community/mcpp#665) worked around this for its own raw compiles by
passing
-isysroot $(xcrun --show-sdk-path)on the compiler command line.That did not help these two jobs, which had looked like proof the runner
image itself was simply broken. It is not: on Darwin,
-isysrootonlyredirects the header search path. The linker's syslibroot — which is what
decides which
.tbdgets opened — follows--sysroot, and--sysrootisexactly what this package's cfg file writes. A
--sysrootbaked intoclang++.cfgat install time wins over a command-line-isysrootforlinking, so mcpp's own fix could never reach a failure caused one layer
below it, in a package mcpp does not own.
The fix. Query
xcrun --show-sdk-path— the same canonical probe mcpp'sown SDK selection tries first (
modules/platform/src/macos/macos.cppm,sdk_path()) — after the existingSDKROOTenv check and before the fixedcandidate list, which now only runs when xcrun cannot answer (absent,
non-zero exit, empty output, or a path that does not actually exist —
__xcrun_sdk_path()checksos.isdiron what it gets back).Runner evidence xcrun answers correctly here. The same failing CI job's
own "System info" and "SDK mcpp selects" steps run
xcrun --show-sdk-pathon the exact
xcode-27image and print/Applications/Xcode_27_Release_Candidate.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk— a working SDK, not the Command Line Tools one (mcpp-community/mcpp run
35288886139). So
xcrunis not itself blind on this runner; only thispackage's own fixed-path preference was.
What I verified, and what I could not
I authored and tested this on Linux, where
__install_macosx_cfg()cannotrun (it only executes when
os.host() == "macosx"), so I personally neverwatched it choose a working sysroot on macOS. What closes that gap is this
PR's own CI, on real macOS runners (see below) — I did not have to assert
it worked, it's checked.
Before pushing, on Linux, I verified:
This repo's static + isolation pytest suites are unaffected:
pytest tests/ -m static(2612 passed, 14 skipped, unchanged) andpytest tests/l/test_llvm.py -m "static or isolation"(12 passed).The file still parses under
lua5.4 loadfile(...).The sysroot-selection logic itself, in isolation: I loaded the real,
unmodified
pkgs/l/llvm.luainto a Lua 5.4 harness that stubs only thexmake-provided globals (
path,pkginfo,log,xvm,import,os.isdir/os.host/os.tryrm/os.mv,io.writefile) and calls__install_macosx_cfg()directly, comparing its output against thepre-change version of the same function under matching fixtures:
xcrunonPATHand answering a real, existing directory → new codepicks that directory (the fix doing its job).
xcrunabsent, nothing exists anywhere (no Xcode at all) → byte-for-byte identical cfg output to the old code (no
--sysrootline, samewarning).
xcrunabsent, only the CommandLineTools path exists → identicalto the old code (CLT path chosen).
xcrunabsent, only the Xcode.app path exists → identical to theold code (Xcode.app path chosen).
xcrunpresent but prints an empty line (exit 0) → falls through tothe fixed candidate list, same as if xcrun were absent.
xcrunpresent but exits non-zero with no output → same fall-through.xcrunpresent but prints a path that does not exist (stale/bogusanswer) → rejected by the
os.isdircheck, same fall-through.SDKROOTenv var set → still wins over everything, unchanged.In short: a machine with no Xcode installed at all, or one where
xcruncannot answer for any reason, lands on exactly the cfg this package wrote
before this change. The only behavior that changes is the case where
xcruncan answer and its answer differs from the old fixed-path guess— which is precisely the runner where this bug shows up.
After pushing, this PR's own CI ran the real macOS install path and it
is green:
macos-install-test(.github/workflows/ci-test.yml,macos-latest)installs and uninstalls
xim:llvm@22.1.8for real viaxlings install,exercising
__install_macosx_cfg()on real macOS. It passed — no"SDK path not detected" warning appeared in the log, meaning the sysroot
selection resolved to something, and every post-install shim check
(
clang,lld, etc.) passed.consumer-smoke (macos-latest, macos)also passed.I corrected myself here: I originally wrote in this PR that I could not
find a macOS job in this repo's CI at all. That was wrong — I had only
looked at
ci-xpkg-test.yml, and the macOS legs live in a differentworkflow,
ci-test.yml. They exist and both ran clean on this branch.What this does NOT prove:
macos-latestis notxcode-27, so thisrun does not reproduce the broken-CLT-SDK runner itself, and the log does
not print which sysroot path
__install_macosx_cfg()actually chose (thejob installs then uninstalls in the same step, and nothing dumps
clang++.cfg's contents before removal). So this confirms the code pathruns cleanly end-to-end on real macOS and does not regress a normal
install — it does not, by itself, confirm the xcode-27 CLT-SDK bug is
gone. That confirmation is downstream, described next.
Where the real end-to-end confirmation comes from
mcpp resolves this package from
mainon every CI run(
.github/actions/setup-macos-llvm→xlings install llvm), so the actualproof this works is downstream: mcpp-community/mcpp's "macOS ARM64 — xlings
LLVM end-to-end (xcode-27)" and "e2e suite (macOS ARM64, self-host,
xcode-27)" jobs turning green on a rerun once this merges. Not requesting
merge in this PR — flagging for review first.