Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
d28bd03
sysroot/compile: add macOS arm64 cross-compilation support
mathetake Jun 16, 2026
b08bda0
ci: add macOS sysroot and darwin libcxx build job
mathetake Jun 16, 2026
fa34f54
fix: shellcheck errors and cmake libunwind dependency
mathetake Jun 16, 2026
95f77ce
fix: copy versioned framework headers in macOS sysroot
mathetake Jun 16, 2026
1af05c5
fix: create parent dirs before copying framework contents
mathetake Jun 16, 2026
b243d41
fix: remove circular symlinks from macOS sysroot
mathetake Jun 16, 2026
064d691
fix: copy entire framework directories to preserve symlink structure
mathetake Jun 16, 2026
e6a3ecc
fix: patch libc++ install names to use /usr/lib/ instead of @rpath/
mathetake Jun 16, 2026
e983b8a
ci: build macOS artifacts on Linux from Apple CDN + LLVM releases
mathetake Jun 16, 2026
c30d577
fix: add user-agent for Apple CDN download, fix comment
mathetake Jun 16, 2026
554e345
fix: use correct LLVM 18.1.8 macOS tarball naming
mathetake Jun 16, 2026
8107587
fix: use Linux llvm-install-name-tool for patching Mach-O install names
mathetake Jun 16, 2026
ee60ef8
fix: extract llvm-install-name-tool from Linux LLVM release
mathetake Jun 16, 2026
04b5979
fix: create llvm-install-name-tool symlink to llvm-objcopy
mathetake Jun 16, 2026
0b6d865
fix: use system llvm-18 package for install-name-tool
mathetake Jun 16, 2026
95372b2
fix: yamllint line-length for Apple CDN URL
mathetake Jun 16, 2026
0da1bd9
fix: use YAML block scalar for long URL per review
mathetake Jun 16, 2026
dc78092
cleanup: remove unused build scripts
mathetake Jun 16, 2026
406c810
fix: rename job/steps to reflect extract, not build
mathetake Jun 16, 2026
d602445
ci: auto-populate macOS sysroot and darwin libcxx hashes on release
mathetake Jun 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions .github/workflows/_bazel.yml
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,95 @@ jobs:
//compile/test:cross_compile_aarch64_no_unwind_test
working-directory: ${{ inputs.bazel-path }}

package-macos-cross-libs:
if: inputs.action == 'build' && inputs.upload
runs-on: ubuntu-24.04
name: Package macOS cross-compilation libs
env:
LLVM_VERSION: "18.1.8"
LLVM_MAJOR: "18"
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"
SDK_PREFIX: "Payload/Library/Developer/CommandLineTools/SDKs/MacOSX15.5.sdk"
steps:
- name: Checkout Repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Extract macOS arm64 sysroot
run: |
set -euo pipefail
# Download pkgutil (extracts macOS .pkg on Linux)
wget "$PKGUTIL_URL" -O pkgutil
echo "${PKGUTIL_SHA256} pkgutil" | sha256sum -c -
chmod +x pkgutil
# Download Apple CLTools SDK package
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
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: Extract darwin libcxx from LLVM release
run: |
set -euo pipefail
# Extract cxx-cross-libs from official LLVM macOS release (no cmake build needed)
# 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"
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 \
"${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"
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: @rpath/ -> /usr/lib/ so binaries use system libc++ at runtime.
# 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 .
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:
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
Expand Down
28 changes: 27 additions & 1 deletion .github/workflows/_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/bazel.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 packaged separately
# in the package-macos-cross-libs job (runs on Linux)
bazel-args: >-
--config=ci
${{ matrix.mode == 'bzlmod'
Expand Down
76 changes: 76 additions & 0 deletions bazel/compile/libcxx_libs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
22 changes: 22 additions & 0 deletions bazel/sysroot/manifests/sysroot-macos.txt
Original file line number Diff line number Diff line change
@@ -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/*
68 changes: 68 additions & 0 deletions bazel/sysroot/sysroot.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
10 changes: 10 additions & 0 deletions bazel/versions.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ VERSIONS = {
"x86_64": "50c7385dd1c17fd3606fa8850cfb1c7d0166ab109e404964f55abd6b508560eb",
},

# Darwin libc++ for cross-compilation (extracted from LLVM macOS release)
"libcxx_libs_darwin_sha256": {
"aarch64": "",
},

# macOS SDK sysroot for cross-compilation (extracted from Apple CLTools)
"macos_sysroot_sha256": {
"arm64": "",
},

# Glint binary hashes by architecture
"glint_sha256": {
"amd64": "a9389398ba5719197f7c81e6a8127262095a1a5f1ea3a509f16c32bf4ee65719",
Expand Down
Loading