Personal notes building zig 0.15.0-dev.xxxx on Macbook M3 Max
20250407 Sequoia 15.4, latest XCode Commandline Tools, homebrew-installed LLVM 20.1.2 (llvm@20)
This way of building probably works on all Apple Silicon Macs, but you must check other models yourself. Some Intel Macs should also work (the only significant difference is the default homebrew path). But I don't test that anymore.
Here is a list of earlier M3 Max builds
DO YOU REALLY NEED TO BUILD FROM SOURCE?
Perhaps all you need is a particular version of zig? Many apps require a slightly older zig version, read more about why here. In that case, download the expected binary yourself or use https://github.com/marler8997/zigup.
Ziglang.org wiki:
"... if your goal is to install a specific version of Zig, you can find pre-built tarballs on the download page. You could also try installing Zig from a package manager. Finally, there is zig-bootstrap to cross-compile an installation of Zig from source for any target. When using zig-bootstrap, be sure to check out the git tag corresponding to the version you want to build, as master branch is not kept in any coherent state."
https://github.com/ziglang/zig/wiki/Building-Zig-From-Source
https://github.com/ziglang/zig/wiki/Troubleshooting-Build-Issues.
BUILDING FROM SOURCE ON A MAC
Below, I describe how to build zig master using the Homebrew package manager + cmake with a few Mac-specific tweaks. There may be better and less common methods that also work. But Mac developers are more likely to be familiar with this way.
I have tried and used some but not all suggestions from this wiki page. In particular, on my Mac cmake is actually slightly faster than ninja.
MY CURRENT TEST MACHINE
➜ system_profiler SPHardwareDataType | grep "Chip:" | cut -c 13-30; sw_vers; clang --version
Apple M3 Max
ProductName: macOS
ProductVersion: 15.4
BuildVersion: 24E248
Apple clang version 17.0.0 (clang-1700.0.13.3)
Target: arm64-apple-darwin24.4.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
BUILD ENVIRONMENT
I use the latest major version of macOS (unless I have specific reasons not to). In general, I also try to keep up with minor version + security updates. But for zig, the two previous major versions of macOS are supposed to work.
Below, I assume the latest version of XCode Command Line Tools is installed. It is included with Apple XCode and can also be installed separately. Building zig without these tools might be possible. But I prefer to test a common configuration.
Use Homebrew to install LLVM, cmake + some Mac-specific dependencies: 'zlib', 'zstd', 'unixodbc' and 'lld'.
brew install cmake; brew install zlib ; brew install zstd; brew install unixodbc; brew install llvm@20; brew install lld
Zig master currently expects LLVM 20 to be installed. If you need it, homebrew allows multiple LLVM versions to be installed side-by-side: 'llvm@18', 'llvm@19' etc. Note that using the wrong major LLVM version will break your zig build.
Unfortunately Homebrew LLVM has issues with the 'zstd' library (see ziglang/zig#20806). Until there is a proper upstream solution, the easiest fix is still to sym-link zstd directly. Do this every time zstd or llvm is updated.
ln "/opt/homebrew/opt/zstd/lib/libzstd.a" "/opt/homebrew/opt/llvm/lib/libzstd.a"
Put Homebrew-installed LLVM first in your path by adding the line below to your shell profile (probably '~/.zshrc'). Remember to restart your shell or source the profile to make LLVM available!
export PATH=/opt/homebrew/opt/llvm/bin:$PATH
Note! Do NOT use "/usr/local/opt", that only works on Intel Mac.
Restart your terminal and make sure there are no configuration issues with homebrew
➜ ~ brew doctor
Your system is ready to brew.
GET THE LATEST ZIG SOURCE CODE AND PREPARE YOUR REPO
Get the latest source code from the zig Github repo. If you plan on contributing to zig itself, create your own fork.
> git clone [email protected]:ziglang/zig.git
> cd zig
BUILD A RELEASE MODE ZIG BINARY
Make sure you are in the folder where you cloned Zig. Pull the latest code. Clean both global and local zig cache. Create an empty build folder. Note that on zig master, the default local cache has changed to '.zig-cache', it's NOT 'zig-cache'.
git pull
rm -rf ~/.cache/zig; rm -rf .zig-cache; rm -rf zig-out; rm -rf build; mkdir build
Set build flag -DZIG_STATIC_LLVM=on to specify you want a statically linked homebrew-installed LLVM. This is currently necessary to build on macOS.
Using -DZIG_NO_LIB=ON is optional but I find it convenient (it prevents creating an extra copy of the library source). The make '-j' parameter is also optional but makes builds faster (use the number of performance CPU cores on your machine).
Now build and install a release mode zig binary. This takes several minutes, even on a fast machine.
cd build; cmake .. -DCMAKE_PREFIX_PATH="$(brew --prefix llvm)" -DZIG_STATIC_LLVM=on -DZIG_NO_LIB=ON -DCMAKE_BUILD_TYPE=Release; make -j12; make install
Note that the build process is still under active development. Using macOS and cmake, you can expect linker warnings + 45 build warnings. A successful build ends similar to this:
... lots of output omitted
/Users/jonas/src/zig/zig/build/zig2.c:3491396:23: warning: incompatible pointer types passing 'uintptr_t *' (aka 'unsigned long *') to parameter of type 'uint64_t *' (aka 'unsigned long long *') [-Wincompatible-pointer-types]
3491396 | t5.f1 = zig_subo_u64(&t5.f0, t4, t0, UINT8_C(64));
| ^~~~~~
/Users/jonas/src/zig/zig/stage1/zig.h:913:43: note: passing argument to parameter 'res' here
913 | static inline bool zig_subo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8_t bits) {
| ^
45 warnings generated.
[ 94%] Linking CXX executable zig2
ld: warning: ignoring duplicate libraries: '/opt/homebrew/opt/llvm/lib/libclangAPINotes.a', '/opt/homebrew/opt/llvm/lib/libclangARCMigrate.a', '/opt/homebrew/opt/llvm/lib/libclangAST.a', '/opt/homebrew/opt/llvm/lib/libclangASTMatchers.a', '/opt/homebrew/opt/llvm/lib/libclangAnalysis.a', '/opt/homebrew/opt/llvm/lib/libclangBasic.a', '/opt/homebrew/opt/llvm/lib/libclangCrossTU.a', '/opt/homebrew/opt/llvm/lib/libclangEdit.a', '/opt/homebrew/opt/llvm/lib/libclangExtractAPI.a', '/opt/homebrew/opt/llvm/lib/libclangIndex.a', '/opt/homebrew/opt/llvm/lib/libclangInstallAPI.a', '/opt/homebrew/opt/llvm/lib/libclangLex.a', '/opt/homebrew/opt/llvm/lib/libclangParse.a', '/opt/homebrew/opt/llvm/lib/libclangRewrite.a', '/opt/homebrew/opt/llvm/lib/libclangRewriteFrontend.a', '/opt/homebrew/opt/llvm/lib/libclangSema.a', '/opt/homebrew/opt/llvm/lib/libclangStaticAnalyzerCheckers.a', '/opt/homebrew/opt/llvm/lib/libclangStaticAnalyzerCore.a', '/opt/homebrew/opt/llvm/lib/libclangStaticAnalyzerFrontend.a', '/opt/homebrew/opt/llvm/lib/libclangSupport.a', '/opt/homebrew/opt/llvm/lib/libclangToolingCore.a'
[ 94%] Built target zig2
[100%] Building stage3
[100%] Built target stage3
[ 36%] Built target zigcpp
[ 47%] Built target zig-wasm2c
[ 68%] Built target zig1
[ 94%] Built target zig2
[100%] Built target stage3
Install the project...
-- Install configuration: "Release"
BUILD A DEBUG MODE ZIG BINARY
Use your release mode zig to build a debug mode version of itself. This is useful for working on zig itself and/or digging deeper when debugging.
➜ stage3/bin/zig build -p stage4 -Dno-lib
➜
ADD ALIASES (optional but convenient)
Some zig developers use https://github.com/marler8997/zigup to deal with multiple zig versions. Personally, I find it simpler to keep a handful of aliases in my profile for projects pinned to older zig versions.
Change the lines below to point at your build folder and put them in '.zshrc'. Absolute path is required, last part must be 'build/stage3/bin/zig' or 'build/stage4/bin/zig'. Feel free to use whatever aliases you want.
alias zig=/Users/jonas/src/zig/zig/build/stage3/bin/zig
alias dzig=/Users/jonas/src/zig/zig/build/stage4/bin/zig
Remember to restart your shell (or source the profile) to make aliases available.
CHECK THAT EVERYTHING WORKS
Open a new terminal and verify that your aliases work.
➜ ~ zig version
0.15.0-dev.256+499550902
➜ ~ which zig
zig: aliased to /Users/jonas/src/zig/zig/build/stage3/bin/zig
➜ ~ zig env
{
"zig_exe": "/Users/jonas/src/zig/zig/build/stage3/bin/zig",
"lib_dir": "/Users/jonas/src/zig/zig/lib",
"std_dir": "/Users/jonas/src/zig/zig/lib/std",
"global_cache_dir": "/Users/jonas/.cache/zig",
"version": "0.15.0-dev.256+499550902",
"target": "aarch64-macos.15.4...15.4-none",
"env": {
"ZIG_GLOBAL_CACHE_DIR": null,
"ZIG_LOCAL_CACHE_DIR": null,
"ZIG_LIB_DIR": null,
"ZIG_LIBC": null,
"ZIG_BUILD_RUNNER": null,
"ZIG_VERBOSE_LINK": null,
"ZIG_VERBOSE_CC": null,
"ZIG_BTRFS_WORKAROUND": null,
"ZIG_DEBUG_CMD": null,
"CC": null,
"NO_COLOR": null,
"CLICOLOR_FORCE": null,
"XDG_CACHE_HOME": null,
"HOME": "/Users/jonas"
}
}
➜ ~ dzig version
0.15.0-dev.256+499550902
➜ ~ which dzig
dzig: aliased to /Users/jonas/src/zig/zig/build/stage4/bin/zig
You can read more about testing here: https://github.com/ziglang/zig/wiki/Contributing#testing Try running native behavior tests as a simple sanity check. There should be no errors.
Important! You must run these tests from your build folder.
➜ build git:(master) zig build test-behavior -Dskip-non-native --summary all
Build Summary: 25/25 steps succeeded; 15606/16448 tests passed; 842 skipped
test-behavior success
... detailed output omitted
Run this to see which native tests are skipped.
➜ ~ cd src/zig/zig/build
➜ build git:(master) zig test ../test/behavior.zig -I../test
... details of skipped tests omitted
1951 passed; 105 skipped; 0 failed.
If you feel ambitious, check behavior tests for all platforms. This takes much longer.
➜ build git:(master) zig build test-behavior
Currently, there are some failing tests. See [https://gist.github.com/kamidev/2ce2b7a0b23314a86974980752f4b24f ](https://gist.github.com/kamidev/2ce2b7a0b23314a86974980752f4b24f). Hopefully, this will be fixed in the next zig release.
Thanks for sharing your notes. It does save me a lot of time from dealing with compiling issues by following the official tutorial.
BTW, I am curious about why not building zig with
-DCMAKE_BUILD_TYPE=Release
? IDK if it's better to build a debug mode zig for a nigthly build.