| author | |
| committer | |
| log | 2e28ab153c39df77403eb64f282589349f05921d |
| tree | 217c88b51804fc416b844e2055d3d78d97324705 |
| parent | ec03619dcfa025442f6a70cbdfeafd5882591b64 |
5 files changed, 203 insertions(+), 39 deletions(-)
src/link/MachO.zig+15-4| ... | @@ -585,7 +585,18 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -585,7 +585,18 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 585 | try lc_writer.writeStruct(macho.source_version_command{ | 585 | try lc_writer.writeStruct(macho.source_version_command{ |
| 586 | .version = 0, | 586 | .version = 0, |
| 587 | }); | 587 | }); |
| 588 | try load_commands.writeBuildVersionLC(&self.base.options, lc_writer); | 588 | { |
| 589 | const platform = load_commands.Platform.fromOptions(&self.base.options); | ||
| 590 | const sdk_version: ?std.SemanticVersion = self.base.options.darwin_sdk_version orelse blk: { | ||
| 591 | if (self.base.options.sysroot) |path| break :blk load_commands.inferSdkVersionFromSdkPath(path); | ||
| 592 | break :blk null; | ||
| 593 | }; | ||
| 594 | if (platform.isBuildVersionCompatible()) { | ||
| 595 | try load_commands.writeBuildVersionLC(platform, sdk_version, lc_writer); | ||
| 596 | } else { | ||
| 597 | try load_commands.writeVersionMinLC(platform, sdk_version, lc_writer); | ||
| 598 | } | ||
| 599 | } | ||
| 589 | 600 | ||
| 590 | const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + @as(u32, @intCast(lc_buffer.items.len)); | 601 | const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + @as(u32, @intCast(lc_buffer.items.len)); |
| 591 | try lc_writer.writeStruct(self.uuid_cmd); | 602 | try lc_writer.writeStruct(self.uuid_cmd); |
| ... | @@ -797,7 +808,7 @@ fn parseObject( | ... | @@ -797,7 +808,7 @@ fn parseObject( |
| 797 | const self_cpu_arch = self.base.options.target.cpu.arch; | 808 | const self_cpu_arch = self.base.options.target.cpu.arch; |
| 798 | 809 | ||
| 799 | if (self_cpu_arch != cpu_arch) { | 810 | if (self_cpu_arch != cpu_arch) { |
| 800 | error_ctx.* = .{ .detected_arch = cpu_arch }; | 811 | error_ctx.detected_arch = cpu_arch; |
| 801 | return error.InvalidArch; | 812 | return error.InvalidArch; |
| 802 | } | 813 | } |
| 803 | } | 814 | } |
| ... | @@ -894,7 +905,7 @@ fn parseArchive( | ... | @@ -894,7 +905,7 @@ fn parseArchive( |
| 894 | else => unreachable, | 905 | else => unreachable, |
| 895 | }; | 906 | }; |
| 896 | if (cpu_arch != parsed_cpu_arch) { | 907 | if (cpu_arch != parsed_cpu_arch) { |
| 897 | error_ctx.* = .{ .detected_arch = parsed_cpu_arch }; | 908 | error_ctx.detected_arch = parsed_cpu_arch; |
| 898 | return error.InvalidArch; | 909 | return error.InvalidArch; |
| 899 | } | 910 | } |
| 900 | } | 911 | } |
| ... | @@ -959,7 +970,7 @@ fn parseDylib( | ... | @@ -959,7 +970,7 @@ fn parseDylib( |
| 959 | else => unreachable, | 970 | else => unreachable, |
| 960 | }; | 971 | }; |
| 961 | if (self_cpu_arch != cpu_arch) { | 972 | if (self_cpu_arch != cpu_arch) { |
| 962 | error_ctx.* = .{ .detected_arch = cpu_arch }; | 973 | error_ctx.detected_arch = cpu_arch; |
| 963 | return error.InvalidArch; | 974 | return error.InvalidArch; |
| 964 | } | 975 | } |
| 965 | 976 |
src/link/MachO/Dylib.zig+4-4| ... | @@ -217,7 +217,7 @@ const TargetMatcher = struct { | ... | @@ -217,7 +217,7 @@ const TargetMatcher = struct { |
| 217 | target: CrossTarget, | 217 | target: CrossTarget, |
| 218 | target_strings: std.ArrayListUnmanaged([]const u8) = .{}, | 218 | target_strings: std.ArrayListUnmanaged([]const u8) = .{}, |
| 219 | 219 | ||
| 220 | fn init(allocator: Allocator, target: CrossTarget) !TargetMatcher { | 220 | pub fn init(allocator: Allocator, target: CrossTarget) !TargetMatcher { |
| 221 | var self = TargetMatcher{ | 221 | var self = TargetMatcher{ |
| 222 | .allocator = allocator, | 222 | .allocator = allocator, |
| 223 | .target = target, | 223 | .target = target, |
| ... | @@ -239,7 +239,7 @@ const TargetMatcher = struct { | ... | @@ -239,7 +239,7 @@ const TargetMatcher = struct { |
| 239 | return self; | 239 | return self; |
| 240 | } | 240 | } |
| 241 | 241 | ||
| 242 | fn deinit(self: *TargetMatcher) void { | 242 | pub fn deinit(self: *TargetMatcher) void { |
| 243 | for (self.target_strings.items) |t| { | 243 | for (self.target_strings.items) |t| { |
| 244 | self.allocator.free(t); | 244 | self.allocator.free(t); |
| 245 | } | 245 | } |
| ... | @@ -263,7 +263,7 @@ const TargetMatcher = struct { | ... | @@ -263,7 +263,7 @@ const TargetMatcher = struct { |
| 263 | }; | 263 | }; |
| 264 | } | 264 | } |
| 265 | 265 | ||
| 266 | fn targetToAppleString(allocator: Allocator, target: CrossTarget) ![]const u8 { | 266 | pub fn targetToAppleString(allocator: Allocator, target: CrossTarget) ![]const u8 { |
| 267 | const cpu_arch = cpuArchToAppleString(target.cpu_arch.?); | 267 | const cpu_arch = cpuArchToAppleString(target.cpu_arch.?); |
| 268 | const os_tag = @tagName(target.os_tag.?); | 268 | const os_tag = @tagName(target.os_tag.?); |
| 269 | const target_abi = abiToAppleString(target.abi orelse .none); | 269 | const target_abi = abiToAppleString(target.abi orelse .none); |
| ... | @@ -291,7 +291,7 @@ const TargetMatcher = struct { | ... | @@ -291,7 +291,7 @@ const TargetMatcher = struct { |
| 291 | return hasValue(archs, cpuArchToAppleString(self.target.cpu_arch.?)); | 291 | return hasValue(archs, cpuArchToAppleString(self.target.cpu_arch.?)); |
| 292 | } | 292 | } |
| 293 | 293 | ||
| 294 | fn matchesTargetTbd(self: TargetMatcher, tbd: Tbd) !bool { | 294 | pub fn matchesTargetTbd(self: TargetMatcher, tbd: Tbd) !bool { |
| 295 | var arena = std.heap.ArenaAllocator.init(self.allocator); | 295 | var arena = std.heap.ArenaAllocator.init(self.allocator); |
| 296 | defer arena.deinit(); | 296 | defer arena.deinit(); |
| 297 | 297 |
src/link/MachO/Object.zig+21| ... | @@ -940,6 +940,26 @@ pub fn parseDwarfInfo(self: Object) DwarfInfo { | ... | @@ -940,6 +940,26 @@ pub fn parseDwarfInfo(self: Object) DwarfInfo { |
| 940 | return di; | 940 | return di; |
| 941 | } | 941 | } |
| 942 | 942 | ||
| 943 | /// Returns Options.Platform composed from the first encountered build version type load command: | ||
| 944 | /// either LC_BUILD_VERSION or LC_VERSION_MIN_*. | ||
| 945 | pub fn getPlatform(self: Object) ?Platform { | ||
| 946 | var it = LoadCommandIterator{ | ||
| 947 | .ncmds = self.header.ncmds, | ||
| 948 | .buffer = self.contents[@sizeOf(macho.mach_header_64)..][0..self.header.sizeofcmds], | ||
| 949 | }; | ||
| 950 | while (it.next()) |cmd| { | ||
| 951 | switch (cmd.cmd()) { | ||
| 952 | .BUILD_VERSION, | ||
| 953 | .VERSION_MIN_MACOSX, | ||
| 954 | .VERSION_MIN_IPHONEOS, | ||
| 955 | .VERSION_MIN_TVOS, | ||
| 956 | .VERSION_MIN_WATCHOS, | ||
| 957 | => return Platform.fromLoadCommand(cmd), | ||
| 958 | else => {}, | ||
| 959 | } | ||
| 960 | } else return null; | ||
| 961 | } | ||
| 962 | |||
| 943 | pub fn getSectionContents(self: Object, sect: macho.section_64) []const u8 { | 963 | pub fn getSectionContents(self: Object, sect: macho.section_64) []const u8 { |
| 944 | const size = @as(usize, @intCast(sect.size)); | 964 | const size = @as(usize, @intCast(sect.size)); |
| 945 | return self.contents[sect.offset..][0..size]; | 965 | return self.contents[sect.offset..][0..size]; |
| ... | @@ -1089,5 +1109,6 @@ const Atom = @import("Atom.zig"); | ... | @@ -1089,5 +1109,6 @@ const Atom = @import("Atom.zig"); |
| 1089 | const DwarfInfo = @import("DwarfInfo.zig"); | 1109 | const DwarfInfo = @import("DwarfInfo.zig"); |
| 1090 | const LoadCommandIterator = macho.LoadCommandIterator; | 1110 | const LoadCommandIterator = macho.LoadCommandIterator; |
| 1091 | const MachO = @import("../MachO.zig"); | 1111 | const MachO = @import("../MachO.zig"); |
| 1112 | const Platform = @import("load_commands.zig").Platform; | ||
| 1092 | const SymbolWithLoc = MachO.SymbolWithLoc; | 1113 | const SymbolWithLoc = MachO.SymbolWithLoc; |
| 1093 | const UnwindInfo = @import("UnwindInfo.zig"); | 1114 | const UnwindInfo = @import("UnwindInfo.zig"); |
src/link/MachO/load_commands.zig+145-27| ... | @@ -76,8 +76,14 @@ fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx | ... | @@ -76,8 +76,14 @@ fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx |
| 76 | } | 76 | } |
| 77 | // LC_SOURCE_VERSION | 77 | // LC_SOURCE_VERSION |
| 78 | sizeofcmds += @sizeOf(macho.source_version_command); | 78 | sizeofcmds += @sizeOf(macho.source_version_command); |
| 79 | // LC_BUILD_VERSION | 79 | // LC_BUILD_VERSION or LC_VERSION_MIN_ |
| 80 | sizeofcmds += @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version); | 80 | if (Platform.fromOptions(options).isBuildVersionCompatible()) { |
| 81 | // LC_BUILD_VERSION | ||
| 82 | sizeofcmds += @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version); | ||
| 83 | } else { | ||
| 84 | // LC_VERSION_MIN_ | ||
| 85 | sizeofcmds += @sizeOf(macho.version_min_command); | ||
| 86 | } | ||
| 81 | // LC_UUID | 87 | // LC_UUID |
| 82 | sizeofcmds += @sizeOf(macho.uuid_command); | 88 | sizeofcmds += @sizeOf(macho.uuid_command); |
| 83 | // LC_LOAD_DYLIB | 89 | // LC_LOAD_DYLIB |
| ... | @@ -252,33 +258,28 @@ pub fn writeRpathLCs(gpa: Allocator, options: *const link.Options, lc_writer: an | ... | @@ -252,33 +258,28 @@ pub fn writeRpathLCs(gpa: Allocator, options: *const link.Options, lc_writer: an |
| 252 | } | 258 | } |
| 253 | } | 259 | } |
| 254 | 260 | ||
| 255 | pub fn writeBuildVersionLC(options: *const link.Options, lc_writer: anytype) !void { | 261 | pub fn writeVersionMinLC(platform: Platform, sdk_version: ?std.SemanticVersion, lc_writer: anytype) !void { |
| 256 | const cmdsize = @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version); | 262 | const cmd: macho.LC = switch (platform.os_tag) { |
| 257 | const platform_version = blk: { | 263 | .macos => .VERSION_MIN_MACOSX, |
| 258 | const ver = options.target.os.version_range.semver.min; | 264 | .ios => .VERSION_MIN_IPHONEOS, |
| 259 | const platform_version = @as(u32, @intCast(ver.major << 16 | ver.minor << 8)); | 265 | .tvos => .VERSION_MIN_TVOS, |
| 260 | break :blk platform_version; | 266 | .watchos => .VERSION_MIN_WATCHOS, |
| 261 | }; | 267 | else => unreachable, |
| 262 | const sdk_version: ?std.SemanticVersion = options.darwin_sdk_version orelse blk: { | ||
| 263 | if (options.sysroot) |path| break :blk inferSdkVersionFromSdkPath(path); | ||
| 264 | break :blk null; | ||
| 265 | }; | 268 | }; |
| 266 | const sdk_version_value: u32 = if (sdk_version) |ver| | 269 | try lc_writer.writeAll(mem.asBytes(&macho.version_min_command{ |
| 267 | @intCast(ver.major << 16 | ver.minor << 8) | 270 | .cmd = cmd, |
| 268 | else | 271 | .version = platform.toAppleVersion(), |
| 269 | platform_version; | 272 | .sdk = if (sdk_version) |ver| Platform.semanticVersionToAppleVersion(ver) else platform.toAppleVersion(), |
| 270 | const is_simulator_abi = options.target.abi == .simulator; | 273 | })); |
| 274 | } | ||
| 275 | |||
| 276 | pub fn writeBuildVersionLC(platform: Platform, sdk_version: ?std.SemanticVersion, lc_writer: anytype) !void { | ||
| 277 | const cmdsize = @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version); | ||
| 271 | try lc_writer.writeStruct(macho.build_version_command{ | 278 | try lc_writer.writeStruct(macho.build_version_command{ |
| 272 | .cmdsize = cmdsize, | 279 | .cmdsize = cmdsize, |
| 273 | .platform = switch (options.target.os.tag) { | 280 | .platform = platform.toApplePlatform(), |
| 274 | .macos => .MACOS, | 281 | .minos = platform.toAppleVersion(), |
| 275 | .ios => if (is_simulator_abi) macho.PLATFORM.IOSSIMULATOR else macho.PLATFORM.IOS, | 282 | .sdk = if (sdk_version) |ver| Platform.semanticVersionToAppleVersion(ver) else platform.toAppleVersion(), |
| 276 | .watchos => if (is_simulator_abi) macho.PLATFORM.WATCHOSSIMULATOR else macho.PLATFORM.WATCHOS, | ||
| 277 | .tvos => if (is_simulator_abi) macho.PLATFORM.TVOSSIMULATOR else macho.PLATFORM.TVOS, | ||
| 278 | else => unreachable, | ||
| 279 | }, | ||
| 280 | .minos = platform_version, | ||
| 281 | .sdk = sdk_version_value, | ||
| 282 | .ntools = 1, | 283 | .ntools = 1, |
| 283 | }); | 284 | }); |
| 284 | try lc_writer.writeAll(mem.asBytes(&macho.build_tool_version{ | 285 | try lc_writer.writeAll(mem.asBytes(&macho.build_tool_version{ |
| ... | @@ -301,7 +302,124 @@ pub fn writeLoadDylibLCs(dylibs: []const Dylib, referenced: []u16, lc_writer: an | ... | @@ -301,7 +302,124 @@ pub fn writeLoadDylibLCs(dylibs: []const Dylib, referenced: []u16, lc_writer: an |
| 301 | } | 302 | } |
| 302 | } | 303 | } |
| 303 | 304 | ||
| 304 | fn inferSdkVersionFromSdkPath(path: []const u8) ?std.SemanticVersion { | 305 | pub const Platform = struct { |
| 306 | os_tag: std.Target.Os.Tag, | ||
| 307 | abi: std.Target.Abi, | ||
| 308 | version: std.SemanticVersion, | ||
| 309 | |||
| 310 | /// Using Apple's ld64 as our blueprint, `min_version` as well as `sdk_version` are set to | ||
| 311 | /// the extracted minimum platform version. | ||
| 312 | pub fn fromLoadCommand(lc: macho.LoadCommandIterator.LoadCommand) Platform { | ||
| 313 | switch (lc.cmd()) { | ||
| 314 | .BUILD_VERSION => { | ||
| 315 | const cmd = lc.cast(macho.build_version_command).?; | ||
| 316 | return .{ | ||
| 317 | .os_tag = switch (cmd.platform) { | ||
| 318 | .MACOS => .macos, | ||
| 319 | .IOS, .IOSSIMULATOR => .ios, | ||
| 320 | .TVOS, .TVOSSIMULATOR => .tvos, | ||
| 321 | .WATCHOS, .WATCHOSSIMULATOR => .watchos, | ||
| 322 | else => @panic("TODO"), | ||
| 323 | }, | ||
| 324 | .abi = switch (cmd.platform) { | ||
| 325 | .IOSSIMULATOR, | ||
| 326 | .TVOSSIMULATOR, | ||
| 327 | .WATCHOSSIMULATOR, | ||
| 328 | => .simulator, | ||
| 329 | else => .none, | ||
| 330 | }, | ||
| 331 | .version = appleVersionToSemanticVersion(cmd.minos), | ||
| 332 | }; | ||
| 333 | }, | ||
| 334 | .VERSION_MIN_MACOSX, | ||
| 335 | .VERSION_MIN_IPHONEOS, | ||
| 336 | .VERSION_MIN_TVOS, | ||
| 337 | .VERSION_MIN_WATCHOS, | ||
| 338 | => { | ||
| 339 | const cmd = lc.cast(macho.version_min_command).?; | ||
| 340 | return .{ | ||
| 341 | .os_tag = switch (lc.cmd()) { | ||
| 342 | .VERSION_MIN_MACOSX => .macos, | ||
| 343 | .VERSION_MIN_IPHONEOS => .ios, | ||
| 344 | .VERSION_MIN_TVOS => .tvos, | ||
| 345 | .VERSION_MIN_WATCHOS => .watchos, | ||
| 346 | else => unreachable, | ||
| 347 | }, | ||
| 348 | .abi = .none, | ||
| 349 | .version = appleVersionToSemanticVersion(cmd.version), | ||
| 350 | }; | ||
| 351 | }, | ||
| 352 | else => unreachable, | ||
| 353 | } | ||
| 354 | } | ||
| 355 | |||
| 356 | pub fn fromOptions(options: *const link.Options) Platform { | ||
| 357 | return .{ | ||
| 358 | .os_tag = options.target.os.tag, | ||
| 359 | .abi = options.target.abi, | ||
| 360 | .version = options.target.os.version_range.semver.min, | ||
| 361 | }; | ||
| 362 | } | ||
| 363 | |||
| 364 | pub fn toAppleVersion(plat: Platform) u32 { | ||
| 365 | return semanticVersionToAppleVersion(plat.version); | ||
| 366 | } | ||
| 367 | |||
| 368 | pub fn toApplePlatform(plat: Platform) macho.PLATFORM { | ||
| 369 | return switch (plat.os_tag) { | ||
| 370 | .macos => .MACOS, | ||
| 371 | .ios => if (plat.abi == .simulator) .IOSSIMULATOR else .IOS, | ||
| 372 | .tvos => if (plat.abi == .simulator) .TVOSSIMULATOR else .TVOS, | ||
| 373 | .watchos => if (plat.abi == .simulator) .WATCHOSSIMULATOR else .WATCHOS, | ||
| 374 | else => unreachable, | ||
| 375 | }; | ||
| 376 | } | ||
| 377 | |||
| 378 | pub fn isBuildVersionCompatible(plat: Platform) bool { | ||
| 379 | inline for (supported_platforms) |sup_plat| { | ||
| 380 | if (sup_plat[0] == plat.os_tag and sup_plat[1] == plat.abi) { | ||
| 381 | return sup_plat[2] <= plat.toAppleVersion(); | ||
| 382 | } | ||
| 383 | } | ||
| 384 | return false; | ||
| 385 | } | ||
| 386 | |||
| 387 | pub inline fn semanticVersionToAppleVersion(version: std.SemanticVersion) u32 { | ||
| 388 | const major = version.major; | ||
| 389 | const minor = version.minor; | ||
| 390 | const patch = version.patch; | ||
| 391 | return (@as(u32, @intCast(major)) << 16) | (@as(u32, @intCast(minor)) << 8) | @as(u32, @intCast(patch)); | ||
| 392 | } | ||
| 393 | |||
| 394 | inline fn appleVersionToSemanticVersion(version: u32) std.SemanticVersion { | ||
| 395 | return .{ | ||
| 396 | .major = @as(u16, @truncate(version >> 16)), | ||
| 397 | .minor = @as(u8, @truncate(version >> 8)), | ||
| 398 | .patch = @as(u8, @truncate(version)), | ||
| 399 | }; | ||
| 400 | } | ||
| 401 | }; | ||
| 402 | |||
| 403 | const SupportedPlatforms = struct { | ||
| 404 | std.Target.Os.Tag, | ||
| 405 | std.Target.Abi, | ||
| 406 | u32, // Min platform version for which to emit LC_BUILD_VERSION | ||
| 407 | u32, // Min supported platform version | ||
| 408 | ?[]const u8, // Env var to look for | ||
| 409 | }; | ||
| 410 | |||
| 411 | // Source: https://github.com/apple-oss-distributions/ld64/blob/59a99ab60399c5e6c49e6945a9e1049c42b71135/src/ld/PlatformSupport.cpp#L52 | ||
| 412 | const supported_platforms = [_]SupportedPlatforms{ | ||
| 413 | .{ .macos, .none, 0xA0E00, 0xA0800, "MACOSX_DEPLOYMENT_TARGET" }, | ||
| 414 | .{ .ios, .none, 0xC0000, 0x70000, "IPHONEOS_DEPLOYMENT_TARGET" }, | ||
| 415 | .{ .tvos, .none, 0xC0000, 0x70000, "TVOS_DEPLOYMENT_TARGET" }, | ||
| 416 | .{ .watchos, .none, 0x50000, 0x20000, "WATCHOS_DEPLOYMENT_TARGET" }, | ||
| 417 | .{ .ios, .simulator, 0xD0000, 0x80000, null }, | ||
| 418 | .{ .tvos, .simulator, 0xD0000, 0x80000, null }, | ||
| 419 | .{ .watchos, .simulator, 0x60000, 0x20000, null }, | ||
| 420 | }; | ||
| 421 | |||
| 422 | pub fn inferSdkVersionFromSdkPath(path: []const u8) ?std.SemanticVersion { | ||
| 305 | const stem = std.fs.path.stem(path); | 423 | const stem = std.fs.path.stem(path); |
| 306 | const start = for (stem, 0..) |c, i| { | 424 | const start = for (stem, 0..) |c, i| { |
| 307 | if (std.ascii.isDigit(c)) break i; | 425 | if (std.ascii.isDigit(c)) break i; |
src/link/MachO/zld.zig+18-4| ... | @@ -345,10 +345,13 @@ pub fn linkWithZld( | ... | @@ -345,10 +345,13 @@ pub fn linkWithZld( |
| 345 | parent: u16, | 345 | parent: u16, |
| 346 | }, .Dynamic).init(arena); | 346 | }, .Dynamic).init(arena); |
| 347 | 347 | ||
| 348 | var parse_error_ctx: union { | 348 | var parse_error_ctx: struct { |
| 349 | none: void, | ||
| 350 | detected_arch: std.Target.Cpu.Arch, | 349 | detected_arch: std.Target.Cpu.Arch, |
| 351 | } = .{ .none = {} }; | 350 | detected_os: std.Target.Os.Tag, |
| 351 | } = .{ | ||
| 352 | .detected_arch = undefined, | ||
| 353 | .detected_os = undefined, | ||
| 354 | }; | ||
| 352 | 355 | ||
| 353 | for (positionals.items) |obj| { | 356 | for (positionals.items) |obj| { |
| 354 | const in_file = try std.fs.cwd().openFile(obj.path, .{}); | 357 | const in_file = try std.fs.cwd().openFile(obj.path, .{}); |
| ... | @@ -586,7 +589,18 @@ pub fn linkWithZld( | ... | @@ -586,7 +589,18 @@ pub fn linkWithZld( |
| 586 | try lc_writer.writeStruct(macho.source_version_command{ | 589 | try lc_writer.writeStruct(macho.source_version_command{ |
| 587 | .version = 0, | 590 | .version = 0, |
| 588 | }); | 591 | }); |
| 589 | try load_commands.writeBuildVersionLC(&macho_file.base.options, lc_writer); | 592 | { |
| 593 | const platform = load_commands.Platform.fromOptions(&macho_file.base.options); | ||
| 594 | const sdk_version: ?std.SemanticVersion = macho_file.base.options.darwin_sdk_version orelse blk: { | ||
| 595 | if (macho_file.base.options.sysroot) |path| break :blk load_commands.inferSdkVersionFromSdkPath(path); | ||
| 596 | break :blk null; | ||
| 597 | }; | ||
| 598 | if (platform.isBuildVersionCompatible()) { | ||
| 599 | try load_commands.writeBuildVersionLC(platform, sdk_version, lc_writer); | ||
| 600 | } else { | ||
| 601 | try load_commands.writeVersionMinLC(platform, sdk_version, lc_writer); | ||
| 602 | } | ||
| 603 | } | ||
| 590 | 604 | ||
| 591 | const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + @as(u32, @intCast(lc_buffer.items.len)); | 605 | const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + @as(u32, @intCast(lc_buffer.items.len)); |
| 592 | try lc_writer.writeStruct(macho_file.uuid_cmd); | 606 | try lc_writer.writeStruct(macho_file.uuid_cmd); |