diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index 33ef137eb6..b969fe8d96 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -17,6 +17,8 @@ const macos = @import("system/macos.zig"); const is_windows = Target.current.os.tag == .windows; +pub const getSDKPath = macos.getSDKPath; + pub const NativePaths = struct { include_dirs: ArrayList([:0]u8), lib_dirs: ArrayList([:0]u8), diff --git a/lib/std/zig/system/macos.zig b/lib/std/zig/system/macos.zig index e0e69b6b8b..6895fa3f3a 100644 --- a/lib/std/zig/system/macos.zig +++ b/lib/std/zig/system/macos.zig @@ -4,6 +4,8 @@ // The MIT license requires this copyright notice to be included in all copies // and substantial portions of the software. const std = @import("std"); +const assert = std.debug.assert; +const mem = std.mem; pub fn version_from_build(build: []const u8) !std.builtin.Version { // build format: @@ -452,3 +454,25 @@ test "version_from_build" { std.testing.expect(std.mem.eql(u8, sver, pair[1])); } } + +/// Detect SDK path on Darwin. +/// Calls `xcrun --show-sdk-path` which result can be used to specify +/// `-syslibroot` param of the linker. +/// The caller needs to free the resulting path slice. +pub fn getSDKPath(allocator: *mem.Allocator) ![]u8 { + assert(std.Target.current.isDarwin()); + const argv = &[_][]const u8{ "xcrun", "--show-sdk-path" }; + const result = try std.ChildProcess.exec(.{ .allocator = allocator, .argv = argv }); + defer { + allocator.free(result.stderr); + allocator.free(result.stdout); + } + if (result.stderr.len != 0) { + std.log.err("unexpected 'xcrun --show-sdk-path' stderr: {}", .{result.stderr}); + } + if (result.term.Exited != 0) { + return error.ProcessTerminated; + } + const syslibroot = mem.trimRight(u8, result.stdout, "\r\n"); + return mem.dupe(allocator, u8, syslibroot); +} diff --git a/src/Compilation.zig b/src/Compilation.zig index 472f367b91..d4289fad34 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -472,6 +472,14 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { break :blk false; }; + const syslibroot = if (build_options.have_llvm and comptime std.Target.current.isDarwin()) outer: { + const path = if (use_lld and options.is_native_os and options.target.isDarwin()) inner: { + const syslibroot_path = try std.zig.system.getSDKPath(arena); + break :inner syslibroot_path; + } else null; + break :outer path; + } else null; + const link_libc = options.link_libc or target_util.osRequiresLibC(options.target); const must_dynamic_link = dl: { @@ -773,6 +781,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { .frameworks = options.frameworks, .framework_dirs = options.framework_dirs, .system_libs = system_libs, + .syslibroot = syslibroot, .lib_dirs = options.lib_dirs, .rpath_list = options.rpath_list, .strip = strip, diff --git a/src/link.zig b/src/link.zig index 3f6ceb7ac3..02433ecde7 100644 --- a/src/link.zig +++ b/src/link.zig @@ -88,6 +88,8 @@ pub const Options = struct { llvm_cpu_features: ?[*:0]const u8, /// Extra args passed directly to LLD. Ignored when not linking with LLD. extra_lld_args: []const []const u8, + /// Darwin-only. Set the root path to the system libraries and frameworks. + syslibroot: ?[]const u8, objects: []const []const u8, framework_dirs: []const []const u8, diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 7344a698f9..01830c1561 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -628,6 +628,11 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { } } + if (self.base.options.syslibroot) |dir| { + try argv.append("-syslibroot"); + try argv.append(dir); + } + for (self.base.options.lib_dirs) |lib_dir| { try argv.append("-L"); try argv.append(lib_dir);