Commit 317c555a5c
Changed files (7)
lib
std
zig
system
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{ "/usr/bin/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);
+}
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),
lib/std/build.zig
@@ -1207,6 +1207,7 @@ pub const LibExeObjStep = struct {
name_only_filename: []const u8,
strip: bool,
lib_paths: ArrayList([]const u8),
+ syslibroot: ?[]const u8 = null,
framework_dirs: ArrayList([]const u8),
frameworks: BufSet,
verbose_link: bool,
@@ -1841,6 +1842,10 @@ pub const LibExeObjStep = struct {
self.lib_paths.append(self.builder.dupe(path)) catch unreachable;
}
+ pub fn addSyslibroot(self: *LibExeObjStep, path: []const u8) void {
+ self.syslibroot = path;
+ }
+
pub fn addFrameworkDir(self: *LibExeObjStep, dir_path: []const u8) void {
self.framework_dirs.append(self.builder.dupe(dir_path)) catch unreachable;
}
@@ -1915,11 +1920,18 @@ pub const LibExeObjStep = struct {
}
}
- // Inherit dependencies on darwin frameworks
- if (self.target.isDarwin() and !other.isDynamicLibrary()) {
- var it = other.frameworks.iterator();
- while (it.next()) |entry| {
- self.frameworks.put(entry.key) catch unreachable;
+ if (self.target.isDarwin()) {
+ // Inherit syslibroot
+ if (other.syslibroot) |path| {
+ self.syslibroot = path;
+ }
+
+ // Inherit dependencies on darwin frameworks
+ if (!other.isDynamicLibrary()) {
+ var it = other.frameworks.iterator();
+ while (it.next()) |entry| {
+ self.frameworks.put(entry.key) catch unreachable;
+ }
}
}
}
@@ -2271,6 +2283,18 @@ pub const LibExeObjStep = struct {
}
if (self.target.isDarwin()) {
+ if (self.syslibroot) |path| {
+ try zig_args.append("-syslibroot");
+ try zig_args.append(path);
+ } else {
+ if (self.target.isNative()) {
+ const syslibroot = try std.zig.system.getSDKPath(builder.allocator);
+ errdefer builder.allocator.free(syslibroot);
+ try zig_args.append("-syslibroot");
+ try zig_args.append(syslibroot);
+ }
+ }
+
for (self.framework_dirs.span()) |dir| {
try zig_args.append("-F");
try zig_args.append(dir);
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);
src/Compilation.zig
@@ -333,6 +333,7 @@ pub const InitOptions = struct {
keep_source_files_loaded: bool = false,
clang_argv: []const []const u8 = &[0][]const u8{},
lld_argv: []const []const u8 = &[0][]const u8{},
+ syslibroot: ?[]const u8 = null,
lib_dirs: []const []const u8 = &[0][]const u8{},
rpath_list: []const []const u8 = &[0][]const u8{},
c_source_files: []const CSourceFile = &[0]CSourceFile{},
@@ -773,6 +774,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.frameworks = options.frameworks,
.framework_dirs = options.framework_dirs,
.system_libs = system_libs,
+ .syslibroot = options.syslibroot,
.lib_dirs = options.lib_dirs,
.rpath_list = options.rpath_list,
.strip = strip,
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,
src/main.zig
@@ -315,8 +315,9 @@ const usage_build_generic =
\\ --subsystem [subsystem] (windows) /SUBSYSTEM:<subsystem> to the linker\n"
\\ --stack [size] Override default stack size
\\ --image-base [addr] Set base address for executable image
+ \\ -syslibroot [dir] (darwin) prepend a prefix to all search paths
\\ -framework [name] (darwin) link against framework
- \\ -F[dir] (darwin) add search path for frameworks
+ \\ -F [dir] (darwin) add search path for frameworks
\\
\\Test Options:
\\ --test-filter [text] Skip tests that do not match filter
@@ -492,6 +493,7 @@ fn buildOutputType(
var main_pkg_path: ?[]const u8 = null;
var clang_preprocessor_mode: Compilation.ClangPreprocessorMode = .no;
var subsystem: ?std.Target.SubSystem = null;
+ var syslibroot: ?[]const u8 = null;
var system_libs = std.ArrayList([]const u8).init(gpa);
defer system_libs.deinit();
@@ -682,6 +684,10 @@ fn buildOutputType(
if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
i += 1;
try lib_dirs.append(args[i]);
+ } else if (mem.eql(u8, arg, "-syslibroot")) {
+ if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
+ i += 1;
+ syslibroot = args[i];
} else if (mem.eql(u8, arg, "-F")) {
if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
i += 1;
@@ -1380,6 +1386,12 @@ fn buildOutputType(
}
}
+ if (cross_target.isNativeOs() and std.Target.current.isDarwin()) {
+ if (syslibroot == null) {
+ syslibroot = try std.zig.system.getSDKPath(arena);
+ }
+ }
+
const object_format: std.Target.ObjectFormat = blk: {
const ofmt = target_ofmt orelse break :blk target_info.target.getObjectFormat();
if (mem.eql(u8, ofmt, "elf")) {
@@ -1628,6 +1640,7 @@ fn buildOutputType(
.rpath_list = rpath_list.items,
.c_source_files = c_source_files.items,
.link_objects = link_objects.items,
+ .syslibroot = syslibroot,
.framework_dirs = framework_dirs.items,
.frameworks = frameworks.items,
.system_libs = system_libs.items,
@@ -2159,6 +2172,7 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
var override_lib_dir: ?[]const u8 = null;
var override_global_cache_dir: ?[]const u8 = null;
var override_local_cache_dir: ?[]const u8 = null;
+ var syslibroot: ?[]const u8 = null;
var child_argv = std.ArrayList([]const u8).init(arena);
const argv_index_exe = child_argv.items.len;
@@ -2200,6 +2214,11 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
override_global_cache_dir = args[i];
try child_argv.appendSlice(&[_][]const u8{ arg, args[i] });
continue;
+ } else if (mem.eql(u8, arg, "--syslibroot")) {
+ if (i + 1 >= args.len) fatal("expected argument after '{}'", .{arg});
+ i += 1;
+ syslibroot = args[i];
+ continue;
}
}
try child_argv.append(arg);
@@ -2305,6 +2324,12 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
const cross_target: std.zig.CrossTarget = .{};
const target_info = try detectNativeTargetInfo(gpa, cross_target);
+ if (cross_target.isNativeOs() and target_info.target.isDarwin()) {
+ if (syslibroot == null) {
+ syslibroot = try std.zig.system.getSDKPath(arena);
+ }
+ }
+
const exe_basename = try std.zig.binNameAlloc(arena, .{
.root_name = "build",
.target = target_info.target,
@@ -2328,6 +2353,7 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
.target = target_info.target,
.is_native_os = cross_target.isNativeOs(),
.dynamic_linker = target_info.dynamic_linker.get(),
+ .syslibroot = syslibroot,
.output_mode = .Exe,
.root_pkg = &root_pkg,
.emit_bin = emit_bin,