From d28bd03f63c3a0e832372301d011f7cbdb76e40e Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 16 Jun 2026 03:39:25 +0000 Subject: [PATCH 01/20] sysroot/compile: add macOS arm64 cross-compilation support Add repository rules and build scripts for cross-compiling to macOS arm64 from Linux x86_64: - sysroot.bzl: add `macos_sysroot` rule and `setup_macos_sysroot()` for macOS SDK sysroot (headers, frameworks, .tbd stubs) - libcxx_libs.bzl: add `libcxx_libs_darwin` rule and `setup_libcxx_libs_darwin()` for darwin libc++ (dylibs + __config_site) - versions.bzl: add placeholder hashes for macOS sysroot and darwin libcxx - build_macos_sysroot.sh: script to package macOS SDK from Xcode - build_libcxx_darwin.sh: script to build darwin libc++ from LLVM source The macOS SDK sysroot provides system headers and .tbd library stubs. The darwin libcxx provides libc++ dylibs and the __config_site header needed by the LLVM toolchain for cross-compilation. When hashes are empty (tarballs not yet built/uploaded), the rules generate fallback content: the sysroot creates an empty directory, and libcxx_libs generates __config_site from the Linux LLVM version. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Takeshi Yoneda --- bazel/compile/build_libcxx_darwin.sh | 104 +++++++++++++++++++ bazel/compile/libcxx_libs.bzl | 76 ++++++++++++++ bazel/sysroot/build_macos_sysroot.sh | 145 +++++++++++++++++++++++++++ bazel/sysroot/sysroot.bzl | 68 +++++++++++++ bazel/versions.bzl | 11 ++ 5 files changed, 404 insertions(+) create mode 100755 bazel/compile/build_libcxx_darwin.sh create mode 100755 bazel/sysroot/build_macos_sysroot.sh diff --git a/bazel/compile/build_libcxx_darwin.sh b/bazel/compile/build_libcxx_darwin.sh new file mode 100755 index 0000000000..35f3a934fe --- /dev/null +++ b/bazel/compile/build_libcxx_darwin.sh @@ -0,0 +1,104 @@ +#!/usr/bin/env bash + +# Build darwin arm64 libc++ cross-compilation libraries from an LLVM release. +# +# This produces a tarball containing: +# include/__config_site — darwin-specific libc++ configuration +# lib/libc++.1.dylib — libc++ dynamic library for darwin arm64 +# lib/libc++abi.1.0.dylib — libc++abi dynamic library for darwin arm64 +# +# Requirements: +# - A macOS SDK sysroot (from build_macos_sysroot.sh or Xcode) +# - cmake, ninja +# - clang with darwin target support (the hermetic LLVM works) +# +# Usage: +# ./build_libcxx_darwin.sh \ +# --llvm-source /path/to/llvm-project-source \ +# --sysroot /path/to/macos-sdk-sysroot \ +# --clang /path/to/clang \ +# --output libcxx-darwin-arm64.tar.xz + +set -e -o pipefail + +LLVM_SOURCE="" +SYSROOT="" +CLANG="" +OUTPUT="libcxx-darwin-arm64.tar.xz" +ARCH="arm64" + +usage() { + echo "Usage: $0 [options]" + echo "" + echo "Options:" + echo " --llvm-source DIR Path to LLVM monorepo source (containing libcxx/, libcxxabi/)" + echo " --sysroot DIR Path to macOS SDK sysroot" + echo " --clang PATH Path to clang binary (must support --target=aarch64-apple-macosx)" + echo " --output FILE Output tarball (default: libcxx-darwin-arm64.tar.xz)" + exit 1 +} + +while [[ $# -gt 0 ]]; do + case $1 in + --llvm-source) LLVM_SOURCE="$2"; shift 2 ;; + --sysroot) SYSROOT="$2"; shift 2 ;; + --clang) CLANG="$2"; shift 2 ;; + --output) OUTPUT="$2"; shift 2 ;; + --help|-h) usage ;; + *) echo "Unknown option: $1"; usage ;; + esac +done + +if [[ -z "$LLVM_SOURCE" ]] || [[ -z "$SYSROOT" ]] || [[ -z "$CLANG" ]]; then + echo "Error: --llvm-source, --sysroot, and --clang are required" + usage +fi + +WORK_DIR=$(mktemp -d) +trap 'rm -rf "$WORK_DIR"' EXIT + +BUILD_DIR="$WORK_DIR/build" +INSTALL_DIR="$WORK_DIR/install" +mkdir -p "$BUILD_DIR" "$INSTALL_DIR/include" "$INSTALL_DIR/lib" + +TARGET="aarch64-apple-macosx" + +echo "Building libc++ for darwin arm64..." +echo " LLVM source: $LLVM_SOURCE" +echo " Sysroot: $SYSROOT" +echo " Clang: $CLANG" + +cmake -G Ninja -S "$LLVM_SOURCE/runtimes" -B "$BUILD_DIR" \ + -DCMAKE_C_COMPILER="$CLANG" \ + -DCMAKE_CXX_COMPILER="$CLANG++" \ + -DCMAKE_C_COMPILER_TARGET="$TARGET" \ + -DCMAKE_CXX_COMPILER_TARGET="$TARGET" \ + -DCMAKE_SYSTEM_NAME=Darwin \ + -DCMAKE_SYSTEM_PROCESSOR=arm64 \ + -DCMAKE_OSX_ARCHITECTURES=arm64 \ + -DCMAKE_SYSROOT="$SYSROOT" \ + -DCMAKE_INSTALL_PREFIX="$INSTALL_DIR" \ + -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" \ + -DLIBCXX_ENABLE_SHARED=ON \ + -DLIBCXX_ENABLE_STATIC=OFF \ + -DLIBCXXABI_ENABLE_SHARED=ON \ + -DLIBCXXABI_ENABLE_STATIC=OFF \ + -DLIBCXX_CXX_ABI=libcxxabi \ + -DLIBCXX_USE_COMPILER_RT=ON \ + -DLIBCXXABI_USE_COMPILER_RT=ON \ + -DCMAKE_BUILD_TYPE=Release + +ninja -C "$BUILD_DIR" install-cxx install-cxxabi + +echo "Packaging..." +STAGING="$WORK_DIR/staging" +mkdir -p "$STAGING/include" "$STAGING/lib" + +cp "$INSTALL_DIR/include/c++/v1/__config_site" "$STAGING/include/" +find "$INSTALL_DIR/lib" -name "libc++*.dylib" -exec cp -a {} "$STAGING/lib/" \; + +tar -cJf "$OUTPUT" -C "$STAGING" . +SIZE=$(du -sh "$OUTPUT" | cut -f1) +echo "" +echo "Built: $OUTPUT ($SIZE)" +echo "SHA256: $(sha256sum "$OUTPUT" 2>/dev/null | cut -d' ' -f1 || shasum -a 256 "$OUTPUT" | cut -d' ' -f1)" diff --git a/bazel/compile/libcxx_libs.bzl b/bazel/compile/libcxx_libs.bzl index 859332cbf3..3f984761f5 100644 --- a/bazel/compile/libcxx_libs.bzl +++ b/bazel/compile/libcxx_libs.bzl @@ -55,6 +55,82 @@ libcxx_libs = repository_rule( doc = "Downloads prebuilt libcxx bundles for cross-compilation with toolchains_llvm", ) +def _libcxx_libs_darwin_impl(ctx): + """Implementation for darwin libcxx libs repository rule.""" + arch = ctx.attr.arch + + sha256 = ctx.attr.sha256 + if sha256: + ctx.download_and_extract( + url = "https://github.com/envoyproxy/toolshed/releases/download/bins-v{version}/libcxx-llvm{llvm_version}-darwin-{arch}.tar.xz".format( + arch = arch, + version = ctx.attr.version, + llvm_version = VERSIONS["llvm"], + ), + sha256 = sha256, + ) + else: + # No hash available yet — generate __config_site from the Linux version. + ctx.execute(["mkdir", "-p", "include", "lib"]) + linux_config_site = ctx.path(Label("@llvm_toolchain_llvm//:include/x86_64-unknown-linux-gnu/c++/v1/__config_site")) + ctx.execute(["cp", str(linux_config_site), "include/__config_site"]) + + ctx.file("BUILD.bazel", """ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "libcxx_libs_darwin_{arch}", + srcs = glob(["include/**", "lib/**"]), +) + +filegroup( + name = "headers", + srcs = glob(["include/**"]), +) + +filegroup( + name = "libs", + srcs = glob(["lib/**"]), +) + +""".format(arch = arch)) + +libcxx_libs_darwin = repository_rule( + implementation = _libcxx_libs_darwin_impl, + attrs = { + "version": attr.string( + mandatory = True, + doc = "Release version to download", + ), + "sha256": attr.string( + default = "", + doc = "SHA256 hash of the darwin libcxx archive. Empty string generates a fallback __config_site.", + ), + "arch": attr.string( + mandatory = True, + doc = "Architecture (aarch64)", + values = ["aarch64"], + ), + }, + doc = "Downloads prebuilt darwin libcxx for cross-compilation with toolchains_llvm", +) + +def setup_libcxx_libs_darwin( + aarch64_version = None, + aarch64_sha256 = None): + """Setup function for WORKSPACE. + + Creates @libcxx_libs_darwin_aarch64 repository. + """ + sha256 = aarch64_sha256 or VERSIONS.get("libcxx_libs_darwin_sha256", {}).get("aarch64", "") + if "libcxx_libs_darwin_aarch64" not in native.existing_rules(): + libcxx_libs_darwin( + name = "libcxx_libs_darwin_aarch64", + version = aarch64_version or VERSIONS["bins_release"], + sha256 = sha256, + arch = "aarch64", + ) + def setup_libcxx_libs( aarch64_version = None, aarch64_sha256 = None, diff --git a/bazel/sysroot/build_macos_sysroot.sh b/bazel/sysroot/build_macos_sysroot.sh new file mode 100755 index 0000000000..5e53282312 --- /dev/null +++ b/bazel/sysroot/build_macos_sysroot.sh @@ -0,0 +1,145 @@ +#!/usr/bin/env bash + +# Build a macOS SDK sysroot tarball for cross-compilation from Linux. +# +# Usage (on macOS): +# ./build_macos_sysroot.sh [--sdk-path /path/to/MacOSX.sdk] [--output sysroot-macos.tar.xz] +# +# The default SDK path is detected via `xcrun --show-sdk-path`. +# Output is a tarball suitable for use with the `macos_sysroot` Bazel repository rule. + +set -e -o pipefail + +SDK_PATH="" +OUTPUT="sysroot-macos-arm64.tar.xz" + +usage() { + echo "Usage: $0 [options]" + echo "" + echo "Options:" + echo " --sdk-path PATH Path to MacOSX.sdk (default: auto-detect via xcrun)" + echo " --output FILE Output tarball path (default: sysroot-macos-arm64.tar.xz)" + echo "" + echo "Examples:" + echo " # Auto-detect SDK on macOS" + echo " $0" + echo "" + echo " # Use a specific SDK" + echo " $0 --sdk-path /Library/Developer/CommandLineTools/SDKs/MacOSX15.0.sdk" + echo "" + echo " # Extract from Xcode" + echo " $0 --sdk-path /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk" + exit 1 +} + +while [[ $# -gt 0 ]]; do + case $1 in + --sdk-path) + SDK_PATH="$2" + shift 2 + ;; + --output) + OUTPUT="$2" + shift 2 + ;; + --help|-h) + usage + ;; + *) + echo "Unknown option: $1" + usage + ;; + esac +done + +if [[ -z "$SDK_PATH" ]]; then + if command -v xcrun &>/dev/null; then + SDK_PATH=$(xcrun --show-sdk-path --sdk macosx) + echo "Auto-detected SDK: $SDK_PATH" + else + echo "Error: --sdk-path required (xcrun not available)" + exit 1 + fi +fi + +if [[ ! -d "$SDK_PATH" ]]; then + echo "Error: SDK path does not exist: $SDK_PATH" + exit 1 +fi + +if [[ ! -f "$SDK_PATH/SDKSettings.json" ]] && [[ ! -f "$SDK_PATH/SDKSettings.plist" ]]; then + echo "Error: $SDK_PATH does not look like a macOS SDK (no SDKSettings found)" + exit 1 +fi + +echo "Building macOS sysroot from: $SDK_PATH" +echo "Output: $OUTPUT" + +WORK_DIR=$(mktemp -d) +trap 'rm -rf "$WORK_DIR"' EXIT + +SYSROOT="$WORK_DIR/sysroot" +mkdir -p "$SYSROOT" + +echo "Copying SDK headers..." +# System headers +if [[ -d "$SDK_PATH/usr/include" ]]; then + mkdir -p "$SYSROOT/usr" + cp -a "$SDK_PATH/usr/include" "$SYSROOT/usr/include" +fi + +echo "Copying library stubs (.tbd files)..." +# Library stubs — .tbd files are text-based stubs that tell the linker about symbols +if [[ -d "$SDK_PATH/usr/lib" ]]; then + mkdir -p "$SYSROOT/usr/lib" + find "$SDK_PATH/usr/lib" -name "*.tbd" -exec cp --parents -a {} "$SYSROOT/" \; 2>/dev/null || \ + find "$SDK_PATH/usr/lib" -name "*.tbd" | while read -r f; do + rel="${f#$SDK_PATH/}" + mkdir -p "$SYSROOT/$(dirname "$rel")" + cp -a "$f" "$SYSROOT/$rel" + done +fi + +echo "Copying frameworks..." +# Frameworks — headers and .tbd stubs +FRAMEWORKS_DIR="$SDK_PATH/System/Library/Frameworks" +if [[ -d "$FRAMEWORKS_DIR" ]]; then + mkdir -p "$SYSROOT/System/Library/Frameworks" + for fw in "$FRAMEWORKS_DIR"/*.framework; do + fw_name=$(basename "$fw") + mkdir -p "$SYSROOT/System/Library/Frameworks/$fw_name" + # Copy headers + if [[ -d "$fw/Headers" ]]; then + cp -a "$fw/Headers" "$SYSROOT/System/Library/Frameworks/$fw_name/" + fi + # Copy Modules (for module maps) + if [[ -d "$fw/Modules" ]]; then + cp -a "$fw/Modules" "$SYSROOT/System/Library/Frameworks/$fw_name/" + fi + # Copy .tbd files + find "$fw" -maxdepth 1 -name "*.tbd" -exec cp -a {} "$SYSROOT/System/Library/Frameworks/$fw_name/" \; 2>/dev/null || true + # Copy versioned .tbd files + if [[ -d "$fw/Versions" ]]; then + find "$fw/Versions" -name "*.tbd" | while read -r f; do + rel="${f#$SDK_PATH/}" + mkdir -p "$SYSROOT/$(dirname "$rel")" + cp -a "$f" "$SYSROOT/$rel" + done + fi + done +fi + +# SDK settings +for f in SDKSettings.json SDKSettings.plist; do + if [[ -f "$SDK_PATH/$f" ]]; then + cp -a "$SDK_PATH/$f" "$SYSROOT/" + fi +done + +echo "Packaging sysroot..." +tar -cJf "$OUTPUT" -C "$SYSROOT" . + +SIZE=$(du -sh "$OUTPUT" | cut -f1) +echo "" +echo "Successfully built macOS sysroot: $OUTPUT ($SIZE)" +echo "SHA256: $(sha256sum "$OUTPUT" | cut -d' ' -f1 2>/dev/null || shasum -a 256 "$OUTPUT" | cut -d' ' -f1)" diff --git a/bazel/sysroot/sysroot.bzl b/bazel/sysroot/sysroot.bzl index 545bf27b66..051e7cd5d2 100644 --- a/bazel/sysroot/sysroot.bzl +++ b/bazel/sysroot/sysroot.bzl @@ -156,6 +156,74 @@ def _get_sysroot_hash(glibc_version, stdcc_version, arch): return sha256 +_MACOS_SYSROOT_BUILD = """\ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "sysroot", + srcs = glob( + ["**"], + exclude = ["**/*:*"], + ), +) +""" + +def _macos_sysroot_impl(ctx): + """Implementation for macOS SDK sysroot repository rule.""" + if ctx.os.name.startswith("mac"): + # On macOS, no cross-compilation sysroot needed. + ctx.file("BUILD.bazel", _MACOS_SYSROOT_BUILD) + return + + sha256 = ctx.attr.sha256 + if sha256: + url = "https://github.com/envoyproxy/toolshed/releases/download/bins-v{version}/sysroot-macos-{arch}.tar.xz".format( + version = ctx.attr.version, + arch = ctx.attr.arch, + ) + ctx.download_and_extract( + url, + sha256 = sha256, + ) + else: + # No hash available yet — create an empty sysroot. + ctx.execute(["mkdir", "-p", "usr/include"]) + + ctx.file("BUILD.bazel", _MACOS_SYSROOT_BUILD) + +macos_sysroot = repository_rule( + implementation = _macos_sysroot_impl, + attrs = { + "version": attr.string( + mandatory = True, + doc = "Release version to download", + ), + "sha256": attr.string( + default = "", + doc = "SHA256 hash of the macOS sysroot archive. Empty string skips download.", + ), + "arch": attr.string( + default = "arm64", + doc = "Architecture (arm64)", + ), + }, + doc = "Downloads macOS SDK sysroot for cross-compilation from Linux", +) + +def setup_macos_sysroot(version = None): + """Set up macOS arm64 sysroot for cross-compilation. + + Creates @sysroot_macos_arm64 repository. + """ + sha256 = VERSIONS.get("macos_sysroot_sha256", {}).get("arm64", "") + if "sysroot_macos_arm64" not in native.existing_rules(): + macos_sysroot( + name = "sysroot_macos_arm64", + version = version or VERSIONS["bins_release"], + sha256 = sha256, + arch = "arm64", + ) + def setup_sysroots( version = None, glibc_version = "2.31", diff --git a/bazel/versions.bzl b/bazel/versions.bzl index 4df6126dbf..3262555354 100644 --- a/bazel/versions.bzl +++ b/bazel/versions.bzl @@ -39,6 +39,17 @@ VERSIONS = { "x86_64": "50c7385dd1c17fd3606fa8850cfb1c7d0166ab109e404964f55abd6b508560eb", }, + # Darwin libc++ cross-compilation libraries (built from LLVM source for macOS arm64) + # Contains include/__config_site and lib/libc++.dylib, lib/libc++abi.dylib + "libcxx_libs_darwin_sha256": { + "aarch64": "", # TODO: populate after building and uploading tarball + }, + + # macOS SDK sysroot for cross-compilation (headers, frameworks, .tbd stubs) + "macos_sysroot_sha256": { + "arm64": "", # TODO: populate after building and uploading tarball + }, + # Glint binary hashes by architecture "glint_sha256": { "amd64": "a9389398ba5719197f7c81e6a8127262095a1a5f1ea3a509f16c32bf4ee65719", From b08bda0173f464d6b47981ccd2f6013d2d31e295 Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 16 Jun 2026 03:44:50 +0000 Subject: [PATCH 02/20] ci: add macOS sysroot and darwin libcxx build job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a `build-macos-sysroot` job to the Bazel CI workflow that runs on `macos-14` and produces two artifacts: 1. `sysroot-macos-arm64.tar.xz` — macOS SDK sysroot extracted from the Xcode installation on the CI runner (headers, frameworks, .tbd stubs) 2. `libcxx-llvm18.1.8-darwin-aarch64.tar.xz` — libc++ built from LLVM source for darwin arm64 (dylibs + __config_site) These artifacts are needed for cross-compiling Envoy (and other C++ projects) from Linux x86_64 to macOS arm64. The Linux sysroots are built by debootstrap on Linux runners; the macOS sysroot requires a macOS runner with Xcode to extract Apple's SDK. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Takeshi Yoneda --- .github/workflows/_bazel.yml | 54 ++++++++++++++++++ .github/workflows/bazel.yml | 2 + bazel/sysroot/build_macos_sysroot_ci.sh | 74 +++++++++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100755 bazel/sysroot/build_macos_sysroot_ci.sh diff --git a/.github/workflows/_bazel.yml b/.github/workflows/_bazel.yml index 30b03d5e7b..08c296a178 100644 --- a/.github/workflows/_bazel.yml +++ b/.github/workflows/_bazel.yml @@ -180,6 +180,60 @@ jobs: //compile/test:cross_compile_aarch64_no_unwind_test working-directory: ${{ inputs.bazel-path }} + build-macos-sysroot: + if: inputs.action == 'build' && inputs.upload + runs-on: macos-14 + name: Build macOS sysroot + steps: + - name: Checkout Repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Build macOS arm64 sysroot + run: bash bazel/sysroot/build_macos_sysroot_ci.sh + - name: Build darwin libcxx + run: | + LLVM_VERSION=18.1.8 + SYSROOT=$(xcrun --show-sdk-path --sdk macosx) + + # Download LLVM source + curl -L -o /tmp/llvm-source.tar.xz \ + "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/llvm-project-${LLVM_VERSION}.src.tar.xz" + mkdir -p /tmp/llvm-source + tar -xf /tmp/llvm-source.tar.xz -C /tmp/llvm-source --strip-components=1 + + # Build libc++ for darwin arm64 + cmake -G Ninja -S /tmp/llvm-source/runtimes -B /tmp/libcxx-build \ + -DCMAKE_C_COMPILER=$(xcrun -f clang) \ + -DCMAKE_CXX_COMPILER=$(xcrun -f clang++) \ + -DCMAKE_OSX_ARCHITECTURES=arm64 \ + -DCMAKE_SYSROOT="$SYSROOT" \ + -DCMAKE_INSTALL_PREFIX=/tmp/libcxx-install \ + -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" \ + -DLIBCXX_ENABLE_SHARED=ON \ + -DLIBCXX_ENABLE_STATIC=OFF \ + -DLIBCXXABI_ENABLE_SHARED=ON \ + -DLIBCXXABI_ENABLE_STATIC=OFF \ + -DLIBCXX_CXX_ABI=libcxxabi \ + -DCMAKE_BUILD_TYPE=Release + + ninja -C /tmp/libcxx-build install-cxx install-cxxabi + + # Package + mkdir -p /tmp/libcxx-darwin/{include,lib} + cp /tmp/libcxx-install/include/c++/v1/__config_site /tmp/libcxx-darwin/include/ + cp -a /tmp/libcxx-install/lib/libc++*.dylib /tmp/libcxx-darwin/lib/ + tar -cJf libcxx-llvm${LLVM_VERSION}-darwin-aarch64.tar.xz -C /tmp/libcxx-darwin . + + SHA=$(shasum -a 256 libcxx-llvm${LLVM_VERSION}-darwin-aarch64.tar.xz | cut -d' ' -f1) + echo "SHA256: $SHA" + - name: Upload artifacts + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: macos-sysroot-artifacts + path: | + sysroot-macos-arm64.tar.xz + libcxx-llvm*-darwin-aarch64.tar.xz + retention-days: 30 + xcompile-arm-to-x86: if: inputs.action == 'test' runs-on: ubuntu-24.04-arm diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 1d81d386df..7e181e11ed 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -77,6 +77,8 @@ jobs: compile/msan-llvm18.1.8-x86_64.tar.xz compile/tsan-llvm18.1.8-x86_64.tar.xz sysroot/sysroot-*.tar.xz + # Note: macOS sysroot + darwin libcxx are built separately + # in the build-macos-sysroot job (runs on macos-14) bazel-args: >- --config=ci ${{ matrix.mode == 'bzlmod' diff --git a/bazel/sysroot/build_macos_sysroot_ci.sh b/bazel/sysroot/build_macos_sysroot_ci.sh new file mode 100755 index 0000000000..0e86d4e4a5 --- /dev/null +++ b/bazel/sysroot/build_macos_sysroot_ci.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash + +# Build a macOS SDK sysroot tarball for cross-compilation. +# Runs on macOS CI (GitHub Actions macos-14/15 runners have Xcode pre-installed). +# +# Output: sysroot-macos-arm64.tar.xz + +set -e -o pipefail + +SDK_PATH="${1:-$(xcrun --show-sdk-path --sdk macosx)}" +OUTPUT="${2:-sysroot-macos-arm64.tar.xz}" + +if [[ ! -d "$SDK_PATH" ]]; then + echo "Error: SDK path does not exist: $SDK_PATH" + exit 1 +fi + +echo "Building macOS sysroot from: $SDK_PATH" + +WORK_DIR=$(mktemp -d) +trap 'rm -rf "$WORK_DIR"' EXIT + +SYSROOT="$WORK_DIR/sysroot" +mkdir -p "$SYSROOT" + +# System headers +if [[ -d "$SDK_PATH/usr/include" ]]; then + mkdir -p "$SYSROOT/usr" + cp -a "$SDK_PATH/usr/include" "$SYSROOT/usr/include" +fi + +# Library stubs (.tbd files) +if [[ -d "$SDK_PATH/usr/lib" ]]; then + mkdir -p "$SYSROOT/usr/lib" + find "$SDK_PATH/usr/lib" -name "*.tbd" | while read -r f; do + rel="${f#"$SDK_PATH"/}" + mkdir -p "$SYSROOT/$(dirname "$rel")" + cp -a "$f" "$SYSROOT/$rel" + done +fi + +# Frameworks (headers + .tbd stubs) +FRAMEWORKS_DIR="$SDK_PATH/System/Library/Frameworks" +if [[ -d "$FRAMEWORKS_DIR" ]]; then + mkdir -p "$SYSROOT/System/Library/Frameworks" + for fw in "$FRAMEWORKS_DIR"/*.framework; do + fw_name=$(basename "$fw") + mkdir -p "$SYSROOT/System/Library/Frameworks/$fw_name" + [[ -d "$fw/Headers" ]] && cp -a "$fw/Headers" "$SYSROOT/System/Library/Frameworks/$fw_name/" + [[ -d "$fw/Modules" ]] && cp -a "$fw/Modules" "$SYSROOT/System/Library/Frameworks/$fw_name/" + find "$fw" -maxdepth 1 -name "*.tbd" -exec cp -a {} "$SYSROOT/System/Library/Frameworks/$fw_name/" \; 2>/dev/null || true + if [[ -d "$fw/Versions" ]]; then + find "$fw/Versions" -name "*.tbd" | while read -r f; do + rel="${f#"$SDK_PATH"/}" + mkdir -p "$SYSROOT/$(dirname "$rel")" + cp -a "$f" "$SYSROOT/$rel" + done + fi + done +fi + +# SDK settings +for f in SDKSettings.json SDKSettings.plist; do + [[ -f "$SDK_PATH/$f" ]] && cp -a "$SDK_PATH/$f" "$SYSROOT/" +done + +echo "Packaging sysroot..." +tar -cJf "$OUTPUT" -C "$SYSROOT" . + +SIZE=$(du -sh "$OUTPUT" | cut -f1) +SHA=$(shasum -a 256 "$OUTPUT" | cut -d' ' -f1) +echo "" +echo "Built: $OUTPUT ($SIZE)" +echo "SHA256: $SHA" From fa34f54dc52d6b65d6ca91f69cb9034afa8e2bd7 Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 16 Jun 2026 14:53:34 +0000 Subject: [PATCH 03/20] fix: shellcheck errors and cmake libunwind dependency - Fix shellcheck SC2295: quote expansions inside ${..} in sysroot scripts - Fix shellcheck SC2034: remove unused ARCH variable in libcxx script - Fix cmake error: add libunwind to LLVM_ENABLE_RUNTIMES and set LIBCXXABI_USE_LLVM_UNWINDER=ON (required by libcxxabi) Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Takeshi Yoneda --- .github/workflows/_bazel.yml | 3 ++- bazel/compile/build_libcxx_darwin.sh | 4 ++-- bazel/sysroot/build_macos_sysroot.sh | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/_bazel.yml b/.github/workflows/_bazel.yml index 08c296a178..80fa7235e8 100644 --- a/.github/workflows/_bazel.yml +++ b/.github/workflows/_bazel.yml @@ -207,12 +207,13 @@ jobs: -DCMAKE_OSX_ARCHITECTURES=arm64 \ -DCMAKE_SYSROOT="$SYSROOT" \ -DCMAKE_INSTALL_PREFIX=/tmp/libcxx-install \ - -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" \ + -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \ -DLIBCXX_ENABLE_SHARED=ON \ -DLIBCXX_ENABLE_STATIC=OFF \ -DLIBCXXABI_ENABLE_SHARED=ON \ -DLIBCXXABI_ENABLE_STATIC=OFF \ -DLIBCXX_CXX_ABI=libcxxabi \ + -DLIBCXXABI_USE_LLVM_UNWINDER=ON \ -DCMAKE_BUILD_TYPE=Release ninja -C /tmp/libcxx-build install-cxx install-cxxabi diff --git a/bazel/compile/build_libcxx_darwin.sh b/bazel/compile/build_libcxx_darwin.sh index 35f3a934fe..fc85e0c967 100755 --- a/bazel/compile/build_libcxx_darwin.sh +++ b/bazel/compile/build_libcxx_darwin.sh @@ -25,7 +25,6 @@ LLVM_SOURCE="" SYSROOT="" CLANG="" OUTPUT="libcxx-darwin-arm64.tar.xz" -ARCH="arm64" usage() { echo "Usage: $0 [options]" @@ -78,12 +77,13 @@ cmake -G Ninja -S "$LLVM_SOURCE/runtimes" -B "$BUILD_DIR" \ -DCMAKE_OSX_ARCHITECTURES=arm64 \ -DCMAKE_SYSROOT="$SYSROOT" \ -DCMAKE_INSTALL_PREFIX="$INSTALL_DIR" \ - -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" \ + -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \ -DLIBCXX_ENABLE_SHARED=ON \ -DLIBCXX_ENABLE_STATIC=OFF \ -DLIBCXXABI_ENABLE_SHARED=ON \ -DLIBCXXABI_ENABLE_STATIC=OFF \ -DLIBCXX_CXX_ABI=libcxxabi \ + -DLIBCXXABI_USE_LLVM_UNWINDER=ON \ -DLIBCXX_USE_COMPILER_RT=ON \ -DLIBCXXABI_USE_COMPILER_RT=ON \ -DCMAKE_BUILD_TYPE=Release diff --git a/bazel/sysroot/build_macos_sysroot.sh b/bazel/sysroot/build_macos_sysroot.sh index 5e53282312..484505cd3c 100755 --- a/bazel/sysroot/build_macos_sysroot.sh +++ b/bazel/sysroot/build_macos_sysroot.sh @@ -94,7 +94,7 @@ if [[ -d "$SDK_PATH/usr/lib" ]]; then mkdir -p "$SYSROOT/usr/lib" find "$SDK_PATH/usr/lib" -name "*.tbd" -exec cp --parents -a {} "$SYSROOT/" \; 2>/dev/null || \ find "$SDK_PATH/usr/lib" -name "*.tbd" | while read -r f; do - rel="${f#$SDK_PATH/}" + rel="${f#"$SDK_PATH"/}" mkdir -p "$SYSROOT/$(dirname "$rel")" cp -a "$f" "$SYSROOT/$rel" done @@ -121,7 +121,7 @@ if [[ -d "$FRAMEWORKS_DIR" ]]; then # Copy versioned .tbd files if [[ -d "$fw/Versions" ]]; then find "$fw/Versions" -name "*.tbd" | while read -r f; do - rel="${f#$SDK_PATH/}" + rel="${f#"$SDK_PATH"/}" mkdir -p "$SYSROOT/$(dirname "$rel")" cp -a "$f" "$SYSROOT/$rel" done From 95f77ce17fe2e21b254d39200ac820cbab7fac5c Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 16 Jun 2026 15:13:20 +0000 Subject: [PATCH 04/20] fix: copy versioned framework headers in macOS sysroot Some frameworks (e.g., SystemConfiguration) have headers under Versions/A/Headers/ instead of just Headers/. Copy the full framework structure including versioned directories so clang can find all headers. Signed-off-by: Takeshi Yoneda Co-Authored-By: Claude Opus 4.6 (1M context) --- bazel/sysroot/build_macos_sysroot_ci.sh | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/bazel/sysroot/build_macos_sysroot_ci.sh b/bazel/sysroot/build_macos_sysroot_ci.sh index 0e86d4e4a5..c79cc60455 100755 --- a/bazel/sysroot/build_macos_sysroot_ci.sh +++ b/bazel/sysroot/build_macos_sysroot_ci.sh @@ -46,16 +46,17 @@ if [[ -d "$FRAMEWORKS_DIR" ]]; then for fw in "$FRAMEWORKS_DIR"/*.framework; do fw_name=$(basename "$fw") mkdir -p "$SYSROOT/System/Library/Frameworks/$fw_name" - [[ -d "$fw/Headers" ]] && cp -a "$fw/Headers" "$SYSROOT/System/Library/Frameworks/$fw_name/" - [[ -d "$fw/Modules" ]] && cp -a "$fw/Modules" "$SYSROOT/System/Library/Frameworks/$fw_name/" - find "$fw" -maxdepth 1 -name "*.tbd" -exec cp -a {} "$SYSROOT/System/Library/Frameworks/$fw_name/" \; 2>/dev/null || true - if [[ -d "$fw/Versions" ]]; then - find "$fw/Versions" -name "*.tbd" | while read -r f; do - rel="${f#"$SDK_PATH"/}" + # Copy the entire framework structure (Headers, Modules, .tbd, Versions/) + # preserving the layout so clang can find versioned headers. + find "$fw" \( -name "Headers" -type d -o -name "Modules" -type d -o -name "*.tbd" \) -print0 | while IFS= read -r -d '' item; do + rel="${item#"$SDK_PATH"/}" + if [[ -d "$item" ]]; then + cp -a "$item" "$SYSROOT/$rel" + else mkdir -p "$SYSROOT/$(dirname "$rel")" - cp -a "$f" "$SYSROOT/$rel" - done - fi + cp -a "$item" "$SYSROOT/$rel" + fi + done done fi From 1af05c5b9aa5bb8743b68fe4493225a6f75efc64 Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 16 Jun 2026 15:33:52 +0000 Subject: [PATCH 05/20] fix: create parent dirs before copying framework contents macOS `cp -a` requires the parent directory to exist. Create it with mkdir -p before copying Headers/Modules directories. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Takeshi Yoneda --- bazel/sysroot/build_macos_sysroot_ci.sh | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/bazel/sysroot/build_macos_sysroot_ci.sh b/bazel/sysroot/build_macos_sysroot_ci.sh index c79cc60455..d1cef24358 100755 --- a/bazel/sysroot/build_macos_sysroot_ci.sh +++ b/bazel/sysroot/build_macos_sysroot_ci.sh @@ -48,14 +48,10 @@ if [[ -d "$FRAMEWORKS_DIR" ]]; then mkdir -p "$SYSROOT/System/Library/Frameworks/$fw_name" # Copy the entire framework structure (Headers, Modules, .tbd, Versions/) # preserving the layout so clang can find versioned headers. - find "$fw" \( -name "Headers" -type d -o -name "Modules" -type d -o -name "*.tbd" \) -print0 | while IFS= read -r -d '' item; do + find "$fw" \( -name "Headers" -type d -o -name "Modules" -type d -o -name "*.tbd" \) | while IFS= read -r item; do rel="${item#"$SDK_PATH"/}" - if [[ -d "$item" ]]; then - cp -a "$item" "$SYSROOT/$rel" - else - mkdir -p "$SYSROOT/$(dirname "$rel")" - cp -a "$item" "$SYSROOT/$rel" - fi + mkdir -p "$(dirname "$SYSROOT/$rel")" + cp -a "$item" "$SYSROOT/$rel" done done fi From b243d413fb37974bdc19cc69be6f2b069d2bf031 Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 16 Jun 2026 15:37:51 +0000 Subject: [PATCH 06/20] fix: remove circular symlinks from macOS sysroot Ruby.framework contains self-referencing symlinks (ruby -> .) that cause infinite recursion during Bazel's glob expansion. Remove these circular symlinks before packaging. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Takeshi Yoneda --- bazel/sysroot/build_macos_sysroot_ci.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bazel/sysroot/build_macos_sysroot_ci.sh b/bazel/sysroot/build_macos_sysroot_ci.sh index d1cef24358..70fd85ddcc 100755 --- a/bazel/sysroot/build_macos_sysroot_ci.sh +++ b/bazel/sysroot/build_macos_sysroot_ci.sh @@ -61,6 +61,15 @@ for f in SDKSettings.json SDKSettings.plist; do [[ -f "$SDK_PATH/$f" ]] && cp -a "$SDK_PATH/$f" "$SYSROOT/" done +# Remove circular symlinks (e.g., Ruby.framework/Versions/2.6/Headers/ruby/ruby -> .) +echo "Removing circular symlinks..." +find "$SYSROOT" -type l | while read -r link; do + target=$(readlink "$link") + if [[ "$target" == "." || "$target" == ".." ]]; then + rm "$link" + fi +done + echo "Packaging sysroot..." tar -cJf "$OUTPUT" -C "$SYSROOT" . From 064d6913158e7c0c92706342fdcd7e0ea69ba1f5 Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 16 Jun 2026 15:51:08 +0000 Subject: [PATCH 07/20] fix: copy entire framework directories to preserve symlink structure Selectively copying Headers/Modules/tbd from frameworks breaks clang's framework header lookup, which depends on symlinks like: Headers -> Versions/Current/Headers Versions/Current -> A SDK frameworks contain only headers, modules, and .tbd stubs (no large binaries), so copying the entire directory is safe and correct. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Takeshi Yoneda --- bazel/sysroot/build_macos_sysroot_ci.sh | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/bazel/sysroot/build_macos_sysroot_ci.sh b/bazel/sysroot/build_macos_sysroot_ci.sh index 70fd85ddcc..70d79aba22 100755 --- a/bazel/sysroot/build_macos_sysroot_ci.sh +++ b/bazel/sysroot/build_macos_sysroot_ci.sh @@ -39,21 +39,13 @@ if [[ -d "$SDK_PATH/usr/lib" ]]; then done fi -# Frameworks (headers + .tbd stubs) -FRAMEWORKS_DIR="$SDK_PATH/System/Library/Frameworks" -if [[ -d "$FRAMEWORKS_DIR" ]]; then - mkdir -p "$SYSROOT/System/Library/Frameworks" - for fw in "$FRAMEWORKS_DIR"/*.framework; do - fw_name=$(basename "$fw") - mkdir -p "$SYSROOT/System/Library/Frameworks/$fw_name" - # Copy the entire framework structure (Headers, Modules, .tbd, Versions/) - # preserving the layout so clang can find versioned headers. - find "$fw" \( -name "Headers" -type d -o -name "Modules" -type d -o -name "*.tbd" \) | while IFS= read -r item; do - rel="${item#"$SDK_PATH"/}" - mkdir -p "$(dirname "$SYSROOT/$rel")" - cp -a "$item" "$SYSROOT/$rel" - done - done +# Frameworks — copy entire directory. SDK frameworks contain only headers, +# modules, .tbd stubs, and symlinks (no large binaries). Preserving the +# complete structure is essential because clang's framework header lookup +# depends on symlinks like Headers -> Versions/Current/Headers. +if [[ -d "$SDK_PATH/System/Library/Frameworks" ]]; then + mkdir -p "$SYSROOT/System/Library" + cp -a "$SDK_PATH/System/Library/Frameworks" "$SYSROOT/System/Library/" fi # SDK settings From e6a3ecc58ce55c04a1ccde81bf639527f3f4261e Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 16 Jun 2026 16:22:56 +0000 Subject: [PATCH 08/20] fix: patch libc++ install names to use /usr/lib/ instead of @rpath/ Without this, binaries linked against the cross-compiled libc++ fail at runtime with "no LC_RPATH's found" because the dylib install name is @rpath/libc++.1.dylib. macOS ships libc++ at /usr/lib/libc++.1.dylib, so patching the install names makes binaries use the system library. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Takeshi Yoneda --- .github/workflows/_bazel.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/_bazel.yml b/.github/workflows/_bazel.yml index 80fa7235e8..88b609dc5c 100644 --- a/.github/workflows/_bazel.yml +++ b/.github/workflows/_bazel.yml @@ -222,6 +222,12 @@ jobs: mkdir -p /tmp/libcxx-darwin/{include,lib} cp /tmp/libcxx-install/include/c++/v1/__config_site /tmp/libcxx-darwin/include/ cp -a /tmp/libcxx-install/lib/libc++*.dylib /tmp/libcxx-darwin/lib/ + + # Patch install names so binaries link against /usr/lib/ (system libc++) + # instead of @rpath/ which requires LC_RPATH entries at runtime. + install_name_tool -id /usr/lib/libc++.1.dylib /tmp/libcxx-darwin/lib/libc++.1.dylib + install_name_tool -id /usr/lib/libc++abi.dylib /tmp/libcxx-darwin/lib/libc++abi.1.dylib + tar -cJf libcxx-llvm${LLVM_VERSION}-darwin-aarch64.tar.xz -C /tmp/libcxx-darwin . SHA=$(shasum -a 256 libcxx-llvm${LLVM_VERSION}-darwin-aarch64.tar.xz | cut -d' ' -f1) From e983b8a2e39b96487ec500df88a78ab01eb5fc30 Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 16 Jun 2026 16:27:24 +0000 Subject: [PATCH 09/20] ci: build macOS artifacts on Linux from Apple CDN + LLVM releases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the macos-14 runner approach with a fully Linux-based build: Sysroot: Download Apple's CLTools SDK package from their public CDN (swcdn.apple.com, no auth required) and extract on Linux using cerisier/pkgutil. A manifest file selects only the needed files (headers, .tbd stubs, 6 frameworks). Result: ~6MB vs 205MB. Libcxx: Extract __config_site and libc++ dylibs directly from the official LLVM macOS-ARM64 release tarball — no cmake build needed. Patch install names from @rpath/ to /usr/lib/ so binaries use the system libc++ at runtime. Benefits: - No macOS runner needed (cheaper, faster) - Deterministic (pinned URLs + SHA256 checksums) - Minimal sysroot (only files needed for cross-compilation) Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Takeshi Yoneda --- .github/workflows/_bazel.yml | 106 ++++++++++++++-------- bazel/sysroot/manifests/sysroot-macos.txt | 22 +++++ 2 files changed, 89 insertions(+), 39 deletions(-) create mode 100644 bazel/sysroot/manifests/sysroot-macos.txt diff --git a/.github/workflows/_bazel.yml b/.github/workflows/_bazel.yml index 88b609dc5c..e0c8998c05 100644 --- a/.github/workflows/_bazel.yml +++ b/.github/workflows/_bazel.yml @@ -180,58 +180,86 @@ jobs: //compile/test:cross_compile_aarch64_no_unwind_test working-directory: ${{ inputs.bazel-path }} - build-macos-sysroot: + build-macos-artifacts: if: inputs.action == 'build' && inputs.upload - runs-on: macos-14 - name: Build macOS sysroot + runs-on: ubuntu-24.04 + name: Build macOS cross-compilation artifacts + env: + LLVM_VERSION: "18.1.8" + LLVM_MAJOR: "18" + # Apple CLTools SDK package URL (from Apple's public software update catalog) + SDK_PKG_URL: "https://swcdn.apple.com/content/downloads/52/01/082-41241-A_0747ZN8FHV/dectd075r63pppkkzsb75qk61s0lfee22j/CLTools_macOSNMOS_SDK.pkg" + SDK_PKG_SHA256: "ba3453d62b3d2babf67f3a4a44e8073d6555c85f114856f4390a1f53bd76e24a" + # pkgutil: extracts macOS .pkg files on Linux + PKGUTIL_URL: "https://github.com/cerisier/pkgutil/releases/download/v1.2.0/pkgutil_linux_amd64" + PKGUTIL_SHA256: "3bcf79dbec6b7858ca0c1b6db03952ac122501a74073bac186c8080fcfb391fd" + SDK_PREFIX: "Payload/Library/Developer/CommandLineTools/SDKs/MacOSX15.5.sdk" steps: - name: Checkout Repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Build macOS arm64 sysroot - run: bash bazel/sysroot/build_macos_sysroot_ci.sh - - name: Build darwin libcxx run: | - LLVM_VERSION=18.1.8 - SYSROOT=$(xcrun --show-sdk-path --sdk macosx) + set -euo pipefail + + # Download pkgutil (extracts macOS .pkg on Linux) + wget -q "$PKGUTIL_URL" -O pkgutil + echo "${PKGUTIL_SHA256} pkgutil" | sha256sum -c - + chmod +x pkgutil + + # Download Apple CLTools SDK package + wget -q "$SDK_PKG_URL" -O CLTools_macOSNMOS_SDK.pkg + echo "${SDK_PKG_SHA256} CLTools_macOSNMOS_SDK.pkg" | sha256sum -c - + + # Extract only the files we need from the SDK package + mkdir -p out/macos_arm64 + includes=() + while IFS=$'\n' read -r line; do + includes+=("--include" "${SDK_PREFIX}/${line}") + done < bazel/sysroot/manifests/sysroot-macos.txt + ./pkgutil "${includes[@]}" --strip-components 6 --expand-full CLTools_macOSNMOS_SDK.pkg out/macos_arm64 + + tar -cf sysroot-macos-arm64.tar -C out/ macos_arm64 + zstd -T0 --long -10 --rm sysroot-macos-arm64.tar + # Also create .tar.xz for compatibility with existing toolshed patterns + tar -cJf sysroot-macos-arm64.tar.xz -C out/ macos_arm64 + + echo "Sysroot size: $(du -sh sysroot-macos-arm64.tar.xz | cut -f1)" + sha256sum sysroot-macos-arm64.tar.xz + - name: Build darwin libcxx cross-compilation libs + run: | + set -euo pipefail - # Download LLVM source - curl -L -o /tmp/llvm-source.tar.xz \ - "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/llvm-project-${LLVM_VERSION}.src.tar.xz" - mkdir -p /tmp/llvm-source - tar -xf /tmp/llvm-source.tar.xz -C /tmp/llvm-source --strip-components=1 + # Extract cxx-cross-libs from official LLVM macOS release (no cmake build needed) + wget -q "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/LLVM-${LLVM_VERSION}-macOS-ARM64.tar.xz" \ + -O llvm-macos.tar.xz - # Build libc++ for darwin arm64 - cmake -G Ninja -S /tmp/llvm-source/runtimes -B /tmp/libcxx-build \ - -DCMAKE_C_COMPILER=$(xcrun -f clang) \ - -DCMAKE_CXX_COMPILER=$(xcrun -f clang++) \ - -DCMAKE_OSX_ARCHITECTURES=arm64 \ - -DCMAKE_SYSROOT="$SYSROOT" \ - -DCMAKE_INSTALL_PREFIX=/tmp/libcxx-install \ - -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \ - -DLIBCXX_ENABLE_SHARED=ON \ - -DLIBCXX_ENABLE_STATIC=OFF \ - -DLIBCXXABI_ENABLE_SHARED=ON \ - -DLIBCXXABI_ENABLE_STATIC=OFF \ - -DLIBCXX_CXX_ABI=libcxxabi \ - -DLIBCXXABI_USE_LLVM_UNWINDER=ON \ - -DCMAKE_BUILD_TYPE=Release + LLVM_PREFIX="LLVM-${LLVM_VERSION}-macOS-ARM64" - ninja -C /tmp/libcxx-build install-cxx install-cxxabi + # Extract only the files we need + tar -xf llvm-macos.tar.xz \ + "${LLVM_PREFIX}/include/c++/v1/__config_site" \ + "${LLVM_PREFIX}/lib/libc++.1.0.dylib" \ + "${LLVM_PREFIX}/lib/libc++.1.dylib" \ + "${LLVM_PREFIX}/lib/libc++.dylib" \ + "${LLVM_PREFIX}/lib/libc++abi.1.0.dylib" \ + "${LLVM_PREFIX}/lib/libc++abi.1.dylib" \ + "${LLVM_PREFIX}/lib/libc++abi.dylib" - # Package - mkdir -p /tmp/libcxx-darwin/{include,lib} - cp /tmp/libcxx-install/include/c++/v1/__config_site /tmp/libcxx-darwin/include/ - cp -a /tmp/libcxx-install/lib/libc++*.dylib /tmp/libcxx-darwin/lib/ + mkdir -p libcxx-darwin/{include,lib} + cp "${LLVM_PREFIX}/include/c++/v1/__config_site" libcxx-darwin/include/ + cp -a "${LLVM_PREFIX}/lib/libc++"*.dylib libcxx-darwin/lib/ - # Patch install names so binaries link against /usr/lib/ (system libc++) - # instead of @rpath/ which requires LC_RPATH entries at runtime. - install_name_tool -id /usr/lib/libc++.1.dylib /tmp/libcxx-darwin/lib/libc++.1.dylib - install_name_tool -id /usr/lib/libc++abi.dylib /tmp/libcxx-darwin/lib/libc++abi.1.dylib + # Patch install names: @rpath/ -> /usr/lib/ so binaries use system libc++ at runtime + INSTALL_NAME_TOOL="${LLVM_PREFIX}/bin/llvm-install-name-tool" + tar -xf llvm-macos.tar.xz "${INSTALL_NAME_TOOL}" + chmod +x "${INSTALL_NAME_TOOL}" + "${INSTALL_NAME_TOOL}" -id /usr/lib/libc++.1.dylib libcxx-darwin/lib/libc++.1.dylib + "${INSTALL_NAME_TOOL}" -id /usr/lib/libc++abi.dylib libcxx-darwin/lib/libc++abi.1.dylib - tar -cJf libcxx-llvm${LLVM_VERSION}-darwin-aarch64.tar.xz -C /tmp/libcxx-darwin . + tar -cJf "libcxx-llvm${LLVM_VERSION}-darwin-aarch64.tar.xz" -C libcxx-darwin . - SHA=$(shasum -a 256 libcxx-llvm${LLVM_VERSION}-darwin-aarch64.tar.xz | cut -d' ' -f1) - echo "SHA256: $SHA" + echo "Libcxx size: $(du -sh "libcxx-llvm${LLVM_VERSION}-darwin-aarch64.tar.xz" | cut -f1)" + sha256sum "libcxx-llvm${LLVM_VERSION}-darwin-aarch64.tar.xz" - name: Upload artifacts uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: diff --git a/bazel/sysroot/manifests/sysroot-macos.txt b/bazel/sysroot/manifests/sysroot-macos.txt new file mode 100644 index 0000000000..efebd71398 --- /dev/null +++ b/bazel/sysroot/manifests/sysroot-macos.txt @@ -0,0 +1,22 @@ +usr/include/* +usr/lib/libc.tbd +usr/lib/libcharset* +usr/lib/libdl* +usr/lib/libiconv* +usr/lib/libm.tbd +usr/lib/libobjc* +usr/lib/libresolv* +usr/lib/libpthread.tbd +usr/lib/libSystem* +System/Library/Frameworks/CoreFoundation.framework/* +System/Library/PrivateFrameworks/CoreFoundation.framework/* +System/Library/Frameworks/Foundation.framework/* +System/Library/PrivateFrameworks/Foundation.framework/* +System/Library/Frameworks/Kernel.framework/* +System/Library/PrivateFrameworks/Kernel.framework/* +System/Library/Frameworks/OSLog.framework/* +System/Library/PrivateFrameworks/OSLog.framework/* +System/Library/Frameworks/Security.framework/* +System/Library/PrivateFrameworks/Security.framework/* +System/Library/Frameworks/SystemConfiguration.framework/* +System/Library/PrivateFrameworks/SystemConfiguration.framework/* From c30d5772efb46136f347d4ad95fe6b034ac8c561 Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 16 Jun 2026 16:49:50 +0000 Subject: [PATCH 10/20] fix: add user-agent for Apple CDN download, fix comment Apple's CDN may reject requests without a browser user-agent. Also fix stale comment referencing macos-14 runner. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Takeshi Yoneda --- .github/workflows/_bazel.yml | 4 ++-- .github/workflows/bazel.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/_bazel.yml b/.github/workflows/_bazel.yml index e0c8998c05..59127deac9 100644 --- a/.github/workflows/_bazel.yml +++ b/.github/workflows/_bazel.yml @@ -202,12 +202,12 @@ jobs: set -euo pipefail # Download pkgutil (extracts macOS .pkg on Linux) - wget -q "$PKGUTIL_URL" -O pkgutil + wget "$PKGUTIL_URL" -O pkgutil echo "${PKGUTIL_SHA256} pkgutil" | sha256sum -c - chmod +x pkgutil # Download Apple CLTools SDK package - wget -q "$SDK_PKG_URL" -O CLTools_macOSNMOS_SDK.pkg + wget --user-agent="Mozilla/5.0" "$SDK_PKG_URL" -O CLTools_macOSNMOS_SDK.pkg echo "${SDK_PKG_SHA256} CLTools_macOSNMOS_SDK.pkg" | sha256sum -c - # Extract only the files we need from the SDK package diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 7e181e11ed..80afad641b 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -78,7 +78,7 @@ jobs: compile/tsan-llvm18.1.8-x86_64.tar.xz sysroot/sysroot-*.tar.xz # Note: macOS sysroot + darwin libcxx are built separately - # in the build-macos-sysroot job (runs on macos-14) + # in the build-macos-artifacts job (runs on Linux) bazel-args: >- --config=ci ${{ matrix.mode == 'bzlmod' From 554e3456c600e6049c9951b1ea4e634f33dd73e0 Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 16 Jun 2026 17:02:15 +0000 Subject: [PATCH 11/20] fix: use correct LLVM 18.1.8 macOS tarball naming LLVM 18.x uses "clang+llvm-VER-arm64-apple-macosNN" naming convention, not "LLVM-VER-macOS-ARM64" (which is the newer format from LLVM 20+). Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Takeshi Yoneda --- .github/workflows/_bazel.yml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/_bazel.yml b/.github/workflows/_bazel.yml index 59127deac9..6d91ecd76f 100644 --- a/.github/workflows/_bazel.yml +++ b/.github/workflows/_bazel.yml @@ -230,10 +230,12 @@ jobs: set -euo pipefail # Extract cxx-cross-libs from official LLVM macOS release (no cmake build needed) - wget -q "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/LLVM-${LLVM_VERSION}-macOS-ARM64.tar.xz" \ - -O llvm-macos.tar.xz + # LLVM 18.x uses "clang+llvm-VER-arm64-apple-macosNN" naming + LLVM_TARBALL="clang+llvm-${LLVM_VERSION}-arm64-apple-macos11.tar.xz" + LLVM_PREFIX="clang+llvm-${LLVM_VERSION}-arm64-apple-macos11" - LLVM_PREFIX="LLVM-${LLVM_VERSION}-macOS-ARM64" + wget "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/${LLVM_TARBALL}" \ + -O llvm-macos.tar.xz # Extract only the files we need tar -xf llvm-macos.tar.xz \ @@ -250,11 +252,11 @@ jobs: cp -a "${LLVM_PREFIX}/lib/libc++"*.dylib libcxx-darwin/lib/ # Patch install names: @rpath/ -> /usr/lib/ so binaries use system libc++ at runtime - INSTALL_NAME_TOOL="${LLVM_PREFIX}/bin/llvm-install-name-tool" - tar -xf llvm-macos.tar.xz "${INSTALL_NAME_TOOL}" - chmod +x "${INSTALL_NAME_TOOL}" - "${INSTALL_NAME_TOOL}" -id /usr/lib/libc++.1.dylib libcxx-darwin/lib/libc++.1.dylib - "${INSTALL_NAME_TOOL}" -id /usr/lib/libc++abi.dylib libcxx-darwin/lib/libc++abi.1.dylib + # llvm-install-name-tool is a Mach-O tool but works on Linux (it's in the LLVM distribution) + tar -xf llvm-macos.tar.xz "${LLVM_PREFIX}/bin/llvm-install-name-tool" + chmod +x "${LLVM_PREFIX}/bin/llvm-install-name-tool" + "${LLVM_PREFIX}/bin/llvm-install-name-tool" -id /usr/lib/libc++.1.dylib libcxx-darwin/lib/libc++.1.dylib + "${LLVM_PREFIX}/bin/llvm-install-name-tool" -id /usr/lib/libc++abi.dylib libcxx-darwin/lib/libc++abi.1.dylib tar -cJf "libcxx-llvm${LLVM_VERSION}-darwin-aarch64.tar.xz" -C libcxx-darwin . From 81075877daf251e5428c3531a0ea44a50566130a Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 16 Jun 2026 17:15:39 +0000 Subject: [PATCH 12/20] fix: use Linux llvm-install-name-tool for patching Mach-O install names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The macOS LLVM tarball's llvm-install-name-tool is a Mach-O binary that can't run on Linux. Use the Linux distro's llvm-install-name-tool instead — it can edit Mach-O files cross-platform. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Takeshi Yoneda --- .github/workflows/_bazel.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/_bazel.yml b/.github/workflows/_bazel.yml index 6d91ecd76f..31a15f8fc4 100644 --- a/.github/workflows/_bazel.yml +++ b/.github/workflows/_bazel.yml @@ -251,12 +251,11 @@ jobs: cp "${LLVM_PREFIX}/include/c++/v1/__config_site" libcxx-darwin/include/ cp -a "${LLVM_PREFIX}/lib/libc++"*.dylib libcxx-darwin/lib/ - # Patch install names: @rpath/ -> /usr/lib/ so binaries use system libc++ at runtime - # llvm-install-name-tool is a Mach-O tool but works on Linux (it's in the LLVM distribution) - tar -xf llvm-macos.tar.xz "${LLVM_PREFIX}/bin/llvm-install-name-tool" - chmod +x "${LLVM_PREFIX}/bin/llvm-install-name-tool" - "${LLVM_PREFIX}/bin/llvm-install-name-tool" -id /usr/lib/libc++.1.dylib libcxx-darwin/lib/libc++.1.dylib - "${LLVM_PREFIX}/bin/llvm-install-name-tool" -id /usr/lib/libc++abi.dylib libcxx-darwin/lib/libc++abi.1.dylib + # Patch install names: @rpath/ -> /usr/lib/ so binaries use system libc++ at runtime. + # Use the Linux LLVM's llvm-install-name-tool (can edit Mach-O files cross-platform). + sudo apt-get -qq install -y llvm + llvm-install-name-tool -id /usr/lib/libc++.1.dylib libcxx-darwin/lib/libc++.1.dylib + llvm-install-name-tool -id /usr/lib/libc++abi.dylib libcxx-darwin/lib/libc++abi.1.dylib tar -cJf "libcxx-llvm${LLVM_VERSION}-darwin-aarch64.tar.xz" -C libcxx-darwin . From ee60ef8b49181343f1837d21a72286e6bd3e49da Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 16 Jun 2026 19:57:14 +0000 Subject: [PATCH 13/20] fix: extract llvm-install-name-tool from Linux LLVM release The system llvm package doesn't include llvm-install-name-tool. Extract it from the Linux LLVM 18.1.8 release instead. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Takeshi Yoneda --- .github/workflows/_bazel.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/_bazel.yml b/.github/workflows/_bazel.yml index 31a15f8fc4..595074ae02 100644 --- a/.github/workflows/_bazel.yml +++ b/.github/workflows/_bazel.yml @@ -252,10 +252,14 @@ jobs: cp -a "${LLVM_PREFIX}/lib/libc++"*.dylib libcxx-darwin/lib/ # Patch install names: @rpath/ -> /usr/lib/ so binaries use system libc++ at runtime. - # Use the Linux LLVM's llvm-install-name-tool (can edit Mach-O files cross-platform). - sudo apt-get -qq install -y llvm - llvm-install-name-tool -id /usr/lib/libc++.1.dylib libcxx-darwin/lib/libc++.1.dylib - llvm-install-name-tool -id /usr/lib/libc++abi.dylib libcxx-darwin/lib/libc++abi.1.dylib + # Extract llvm-install-name-tool from the Linux LLVM release (works cross-platform on Mach-O). + LINUX_LLVM_TARBALL="clang+llvm-${LLVM_VERSION}-x86_64-linux-gnu-ubuntu-18.04.tar.xz" + LINUX_LLVM_PREFIX="clang+llvm-${LLVM_VERSION}-x86_64-linux-gnu-ubuntu-18.04" + wget -q "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/${LINUX_LLVM_TARBALL}" \ + -O llvm-linux.tar.xz + tar -xf llvm-linux.tar.xz "${LINUX_LLVM_PREFIX}/bin/llvm-install-name-tool" + "${LINUX_LLVM_PREFIX}/bin/llvm-install-name-tool" -id /usr/lib/libc++.1.dylib libcxx-darwin/lib/libc++.1.dylib + "${LINUX_LLVM_PREFIX}/bin/llvm-install-name-tool" -id /usr/lib/libc++abi.dylib libcxx-darwin/lib/libc++abi.1.dylib tar -cJf "libcxx-llvm${LLVM_VERSION}-darwin-aarch64.tar.xz" -C libcxx-darwin . From 04b5979f3220ea10c53d8805d2668e4047e3d8b2 Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 16 Jun 2026 20:10:20 +0000 Subject: [PATCH 14/20] fix: create llvm-install-name-tool symlink to llvm-objcopy llvm-install-name-tool is a symlink to llvm-objcopy that changes behavior based on argv[0]. Extract llvm-objcopy and create the symlink. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Takeshi Yoneda --- .github/workflows/_bazel.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/_bazel.yml b/.github/workflows/_bazel.yml index 595074ae02..e8d54a0ac1 100644 --- a/.github/workflows/_bazel.yml +++ b/.github/workflows/_bazel.yml @@ -252,12 +252,14 @@ jobs: cp -a "${LLVM_PREFIX}/lib/libc++"*.dylib libcxx-darwin/lib/ # Patch install names: @rpath/ -> /usr/lib/ so binaries use system libc++ at runtime. - # Extract llvm-install-name-tool from the Linux LLVM release (works cross-platform on Mach-O). + # Extract llvm-objcopy from the Linux LLVM release — llvm-install-name-tool is a + # symlink to llvm-objcopy, which handles Mach-O files cross-platform. LINUX_LLVM_TARBALL="clang+llvm-${LLVM_VERSION}-x86_64-linux-gnu-ubuntu-18.04.tar.xz" LINUX_LLVM_PREFIX="clang+llvm-${LLVM_VERSION}-x86_64-linux-gnu-ubuntu-18.04" wget -q "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/${LINUX_LLVM_TARBALL}" \ -O llvm-linux.tar.xz - tar -xf llvm-linux.tar.xz "${LINUX_LLVM_PREFIX}/bin/llvm-install-name-tool" + tar -xf llvm-linux.tar.xz "${LINUX_LLVM_PREFIX}/bin/llvm-objcopy" + ln -s llvm-objcopy "${LINUX_LLVM_PREFIX}/bin/llvm-install-name-tool" "${LINUX_LLVM_PREFIX}/bin/llvm-install-name-tool" -id /usr/lib/libc++.1.dylib libcxx-darwin/lib/libc++.1.dylib "${LINUX_LLVM_PREFIX}/bin/llvm-install-name-tool" -id /usr/lib/libc++abi.dylib libcxx-darwin/lib/libc++abi.1.dylib From 0b6d86504d1a651cc655dfbb36ef6aa121ad877b Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 16 Jun 2026 20:22:23 +0000 Subject: [PATCH 15/20] fix: use system llvm-18 package for install-name-tool The pre-built LLVM 18 binaries need libtinfo.so.5 which isn't on Ubuntu 24.04. Use the system llvm-18 package instead. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Takeshi Yoneda --- .github/workflows/_bazel.yml | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/.github/workflows/_bazel.yml b/.github/workflows/_bazel.yml index e8d54a0ac1..fa93980772 100644 --- a/.github/workflows/_bazel.yml +++ b/.github/workflows/_bazel.yml @@ -252,16 +252,10 @@ jobs: cp -a "${LLVM_PREFIX}/lib/libc++"*.dylib libcxx-darwin/lib/ # Patch install names: @rpath/ -> /usr/lib/ so binaries use system libc++ at runtime. - # Extract llvm-objcopy from the Linux LLVM release — llvm-install-name-tool is a - # symlink to llvm-objcopy, which handles Mach-O files cross-platform. - LINUX_LLVM_TARBALL="clang+llvm-${LLVM_VERSION}-x86_64-linux-gnu-ubuntu-18.04.tar.xz" - LINUX_LLVM_PREFIX="clang+llvm-${LLVM_VERSION}-x86_64-linux-gnu-ubuntu-18.04" - wget -q "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/${LINUX_LLVM_TARBALL}" \ - -O llvm-linux.tar.xz - tar -xf llvm-linux.tar.xz "${LINUX_LLVM_PREFIX}/bin/llvm-objcopy" - ln -s llvm-objcopy "${LINUX_LLVM_PREFIX}/bin/llvm-install-name-tool" - "${LINUX_LLVM_PREFIX}/bin/llvm-install-name-tool" -id /usr/lib/libc++.1.dylib libcxx-darwin/lib/libc++.1.dylib - "${LINUX_LLVM_PREFIX}/bin/llvm-install-name-tool" -id /usr/lib/libc++abi.dylib libcxx-darwin/lib/libc++abi.1.dylib + # Use llvm-objcopy from the system (Ubuntu 24.04 has llvm-18 available). + sudo apt-get -qq update && sudo apt-get -qq install -y llvm-18 + llvm-install-name-tool-18 -id /usr/lib/libc++.1.dylib libcxx-darwin/lib/libc++.1.dylib + llvm-install-name-tool-18 -id /usr/lib/libc++abi.dylib libcxx-darwin/lib/libc++abi.1.dylib tar -cJf "libcxx-llvm${LLVM_VERSION}-darwin-aarch64.tar.xz" -C libcxx-darwin . From 95372b2a38dc01b9a70d48078cb217ae582c30d2 Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 16 Jun 2026 20:58:43 +0000 Subject: [PATCH 16/20] fix: yamllint line-length for Apple CDN URL Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Takeshi Yoneda --- .github/workflows/_bazel.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/_bazel.yml b/.github/workflows/_bazel.yml index fa93980772..cbba71ebb8 100644 --- a/.github/workflows/_bazel.yml +++ b/.github/workflows/_bazel.yml @@ -187,10 +187,9 @@ jobs: env: LLVM_VERSION: "18.1.8" LLVM_MAJOR: "18" - # Apple CLTools SDK package URL (from Apple's public software update catalog) + # yamllint disable-line rule:line-length SDK_PKG_URL: "https://swcdn.apple.com/content/downloads/52/01/082-41241-A_0747ZN8FHV/dectd075r63pppkkzsb75qk61s0lfee22j/CLTools_macOSNMOS_SDK.pkg" SDK_PKG_SHA256: "ba3453d62b3d2babf67f3a4a44e8073d6555c85f114856f4390a1f53bd76e24a" - # pkgutil: extracts macOS .pkg files on Linux PKGUTIL_URL: "https://github.com/cerisier/pkgutil/releases/download/v1.2.0/pkgutil_linux_amd64" PKGUTIL_SHA256: "3bcf79dbec6b7858ca0c1b6db03952ac122501a74073bac186c8080fcfb391fd" SDK_PREFIX: "Payload/Library/Developer/CommandLineTools/SDKs/MacOSX15.5.sdk" From 0da1bd97147577dff56e3a3efe995048cdabd515 Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 16 Jun 2026 21:07:04 +0000 Subject: [PATCH 17/20] fix: use YAML block scalar for long URL per review Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Takeshi Yoneda --- .github/workflows/_bazel.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/_bazel.yml b/.github/workflows/_bazel.yml index cbba71ebb8..72f620c398 100644 --- a/.github/workflows/_bazel.yml +++ b/.github/workflows/_bazel.yml @@ -187,8 +187,8 @@ jobs: env: LLVM_VERSION: "18.1.8" LLVM_MAJOR: "18" - # yamllint disable-line rule:line-length - SDK_PKG_URL: "https://swcdn.apple.com/content/downloads/52/01/082-41241-A_0747ZN8FHV/dectd075r63pppkkzsb75qk61s0lfee22j/CLTools_macOSNMOS_SDK.pkg" + SDK_PKG_URL: >- + https://swcdn.apple.com/content/downloads/52/01/082-41241-A_0747ZN8FHV/dectd075r63pppkkzsb75qk61s0lfee22j/CLTools_macOSNMOS_SDK.pkg SDK_PKG_SHA256: "ba3453d62b3d2babf67f3a4a44e8073d6555c85f114856f4390a1f53bd76e24a" PKGUTIL_URL: "https://github.com/cerisier/pkgutil/releases/download/v1.2.0/pkgutil_linux_amd64" PKGUTIL_SHA256: "3bcf79dbec6b7858ca0c1b6db03952ac122501a74073bac186c8080fcfb391fd" From dc780924b39af8fb72878bf01d98b80dafaad6f5 Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 16 Jun 2026 21:33:32 +0000 Subject: [PATCH 18/20] cleanup: remove unused build scripts These cmake/Xcode-based scripts are superseded by the CI job that extracts pre-built artifacts from Apple's CDN and LLVM releases. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Takeshi Yoneda --- bazel/compile/build_libcxx_darwin.sh | 104 ----------------- bazel/sysroot/build_macos_sysroot.sh | 145 ------------------------ bazel/sysroot/build_macos_sysroot_ci.sh | 72 ------------ 3 files changed, 321 deletions(-) delete mode 100755 bazel/compile/build_libcxx_darwin.sh delete mode 100755 bazel/sysroot/build_macos_sysroot.sh delete mode 100755 bazel/sysroot/build_macos_sysroot_ci.sh diff --git a/bazel/compile/build_libcxx_darwin.sh b/bazel/compile/build_libcxx_darwin.sh deleted file mode 100755 index fc85e0c967..0000000000 --- a/bazel/compile/build_libcxx_darwin.sh +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env bash - -# Build darwin arm64 libc++ cross-compilation libraries from an LLVM release. -# -# This produces a tarball containing: -# include/__config_site — darwin-specific libc++ configuration -# lib/libc++.1.dylib — libc++ dynamic library for darwin arm64 -# lib/libc++abi.1.0.dylib — libc++abi dynamic library for darwin arm64 -# -# Requirements: -# - A macOS SDK sysroot (from build_macos_sysroot.sh or Xcode) -# - cmake, ninja -# - clang with darwin target support (the hermetic LLVM works) -# -# Usage: -# ./build_libcxx_darwin.sh \ -# --llvm-source /path/to/llvm-project-source \ -# --sysroot /path/to/macos-sdk-sysroot \ -# --clang /path/to/clang \ -# --output libcxx-darwin-arm64.tar.xz - -set -e -o pipefail - -LLVM_SOURCE="" -SYSROOT="" -CLANG="" -OUTPUT="libcxx-darwin-arm64.tar.xz" - -usage() { - echo "Usage: $0 [options]" - echo "" - echo "Options:" - echo " --llvm-source DIR Path to LLVM monorepo source (containing libcxx/, libcxxabi/)" - echo " --sysroot DIR Path to macOS SDK sysroot" - echo " --clang PATH Path to clang binary (must support --target=aarch64-apple-macosx)" - echo " --output FILE Output tarball (default: libcxx-darwin-arm64.tar.xz)" - exit 1 -} - -while [[ $# -gt 0 ]]; do - case $1 in - --llvm-source) LLVM_SOURCE="$2"; shift 2 ;; - --sysroot) SYSROOT="$2"; shift 2 ;; - --clang) CLANG="$2"; shift 2 ;; - --output) OUTPUT="$2"; shift 2 ;; - --help|-h) usage ;; - *) echo "Unknown option: $1"; usage ;; - esac -done - -if [[ -z "$LLVM_SOURCE" ]] || [[ -z "$SYSROOT" ]] || [[ -z "$CLANG" ]]; then - echo "Error: --llvm-source, --sysroot, and --clang are required" - usage -fi - -WORK_DIR=$(mktemp -d) -trap 'rm -rf "$WORK_DIR"' EXIT - -BUILD_DIR="$WORK_DIR/build" -INSTALL_DIR="$WORK_DIR/install" -mkdir -p "$BUILD_DIR" "$INSTALL_DIR/include" "$INSTALL_DIR/lib" - -TARGET="aarch64-apple-macosx" - -echo "Building libc++ for darwin arm64..." -echo " LLVM source: $LLVM_SOURCE" -echo " Sysroot: $SYSROOT" -echo " Clang: $CLANG" - -cmake -G Ninja -S "$LLVM_SOURCE/runtimes" -B "$BUILD_DIR" \ - -DCMAKE_C_COMPILER="$CLANG" \ - -DCMAKE_CXX_COMPILER="$CLANG++" \ - -DCMAKE_C_COMPILER_TARGET="$TARGET" \ - -DCMAKE_CXX_COMPILER_TARGET="$TARGET" \ - -DCMAKE_SYSTEM_NAME=Darwin \ - -DCMAKE_SYSTEM_PROCESSOR=arm64 \ - -DCMAKE_OSX_ARCHITECTURES=arm64 \ - -DCMAKE_SYSROOT="$SYSROOT" \ - -DCMAKE_INSTALL_PREFIX="$INSTALL_DIR" \ - -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \ - -DLIBCXX_ENABLE_SHARED=ON \ - -DLIBCXX_ENABLE_STATIC=OFF \ - -DLIBCXXABI_ENABLE_SHARED=ON \ - -DLIBCXXABI_ENABLE_STATIC=OFF \ - -DLIBCXX_CXX_ABI=libcxxabi \ - -DLIBCXXABI_USE_LLVM_UNWINDER=ON \ - -DLIBCXX_USE_COMPILER_RT=ON \ - -DLIBCXXABI_USE_COMPILER_RT=ON \ - -DCMAKE_BUILD_TYPE=Release - -ninja -C "$BUILD_DIR" install-cxx install-cxxabi - -echo "Packaging..." -STAGING="$WORK_DIR/staging" -mkdir -p "$STAGING/include" "$STAGING/lib" - -cp "$INSTALL_DIR/include/c++/v1/__config_site" "$STAGING/include/" -find "$INSTALL_DIR/lib" -name "libc++*.dylib" -exec cp -a {} "$STAGING/lib/" \; - -tar -cJf "$OUTPUT" -C "$STAGING" . -SIZE=$(du -sh "$OUTPUT" | cut -f1) -echo "" -echo "Built: $OUTPUT ($SIZE)" -echo "SHA256: $(sha256sum "$OUTPUT" 2>/dev/null | cut -d' ' -f1 || shasum -a 256 "$OUTPUT" | cut -d' ' -f1)" diff --git a/bazel/sysroot/build_macos_sysroot.sh b/bazel/sysroot/build_macos_sysroot.sh deleted file mode 100755 index 484505cd3c..0000000000 --- a/bazel/sysroot/build_macos_sysroot.sh +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env bash - -# Build a macOS SDK sysroot tarball for cross-compilation from Linux. -# -# Usage (on macOS): -# ./build_macos_sysroot.sh [--sdk-path /path/to/MacOSX.sdk] [--output sysroot-macos.tar.xz] -# -# The default SDK path is detected via `xcrun --show-sdk-path`. -# Output is a tarball suitable for use with the `macos_sysroot` Bazel repository rule. - -set -e -o pipefail - -SDK_PATH="" -OUTPUT="sysroot-macos-arm64.tar.xz" - -usage() { - echo "Usage: $0 [options]" - echo "" - echo "Options:" - echo " --sdk-path PATH Path to MacOSX.sdk (default: auto-detect via xcrun)" - echo " --output FILE Output tarball path (default: sysroot-macos-arm64.tar.xz)" - echo "" - echo "Examples:" - echo " # Auto-detect SDK on macOS" - echo " $0" - echo "" - echo " # Use a specific SDK" - echo " $0 --sdk-path /Library/Developer/CommandLineTools/SDKs/MacOSX15.0.sdk" - echo "" - echo " # Extract from Xcode" - echo " $0 --sdk-path /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk" - exit 1 -} - -while [[ $# -gt 0 ]]; do - case $1 in - --sdk-path) - SDK_PATH="$2" - shift 2 - ;; - --output) - OUTPUT="$2" - shift 2 - ;; - --help|-h) - usage - ;; - *) - echo "Unknown option: $1" - usage - ;; - esac -done - -if [[ -z "$SDK_PATH" ]]; then - if command -v xcrun &>/dev/null; then - SDK_PATH=$(xcrun --show-sdk-path --sdk macosx) - echo "Auto-detected SDK: $SDK_PATH" - else - echo "Error: --sdk-path required (xcrun not available)" - exit 1 - fi -fi - -if [[ ! -d "$SDK_PATH" ]]; then - echo "Error: SDK path does not exist: $SDK_PATH" - exit 1 -fi - -if [[ ! -f "$SDK_PATH/SDKSettings.json" ]] && [[ ! -f "$SDK_PATH/SDKSettings.plist" ]]; then - echo "Error: $SDK_PATH does not look like a macOS SDK (no SDKSettings found)" - exit 1 -fi - -echo "Building macOS sysroot from: $SDK_PATH" -echo "Output: $OUTPUT" - -WORK_DIR=$(mktemp -d) -trap 'rm -rf "$WORK_DIR"' EXIT - -SYSROOT="$WORK_DIR/sysroot" -mkdir -p "$SYSROOT" - -echo "Copying SDK headers..." -# System headers -if [[ -d "$SDK_PATH/usr/include" ]]; then - mkdir -p "$SYSROOT/usr" - cp -a "$SDK_PATH/usr/include" "$SYSROOT/usr/include" -fi - -echo "Copying library stubs (.tbd files)..." -# Library stubs — .tbd files are text-based stubs that tell the linker about symbols -if [[ -d "$SDK_PATH/usr/lib" ]]; then - mkdir -p "$SYSROOT/usr/lib" - find "$SDK_PATH/usr/lib" -name "*.tbd" -exec cp --parents -a {} "$SYSROOT/" \; 2>/dev/null || \ - find "$SDK_PATH/usr/lib" -name "*.tbd" | while read -r f; do - rel="${f#"$SDK_PATH"/}" - mkdir -p "$SYSROOT/$(dirname "$rel")" - cp -a "$f" "$SYSROOT/$rel" - done -fi - -echo "Copying frameworks..." -# Frameworks — headers and .tbd stubs -FRAMEWORKS_DIR="$SDK_PATH/System/Library/Frameworks" -if [[ -d "$FRAMEWORKS_DIR" ]]; then - mkdir -p "$SYSROOT/System/Library/Frameworks" - for fw in "$FRAMEWORKS_DIR"/*.framework; do - fw_name=$(basename "$fw") - mkdir -p "$SYSROOT/System/Library/Frameworks/$fw_name" - # Copy headers - if [[ -d "$fw/Headers" ]]; then - cp -a "$fw/Headers" "$SYSROOT/System/Library/Frameworks/$fw_name/" - fi - # Copy Modules (for module maps) - if [[ -d "$fw/Modules" ]]; then - cp -a "$fw/Modules" "$SYSROOT/System/Library/Frameworks/$fw_name/" - fi - # Copy .tbd files - find "$fw" -maxdepth 1 -name "*.tbd" -exec cp -a {} "$SYSROOT/System/Library/Frameworks/$fw_name/" \; 2>/dev/null || true - # Copy versioned .tbd files - if [[ -d "$fw/Versions" ]]; then - find "$fw/Versions" -name "*.tbd" | while read -r f; do - rel="${f#"$SDK_PATH"/}" - mkdir -p "$SYSROOT/$(dirname "$rel")" - cp -a "$f" "$SYSROOT/$rel" - done - fi - done -fi - -# SDK settings -for f in SDKSettings.json SDKSettings.plist; do - if [[ -f "$SDK_PATH/$f" ]]; then - cp -a "$SDK_PATH/$f" "$SYSROOT/" - fi -done - -echo "Packaging sysroot..." -tar -cJf "$OUTPUT" -C "$SYSROOT" . - -SIZE=$(du -sh "$OUTPUT" | cut -f1) -echo "" -echo "Successfully built macOS sysroot: $OUTPUT ($SIZE)" -echo "SHA256: $(sha256sum "$OUTPUT" | cut -d' ' -f1 2>/dev/null || shasum -a 256 "$OUTPUT" | cut -d' ' -f1)" diff --git a/bazel/sysroot/build_macos_sysroot_ci.sh b/bazel/sysroot/build_macos_sysroot_ci.sh deleted file mode 100755 index 70d79aba22..0000000000 --- a/bazel/sysroot/build_macos_sysroot_ci.sh +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env bash - -# Build a macOS SDK sysroot tarball for cross-compilation. -# Runs on macOS CI (GitHub Actions macos-14/15 runners have Xcode pre-installed). -# -# Output: sysroot-macos-arm64.tar.xz - -set -e -o pipefail - -SDK_PATH="${1:-$(xcrun --show-sdk-path --sdk macosx)}" -OUTPUT="${2:-sysroot-macos-arm64.tar.xz}" - -if [[ ! -d "$SDK_PATH" ]]; then - echo "Error: SDK path does not exist: $SDK_PATH" - exit 1 -fi - -echo "Building macOS sysroot from: $SDK_PATH" - -WORK_DIR=$(mktemp -d) -trap 'rm -rf "$WORK_DIR"' EXIT - -SYSROOT="$WORK_DIR/sysroot" -mkdir -p "$SYSROOT" - -# System headers -if [[ -d "$SDK_PATH/usr/include" ]]; then - mkdir -p "$SYSROOT/usr" - cp -a "$SDK_PATH/usr/include" "$SYSROOT/usr/include" -fi - -# Library stubs (.tbd files) -if [[ -d "$SDK_PATH/usr/lib" ]]; then - mkdir -p "$SYSROOT/usr/lib" - find "$SDK_PATH/usr/lib" -name "*.tbd" | while read -r f; do - rel="${f#"$SDK_PATH"/}" - mkdir -p "$SYSROOT/$(dirname "$rel")" - cp -a "$f" "$SYSROOT/$rel" - done -fi - -# Frameworks — copy entire directory. SDK frameworks contain only headers, -# modules, .tbd stubs, and symlinks (no large binaries). Preserving the -# complete structure is essential because clang's framework header lookup -# depends on symlinks like Headers -> Versions/Current/Headers. -if [[ -d "$SDK_PATH/System/Library/Frameworks" ]]; then - mkdir -p "$SYSROOT/System/Library" - cp -a "$SDK_PATH/System/Library/Frameworks" "$SYSROOT/System/Library/" -fi - -# SDK settings -for f in SDKSettings.json SDKSettings.plist; do - [[ -f "$SDK_PATH/$f" ]] && cp -a "$SDK_PATH/$f" "$SYSROOT/" -done - -# Remove circular symlinks (e.g., Ruby.framework/Versions/2.6/Headers/ruby/ruby -> .) -echo "Removing circular symlinks..." -find "$SYSROOT" -type l | while read -r link; do - target=$(readlink "$link") - if [[ "$target" == "." || "$target" == ".." ]]; then - rm "$link" - fi -done - -echo "Packaging sysroot..." -tar -cJf "$OUTPUT" -C "$SYSROOT" . - -SIZE=$(du -sh "$OUTPUT" | cut -f1) -SHA=$(shasum -a 256 "$OUTPUT" | cut -d' ' -f1) -echo "" -echo "Built: $OUTPUT ($SIZE)" -echo "SHA256: $SHA" From 406c81048363108b86ad6f6f3881bd0182cae31d Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 16 Jun 2026 21:35:23 +0000 Subject: [PATCH 19/20] fix: rename job/steps to reflect extract, not build Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Takeshi Yoneda --- .github/workflows/_bazel.yml | 8 ++++---- .github/workflows/bazel.yml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/_bazel.yml b/.github/workflows/_bazel.yml index 72f620c398..9a1101901a 100644 --- a/.github/workflows/_bazel.yml +++ b/.github/workflows/_bazel.yml @@ -180,10 +180,10 @@ jobs: //compile/test:cross_compile_aarch64_no_unwind_test working-directory: ${{ inputs.bazel-path }} - build-macos-artifacts: + package-macos-cross-libs: if: inputs.action == 'build' && inputs.upload runs-on: ubuntu-24.04 - name: Build macOS cross-compilation artifacts + name: Package macOS cross-compilation libs env: LLVM_VERSION: "18.1.8" LLVM_MAJOR: "18" @@ -196,7 +196,7 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Build macOS arm64 sysroot + - name: Extract macOS arm64 sysroot run: | set -euo pipefail @@ -224,7 +224,7 @@ jobs: echo "Sysroot size: $(du -sh sysroot-macos-arm64.tar.xz | cut -f1)" sha256sum sysroot-macos-arm64.tar.xz - - name: Build darwin libcxx cross-compilation libs + - name: Extract darwin libcxx from LLVM release run: | set -euo pipefail diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 80afad641b..01389d1759 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -77,8 +77,8 @@ jobs: compile/msan-llvm18.1.8-x86_64.tar.xz compile/tsan-llvm18.1.8-x86_64.tar.xz sysroot/sysroot-*.tar.xz - # Note: macOS sysroot + darwin libcxx are built separately - # in the build-macos-artifacts job (runs on Linux) + # Note: macOS sysroot + darwin libcxx are packaged separately + # in the package-macos-cross-libs job (runs on Linux) bazel-args: >- --config=ci ${{ matrix.mode == 'bzlmod' From d602445cc5bad9580db07d7a1fd3f138c1394f8c Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 16 Jun 2026 21:49:26 +0000 Subject: [PATCH 20/20] ci: auto-populate macOS sysroot and darwin libcxx hashes on release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hook the macOS cross-compilation artifact hashes into the bazel release prepare step in _release.yml. When a bins release is created, the jq filter now also updates macos_sysroot_sha256 and libcxx_libs_darwin_sha256 in versions.bzl from the release asset checksums. Handles both initial population (empty string → hash) and updates (old hash → new hash). Signed-off-by: Takeshi Yoneda Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Takeshi Yoneda --- .github/workflows/_release.yml | 28 +++++++++++++++++++++++++++- bazel/versions.bzl | 9 ++++----- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/.github/workflows/_release.yml b/.github/workflows/_release.yml index 98f5632519..eec660a7b0 100644 --- a/.github/workflows/_release.yml +++ b/.github/workflows/_release.yml @@ -246,7 +246,33 @@ jobs: "sed -i s/\($current_sha)/\($new_sha)/g \($versions_file)" else "" end] as $sysroot_updates | $glint_updates + $sysroot_updates] as $arch_updates - | $bins_update + $san_updates + $arch_updates + | [ + # macOS sysroot hash + ($shas["sysroot-macos-arm64.tar.xz"] // null) as $sha_entry + | if $sha_entry then + ($sha_entry | split(":") | .[1]) as $new_sha + | $current.macos_sysroot_sha256.arm64 as $cur + | if $cur == $new_sha then "" + elif ($cur | length) > 0 then + "sed -i s/\($cur)/\($new_sha)/g \($versions_file)" + else + "sed -i '0,/\"arm64\": \"\"/s//\"arm64\": \"\($new_sha)\"/' \($versions_file)" + end + else "" end, + # darwin libcxx hash + ($shas["libcxx-llvm18.1.8-darwin-aarch64.tar.xz"] // null) as $sha_entry + | if $sha_entry then + ($sha_entry | split(":") | .[1]) as $new_sha + | $current.libcxx_libs_darwin_sha256.aarch64 as $cur + | if $cur == $new_sha then "" + elif ($cur | length) > 0 then + "sed -i s/\($cur)/\($new_sha)/g \($versions_file)" + else + "sed -i '0,/\"aarch64\": \"\"/s//\"aarch64\": \"\($new_sha)\"/' \($versions_file)" + end + else "" end + ] as $macos_updates + | $bins_update + $san_updates + $arch_updates + $macos_updates | [flatten[] | select(. != "")] | join("\n") diff --git a/bazel/versions.bzl b/bazel/versions.bzl index 3262555354..1b59cc04d6 100644 --- a/bazel/versions.bzl +++ b/bazel/versions.bzl @@ -39,15 +39,14 @@ VERSIONS = { "x86_64": "50c7385dd1c17fd3606fa8850cfb1c7d0166ab109e404964f55abd6b508560eb", }, - # Darwin libc++ cross-compilation libraries (built from LLVM source for macOS arm64) - # Contains include/__config_site and lib/libc++.dylib, lib/libc++abi.dylib + # Darwin libc++ for cross-compilation (extracted from LLVM macOS release) "libcxx_libs_darwin_sha256": { - "aarch64": "", # TODO: populate after building and uploading tarball + "aarch64": "", }, - # macOS SDK sysroot for cross-compilation (headers, frameworks, .tbd stubs) + # macOS SDK sysroot for cross-compilation (extracted from Apple CLTools) "macos_sysroot_sha256": { - "arm64": "", # TODO: populate after building and uploading tarball + "arm64": "", }, # Glint binary hashes by architecture