Personal notes building zig 0.13.0-dev.xxxx on Macbook M3 Max
This probably works on all current Apple Silicon Macs, but you must check other models yourself. Newer Intel Macs are also likely to work, with one significant difference: homebrew has a different default path.
20230926: Updated for macOS Sonoma, homebrew-installed LLVM 17.01 and latest XCode Commandline Tools
20231001: Build zig binaries for both release and debug mode (with release mode as default)
20231212: Updated for Sonoma 14.2, homebrew-installed LLVM 17.0.6 and latest XCode Commandline Tools
20240204 Updated for Sonoma 14.3, homebrew-installed LLVM 17.0.6 and latest XCode Commandline Tools
20240319 Now testing on M3 Max. Sonoma 14.4.1, homebrew-installed LLVM 17.0.6, latest XCode Commandline Tools
20240420 M3 Max, Sonoma 14.4.1. homebrew-installed LLVM 17.0.6, latest XCode Commandline Tools
20240423 M3 Max, Sonoma 14.4.1. homebrew LLVM 17.0.6 (installed using formula llvm@17), latest XCode Commandline Tools
20240508 M3 Max, Sonoma 14.4.1. homebrew LLVM 18.1.5 (installed using formula llvm), latest XCode Commandline Tools
20240514 M3 Max, Sonoma 14.5 homebrew LLVM 18.1.5 (installed using formula llvm), latest XCode Commandline Tools
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, simply download the right binary yourself or use https://github.com/marler8997/zigup.
Here is what the official wiki says:
"... 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 flags. There may be better and less common methods, but this is what most Mac developers are likely to use.
MY CURRENT TEST MACHINE
➜ system_profiler SPHardwareDataType | grep "Chip:" | cut -c 13-30; sw_vers; clang --version
Apple M3 Max
ProductName: macOS
ProductVersion: 14.5
BuildVersion: 23F79
Homebrew clang version 18.1.5
Target: arm64-apple-darwin23.5.0
Thread model: posix
InstalledDir: /opt/homebrew/opt/llvm/bin
BUILD ENVIRONMENT
I use the latest major version of macOS (unless there is a specific reason not to). In general, I try to keep up with the latest minor version + security updates. The two previous major versions of macOS are supposed to work.
Below, I assume the latest version of XCode Command Line Tools is installed. They are part of the Apple XCode IDE, but can also be installed separately. It may be possible to build zig without these tools but I don't test that.
Use Homebrew to install cmake + Mac-specific dependencies 'zlib' and 'zstd', then install 'llvm'.
> brew install cmake; brew install zlib; brew install zstd; brew install llvm;
Put the Homebrew-installed LLVM first in your path by adding this line 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! Building zig master currently requires LLVM 18. Using the wrong major LLVM version will break your build! If you also need to build older zig versions, use 'brew install llvm@17' to setup a side-by-side LLVM version.
Note! On Intel Macs, the homebrew path is "/usr/local/opt", NOT "/opt/homebrew/opt/".
Restart your terminal, then check that you don't have any 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 want to contribute to zig itself, create your own fork first.
> git clone git@github.com:ziglang/zig.git
> cd zig
BUILD A RELEASE MODE ZIG BINARY
Make sure you are in the folder where you cloned Zig. Then pull the latest code, create an empty build folder and clean both global and local zig cache.
> git pull
> rm -rf ~/.cache/zig, rm -rf zig-cache; rm -rf build; mkdir build
Some Mac-specific build flags are currently necessary: specify that you want a statically linked homebrew-installed LLVM and also add a special flag for the 'zstd' dependency. The make '-j12' parameter is optional but makes builds faster if you have that number of performance CPU cores.
Zig can be built in different build modes, see https://github.com/ziglang/zig/wiki/Contributing#editing-source-code. To build a release mode version, add these flags:
'-DCMAKE_BUILD_TYPE=Release' build the zig binary in release mode.
'-DZIG_NO_LIB=ON' use existing 'lib' folder in the source tree (don't create a copy for the new binary)
Now build and install your release mode zig binary. This will take several minutes.
cd build; cmake .. -DCMAKE_PREFIX_PATH="$(brew --prefix llvm);$(brew --prefix zstd)" -DZIG_STATIC_LLVM=on -DZIG_NO_LIB=ON -DCMAKE_BUILD_TYPE=Release; make -j12; make install
Note that the build process is under active development. Using macOS and cmake, you can expect linker warnings + 47 build warnings. A successful build ends similar to this:
... lots of details omitted
/Users/jonas/src/zig/zig/build/zig2.c:3609236:23: warning: incompatible pointer types passing 'uintptr_t *' (aka 'unsigned long *') to parameter of type 'uint64_t *' (aka 'unsigned long long *') [-Wincompatible-pointer-types]
t5.f1 = zig_subo_u64(&t5.f0, t4, t0, UINT8_C(64));
^~~~~~
/Users/jonas/src/zig/zig/stage1/zig.h:721:43: note: passing argument to parameter 'res' here
static inline bool zig_subo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8_t bits) {
^
47 warnings generated.
[ 94%] Linking CXX executable zig2
ld: warning: ignoring duplicate libraries: '/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/libclangParse.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'
ld: warning: reexported library with install name '/opt/homebrew/opt/llvm/lib/libunwind.1.dylib' found at '/opt/homebrew/Cellar/llvm/18.1.5/lib/libunwind.1.0.dylib' couldn't be matched with any parent library and will be linked directly
[ 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 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.13.0-dev.211+6a65561e3
➜ ~ which zig
zig13: 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": "src/zig/zig/lib",
"std_dir": "src/zig/zig/lib/std",
"global_cache_dir": "/Users/jonas/.cache/zig",
"version": "0.13.0-dev.211+6a65561e3",
"target": "aarch64-macos.14.5...14.5-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,
"XDG_CACHE_HOME": null,
"HOME": "/Users/jonas"
}
}
➜ ~ dzig version
0.13.0-dev.211+6a65561e3
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.
➜ build git:(master) zig build test-behavior -Dskip-non-native --summary all
Build Summary: 27/27 steps succeeded; 16414/17379 tests passed; 965 skipped
test-behavior success
... detailed output omitted
Run this to see which native tests were skipped. Note! You should run these tests from your build folder.
➜ ~ cd src/zig/zig/build
➜ build git:(master) zig test ../test/behavior.zig -I../test
... details of skipped tests omitted
1824 passed; 107 skipped; 0 failed.
If you feel ambitious, check behavior tests for all platforms. This takes much longer. There are currently no expected errors.
➜ build git:(master) zig build test-behavior
➜ build git:(master)
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.