ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
34.8k stars 2.54k forks source link

`zig build` mixes non-system headers with system libraries #10957

Open carlocab opened 2 years ago

carlocab commented 2 years ago

Zig Version

0.9.0

Steps to Reproduce

First, try to build fastfec 0.0.4 with only zig build -Dvendored-pcre=false:

curl -L https://github.com/washingtonpost/FastFEC/archive/refs/tags/0.0.4.tar.gz | tar -x
cd FastFEC-0.0.4
zig build -Dvendored-pcre=false

if you don't have pcre installed, this will fail with the following error:

error(compilation): clang failed with stderr: In file included from /private/var/folders/kb/pf4wbfc512z47l56g5072l900000gn/T/tmp.I7m44QsSX4/FastFEC-0.0.4/src/writer.c:1:
/private/var/folders/kb/pf4wbfc512z47l56g5072l900000gn/T/tmp.I7m44QsSX4/FastFEC-0.0.4/src/memory.h:5:10: fatal error: 'pcre.h' file not found

Now, do the same after installing pcre and pkg-config (e.g. brew install pcre pkg-config). Compilation succeeds, but fastfec links with /usr/lib/libpcre.dylib:

❯ otool -L zig-out/*/*fastfec*
zig-out/bin/fastfec:
        /usr/lib/libcurl.4.dylib (compatibility version 7.0.0, current version 9.0.0)
        /usr/lib/libpcre.0.dylib (compatibility version 1.0.0, current version 1.10.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1311.0.0)
zig-out/lib/libfastfec.dylib:
        @rpath/libfastfec.dylib (compatibility version 1.0.0, current version 1.0.0)
        /usr/lib/libpcre.0.dylib (compatibility version 1.0.0, current version 1.10.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1311.0.0)

The macOS SDK does not provide headers for PCRE, which means that zig used the headers from Homebrew except linked with the system libpcre.

Expected Behavior

I expected my build to link with Homebrew pcre. This was the behaviour under Zig 0.8.1:

❯ brew install fastfec
[snip]
❯ brew linkage fastfec
System libraries:
  /usr/lib/libSystem.B.dylib
  /usr/lib/libcurl.4.dylib
Homebrew libraries:
  /usr/local/opt/pcre/lib/libpcre.1.dylib (pcre)
❯ otool -L $(brew --prefix fastfec)/*/*fastfec*
/usr/local/opt/fastfec/bin/fastfec:
        /usr/lib/libcurl.4.dylib (compatibility version 7.0.0, current version 9.0.0)
        /usr/local/opt/pcre/lib/libpcre.1.dylib (compatibility version 4.0.0, current version 4.13.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1311.0.0)
/usr/local/opt/fastfec/lib/libfastfec.dylib:
        /usr/local/opt/fastfec/lib/libfastfec.dylib (compatibility version 0.0.0, current version 0.0.0)
        /usr/local/opt/pcre/lib/libpcre.1.dylib (compatibility version 4.0.0, current version 4.13.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1311.0.0)

Actual Behavior

Linkage with macOS libpcre.

carlocab commented 2 years ago

This is probably related to #10946. I haven't been able to dig deeply into it, but I think the behaviour we're seeing in Zig 0.9.1 on Darwin is that:

  1. It has difficulty finding system headers
  2. It has difficulty avoiding linkage with system libraries

This leads to the rather undesirable situation that it uses non-system headers (e.g. provided by Homebrew) but links with system libraries, which sounds like a recipe for disaster.

carlocab commented 2 years ago

This comment seems to be a good summary of what's happening:

Note that the issue occurs with existing zig 0.9.0 bottle. It appears to work on previous zig 0.8.1, so breakage may be changes between those releases.

With zig 0.8.1, fastfec build uses sysroot and SDK paths (snippets of command): /opt/homebrew/Cellar/zig/0.8.1_1/bin/zig clang -fno-caret-diagnostics -target aarch64-unknown-macosx-gnu -nostdinc -fno-spell-checking -isystem /opt/homebrew/Cellar/zig/0.8.1_1/lib/zig/include -isystem /Library/Developer/CommandLineTools/SDKs/MacOSX12.sdk/usr/include -Xclang ........... -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX12.sdk -iwithsysroot /usr/include -iwithsysroot /usr/local/include -iframeworkwithsysroot /Library/Frameworks -iframeworkwithsysroot /System/Library/Frameworks ...........

With zig 0.9+, there is no sysroot or SDK paths /opt/homebrew/Cellar/zig/0.9.0/bin/zig clang -fno-caret-diagnostics -target aarch64-unknown-macosx-gnu -nostdinc -fno-spell-checking -isystem /opt/homebrew/Cellar/zig/0.9.0/lib/zig/include -isystem /opt/homebrew/Cellar/zig/0.9.0/lib/zig/libc/include/aarch64-macos.12-gnu -isystem /opt/homebrew/Cellar/zig/0.9.0/lib/zig/libc/include/any-macos.12-any -isystem /opt/homebrew/Cellar/zig/0.9.0/lib/zig/libc/include/any-macos-any .......... -I /opt/homebrew/Cellar/pcre/8.45/include -isystem /usr/include /System/Library/Frameworks .........

Zig seems to want to replace headers from the macOS SDK with its own bundled ones, but then only provides a limited subset of them.

I guess this might be fine (albeit not ideal) if the linker avoids linkage with system libraries too, but the linker seems to do the exact opposite vis a vis the system headers here.