toolchains_llvm is a great Bazel ruleset for providing a hermetic llvm C / C++ (CC) toolchain.

By default, this ruleset will download official llvm release packages. This is a good starting point, but you may want to build your own. Some reasons include:

  • Not wanting to rely on GitHub hosted artifacts
  • Wanting to take ownership over your CC toolchain
  • Downloading and extracting these large official releases is significantly impacting your CI startup time
  • You want to use a version that doesn’t have official releases for your platforms

By the end of this article you will be able to build your own macOS llvm package with libc++ for use with toolchains_llvm. In addition to native macOS builds, this toolchain will be able to cross-compile for both Linux-x86_64 and Linux-aarch64 with an appropriate Linux sysroot package.

Link to source code: https://github.com/scasagrande/build_macos_llvm

Note

This example is geared towards building a toolchain package with libc++ for macOS.

For Linux toolchain builds please see David Zbarsky’s static-clang repository as well as my previous post on building a Linux sysroot package for use with toolchains_llvm. David’s repo can also build a toolchain for macOS, but it does not include libc++, leaving you reliant on your system copy.

Prerequisites Link to heading

You will need to install all the required tools that the LLVM project requires.

  • Make sure you have XCode installed and operational through the Apple App Store.
  • Next, use brew (or your other preferred method) to install the following:
brew install bzip2 cmake coreutils git lz4 make ninja xz zlib zstd

Build Link to heading

Now we’re ready to invoke the build. For this example, I am building version 17.0.6. This will be using a multi-stage build process, so expect it to take a while. This took approx 40min on my M3 Macbook pro.

The build will match your system architecture. If you need to generate packages for both x86_64 and aarch64/arm64, you will need to execute this build on both platforms.

./build-macos-llvm.sh 17.0.6 ~/clang-17.0.6-aarch64-apple-darwin.tar.xz

For me, this resulted in an approximately 125MB package, down from 767MB for the official release. Could this be even smaller? Probably. If you see more files that can be deleted, feel free to submit a PR!

Test Link to heading

Before we upload this package to your team’s or organization’s file storage system (eg, Artifactory) we want to test it to make sure it will work for your project.

Let’s start by unpacking this archive to a temporary folder on your system. Here we will use /tmp/llvm.

mkdir /tmp/llvm
tar xf ~/clang-17.0.6-aarch64-apple-darwin.tar.xz -C /tmp/llvm

Copy this build file onto your unpacked dir: https://github.com/bazel-contrib/toolchains_llvm/blob/v1.1.2/toolchain/BUILD.llvm_repo

wget https://raw.githubusercontent.com/bazel-contrib/toolchains_llvm/refs/tags/v1.1.2/toolchain/BUILD.llvm_repo -O /tmp/llvm/BUILD.llvm_repo

Update your project to point to this unpacked directory:

MODULE.bazel

 1bazel_dep(name = "toolchains_llvm", version = "1.1.2", dev_dependency = True)
 2
 3llvm = use_extension("@toolchains_llvm//toolchain/extensions:llvm.bzl", "llvm", dev_dependency = True)
 4llvm.toolchain(
 5    stdlib = {
 6        "linux-x86_64": "stdc++",
 7        "linux-aarch64": "stdc++",
 8    },
 9)
10llvm.toolchain_root(
11    name = "llvm_toolchain",
12    path = "/tmp/llvm"
13)

Now run your bazel build and test!

Use with toolchains_llvm Link to heading

Once everything has passed, and you’re ready to share this toolchain with your colleagues, upload it to your file store platform and update your toolchains_llvm configuration like so:

MODULE.bazel

 1bazel_dep(name = "toolchains_llvm", version = "1.1.2", dev_dependency = True)
 2
 3llvm = use_extension("@toolchains_llvm//toolchain/extensions:llvm.bzl", "llvm", dev_dependency = True)
 4llvm.toolchain(
 5    llvm_version = "17.0.6",
 6    sha256 = {
 7        "darwin-aarch64": "...",
 8        "darwin-x86_64": "...",
 9    },
10    stdlib = {
11        "linux-x86_64": "stdc++",
12        "linux-aarch64": "stdc++",
13    },
14    urls = {
15        "darwin-aarch64": ["..."],
16        "darwin-x86_64": ["..."],
17    },
18)

Feedback Link to heading

Please leave your questions and comments in this discussions thread on the repository.

I can also be reached on the Bazel slack community under my full name.