fix(bazel): make the Bazel build work on macOS hosts - #409
Conversation
The Bazel build cannot link anything on macOS. `MODULE.bazel` pins
`llvm_version = "15.0.6"`, which predates the current macOS SDKs, and that
LLVM's `ld64.lld` cannot read their text-based `.tbd` stub libraries:
ld64.lld: error: MacOSX26.5.sdk/usr/lib/libSystem.tbd(libSystem.B.dylib)
is incompatible with arm64 (macOS)
This fails every Rust link, including `rules_rust`'s own `process_wrapper`
host tool, so the build dies before reaching any rust_icu or ICU code.
Switch from `llvm_version` to `llvm_versions`, which allows per-host
overrides. The `""` entry keeps 15.0.6 for every platform the presubmit
currently exercises, so the Linux CI toolchain is unchanged; only the two
Darwin hosts move to 21.1.8.
This is a prerequisite for google#405, not a complete fix. Two further macOS
blockers remain after this change:
* ICU's Darwin archiving invokes `libtool -static r -c`, which the
toolchain's `llvm-libtool-darwin` rejects with "unknown argument '-c'".
* `third_party/icu_*/icu.BUILD.bazel` hardcode `.so` names in
`out_shared_libs`; macOS produces `.dylib`.
Verified on macOS 26.5 / arm64: before this change `bazel build //...`
executed a single action before failing; after it, it clears all Rust
linking and proceeds to compiling ICU from source.
This commit was created by an automated coding assistant, with human
supervision.
Follows the LLVM toolchain fix in the previous commit with the remaining changes needed for `bazel build //...` and `bazel test //...` to work on macOS. Each is a place where the build assumed GNU/ELF conventions. * ICU archives static libraries with `$(AR) $(ARFLAGS) $(AR_OUTOPT)$@ $^` but never defines `AR_OUTOPT`, so the output name is passed positionally, as GNU `ar` expects. On Apple platforms rules_foreign_cc supplies `libtool` as AR, which requires an explicit `-o` and fails with "no output file (-o) specified". `config/mh-darwin` additionally does `ARFLAGS += -c`, appending to make's built-in `r`; both spellings are GNU ar-isms libtool rejects. Patch that single line to `ARFLAGS := -static -o` at fetch time. The fragment is read only on Darwin, so Linux is unaffected. * `out_shared_libs` named `.so` files, which do not exist on macOS. Select `.dylib` there. * rust_icu_ecma402 passed `-Wl,--whole-archive`, a GNU ld spelling that the Mach-O linker rejects. Select Apple's `-all_load` equivalent. The Linux behaviour of all three is unchanged: every `select()` keeps the existing value under `//conditions:default`, and the ICU patch touches a file only Darwin reads. Verified on macOS 26.5 / arm64 with the default ICU 74 backend: `bazel build //...` succeeds and `bazel test --jobs=1 --test_env=RUST_TEST_THREADS=1 //...` reports 26 of 26 tests passing. Note that `--config=icu_75`, `icu_76`, `icu_77` and `icu_tot` still fail, but for an unrelated and platform-independent reason: 26 BUILD.bazel files hardcode `RUST_ICU_MAJOR_VERSION_NUMBER` to "74", so renamed symbols are looked up with a `_74` suffix against a differently-versioned library. That is the subject of google#406 and is not addressed here. ICU 77 itself compiles cleanly on macOS with these changes. Progresses google#405. This commit was created by an automated coding assistant, with human supervision.
|
hm, I thought we had a macos builder running already, what gives? |
|
@filmil - There is one, but it's on the Cargo path, not the Bazel one. test.yml's test-static-linking job runs a [ubuntu-latest, macos-latest] matrix and calls make macos-test on the Mac, which is brew install icu4c + cargo test. That's green and has been for a while. bazel.yml is runs-on: ubuntu-latest, and its matrix only varies bazel_version — there's no macOS entry. So the Bazel build has never actually executed on a Mac, which is how these four issues accumulated:
Each one fully blocks the build, and each hid the next. I can add macos-latest to the bazel.yml matrix here so it stays fixed — that's the CI half of issue #405. |
|
I'm OK with this change, but we'll want to get a MacOS builder in. I distinctly remember working on the arch matrix for bazel builders recently, not sure where it went. (Still think it's better that someone who actually has a Mac work on MacOS builder.) |
Summary
The Bazel build currently cannot produce a single binary on macOS. This makes
bazel build //...andbazel test //...work there, which is a prerequisitefor #405.
Each change is a place where the build assumed GNU/ELF conventions. Linux
behaviour is unchanged throughout: every
select()keeps the existing valueunder
//conditions:default, and the ICU patch edits a file only Darwin reads.The four blockers
1. LLVM toolchain is too old for current macOS SDKs.
llvm_versionwaspinned to
15.0.6(2022). Itsld64.lldcannot read the.tbdstub librariesin a current SDK:
This kills every Rust link, including
rules_rust's ownprocess_wrapperhost tool, so the build died before reaching any rust_icu or ICU code. Switched
to
llvm_versions, whose""entry holds 15.0.6 for every platform thepresubmit exercises; only the two Darwin hosts move to 21.1.8.
2. ICU static archiving assumes GNU
ar. ICU archives with$(AR) $(ARFLAGS) $(AR_OUTOPT)$@ $^but never definesAR_OUTOPT, so theoutput name is passed positionally. On Apple platforms rules_foreign_cc supplies
libtoolas AR, which requires an explicit-oand fails withno output file (-o) specified.config/mh-darwinalso doesARFLAGS += -c,appending to make's built-in
r; both are GNU ar spellings libtool rejects.Patched that one line to
ARFLAGS := -static -oat fetch time.3.
out_shared_libsnamed.sofiles, which do not exist on macOS.Selected
.dylibthere.4.
-Wl,--whole-archiveinrust_icu_ecma402is a GNU ld spelling theMach-O linker rejects. Selected Apple's
-all_loadequivalent.Verification
On macOS 26.5 / arm64 with the default ICU 74 backend:
I have no Linux machine to verify against, so the Linux presubmit is the real
check there. The changes are structured so that path is untouched.
Out of scope
--config=icu_75,icu_76,icu_77andicu_totstill fail, but for anunrelated and platform-independent reason: 26
BUILD.bazelfiles hardcodeRUST_ICU_MAJOR_VERSION_NUMBERto"74", so renamed symbols are looked up witha
_74suffix against a differently-versioned library(
undefined symbol: utext_clone_74). This fails identically on Linux and is thesubject of #406. ICU 77 itself compiles cleanly on macOS with these changes.
One note for reviewers:
bazel run //:buildifierreformats ~30 furtherBUILD.bazelfiles by hoistingload()statements. That churn is unrelated tothis change, so I reverted it and kept the diff to the 8 files above.
Progresses #405.
This commit was created by an automated coding assistant, with human
supervision.