Skip to content

Instantly share code, notes, and snippets.

@kamidev
Last active September 17, 2024 13:54
Show Gist options
  • Save kamidev/ee0d4b3deeaf6996a24d1fca9acc6b07 to your computer and use it in GitHub Desktop.
Save kamidev/ee0d4b3deeaf6996a24d1fca9acc6b07 to your computer and use it in GitHub Desktop.
zig_macos_m3_max_install

Personal notes building zig 0.14.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, latest XCode Commandline Tools, homebrew-installed LLVM 17.01

20231001: Build zig binaries for both release and debug mode (with release mode as default)

20231212: Updated for Sonoma 14.2, latest XCode Commandline Tools, homebrew-installed LLVM 17.0.6

20240204 Updated for Sonoma 14.3, latest XCode Commandline Tools, homebrew-installed LLVM 17.0.6

20240319 Now on M3 Max. Sonoma 14.4.1, latest XCode Commandline Tools, homebrew-installed LLVM 17.0.6

20240420 Sonoma 14.4.1. latest XCode Commandline Tools, homebrew-installed LLVM 17.0.6

20240423 Sonoma 14.4.1. latest XCode Commandline Tools, homebrew-installed LLVM 17.0.6

20240508 Sonoma 14.4.1. latest XCode Commandline Tools, homebrew-installed LLVM LLVM 18.1.5 (formula 'llvm')

20240514 Sonoma 14.5 latest XCode Commandline Tools, homebrew-installed LLVM 18.1.5 (formula 'llvm')

20240531 Sonoma 14.5 latest XCode Commandline Tools, homebrew-installed LLVM 18.1.6 (formula 'llvm')

20240607 Sonoma 14.5 latest XCode Commandline Tools, homebrew-installed LLVM 18.1.6 (formula 'llvm@18')

20240726 Sonoma 14.5 latest XCode Commandline Tools, homebrew-installed LLVM 18.1.8 (formula 'llvm@18')

20240802 Sonoma 14.6 latest XCode Commandline Tools, homebrew-installed LLVM 18.1.8 (formula 'llvm@18')

20240819 Sonoma 14.6.1 latest XCode Commandline Tools, homebrew-installed LLVM 18.1.8 (formula 'llvm@18')

20240917 Sonoma 15.0 latest XCode Commandline Tools, homebrew-installed LLVM 18.1.8 (formula 'llvm@18')

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.

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 work. But Mac developers are more likely to be familiar with this way.

I used a few things from https://github.com/ziglang/zig/wiki/Contributing. However, when compiling on macOS 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.0
BuildVersion:		24A335
Homebrew clang version 18.1.8
Target: arm64-apple-darwin24.0.0
Thread model: posix
InstalledDir: /opt/homebrew/opt/llvm/bin

BUILD ENVIRONMENT

I use the latest major version of macOS (unless I have specific reasons not to). In general, I try to keep up with the latest minor version + security updates. 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. They are included with Apple XCode but can also be installed separately. Building zig without these tools may work. But I need them for other macOS development and test this way.

Use Homebrew to install cmake, Mac-specific dependencies 'zlib' and 'zstd' + the latest LLVM. Building zig master currently requires LLVM 18. Using the wrong LLVM version will break your build!

To build an older zig version, you can use 'brew install llvm@17' to setup a side-by-side LLVM version.

brew install cmake; brew install zlib; brew install zstd; brew install llvm@18

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! 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.

> 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. Pull the latest code. Clean both global and local zig cache. Create an empty build folder. Note that zig master has changed the default local cache: it's now '.zig-cache', NOT 'zig-cache'.

git pull
rm -rf ~/.cache/zig; rm -rf .zig-cache; rm -rf zig-out; rm -rf build; mkdir build 

Unfortunately, the latest homebrew-installed LLVM includes the zstd library in a problematic way. To build zig, you must currently link it directly. Hopefully, this is just a temporary fix until there is an upstream solution.

ln "/opt/homebrew/opt/zstd/lib/libzstd.a" "/opt/homebrew/opt/llvm/lib/libzstd.a"

One Mac-specific build flag is currently needed, to specify that you want a statically linked homebrew-installed LLVM. You must specify that you want a release build.

Using -DZIG_NO_LIB=ON is not necessary but I find it convenient (it prevents creating an extra copy of the library source). Adding a make '-j' parameter is optional but makes builds faster (change the number below to the number of performance CPU cores on your machine).

Now build and install your release mode zig binary. This will take 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 under active development. Using macOS and cmake, you can expect linker warnings + 58 build warnings. A successful build ends similar to this:

... lots of output omitted

