authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-11-26 16:08:44+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-11-26 16:26:44+01:00
log8317dbd1cb32eaeafa509e7142766f3d9a82de5f
tree780a0c6d17d3b10b22a3cce70543240a4900d13e
parent02d8ca71f98800df08754ce3d2d2e39541178f64

macos: detect SDK path and version, then pass to the linker

Since we are already detecting the path to the native SDK, if available, also fetch SDK's version and route that to the linker. The linker can then use it to correctly populate LC_BUILD_VERSION load command.

5 files changed, 87 insertions(+), 34 deletions(-)

lib/std/zig/system/darwin.zig+52-18
...@@ -2,14 +2,15 @@ const std = @import("std");...@@ -2,14 +2,15 @@ const std = @import("std");
2const mem = std.mem;2const mem = std.mem;
3const Allocator = mem.Allocator;3const Allocator = mem.Allocator;
4const Target = std.Target;4const Target = std.Target;
5const Version = std.builtin.Version;
56
6pub const macos = @import("darwin/macos.zig");7pub const macos = @import("darwin/macos.zig");
78
8/// Detect SDK path on Darwin.9/// Detect SDK on Darwin.
9/// Calls `xcrun --sdk <target_sdk> --show-sdk-path` which result can be used to specify10/// Calls `xcrun --sdk <target_sdk> --show-sdk-path` which fetches the path to the SDK sysroot (if any).
10/// `--sysroot` of the compiler.11/// Subsequently calls `xcrun --sdk <target_sdk> --show-sdk-version` which fetches version of the SDK.
11/// The caller needs to free the resulting path slice.12/// The caller needs to deinit the resulting struct.
12pub fn getSDKPath(allocator: *Allocator, target: Target) !?[]u8 {13pub fn getDarwinSDK(allocator: *Allocator, target: Target) !?DarwinSDK {
13 const is_simulator_abi = target.abi == .simulator;14 const is_simulator_abi = target.abi == .simulator;
14 const sdk = switch (target.os.tag) {15 const sdk = switch (target.os.tag) {
15 .macos => "macosx",16 .macos => "macosx",
...@@ -18,21 +19,54 @@ pub fn getSDKPath(allocator: *Allocator, target: Target) !?[]u8 {...@@ -18,21 +19,54 @@ pub fn getSDKPath(allocator: *Allocator, target: Target) !?[]u8 {
18 .tvos => if (is_simulator_abi) "appletvsimulator" else "appletvos",19 .tvos => if (is_simulator_abi) "appletvsimulator" else "appletvos",
19 else => return null,20 else => return null,
20 };21 };
22 const path = path: {
23 const argv = &[_][]const u8{ "xcrun", "--sdk", sdk, "--show-sdk-path" };
24 const result = try std.ChildProcess.exec(.{ .allocator = allocator, .argv = argv });
25 defer {
26 allocator.free(result.stderr);
27 allocator.free(result.stdout);
28 }
29 if (result.stderr.len != 0 or result.term.Exited != 0) {
30 // We don't actually care if there were errors as this is best-effort check anyhow
31 // and in the worst case the user can specify the sysroot manually.
32 return null;
33 }
34 const path = try allocator.dupe(u8, mem.trimRight(u8, result.stdout, "\r\n"));
35 break :path path;
36 };
37 const version = version: {
38 const argv = &[_][]const u8{ "xcrun", "--sdk", sdk, "--show-sdk-version" };
39 const result = try std.ChildProcess.exec(.{ .allocator = allocator, .argv = argv });
40 defer {
41 allocator.free(result.stderr);
42 allocator.free(result.stdout);
43 }
44 if (result.stderr.len != 0 or result.term.Exited != 0) {
45 // We don't actually care if there were errors as this is best-effort check anyhow
46 // and in the worst case the user can specify the sysroot manually.
47 return null;
48 }
49 const raw_version = mem.trimRight(u8, result.stdout, "\r\n");
50 const version = Version.parse(raw_version) catch Version{
51 .major = 0,
52 .minor = 0,
53 };
54 break :version version;
55 };
56 return DarwinSDK{
57 .path = path,
58 .version = version,
59 };
60}
2161
22 const argv = &[_][]const u8{ "xcrun", "--sdk", sdk, "--show-sdk-path" };62pub const DarwinSDK = struct {
23 const result = try std.ChildProcess.exec(.{ .allocator = allocator, .argv = argv });63 path: []const u8,
24 defer {64 version: Version,
25 allocator.free(result.stderr);65
26 allocator.free(result.stdout);66 pub fn deinit(self: DarwinSDK, allocator: *Allocator) void {
27 }67 allocator.free(self.path);
28 if (result.stderr.len != 0 or result.term.Exited != 0) {
29 // We don't actually care if there were errors as this is best-effort check anyhow
30 // and in the worst case the user can specify the sysroot manually.
31 return null;
32 }68 }
33 const sysroot = try allocator.dupe(u8, mem.trimRight(u8, result.stdout, "\r\n"));69};
34 return sysroot;
35}
3670
37test "" {71test "" {
38 _ = @import("darwin/macos.zig");72 _ = @import("darwin/macos.zig");
src/Compilation.zig+15-7
...@@ -773,8 +773,8 @@ pub const InitOptions = struct {...@@ -773,8 +773,8 @@ pub const InitOptions = struct {
773 wasi_exec_model: ?std.builtin.WasiExecModel = null,773 wasi_exec_model: ?std.builtin.WasiExecModel = null,
774 /// (Zig compiler development) Enable dumping linker's state as JSON.774 /// (Zig compiler development) Enable dumping linker's state as JSON.
775 enable_link_snapshots: bool = false,775 enable_link_snapshots: bool = false,
776 /// (Darwin). Path to native macOS SDK if detected.776 /// (Darwin) Path and version of the native SDK if detected.
777 native_macos_sdk_path: ?[]const u8 = null,777 native_darwin_sdk: ?std.zig.system.darwin.DarwinSDK = null,
778};778};
779779
780fn addPackageTableToCacheHash(780fn addPackageTableToCacheHash(
...@@ -967,8 +967,8 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -967,8 +967,8 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
967 const sysroot = blk: {967 const sysroot = blk: {
968 if (options.sysroot) |sysroot| {968 if (options.sysroot) |sysroot| {
969 break :blk sysroot;969 break :blk sysroot;
970 } else if (options.native_macos_sdk_path) |sdk_path| {970 } else if (options.native_darwin_sdk) |sdk| {
971 break :blk sdk_path;971 break :blk sdk.path;
972 } else {972 } else {
973 break :blk null;973 break :blk null;
974 }974 }
...@@ -1055,7 +1055,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -1055,7 +1055,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
1055 link_libc,1055 link_libc,
1056 options.system_lib_names.len != 0 or options.frameworks.len != 0,1056 options.system_lib_names.len != 0 or options.frameworks.len != 0,
1057 options.libc_installation,1057 options.libc_installation,
1058 options.native_macos_sdk_path != null,1058 options.native_darwin_sdk != null,
1059 );1059 );
10601060
1061 const must_pie = target_util.requiresPIE(options.target);1061 const must_pie = target_util.requiresPIE(options.target);
...@@ -1492,6 +1492,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -1492,6 +1492,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
1492 .wasi_exec_model = wasi_exec_model,1492 .wasi_exec_model = wasi_exec_model,
1493 .use_stage1 = use_stage1,1493 .use_stage1 = use_stage1,
1494 .enable_link_snapshots = options.enable_link_snapshots,1494 .enable_link_snapshots = options.enable_link_snapshots,
1495 .native_darwin_sdk = options.native_darwin_sdk,
1495 });1496 });
1496 errdefer bin_file.destroy();1497 errdefer bin_file.destroy();
1497 comp.* = .{1498 comp.* = .{
...@@ -3829,7 +3830,7 @@ fn detectLibCIncludeDirs(...@@ -3829,7 +3830,7 @@ fn detectLibCIncludeDirs(
3829 if (link_system_libs and is_native_abi and !target.isMinGW()) {3830 if (link_system_libs and is_native_abi and !target.isMinGW()) {
3830 if (target.isDarwin()) {3831 if (target.isDarwin()) {
3831 return if (has_macos_sdk)3832 return if (has_macos_sdk)
3832 // For Darwin/macOS, we are all set with getSDKPath found earlier.3833 // For Darwin/macOS, we are all set with getDarwinSDK found earlier.
3833 LibCDirs{3834 LibCDirs{
3834 .libc_include_dir_list = &[0][]u8{},3835 .libc_include_dir_list = &[0][]u8{},
3835 .libc_installation = null,3836 .libc_installation = null,
...@@ -3846,7 +3847,14 @@ fn detectLibCIncludeDirs(...@@ -3846,7 +3847,14 @@ fn detectLibCIncludeDirs(
3846 // default if possible.3847 // default if possible.
3847 if (target_util.canBuildLibC(target)) {3848 if (target_util.canBuildLibC(target)) {
3848 switch (target.os.tag) {3849 switch (target.os.tag) {
3849 .macos => return getZigShippedLibCIncludeDirsDarwin(arena, zig_lib_dir, target),3850 .macos => return if (has_macos_sdk)
3851 // For Darwin/macOS, we are all set with getDarwinSDK found earlier.
3852 LibCDirs{
3853 .libc_include_dir_list = &[0][]u8{},
3854 .libc_installation = null,
3855 }
3856 else
3857 getZigShippedLibCIncludeDirsDarwin(arena, zig_lib_dir, target),
3850 else => {3858 else => {
3851 const generic_name = target_util.libCGenericName(target);3859 const generic_name = target_util.libCGenericName(target);
3852 // Some architectures are handled by the same set of headers.3860 // Some architectures are handled by the same set of headers.
src/link.zig+3
...@@ -153,6 +153,9 @@ pub const Options = struct {...@@ -153,6 +153,9 @@ pub const Options = struct {
153 /// (Zig compiler development) Enable dumping of linker's state as JSON.153 /// (Zig compiler development) Enable dumping of linker's state as JSON.
154 enable_link_snapshots: bool = false,154 enable_link_snapshots: bool = false,
155155
156 /// (Darwin) Path and version of the native SDK if detected.
157 native_darwin_sdk: ?std.zig.system.darwin.DarwinSDK = null,
158
156 pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode {159 pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode {
157 return if (options.use_lld) .Obj else options.output_mode;160 return if (options.use_lld) .Obj else options.output_mode;
158 }161 }
src/link/MachO.zig+12-4
...@@ -4077,8 +4077,16 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -4077,8 +4077,16 @@ pub fn populateMissingMetadata(self: *MachO) !void {
4077 @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version),4077 @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version),
4078 @sizeOf(u64),4078 @sizeOf(u64),
4079 ));4079 ));
4080 const ver = self.base.options.target.os.version_range.semver.min;4080 const platform_version = blk: {
4081 const version = ver.major << 16 | ver.minor << 8 | ver.patch;4081 const ver = self.base.options.target.os.version_range.semver.min;
4082 const platform_version = ver.major << 16 | ver.minor << 8;
4083 break :blk platform_version;
4084 };
4085 const sdk_version = if (self.base.options.native_darwin_sdk) |sdk| blk: {
4086 const ver = sdk.version;
4087 const sdk_version = ver.major << 16 | ver.minor << 8;
4088 break :blk sdk_version;
4089 } else platform_version;
4082 const is_simulator_abi = self.base.options.target.abi == .simulator;4090 const is_simulator_abi = self.base.options.target.abi == .simulator;
4083 var cmd = commands.emptyGenericCommandWithData(macho.build_version_command{4091 var cmd = commands.emptyGenericCommandWithData(macho.build_version_command{
4084 .cmd = macho.LC_BUILD_VERSION,4092 .cmd = macho.LC_BUILD_VERSION,
...@@ -4090,8 +4098,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -4090,8 +4098,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
4090 .tvos => if (is_simulator_abi) macho.PLATFORM_TVOSSIMULATOR else macho.PLATFORM_TVOS,4098 .tvos => if (is_simulator_abi) macho.PLATFORM_TVOSSIMULATOR else macho.PLATFORM_TVOS,
4091 else => unreachable,4099 else => unreachable,
4092 },4100 },
4093 .minos = version,4101 .minos = platform_version,
4094 .sdk = version,4102 .sdk = sdk_version,
4095 .ntools = 1,4103 .ntools = 1,
4096 });4104 });
4097 const ld_ver = macho.build_tool_version{4105 const ld_ver = macho.build_tool_version{
src/main.zig+5-5
...@@ -663,7 +663,7 @@ fn buildOutputType(...@@ -663,7 +663,7 @@ fn buildOutputType(
663 var minor_subsystem_version: ?u32 = null;663 var minor_subsystem_version: ?u32 = null;
664 var wasi_exec_model: ?std.builtin.WasiExecModel = null;664 var wasi_exec_model: ?std.builtin.WasiExecModel = null;
665 var enable_link_snapshots: bool = false;665 var enable_link_snapshots: bool = false;
666 var native_macos_sdk_path: ?[]const u8 = null;666 var native_darwin_sdk: ?std.zig.system.darwin.DarwinSDK = null;
667667
668 var system_libs = std.StringArrayHashMap(Compilation.SystemLib).init(gpa);668 var system_libs = std.StringArrayHashMap(Compilation.SystemLib).init(gpa);
669 defer system_libs.deinit();669 defer system_libs.deinit();
...@@ -1858,11 +1858,11 @@ fn buildOutputType(...@@ -1858,11 +1858,11 @@ fn buildOutputType(
1858 }1858 }
18591859
1860 const has_sysroot = if (comptime builtin.target.isDarwin()) outer: {1860 const has_sysroot = if (comptime builtin.target.isDarwin()) outer: {
1861 if (try std.zig.system.darwin.getSDKPath(arena, target_info.target)) |sdk_path| {1861 if (try std.zig.system.darwin.getDarwinSDK(arena, target_info.target)) |sdk| {
1862 native_macos_sdk_path = sdk_path;1862 native_darwin_sdk = sdk;
1863 try clang_argv.ensureUnusedCapacity(2);1863 try clang_argv.ensureUnusedCapacity(2);
1864 clang_argv.appendAssumeCapacity("-isysroot");1864 clang_argv.appendAssumeCapacity("-isysroot");
1865 clang_argv.appendAssumeCapacity(sdk_path);1865 clang_argv.appendAssumeCapacity(sdk.path);
1866 break :outer true;1866 break :outer true;
1867 } else break :outer false;1867 } else break :outer false;
1868 } else false;1868 } else false;
...@@ -2342,7 +2342,7 @@ fn buildOutputType(...@@ -2342,7 +2342,7 @@ fn buildOutputType(
2342 .wasi_exec_model = wasi_exec_model,2342 .wasi_exec_model = wasi_exec_model,
2343 .debug_compile_errors = debug_compile_errors,2343 .debug_compile_errors = debug_compile_errors,
2344 .enable_link_snapshots = enable_link_snapshots,2344 .enable_link_snapshots = enable_link_snapshots,
2345 .native_macos_sdk_path = native_macos_sdk_path,2345 .native_darwin_sdk = native_darwin_sdk,
2346 }) catch |err| {2346 }) catch |err| {
2347 fatal("unable to create compilation: {s}", .{@errorName(err)});2347 fatal("unable to create compilation: {s}", .{@errorName(err)});
2348 };2348 };