diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2023-08-28 21:39:25 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2023-08-29 06:43:41 +0200 |
| commit | 3b2b9fcbc5e162063febf989883f29e55cc64c65 (patch) | |
| tree | c85bbce50c24a18df10e08889b1cb3cc3f69e335 /src | |
| parent | c429bb5d2feb36f83e33ef95a25dd5bb7455f16c (diff) | |
| download | zig-3b2b9fcbc5e162063febf989883f29e55cc64c65.tar.gz zig-3b2b9fcbc5e162063febf989883f29e55cc64c65.zip | |
darwin: move inference of SDK version into the linker
`std.zig.system.darwin.getSdk` now pulls only the SDK path
so we execute a child process only once and not twice as it was
until now since we parse the SDK version directly from the pulled path.
This is actually how `ld64` does it too.
Diffstat (limited to 'src')
| -rw-r--r-- | src/libc_installation.zig | 6 | ||||
| -rw-r--r-- | src/link/MachO/load_commands.zig | 63 |
2 files changed, 64 insertions, 5 deletions
diff --git a/src/libc_installation.zig b/src/libc_installation.zig index 2d42a03a32..c13de5a8e2 100644 --- a/src/libc_installation.zig +++ b/src/libc_installation.zig @@ -187,13 +187,13 @@ pub const LibCInstallation = struct { return error.DarwinSdkNotFound; const sdk = std.zig.system.darwin.getSdk(args.allocator, args.target) orelse return error.DarwinSdkNotFound; - defer args.allocator.free(sdk.path); + defer args.allocator.free(sdk); self.include_dir = try fs.path.join(args.allocator, &.{ - sdk.path, "usr/include", + sdk, "usr/include", }); self.sys_include_dir = try fs.path.join(args.allocator, &.{ - sdk.path, "usr/include", + sdk, "usr/include", }); return self; } else if (is_windows) { diff --git a/src/link/MachO/load_commands.zig b/src/link/MachO/load_commands.zig index 8f803d98cb..c980a764a2 100644 --- a/src/link/MachO/load_commands.zig +++ b/src/link/MachO/load_commands.zig @@ -278,7 +278,11 @@ pub fn writeBuildVersionLC(options: *const link.Options, lc_writer: anytype) !vo const platform_version = @as(u32, @intCast(ver.major << 16 | ver.minor << 8)); break :blk platform_version; }; - const sdk_version: u32 = if (options.darwin_sdk_version) |ver| + const sdk_version: ?std.SemanticVersion = options.darwin_sdk_version orelse blk: { + if (options.sysroot) |path| break :blk inferSdkVersionFromSdkPath(path); + break :blk null; + }; + const sdk_version_value: u32 = if (sdk_version) |ver| @intCast(ver.major << 16 | ver.minor << 8) else platform_version; @@ -293,7 +297,7 @@ pub fn writeBuildVersionLC(options: *const link.Options, lc_writer: anytype) !vo else => unreachable, }, .minos = platform_version, - .sdk = sdk_version, + .sdk = sdk_version_value, .ntools = 1, }); try lc_writer.writeAll(mem.asBytes(&macho.build_tool_version{ @@ -315,3 +319,58 @@ pub fn writeLoadDylibLCs(dylibs: []const Dylib, referenced: []u16, lc_writer: an }, lc_writer); } } + +fn inferSdkVersionFromSdkPath(path: []const u8) ?std.SemanticVersion { + const stem = std.fs.path.stem(path); + const start = for (stem, 0..) |c, i| { + if (std.ascii.isDigit(c)) break i; + } else stem.len; + const end = for (stem[start..], start..) |c, i| { + if (std.ascii.isDigit(c) or c == '.') continue; + break i; + } else stem.len; + return parseSdkVersion(stem[start..end]); +} + +// Versions reported by Apple aren't exactly semantically valid as they usually omit +// the patch component, so we parse SDK value by hand. +fn parseSdkVersion(raw: []const u8) ?std.SemanticVersion { + var parsed: std.SemanticVersion = .{ + .major = 0, + .minor = 0, + .patch = 0, + }; + + const parseNext = struct { + fn parseNext(it: anytype) ?u16 { + const nn = it.next() orelse return null; + return std.fmt.parseInt(u16, nn, 10) catch null; + } + }.parseNext; + + var it = std.mem.splitAny(u8, raw, "."); + parsed.major = parseNext(&it) orelse return null; + parsed.minor = parseNext(&it) orelse return null; + parsed.patch = parseNext(&it) orelse 0; + return parsed; +} + +const expect = std.testing.expect; +const expectEqual = std.testing.expectEqual; + +fn testParseSdkVersionSuccess(exp: std.SemanticVersion, raw: []const u8) !void { + const maybe_ver = parseSdkVersion(raw); + try expect(maybe_ver != null); + const ver = maybe_ver.?; + try expectEqual(exp.major, ver.major); + try expectEqual(exp.minor, ver.minor); + try expectEqual(exp.patch, ver.patch); +} + +test "parseSdkVersion" { + try testParseSdkVersionSuccess(.{ .major = 13, .minor = 4, .patch = 0 }, "13.4"); + try testParseSdkVersionSuccess(.{ .major = 13, .minor = 4, .patch = 1 }, "13.4.1"); + try testParseSdkVersionSuccess(.{ .major = 11, .minor = 15, .patch = 0 }, "11.15"); + + try expect(parseSdkVersion("11") == null); +} |