/Users/jonas/src/zig/zig/stage1/zig.h:613:43: note: passing argument to parameter 'res' here
  613 | static inline bool zig_addo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8_t bits) {
      |                                           ^
58 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.8/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.14.0-dev.1576+5d7fa5513
➜  ~ 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": "src/zig/zig/lib",
 "std_dir": "src/zig/zig/lib/std",
 "global_cache_dir": "/Users/jonas/.cache/zig",
 "version": "0.14.0-dev.1576+5d7fa5513",
 "target": "aarch64-macos.15.0...15.0-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.14.0-dev.1576+5d7fa5513

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.

Note! You should 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; 14918/15728 tests passed; 810 skipped
test-behavior success

... detailed output omitted

Run this to see which native tests were skipped.

➜  ~ cd src/zig/zig/build
➜  build git:(master) zig test ../test/behavior.zig -I../test

... details of skipped tests omitted

1865 passed; 101 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)
@tizee
Copy link

tizee commented Aug 20, 2023

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.

@kamidev
Copy link
Author

kamidev commented Aug 20, 2023

Thank you! I am very happy to hear that. The wiki tutorial is correct for most people most of the time, as it should be. My notes are at best a more detailed complement for one particular setup.

Debug mode makes sense for me. I follow several projects loosely, track master, watch how zig changes affect real code and occasionally help out. Learn more about how production ready zig might be (or not) for clients. If you spend most of your zig time with one specific project, some other build mode is probably more useful.

@owend
Copy link

owend commented Sep 5, 2023

Hello! I know you are not a zig developer but I did try this recently and ran into an error. I am on an Intel/x86 Mac at the moment so that may be one difference. Story: I ran into a segfault with building the export C lib example from the zig docs zig build-lib -femit-h mathtest.zig and I wanted to create a more detailed bug report.

I found some old bug reports from like... 2020 about similar issues with "unable to create target" that all seem to be closed. Is there some additional flag necessary?

I did install home-brew llvm according to these instructions and $PATH has /usr/local/opt/llvm/bin and

which clang
/usr/local/opt/llvm/bin/clang

But the error is:

cmake .. -DCMAKE_PREFIX_PATH="$(brew --prefix llvm);$(brew --prefix zstd)" -DZIG_STATIC_LLVM=on; make

-- Configuring zig version 0.12.0
-- Configuring done (0.5s)
-- Generating done (0.9s)
[ 36%] Built target zigcpp
[ 47%] Built target zig-wasm2c
[ 68%] Built target zig1
[ 94%] Built target zig2
[100%] Building stage3
zig build-exe zig Debug native: error: error(compilation): clang failed with stderr: error: unable to create target: 'Unable to find target for this triple (no targets are registered)'

@kamidev
Copy link
Author

kamidev commented Sep 6, 2023

Hmm... I have seen this error when trying to cross-compile with an incorrect/outdated triple. But not for a native build. I don't test Intel Mac a lot these days. But yesterday I did succcessfully build zig following my own instructions.

➜  zig git:(master) ✗ sw_vers; clang --version; zig version
ProductName:		macOS
ProductVersion:		13.5.1
BuildVersion:		22G90
Homebrew clang version 16.0.6
Target: x86_64-apple-darwin22.6.0
Thread model: posix
InstalledDir: /usr/local/opt/llvm/bin
0.12.0-dev.283+8976ad7ec

What version of macOS are you on? Does 'brew doctor' report any problems? Are you using the latest XCode Command Line Tools?

@owend
Copy link

owend commented Sep 6, 2023

Thanks, it was very helpful to know it should work since I'm on the same version of MacOS and clang. I must have had some build artifacts from some half installed homebrew clang setup. I went through and re-checked all the paths and aliases, cleared all caches and re-built and now it's working. Using this dev build of zig now gives me a much better error message on the other issue I was debugging, with an assertion failure and specific line numbers to look at. So once again, thanks for writing this up and for getting back to me so quickly.

@kamidev
Copy link
Author

kamidev commented Sep 8, 2023

Great! I am happy to hear my notes were helpful. BTW, did you figure out that export c lib problem? Or file an issue?

@owend
Copy link

owend commented Sep 8, 2023

There was an existing bug opened about this particular documentation example so I added this info to it instead of opening a new one (there are so many open bugs!)

ziglang/zig#14416

Homebrew has updated to clang 17.0.1, but I am running into different build errors now. :)

duplicate symbol '__mh_execute_header' in:
    /Projects/zig/build/CMakeFiles/zig2.dir/zig2.c.o

ziglang/zig#17050

I did remove that extra _mh_execute_header definition on line 361839 and that was enough to fix the compile for me. I actually ran into a different build error yesterday but updating to HEAD today fixed it, I think someone just patched the problem I was having.

@kamidev
Copy link
Author

kamidev commented Sep 14, 2023

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.

For more about build modes, see https://github.com/ziglang/zig/wiki/Contributing. The discussion about building zig stage3 and zig stage4 binaries with different modes (release and debug) is perhaps most useful if you are working on zig itself. But it's still good to know about.

@kamidev
Copy link
Author

kamidev commented Feb 4, 2024

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.

For more about build modes, see https://github.com/ziglang/zig/wiki/Contributing. The discussion about building zig stage3 and zig stage4 binaries with different modes (release and debug) is perhaps most useful if you are working on zig itself. But it's still good to know about.

Update: I currently build both release and debug versions. My default for normal use is the release version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment