I recently updated from 0.6.0+2ab0c7391 (a few weeks old) to the most recent nightly build (0.6.0+17837affd), and am having issues withlinkFramework failing at the lld stage on macOS 10.13.16.
Here's a test case, with build.zig:
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
const exe = b.addExecutable("test", "test.zig");
exe.install();
exe.linkFramework("Foundation");
}
And test.zig:
const std = @import("std");
pub fn main() void {
std.debug.print("HELLO\n", .{});
}
Before, this ran successfully:
$ zig build --verbose-link
lld -error-limit 0 -demangle -dynamic -arch x86_64 -macosx_version_min 10.13.6 -sdk_version 10.13.6 -pie -o /Users/mkeeter/code/fr/zig-cache/o/cf9ce15f22f7a161c42707e37ce51843/test /Users/mkeeter/code/fr/zig-cache/o/cf9ce15f22f7a161c42707e37ce51843/test.o /Users/mkeeter/.cache/zig/o/9f6c0af7ad3f2d8fd1da960ab83b0fcd/libcompiler_rt.a -lSystem -framework Foundation
Afterwards, it failed:
```$ zig build --verbose-link
lld -error-limit 0 -demangle -dynamic -arch x86_64 -macosx_version_min 10.13.6 -sdk_version 10.13.6 -pie -o /Users/mkeeter/code/fr/zig-cache/o/4654afabe9457f126d827bbf490a9fb5/test -syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk /Users/mkeeter/code/fr/zig-cache/o/4654afabe9457f126d827bbf490a9fb5/test.o /Users/mkeeter/.cache/zig/o/f1df68771511a4d203f0a4edec21dc7d/libcompiler_rt.a -lSystem -framework Foundation
lld: error: Unable to find framework for -framework Foundation
error: LLDReportedFailure
test...The following command exited with error code 1:
/Users/mkeeter/code/zig-macos-x86_64-0.6.0+17837affd/zig build-exe /Users/mkeeter/code/fr/test.zig --verbose-link --cache-dir /Users/mkeeter/code/fr/zig-cache --name test -framework Foundation --enable-cache
error: the following build command failed with exit code 1:
/Users/mkeeter/code/fr/zig-cache/o/3fd4b3a62b30223625cf595c351fae15/build /Users/mkeeter/code/zig-macos-x86_64-0.6.0+17837affd/zig /Users/mkeeter/code/fr /Users/mkeeter/code/fr/zig-cache --verbose-link
Looking at the linker flags, the only change is adding `-syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk`, which was in PR #6932.
Needless to say, `Foundation` does exist in this folder, so I'm not sure why it's broken:
$ ls /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/Library/Frameworks | grep Foundation
AVFoundation.framework
CoreFoundation.framework
Foundation.framework
SecurityFoundation.framework
----------------------------------------------------------------
Interestingly, this also fails with LLVM 11 and a plain C program:
$ cat main.c
int main(int argc, char** argv) {
printf("Hello, world\n");
return 0;
}
$ cc -c -o main.o main.c
$ /usr/local/Cellar/llvm/11.0.0/bin/ld64.lld -arch x86_64 -sdk_version 10.13.6 main.o -syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -lSystem -framework Foundation -o main -v
Library search paths:
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib
Framework search paths:
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks
ld64.lld: error: Unable to find framework for -framework Foundation
```
Is there something wrong with this use of -syslibroot, in both this C example and the Zig build system?
Are you by any chance not mixing the dev tools from one release and your target? It looks to me as if you're trying to use Framework from 10.14 while building for 10.13.6. What is the output of xcrun --show-sdk-path? Perhaps it picks the latest syslibroot if you have multiple available?
I don't think that's it:
$ xcrun --show-sdk-path
/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk
(and messing with the -sdk_version doesn't seem to change anything)
This llvm-dev thread suggests that the answer is "ld64.lld just doesn't work on macOS", which is a little mindblowing; however, it was working for me until the -syslibroot argument was added.
Hmm, maybe you need to specify a framework search path as well? Could you try adding -F/System/Library/Frameworks? I think I remember seeing something in lld saying it not being not implemented correctly wrt syslibroot and framework search paths (meaning, when the former is specified the latter turns into garbage or something).
One last thing, if you want to force system linker on macOS, you can use export ZIG_SYSTEM_LINKER_HACK=1.
No luck; adding exe.addFrameworkDir("/System/Library/Frameworks"); to build.zig adds it to the command line, but does not fix the issue.
$ zig build --verbose-link
lld -error-limit 0 -demangle -dynamic -arch x86_64 -macosx_version_min 10.13.6 -sdk_version 10.13.6 -pie -o /Users/mkeeter/code/link_test/zig-cache/o/031707241332acf3f5c4c080d175db2f/test -syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk /Users/mkeeter/code/link_test/zig-cache/o/031707241332acf3f5c4c080d175db2f/test.o /Users/mkeeter/.cache/zig/o/fe2c25bbb0ba9a65f3f922c4022fa775/libcompiler_rt.a -lSystem -F /System/Library/Frameworks -framework Foundation
lld: error: Unable to find framework for -framework Foundation
error: LLDReportedFailure
test...The following command exited with error code 1:
/Users/mkeeter/code/zig-macos-x86_64-0.6.0+5430642fa/zig build-exe /Users/mkeeter/code/link_test/test.zig --verbose-link --cache-dir /Users/mkeeter/code/link_test/zig-cache --name test -F /System/Library/Frameworks -framework Foundation --enable-cache
error: the following build command failed with exit code 1:
/Users/mkeeter/code/link_test/zig-cache/o/044b1baf29e61ade75926face4f49a6a/build /Users/mkeeter/code/zig-macos-x86_64-0.6.0+5430642fa/zig /Users/mkeeter/code/link_test /Users/mkeeter/code/link_test/zig-cache --verbose-link
Exporting ZIG_SYSTEM_LINKER_HACK=1 does fix the issue, as expected, but it would be nice not to need it (and indeed, that was the case before -isysroot was added in #6932). Is there a way to make the -isysroot flag only mandatory in Big Sur?
No luck; adding
exe.addFrameworkDir("/System/Library/Frameworks");tobuild.zigadds it to the command line, but does not fix the issue.$ zig build --verbose-link lld -error-limit 0 -demangle -dynamic -arch x86_64 -macosx_version_min 10.13.6 -sdk_version 10.13.6 -pie -o /Users/mkeeter/code/link_test/zig-cache/o/031707241332acf3f5c4c080d175db2f/test -syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk /Users/mkeeter/code/link_test/zig-cache/o/031707241332acf3f5c4c080d175db2f/test.o /Users/mkeeter/.cache/zig/o/fe2c25bbb0ba9a65f3f922c4022fa775/libcompiler_rt.a -lSystem -F /System/Library/Frameworks -framework Foundation lld: error: Unable to find framework for -framework Foundation error: LLDReportedFailure test...The following command exited with error code 1: /Users/mkeeter/code/zig-macos-x86_64-0.6.0+5430642fa/zig build-exe /Users/mkeeter/code/link_test/test.zig --verbose-link --cache-dir /Users/mkeeter/code/link_test/zig-cache --name test -F /System/Library/Frameworks -framework Foundation --enable-cache error: the following build command failed with exit code 1: /Users/mkeeter/code/link_test/zig-cache/o/044b1baf29e61ade75926face4f49a6a/build /Users/mkeeter/code/zig-macos-x86_64-0.6.0+5430642fa/zig /Users/mkeeter/code/link_test /Users/mkeeter/code/link_test/zig-cache --verbose-linkExporting
ZIG_SYSTEM_LINKER_HACK=1_does_ fix the issue, as expected, but it would be nice not to need it (and indeed, that was the case before-isysrootwas added in #6932). Is there a way to make the-isysrootflag only mandatory in Big Sur?
It is possible to contrain it to a specific version of macOS, but it doesn鈥檛 solve the underlying issue that LLD doesn鈥檛 handle the syslibroot properly, so I鈥檓 not sure whether we should provide a hacky patch like this in Zig or help work out a fix for LLD. Thoughts @andrewrk?
My suggestion is to use the target version range to decide whether to pass the -syslibroot argument to LLD. When LLD 12 is released, we can re-evaluate this code. Until then, we don't pass -syslibroot when the minimum target version OS is < big sur and do pass it otherwise. How does that sound @kubkon ?
My suggestion is to use the target version range to decide whether to pass the -syslibroot argument to LLD. When LLD 12 is released, we can re-evaluate this code. Until then, we don't pass
-syslibrootwhen the minimum target version OS is < big sur and do pass it otherwise. How does that sound @kubkon ?
Sounds good to me! Leave that one with me, and I鈥檒l link against this issue and let everyone know once I have a mergeable PR ready.
OK! Here's a diff to get you started, take it or leave it, no attribution necessary:
diff --git a/src/Compilation.zig b/src/Compilation.zig
index 63858a1bc..222c01e1b 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -533,14 +533,13 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
};
const darwin_options: DarwinOptions = if (build_options.have_llvm and comptime std.Target.current.isDarwin()) outer: {
- const opts: DarwinOptions = if (use_lld and options.is_native_os and options.target.isDarwin()) inner: {
- const syslibroot = try std.zig.system.getSDKPath(arena);
- const system_linker_hack = std.os.getenv("ZIG_SYSTEM_LINKER_HACK") != null;
- break :inner .{
- .syslibroot = syslibroot,
- .system_linker_hack = system_linker_hack,
- };
- } else .{};
+ var opts: DarwinOptions = .{};
+ if (use_lld and options.is_native_os and options.target.isDarwin()) {
+ if (options.target.os.getVersionRange().semver.min.major >= 11) {
+ opts.syslibroot = try std.zig.system.getSDKPath(arena);
+ }
+ opts.system_linker_hack = std.os.getenv("ZIG_SYSTEM_LINKER_HACK") != null;
+ }
break :outer opts;
} else .{};
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index 97d233201..a741b75d4 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -421,6 +421,8 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
man.hash.addStringSet(self.base.options.system_libs);
man.hash.add(allow_shlib_undefined);
man.hash.add(self.base.options.bind_global_refs_locally);
+ man.hash.add(self.base.options.system_linker_hack);
+ man.hash.addOptionalBytes(self.base.options.syslibroot);
// We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
_ = try man.hit();