zig build from source error in MacOS
Zig Version
zig master, the latest commit: f2bf6c1b11702179329a4693cea429d550f519e1
Steps to Reproduce and Observed Behavior
PATH> zig/build:
cmake .. -DZIG_STATIC_LLVM=on -DZIG_STATIC_ZLIB=on -DCMAKE_PREFIX_PATH="$(brew --prefix llvm@18);$(brew --prefix zstd);"
make
ERROR ld: library not found for -lcurses
then,
brew install ncurses
cmake .. -DZIG_STATIC_LLVM=on -DZIG_STATIC_ZLIB=on -DCMAKE_PREFIX_PATH="$(brew --prefix llvm@18);$(brew --prefix zstd);$(brew --prefix ncurses);"
make
ERROR ld: library not found for -lzstd
Furthermore,
-DZIG_STATIC_ZLIB is required or else there will be ERROR: ld: library not found for -lz
Expected Behavior
zig build OK.
then if I STATIC link all zlib, zstd, and curses:
cmake .. -DZIG_STATIC_LLVM=on -DZIG_STATIC_ZLIB=on -DZIG_STATIC_ZSTD=on -DZIG_STATIC_CURSES=on -DCMAKE_PREFIX_PATH="$(brew --prefix llvm@18);$(brew --prefix zlib);$(brew --prefix zstd);$(brew --prefix ncurses);$(brew --prefix libxml2);"
ERROR throws ld: library not found for -lxml2
Maybe the errors originate from devbox shell environment.
I'll keep checking.
Close it for the moment.
I'm having library not found for -lzstd
I have zstd installed by brew and passing $(brew --prefix zstd) as well. There is clearly some problem on Mac.
I found the following instructions: There seems to be a problem with homebrew llvm and zstd.
The short way:
Do this (only once):ln -s /opt/homebrew/opt/zstd/lib/libzstd.a /opt/homebrew/opt/llvm/lib/libzstd.a
Then, to build:
load zig: gh repo clone ziglang/zig
Make build directory: cd zig; mkdir build; cd build
Prepare build: cmake .. -DZIG_STATIC_LLVM=on -DZIG_NO_LIB=ON -DCMAKE_BUILD_TYPE=Release
Build and install: make -j22; make install # Change -jn according to your machine
Expect "some" warnings while building...
Check: cd stage3/bin
Check binary: ./zig version
Check existence of lib: ./zig env
For me, this did not work with gcc, only with clang.
It is obviously as easy as just putting the link. Afterwards a standard build works.
Just ran into this as well on a fresh arm mac install. I had to add -DZIG_STATIC_ZLIB=ON -DZIG_STATIC_ZSTD=ON to the cmake command
My working build command is
cmake .. -DZIG_STATIC_LLVM=on -DZIG_STATIC_ZSTD=on -DZIG_NO_LIB=on -DCMAKE_BUILD_TYPE=Release -GNinja
But I've no idea why does it still work without -DCMAKE_PREFIX_PATH.
Looks like adding -DZIG_STATIC_ZLIB=ON -DZIG_STATIC_ZSTD=ON help build latest master (ca012e5b69) for me too, full command:
cmake .. -DZIG_STATIC_LLVM=ON -DCMAKE_SYSTEM_PREFIX_PATH="$(brew --prefix zstd);$(brew --prefix llvm@18)" -DCMAKE_BUILD_TYPE=Release -DZIG_STATIC_ZLIB=ON -DZIG_STATIC_ZSTD=ON
I tried this latest invocation, and am still getting a CMake failure, the relevant part being:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -arch arm64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.1.sdk -mmacosx-version-min=12.6 -Wl,-search_paths_first -Wl,-headerpad_max_install_names -L/opt/homebrew/opt/llvm/lib/c++ -L/opt/homebrew/opt/llvm/lib -lunwind-L/opt/homebrew/opt/llvm/lib -L/usr/local/opt/zstd/lib CMakeFiles/cmTC_5a369.dir/testCCompiler.c.o -o cmTC_5a369
ld: library not found for -lunwind-L/opt/homebrew/opt/llvm/lib
clang: error: linker command failed with exit code 1 (use -v to see invocation)
For the record:
$ ls /opt/homebrew/opt/llvm/lib/libunwind
/opt/homebrew/opt/llvm/lib/libunwind.1.0.dylib /opt/homebrew/opt/llvm/lib/libunwind.a
/opt/homebrew/opt/llvm/lib/libunwind.1.dylib /opt/homebrew/opt/llvm/lib/libunwind.dylib
I was able to build Zig about three weeks ago, so whatever this is, it's recent.
There is a space missing between -lunwind and -L/opt/homebrew/opt/llvm/lib. You could look at the invocation of the command.
That's a good catch.
In trying to troubleshoot this, I did a diff of ./CMakeLists.txt to see if I could spot the commit which introduced this error, and y'know, that might be the culprit.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f99e59e41f..6bd5f24a97 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -945,6 +945,11 @@ set(ZIG_BUILD_ARGS
-Dno-langref
)
+option(ZIG_EXTRA_BUILD_ARGS "Extra zig build args")
+if(ZIG_EXTRA_BUILD_ARGS)
+ list(APPEND ZIG_BUILD_ARGS ${ZIG_EXTRA_BUILD_ARGS})
+endif()
+
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
list(APPEND ZIG_BUILD_ARGS -Doptimize=Debug)
elseif("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
Except that deleting that from the file doesn't fix the build, so ah well, probably not. But it does look related, just eyeballing it.
As another observation, I ended up symlinking /usr/local/opt/zstd/lib, because the $(brew --prefix zstd) part of the build string, which produces /opt/homebrew/opt/zstd, does nothing, CMake tries to use the /opt/local location anyway. As random symlinks go, it's fairly harmless, but as it didn't fix the build anyway, I'd just as soon remove it.
I suppose it has nothing to do with the repository, since I can build it fine.
Maybe something got muddled up in your local copy.
I would try to remove the build directory and to create again.
And, though not absolutely necessary, I would recommend using clang 18, not the one from
your XCode install.
Then:
cd build
cmake .. -DZIG_STATIC_LLVM=ON -DCMAKE_BUILD_TYPE=Release
make
If this doesn't work, it might be an option to clone the repository again.
@mofrisch have you, yourself, done a build from a clean repo clone?
If not, it's at least equally likely that your local state is preserving something which is no longer available from a clean build.
Because I have tried it from a fresh clone, and it didn't work. I didn't use the exact invocation you listed there, but rather, the one from the Wiki. I suppose I could try again with that specific cmake invocation, and see what happens.
No, that specific cmake invocation doesn't work from a fresh repository also.
I'm not opposed to figuring out how to use clang 18 to build Zig, but I don't think it will fix the problem in the build script. Which is the string -lunwind-L/opt/homebrew/opt/llvm/lib, since that's just wrong, and a different version of clang isn't going to parse it any differently.
See here.
After brew install llvm clang obey this:
To use the bundled libc++ please add the following LDFLAGS: LDFLAGS="-L/opt/homebrew/opt/llvm/lib/c++ -L/opt/homebrew/opt/llvm/lib -lunwind"
llvm is keg-only, which means it was not symlinked into /opt/homebrew, because macOS already provides this software and installing another version in parallel can cause all kinds of trouble.
If you need to have llvm first in your PATH, run: echo 'export PATH="/opt/homebrew/opt/llvm/bin:$PATH"' >> ~/.zshrc
For compilers to find llvm you may need to set: export LDFLAGS="-L/opt/homebrew/opt/llvm/lib" export CPPFLAGS="-I/opt/homebrew/opt/llvm/include"
To use the bundled libc++ please add the following LDFLAGS: LDFLAGS="-L/opt/homebrew/opt/llvm/lib/c++ -L/opt/homebrew/opt/llvm/lib -lunwind"
I'm glad you mentioned this, because it turned out that the typo was, in fact, in LDFLAGs. To my chagrin, this almost surely happened from hitting Cmd-S out of muscle memory, while editing the .zshrc. Which in vim, doesn't save your file, it deletes one character. A space in this case.
I'm trying the build now, and since I have managed it before, the outlook is good. Thanks for the prompt!
Yep, that went fine.
What I'm getting from this thread is that the build instructions for MacOS + Homebrew just aren't complete. I don't think it's a case where what's on the Wiki is explicitly intended to work as written, as in, there's something in the build script which needs to be changed so that those exact instructions will work.
Rather, it appears that there's just a bit more to it, which could be added to the Wiki. Looking back at the help thread on Discord which let me build it the first time, it's a consistent list with things brought up in this thread:
- Need to install
llvm:brew install llvm. - LLVM is "keg-only", so you need to add some lines to
LDFLAGS:
-L/opt/homebrew/opt/llvm/lib/c++ -L/opt/homebrew/opt/llvm/lib -lunwind -L/opt/homebrew/opt/llvm/lib -L/usr/local/opt/zstd/lib
- And
CPPFLAGS:
-I/opt/homebrew/opt/llvm/include -I/usr/local/opt/zstd/include
- There's something weird going on with
zstd, this one might be fixable in the build script but if not, and in the meantime:
ln -s /opt/homebrew/opt/zstd/lib/libzstd.a /opt/homebrew/opt/llvm/lib/libzstd.a
- After that, it's just the build script that's on the Wiki already.
mkdir build
cd build
cmake .. -DZIG_STATIC_LLVM=ON -DCMAKE_PREFIX_PATH="$(brew --prefix llvm@18);$(brew --prefix zstd)"
make install
I wanted to get it all in one place as a draft, so others can sanity check this. Is anything else necessary? That's all I remember doing but I didn't take detailed notes or anything. Are some of these steps optional?
I'm particularly wondering if there's a way to eliminate the symlink, everything else here is perfectly reasonable but that feels like a kludge to me.
Once we get those questions sorted out, the missing steps can just be added to the Wiki, and we can close this issue.
😀 Makes absolute sense.
For me, it works without --DCMAKE_PREFIX_PATH. @mnemnion Could you check on your system?
Should add -DCMAKE_BUILD_TYPE=Release anyway, because default will be a debug build.
I suppose, that zstd is missing is a brew llvm thing, I will try with a source build of llvm later.
Right now, on apple platform, we have to invoke cmake with -DCMAKE_PREFIX_PATH to find some needed libs. This could be automated in CMakeLists.txt.
With these changes the following will work, which will probably be what the user expects:
mkdir build
cd build
cmake ..
make
Add:
if(APPLE)
execute_process(
COMMAND brew --prefix # get the brew prefix
RESULT_VARIABLE NO_BREW # if it is 0, brew is installed
OUTPUT_VARIABLE BREW_PREFIX
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(NOT NO_BREW)
list(APPEND CMAKE_PREFIX_PATH "${BREW_PREFIX}") # add the brew prefix to the cmake prefix path
list(APPEND CMAKE_PREFIX_PATH "${BREW_PREFIX}/opt/ncurses") # add the ncurses path to the cmake prefix path
list(APPEND CMAKE_PREFIX_PATH "${BREW_PREFIX}/opt/llvm") # add the llvm path to the cmake prefix path
endif()
endif()
The PATHS for ncurses can be removed.
Could someone review this change and if applicable make it a proposal?
It does work without the prefixes for me @mofrisch.
Unfortunately, with this kind of thing, it's tough to find the 'minimal set', because it involves various persistent changes to the user setup. But I distinctly recall the instructions from the Wiki not working without adding those LLDFLAGS and CPPFLAGS.
That wasn't something I got from the Discord, there were install notes which came with brew install llvm about what would be involved in using it with XCode cc tooling.
I should have some time this afternoon, or tomorrow evening, to reset everything as far as I can: un-simlink libzstd, brew uninstall llvm, remove the link flags, trash the Zig repo, and then try the new instructions and see if I can get away with leaving any of it out.
What else, in terms of a clean slate? Making a new user won't make a difference, because all of this is stored in the common parts of the file system. I don't want to trash Zig's global cache, but there should be no harm in moving it, which should have the same effect.
With my approach, I expect, the following has been executed:
brew install llvm
brew install ncurses
brew install zstd
Have switched to nix.