aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/std/build.zig12
-rw-r--r--lib/std/macho.zig15
-rw-r--r--lib/std/zig/system.zig10
-rw-r--r--lib/std/zig/system/darwin.zig44
-rw-r--r--lib/std/zig/system/darwin/macos.zig (renamed from lib/std/zig/system/macos.zig)22
-rw-r--r--src/Compilation.zig3
-rw-r--r--src/link/MachO.zig153
-rw-r--r--src/link/MachO/Archive.zig13
-rw-r--r--src/link/MachO/Dylib.zig97
-rw-r--r--src/link/MachO/Object.zig13
-rw-r--r--src/link/MachO/commands.zig9
-rw-r--r--src/link/MachO/fat.zig10
-rw-r--r--src/main.zig25
13 files changed, 277 insertions, 149 deletions
diff --git a/lib/std/build.zig b/lib/std/build.zig
index 17cad016e8..efb305d4a3 100644
--- a/lib/std/build.zig
+++ b/lib/std/build.zig
@@ -2672,7 +2672,11 @@ pub const LibExeObjStep = struct {
try zig_args.append(self.builder.pathFromRoot(include_path));
},
.raw_path_system => |include_path| {
- try zig_args.append("-isystem");
+ if (builder.sysroot != null) {
+ try zig_args.append("-iwithsysroot");
+ } else {
+ try zig_args.append("-isystem");
+ }
try zig_args.append(self.builder.pathFromRoot(include_path));
},
.other_step => |other| if (other.emit_h) {
@@ -2700,6 +2704,12 @@ pub const LibExeObjStep = struct {
if (self.target.isDarwin()) {
for (self.framework_dirs.items) |dir| {
+ if (builder.sysroot != null) {
+ try zig_args.append("-iframeworkwithsysroot");
+ } else {
+ try zig_args.append("-iframework");
+ }
+ try zig_args.append(dir);
try zig_args.append("-F");
try zig_args.append(dir);
}
diff --git a/lib/std/macho.zig b/lib/std/macho.zig
index cb030e941e..14be755a70 100644
--- a/lib/std/macho.zig
+++ b/lib/std/macho.zig
@@ -116,6 +116,21 @@ pub const build_tool_version = extern struct {
version: u32,
};
+pub const PLATFORM_MACOS: u32 = 0x1;
+pub const PLATFORM_IOS: u32 = 0x2;
+pub const PLATFORM_TVOS: u32 = 0x3;
+pub const PLATFORM_WATCHOS: u32 = 0x4;
+pub const PLATFORM_BRIDGEOS: u32 = 0x5;
+pub const PLATFORM_MACCATALYST: u32 = 0x6;
+pub const PLATFORM_IOSSIMULATOR: u32 = 0x7;
+pub const PLATFORM_TVOSSIMULATOR: u32 = 0x8;
+pub const PLATFORM_WATCHOSSIMULATOR: u32 = 0x9;
+pub const PLATFORM_DRIVERKIT: u32 = 0x10;
+
+pub const TOOL_CLANG: u32 = 0x1;
+pub const TOOL_SWIFT: u32 = 0x2;
+pub const TOOL_LD: u32 = 0x3;
+
/// The entry_point_command is a replacement for thread_command.
/// It is used for main executables to specify the location (file offset)
/// of main(). If -stack_size was used at link time, the stacksize
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index 4d671efe94..c5c62911cc 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -13,12 +13,10 @@ const assert = std.debug.assert;
const process = std.process;
const Target = std.Target;
const CrossTarget = std.zig.CrossTarget;
-const macos = @import("system/macos.zig");
const native_endian = std.Target.current.cpu.arch.endian();
const linux = @import("system/linux.zig");
pub const windows = @import("system/windows.zig");
-
-pub const getSDKPath = macos.getSDKPath;
+pub const darwin = @import("system/darwin.zig");
pub const NativePaths = struct {
include_dirs: ArrayList([:0]u8),
@@ -255,7 +253,7 @@ pub const NativeTargetInfo = struct {
os.version_range.windows.min = detected_version;
os.version_range.windows.max = detected_version;
},
- .macos => try macos.detect(&os),
+ .macos => try darwin.macos.detect(&os),
.freebsd, .netbsd, .dragonfly => {
const key = switch (Target.current.os.tag) {
.freebsd => "kern.osreldate",
@@ -972,7 +970,7 @@ pub const NativeTargetInfo = struct {
switch (std.Target.current.os.tag) {
.linux => return linux.detectNativeCpuAndFeatures(),
- .macos => return macos.detectNativeCpuAndFeatures(),
+ .macos => return darwin.macos.detectNativeCpuAndFeatures(),
else => {},
}
@@ -983,6 +981,6 @@ pub const NativeTargetInfo = struct {
};
test {
- _ = @import("system/macos.zig");
+ _ = @import("system/darwin.zig");
_ = @import("system/linux.zig");
}
diff --git a/lib/std/zig/system/darwin.zig b/lib/std/zig/system/darwin.zig
new file mode 100644
index 0000000000..1e8d9e4b48
--- /dev/null
+++ b/lib/std/zig/system/darwin.zig
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: MIT
+// Copyright (c) 2015-2021 Zig Contributors
+// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
+// The MIT license requires this copyright notice to be included in all copies
+// and substantial portions of the software.
+const std = @import("std");
+const mem = std.mem;
+const Allocator = mem.Allocator;
+const Target = std.Target;
+
+pub const macos = @import("darwin/macos.zig");
+
+/// Detect SDK path on Darwin.
+/// Calls `xcrun --sdk <target_sdk> --show-sdk-path` which result can be used to specify
+/// `--sysroot` of the compiler.
+/// The caller needs to free the resulting path slice.
+pub fn getSDKPath(allocator: *Allocator, target: Target) !?[]u8 {
+ const is_simulator_abi = target.abi == .simulator;
+ const sdk = switch (target.os.tag) {
+ .macos => "macosx",
+ .ios => if (is_simulator_abi) "iphonesimulator" else "iphoneos",
+ .watchos => if (is_simulator_abi) "watchsimulator" else "watchos",
+ .tvos => if (is_simulator_abi) "appletvsimulator" else "appletvos",
+ else => return null,
+ };
+
+ const argv = &[_][]const u8{ "xcrun", "--sdk", sdk, "--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 or result.term.Exited != 0) {
+ // We don't actually care if there were errors as this is best-effort check anyhow
+ // and in the worst case the user can specify the sysroot manually.
+ return null;
+ }
+ const sysroot = try allocator.dupe(u8, mem.trimRight(u8, result.stdout, "\r\n"));
+ return sysroot;
+}
+
+test "" {
+ _ = @import("darwin/macos.zig");
+}
diff --git a/lib/std/zig/system/macos.zig b/lib/std/zig/system/darwin/macos.zig
index ae450ecae5..c8f48800c5 100644
--- a/lib/std/zig/system/macos.zig
+++ b/lib/std/zig/system/darwin/macos.zig
@@ -408,28 +408,6 @@ fn testVersionEquality(expected: std.builtin.Version, got: std.builtin.Version)
try testing.expectEqualStrings(s_expected, s_got);
}
-/// 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(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: {s}", .{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);
-}
-
pub fn detectNativeCpuAndFeatures() ?Target.Cpu {
var cpu_family: os.CPUFAMILY = undefined;
var len: usize = @sizeOf(os.CPUFAMILY);
diff --git a/src/Compilation.zig b/src/Compilation.zig
index 24e2d9e67f..7987ed95df 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -944,8 +944,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
if (options.sysroot) |sysroot| {
break :blk sysroot;
} else if (darwin_can_use_system_sdk) {
- const at_least_big_sur = options.target.os.getVersionRange().semver.min.major >= 11;
- break :blk if (at_least_big_sur) try std.zig.system.getSDKPath(arena) else null;
+ break :blk try std.zig.system.darwin.getSDKPath(arena, options.target);
} else {
break :blk null;
}
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index 5d9b0e6fe1..d23b696cb8 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -82,8 +82,8 @@ data_in_code_cmd_index: ?u16 = null,
function_starts_cmd_index: ?u16 = null,
main_cmd_index: ?u16 = null,
dylib_id_cmd_index: ?u16 = null,
-version_min_cmd_index: ?u16 = null,
source_version_cmd_index: ?u16 = null,
+build_version_cmd_index: ?u16 = null,
uuid_cmd_index: ?u16 = null,
code_signature_cmd_index: ?u16 = null,
/// Path to libSystem
@@ -794,15 +794,14 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
}
}
- // If we're compiling native and we can find libSystem.B.{dylib, tbd},
- // we link against that instead of embedded libSystem.B.tbd file.
- var native_libsystem_available = false;
- if (self.base.options.is_native_os) blk: {
+ // If we were given the sysroot, try to look there first for libSystem.B.{dylib, tbd}.
+ var libsystem_available = false;
+ if (self.base.options.sysroot != null) blk: {
// Try stub file first. If we hit it, then we're done as the stub file
// re-exports every single symbol definition.
if (try resolveLib(arena, lib_dirs.items, "System", ".tbd")) |full_path| {
try libs.append(full_path);
- native_libsystem_available = true;
+ libsystem_available = true;
break :blk;
}
// If we didn't hit the stub file, try .dylib next. However, libSystem.dylib
@@ -811,12 +810,12 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
if (try resolveLib(arena, lib_dirs.items, "c", ".dylib")) |libc_path| {
try libs.append(libsystem_path);
try libs.append(libc_path);
- native_libsystem_available = true;
+ libsystem_available = true;
break :blk;
}
}
}
- if (!native_libsystem_available) {
+ if (!libsystem_available) {
const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
"libc", "darwin", "libSystem.B.tbd",
});
@@ -841,7 +840,7 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
break;
}
} else {
- log.warn("framework not found for '-f{s}'", .{framework});
+ log.warn("framework not found for '-framework {s}'", .{framework});
framework_not_found = true;
}
}
@@ -901,10 +900,8 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
try argv.append("-o");
try argv.append(full_out_path);
- if (native_libsystem_available) {
- try argv.append("-lSystem");
- try argv.append("-lc");
- }
+ try argv.append("-lSystem");
+ try argv.append("-lc");
for (search_lib_names.items) |l_name| {
try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{l_name}));
@@ -914,6 +911,14 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
try argv.append(try std.fmt.allocPrint(arena, "-L{s}", .{lib_dir}));
}
+ for (self.base.options.frameworks) |framework| {
+ try argv.append(try std.fmt.allocPrint(arena, "-framework {s}", .{framework}));
+ }
+
+ for (self.base.options.framework_dirs) |framework_dir| {
+ try argv.append(try std.fmt.allocPrint(arena, "-F{s}", .{framework_dir}));
+ }
+
Compilation.dump_argv(argv.items);
}
@@ -990,7 +995,6 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
}
fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const u8) !void {
- const arch = self.base.options.target.cpu.arch;
for (files) |file_name| {
const full_path = full_path: {
var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
@@ -999,17 +1003,17 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const
};
defer self.base.allocator.free(full_path);
- if (try Object.createAndParseFromPath(self.base.allocator, arch, full_path)) |object| {
+ if (try Object.createAndParseFromPath(self.base.allocator, self.base.options.target, full_path)) |object| {
try self.objects.append(self.base.allocator, object);
continue;
}
- if (try Archive.createAndParseFromPath(self.base.allocator, arch, full_path)) |archive| {
+ if (try Archive.createAndParseFromPath(self.base.allocator, self.base.options.target, full_path)) |archive| {
try self.archives.append(self.base.allocator, archive);
continue;
}
- if (try Dylib.createAndParseFromPath(self.base.allocator, arch, full_path, .{
+ if (try Dylib.createAndParseFromPath(self.base.allocator, self.base.options.target, full_path, .{
.syslibroot = syslibroot,
})) |dylibs| {
defer self.base.allocator.free(dylibs);
@@ -1027,9 +1031,8 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const
}
fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8) !void {
- const arch = self.base.options.target.cpu.arch;
for (libs) |lib| {
- if (try Dylib.createAndParseFromPath(self.base.allocator, arch, lib, .{
+ if (try Dylib.createAndParseFromPath(self.base.allocator, self.base.options.target, lib, .{
.syslibroot = syslibroot,
})) |dylibs| {
defer self.base.allocator.free(dylibs);
@@ -1042,7 +1045,7 @@ fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8) !v
continue;
}
- if (try Archive.createAndParseFromPath(self.base.allocator, arch, lib)) |archive| {
+ if (try Archive.createAndParseFromPath(self.base.allocator, self.base.options.target, lib)) |archive| {
try self.archives.append(self.base.allocator, archive);
continue;
}
@@ -2231,11 +2234,7 @@ fn resolveSymbols(self: *MachO) !void {
const object_id = @intCast(u16, self.objects.items.len);
const object = try self.objects.addOne(self.base.allocator);
- object.* = try archive.parseObject(
- self.base.allocator,
- self.base.options.target.cpu.arch,
- offsets.items[0],
- );
+ object.* = try archive.parseObject(self.base.allocator, self.base.options.target, offsets.items[0]);
try self.resolveSymbolsInObject(object_id);
continue :loop;
@@ -2717,27 +2716,6 @@ fn populateMetadata(self: *MachO) !void {
try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd });
}
- if (self.version_min_cmd_index == null) {
- self.version_min_cmd_index = @intCast(u16, self.load_commands.items.len);
- const cmd: u32 = switch (self.base.options.target.os.tag) {
- .macos => macho.LC_VERSION_MIN_MACOSX,
- .ios => macho.LC_VERSION_MIN_IPHONEOS,
- .tvos => macho.LC_VERSION_MIN_TVOS,
- .watchos => macho.LC_VERSION_MIN_WATCHOS,
- else => unreachable, // wrong OS
- };
- const ver = self.base.options.target.os.version_range.semver.min;
- const version = ver.major << 16 | ver.minor << 8 | ver.patch;
- try self.load_commands.append(self.base.allocator, .{
- .VersionMin = .{
- .cmd = cmd,
- .cmdsize = @sizeOf(macho.version_min_command),
- .version = version,
- .sdk = version,
- },
- });
- }
-
if (self.source_version_cmd_index == null) {
self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len);
try self.load_commands.append(self.base.allocator, .{
@@ -2749,6 +2727,40 @@ fn populateMetadata(self: *MachO) !void {
});
}
+ if (self.build_version_cmd_index == null) {
+ self.build_version_cmd_index = @intCast(u16, self.load_commands.items.len);
+ const cmdsize = @intCast(u32, mem.alignForwardGeneric(
+ u64,
+ @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version),
+ @sizeOf(u64),
+ ));
+ const ver = self.base.options.target.os.version_range.semver.min;
+ const version = ver.major << 16 | ver.minor << 8 | ver.patch;
+ const is_simulator_abi = self.base.options.target.abi == .simulator;
+ var cmd = commands.emptyGenericCommandWithData(macho.build_version_command{
+ .cmd = macho.LC_BUILD_VERSION,
+ .cmdsize = cmdsize,
+ .platform = switch (self.base.options.target.os.tag) {
+ .macos => macho.PLATFORM_MACOS,
+ .ios => if (is_simulator_abi) macho.PLATFORM_IOSSIMULATOR else macho.PLATFORM_IOS,
+ .watchos => if (is_simulator_abi) macho.PLATFORM_WATCHOSSIMULATOR else macho.PLATFORM_WATCHOS,
+ .tvos => if (is_simulator_abi) macho.PLATFORM_TVOSSIMULATOR else macho.PLATFORM_TVOS,
+ else => unreachable,
+ },
+ .minos = version,
+ .sdk = version,
+ .ntools = 1,
+ });
+ const ld_ver = macho.build_tool_version{
+ .tool = macho.TOOL_LD,
+ .version = 0x0,
+ };
+ cmd.data = try self.base.allocator.alloc(u8, cmdsize - @sizeOf(macho.build_version_command));
+ mem.set(u8, cmd.data, 0);
+ mem.copy(u8, cmd.data, mem.asBytes(&ld_ver));
+ try self.load_commands.append(self.base.allocator, .{ .BuildVersion = cmd });
+ }
+
if (self.uuid_cmd_index == null) {
self.uuid_cmd_index = @intCast(u16, self.load_commands.items.len);
var uuid_cmd: macho.uuid_command = .{
@@ -2880,11 +2892,6 @@ fn flushZld(self: *MachO) !void {
if (self.base.options.target.cpu.arch == .aarch64) {
try self.writeCodeSignature();
}
-
- // if (comptime std.Target.current.isDarwin() and std.Target.current.cpu.arch == .aarch64) {
- // const out_path = self.output.?.path;
- // try fs.cwd().copyFile(out_path, fs.cwd(), out_path, .{});
- // }
}
fn writeGotEntries(self: *MachO) !void {
@@ -4340,26 +4347,38 @@ pub fn populateMissingMetadata(self: *MachO) !void {
});
self.load_commands_dirty = true;
}
- if (self.version_min_cmd_index == null) {
- self.version_min_cmd_index = @intCast(u16, self.load_commands.items.len);
- const cmd: u32 = switch (self.base.options.target.os.tag) {
- .macos => macho.LC_VERSION_MIN_MACOSX,
- .ios => macho.LC_VERSION_MIN_IPHONEOS,
- .tvos => macho.LC_VERSION_MIN_TVOS,
- .watchos => macho.LC_VERSION_MIN_WATCHOS,
- else => unreachable, // wrong OS
- };
+ if (self.build_version_cmd_index == null) {
+ self.build_version_cmd_index = @intCast(u16, self.load_commands.items.len);
+ const cmdsize = @intCast(u32, mem.alignForwardGeneric(
+ u64,
+ @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version),
+ @sizeOf(u64),
+ ));
const ver = self.base.options.target.os.version_range.semver.min;
const version = ver.major << 16 | ver.minor << 8 | ver.patch;
- try self.load_commands.append(self.base.allocator, .{
- .VersionMin = .{
- .cmd = cmd,
- .cmdsize = @sizeOf(macho.version_min_command),
- .version = version,
- .sdk = version,
+ const is_simulator_abi = self.base.options.target.abi == .simulator;
+ var cmd = commands.emptyGenericCommandWithData(macho.build_version_command{
+ .cmd = macho.LC_BUILD_VERSION,
+ .cmdsize = cmdsize,
+ .platform = switch (self.base.options.target.os.tag) {
+ .macos => macho.PLATFORM_MACOS,
+ .ios => if (is_simulator_abi) macho.PLATFORM_IOSSIMULATOR else macho.PLATFORM_IOS,
+ .watchos => if (is_simulator_abi) macho.PLATFORM_WATCHOSSIMULATOR else macho.PLATFORM_WATCHOS,
+ .tvos => if (is_simulator_abi) macho.PLATFORM_TVOSSIMULATOR else macho.PLATFORM_TVOS,
+ else => unreachable,
},
+ .minos = version,
+ .sdk = version,
+ .ntools = 1,
});
- self.load_commands_dirty = true;
+ const ld_ver = macho.build_tool_version{
+ .tool = macho.TOOL_LD,
+ .version = 0x0,
+ };
+ cmd.data = try self.base.allocator.alloc(u8, cmdsize - @sizeOf(macho.build_version_command));
+ mem.set(u8, cmd.data, 0);
+ mem.copy(u8, cmd.data, mem.asBytes(&ld_ver));
+ try self.load_commands.append(self.base.allocator, .{ .BuildVersion = cmd });
}
if (self.source_version_cmd_index == null) {
self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len);
diff --git a/src/link/MachO/Archive.zig b/src/link/MachO/Archive.zig
index 6959dbac89..3b01233e1f 100644
--- a/src/link/MachO/Archive.zig
+++ b/src/link/MachO/Archive.zig
@@ -9,7 +9,6 @@ const mem = std.mem;
const fat = @import("fat.zig");
const Allocator = mem.Allocator;
-const Arch = std.Target.Cpu.Arch;
const Object = @import("Object.zig");
file: fs.File,
@@ -104,7 +103,7 @@ pub fn deinit(self: *Archive, allocator: *Allocator) void {
allocator.free(self.name);
}
-pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8) !?Archive {
+pub fn createAndParseFromPath(allocator: *Allocator, target: std.Target, path: []const u8) !?Archive {
const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
error.FileNotFound => return null,
else => |e| return e,
@@ -119,7 +118,7 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u
.file = file,
};
- archive.parse(allocator, arch) catch |err| switch (err) {
+ archive.parse(allocator, target) catch |err| switch (err) {
error.EndOfStream, error.NotArchive => {
archive.deinit(allocator);
return null;
@@ -130,9 +129,9 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u
return archive;
}
-pub fn parse(self: *Archive, allocator: *Allocator, arch: Arch) !void {
+pub fn parse(self: *Archive, allocator: *Allocator, target: std.Target) !void {
const reader = self.file.reader();
- self.library_offset = try fat.getLibraryOffset(reader, arch);
+ self.library_offset = try fat.getLibraryOffset(reader, target);
try self.file.seekTo(self.library_offset);
const magic = try reader.readBytesNoEof(SARMAG);
@@ -215,7 +214,7 @@ fn parseTableOfContents(self: *Archive, allocator: *Allocator, reader: anytype)
}
}
-pub fn parseObject(self: Archive, allocator: *Allocator, arch: Arch, offset: u32) !Object {
+pub fn parseObject(self: Archive, allocator: *Allocator, target: std.Target, offset: u32) !Object {
const reader = self.file.reader();
try reader.context.seekTo(offset + self.library_offset);
@@ -244,7 +243,7 @@ pub fn parseObject(self: Archive, allocator: *Allocator, arch: Arch, offset: u32
.mtime = try self.header.?.date(),
};
- try object.parse(allocator, arch);
+ try object.parse(allocator, target);
try reader.context.seekTo(0);
return object;
diff --git a/src/link/MachO/Dylib.zig b/src/link/MachO/Dylib.zig
index 71301ccbbf..64be1fd2fa 100644
--- a/src/link/MachO/Dylib.zig
+++ b/src/link/MachO/Dylib.zig
@@ -12,7 +12,6 @@ const fat = @import("fat.zig");
const commands = @import("commands.zig");
const Allocator = mem.Allocator;
-const Arch = std.Target.Cpu.Arch;
const LibStub = @import("../tapi.zig").LibStub;
const LoadCommand = commands.LoadCommand;
const MachO = @import("../MachO.zig");
@@ -139,11 +138,12 @@ pub const Error = error{
pub const CreateOpts = struct {
syslibroot: ?[]const u8 = null,
id: ?Id = null,
+ target: ?std.Target = null,
};
pub fn createAndParseFromPath(
allocator: *Allocator,
- arch: Arch,
+ target: std.Target,
path: []const u8,
opts: CreateOpts,
) Error!?[]Dylib {
@@ -161,7 +161,7 @@ pub fn createAndParseFromPath(
.file = file,
};
- dylib.parse(allocator, arch) catch |err| switch (err) {
+ dylib.parse(allocator, target) catch |err| switch (err) {
error.EndOfStream, error.NotDylib => {
try file.seekTo(0);
@@ -171,7 +171,7 @@ pub fn createAndParseFromPath(
};
defer lib_stub.deinit();
- try dylib.parseFromStub(allocator, arch, lib_stub);
+ try dylib.parseFromStub(allocator, target, lib_stub);
},
else => |e| return e,
};
@@ -195,7 +195,7 @@ pub fn createAndParseFromPath(
try dylibs.append(dylib);
// TODO this should not be performed if the user specifies `-flat_namespace` flag.
// See ld64 manpages.
- try dylib.parseDependentLibs(allocator, arch, &dylibs, opts.syslibroot);
+ try dylib.parseDependentLibs(allocator, target, &dylibs, opts.syslibroot);
return dylibs.toOwnedSlice();
}
@@ -222,10 +222,10 @@ pub fn deinit(self: *Dylib, allocator: *Allocator) void {
}
}
-pub fn parse(self: *Dylib, allocator: *Allocator, arch: Arch) !void {
+pub fn parse(self: *Dylib, allocator: *Allocator, target: std.Target) !void {
log.debug("parsing shared library '{s}'", .{self.name});
- self.library_offset = try fat.getLibraryOffset(self.file.reader(), arch);
+ self.library_offset = try fat.getLibraryOffset(self.file.reader(), target);
try self.file.seekTo(self.library_offset);
@@ -237,10 +237,10 @@ pub fn parse(self: *Dylib, allocator: *Allocator, arch: Arch) !void {
return error.NotDylib;
}
- const this_arch: Arch = try fat.decodeArch(self.header.?.cputype, true);
+ const this_arch: std.Target.Cpu.Arch = try fat.decodeArch(self.header.?.cputype, true);
- if (this_arch != arch) {
- log.err("mismatched cpu architecture: expected {s}, found {s}", .{ arch, this_arch });
+ if (this_arch != target.cpu.arch) {
+ log.err("mismatched cpu architecture: expected {s}, found {s}", .{ target.cpu.arch, this_arch });
return error.MismatchedCpuArchitecture;
}
@@ -334,7 +334,61 @@ fn addObjCClassSymbols(self: *Dylib, allocator: *Allocator, sym_name: []const u8
}
}
-pub fn parseFromStub(self: *Dylib, allocator: *Allocator, arch: Arch, lib_stub: LibStub) !void {
+fn targetToAppleString(allocator: *Allocator, target: std.Target) ![]const u8 {
+ const arch = switch (target.cpu.arch) {
+ .aarch64 => "arm64",
+ .x86_64 => "x86_64",
+ else => unreachable,
+ };
+ const os = @tagName(target.os.tag);
+ const abi: ?[]const u8 = switch (target.abi) {
+ .gnu => null,
+ .simulator => "simulator",
+ else => unreachable,
+ };
+ if (abi) |x| {
+ return std.fmt.allocPrint(allocator, "{s}-{s}-{s}", .{ arch, os, x });
+ }
+ return std.fmt.allocPrint(allocator, "{s}-{s}", .{ arch, os });
+}
+
+const TargetMatcher = struct {
+ allocator: *Allocator,
+ target_strings: std.ArrayListUnmanaged([]const u8) = .{},
+
+ fn init(allocator: *Allocator, target: std.Target) !TargetMatcher {
+ var self = TargetMatcher{ .allocator = allocator };
+ try self.target_strings.append(allocator, try targetToAppleString(allocator, target));
+
+ if (target.abi == .simulator) {
+ // For Apple simulator targets, linking gets tricky as we need to link against the simulator
+ // hosts dylibs too.
+ const host_target = try targetToAppleString(allocator, (std.zig.CrossTarget{
+ .cpu_arch = target.cpu.arch,
+ .os_tag = .macos,
+ }).toTarget());
+ try self.target_strings.append(allocator, host_target);
+ }
+
+ return self;
+ }
+
+ fn deinit(self: *TargetMatcher) void {
+ for (self.target_strings.items) |t| {
+ self.allocator.free(t);
+ }
+ self.target_strings.deinit(self.allocator);
+ }
+
+ fn matches(self: TargetMatcher, targets: []const []const u8) bool {
+ for (self.target_strings.items) |t| {
+ if (hasTarget(targets, t)) return true;
+ }
+ return false;
+ }
+};
+
+pub fn parseFromStub(self: *Dylib, allocator: *Allocator, target: std.Target, lib_stub: LibStub) !void {
if (lib_stub.inner.len == 0) return error.EmptyStubFile;
log.debug("parsing shared library from stub '{s}'", .{self.name});
@@ -350,17 +404,14 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, arch: Arch, lib_stub:
}
self.id = id;
- const target_string: []const u8 = switch (arch) {
- .aarch64 => "arm64-macos",
- .x86_64 => "x86_64-macos",
- else => unreachable,
- };
+ var matcher = try TargetMatcher.init(allocator, target);
+ defer matcher.deinit();
var umbrella_libs = std.StringHashMap(void).init(allocator);
defer umbrella_libs.deinit();
for (lib_stub.inner) |stub, stub_index| {
- if (!hasTarget(stub.targets, target_string)) continue;
+ if (!matcher.matches(stub.targets)) continue;
if (stub_index > 0) {
// TODO I thought that we could switch on presence of `parent-umbrella` map;
@@ -371,7 +422,7 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, arch: Arch, lib_stub:
if (stub.exports) |exports| {
for (exports) |exp| {
- if (!hasTarget(exp.targets, target_string)) continue;
+ if (!matcher.matches(exp.targets)) continue;
if (exp.symbols) |symbols| {
for (symbols) |sym_name| {
@@ -390,7 +441,7 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, arch: Arch, lib_stub:
if (stub.reexports) |reexports| {
for (reexports) |reexp| {
- if (!hasTarget(reexp.targets, target_string)) continue;
+ if (!matcher.matches(reexp.targets)) continue;
if (reexp.symbols) |symbols| {
for (symbols) |sym_name| {
@@ -418,11 +469,11 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, arch: Arch, lib_stub:
// TODO track which libs were already parsed in different steps
for (lib_stub.inner) |stub| {
- if (!hasTarget(stub.targets, target_string)) continue;
+ if (!matcher.matches(stub.targets)) continue;
if (stub.reexported_libraries) |reexports| {
for (reexports) |reexp| {
- if (!hasTarget(reexp.targets, target_string)) continue;
+ if (!matcher.matches(reexp.targets)) continue;
for (reexp.libraries) |lib| {
if (umbrella_libs.contains(lib)) {
@@ -443,7 +494,7 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, arch: Arch, lib_stub:
pub fn parseDependentLibs(
self: *Dylib,
allocator: *Allocator,
- arch: Arch,
+ target: std.Target,
out: *std.ArrayList(Dylib),
syslibroot: ?[]const u8,
) !void {
@@ -475,7 +526,7 @@ pub fn parseDependentLibs(
const dylibs = (try createAndParseFromPath(
allocator,
- arch,
+ target,
full_path,
.{
.id = id,
diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig
index 2e6a20ad4b..c6aa2fb631 100644
--- a/src/link/MachO/Object.zig
+++ b/src/link/MachO/Object.zig
@@ -15,7 +15,6 @@ const segmentName = commands.segmentName;
const sectionName = commands.sectionName;
const Allocator = mem.Allocator;
-const Arch = std.Target.Cpu.Arch;
const LoadCommand = commands.LoadCommand;
const MachO = @import("../MachO.zig");
const TextBlock = @import("TextBlock.zig");
@@ -154,7 +153,7 @@ pub fn deinit(self: *Object, allocator: *Allocator) void {
}
}
-pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8) !?Object {
+pub fn createAndParseFromPath(allocator: *Allocator, target: std.Target, path: []const u8) !?Object {
const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
error.FileNotFound => return null,
else => |e| return e,
@@ -169,7 +168,7 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u
.file = file,
};
- object.parse(allocator, arch) catch |err| switch (err) {
+ object.parse(allocator, target) catch |err| switch (err) {
error.EndOfStream, error.NotObject => {
object.deinit(allocator);
return null;
@@ -180,7 +179,7 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u
return object;
}
-pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void {
+pub fn parse(self: *Object, allocator: *Allocator, target: std.Target) !void {
const reader = self.file.reader();
if (self.file_offset) |offset| {
try reader.context.seekTo(offset);
@@ -195,7 +194,7 @@ pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void {
return error.NotObject;
}
- const this_arch: Arch = switch (header.cputype) {
+ const this_arch: std.Target.Cpu.Arch = switch (header.cputype) {
macho.CPU_TYPE_ARM64 => .aarch64,
macho.CPU_TYPE_X86_64 => .x86_64,
else => |value| {
@@ -203,8 +202,8 @@ pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void {
return error.UnsupportedCpuArchitecture;
},
};
- if (this_arch != arch) {
- log.err("mismatched cpu architecture: expected {s}, found {s}", .{ arch, this_arch });
+ if (this_arch != target.cpu.arch) {
+ log.err("mismatched cpu architecture: expected {s}, found {s}", .{ target.cpu.arch, this_arch });
return error.MismatchedCpuArchitecture;
}
diff --git a/src/link/MachO/commands.zig b/src/link/MachO/commands.zig
index f7a2fd3eda..6e75af08c4 100644
--- a/src/link/MachO/commands.zig
+++ b/src/link/MachO/commands.zig
@@ -43,6 +43,7 @@ pub const LoadCommand = union(enum) {
Main: macho.entry_point_command,
VersionMin: macho.version_min_command,
SourceVersion: macho.source_version_command,
+ BuildVersion: GenericCommandWithData(macho.build_version_command),
Uuid: macho.uuid_command,
LinkeditData: macho.linkedit_data_command,
Rpath: GenericCommandWithData(macho.rpath_command),
@@ -97,6 +98,9 @@ pub const LoadCommand = union(enum) {
macho.LC_SOURCE_VERSION => LoadCommand{
.SourceVersion = try stream.reader().readStruct(macho.source_version_command),
},
+ macho.LC_BUILD_VERSION => LoadCommand{
+ .BuildVersion = try GenericCommandWithData(macho.build_version_command).read(allocator, stream.reader()),
+ },
macho.LC_UUID => LoadCommand{
.Uuid = try stream.reader().readStruct(macho.uuid_command),
},
@@ -129,6 +133,7 @@ pub const LoadCommand = union(enum) {
.Dylinker => |x| x.write(writer),
.Dylib => |x| x.write(writer),
.Rpath => |x| x.write(writer),
+ .BuildVersion => |x| x.write(writer),
.Unknown => |x| x.write(writer),
};
}
@@ -147,6 +152,7 @@ pub const LoadCommand = union(enum) {
.Dylinker => |x| x.inner.cmd,
.Dylib => |x| x.inner.cmd,
.Rpath => |x| x.inner.cmd,
+ .BuildVersion => |x| x.inner.cmd,
.Unknown => |x| x.inner.cmd,
};
}
@@ -165,6 +171,7 @@ pub const LoadCommand = union(enum) {
.Dylinker => |x| x.inner.cmdsize,
.Dylib => |x| x.inner.cmdsize,
.Rpath => |x| x.inner.cmdsize,
+ .BuildVersion => |x| x.inner.cmdsize,
.Unknown => |x| x.inner.cmdsize,
};
}
@@ -175,6 +182,7 @@ pub const LoadCommand = union(enum) {
.Dylinker => |*x| x.deinit(allocator),
.Dylib => |*x| x.deinit(allocator),
.Rpath => |*x| x.deinit(allocator),
+ .BuildVersion => |*x| x.deinit(allocator),
.Unknown => |*x| x.deinit(allocator),
else => {},
};
@@ -193,6 +201,7 @@ pub const LoadCommand = union(enum) {
.Main => |x| meta.eql(x, other.Main),
.VersionMin => |x| meta.eql(x, other.VersionMin),
.SourceVersion => |x| meta.eql(x, other.SourceVersion),
+ .BuildVersion => |x| x.eql(other.BuildVersion),
.Uuid => |x| meta.eql(x, other.Uuid),
.LinkeditData => |x| meta.eql(x, other.LinkeditData),
.Segment => |x| x.eql(other.Segment),
diff --git a/src/link/MachO/fat.zig b/src/link/MachO/fat.zig
index 61592c88a5..c911d89535 100644
--- a/src/link/MachO/fat.zig
+++ b/src/link/MachO/fat.zig
@@ -5,10 +5,8 @@ const macho = std.macho;
const mem = std.mem;
const native_endian = builtin.target.cpu.arch.endian();
-const Arch = std.Target.Cpu.Arch;
-
pub fn decodeArch(cputype: macho.cpu_type_t, comptime logError: bool) !std.Target.Cpu.Arch {
- const arch: Arch = switch (cputype) {
+ const arch: std.Target.Cpu.Arch = switch (cputype) {
macho.CPU_TYPE_ARM64 => .aarch64,
macho.CPU_TYPE_X86_64 => .x86_64,
else => {
@@ -31,7 +29,7 @@ fn readFatStruct(reader: anytype, comptime T: type) !T {
return res;
}
-pub fn getLibraryOffset(reader: anytype, arch: Arch) !u64 {
+pub fn getLibraryOffset(reader: anytype, target: std.Target) !u64 {
const fat_header = try readFatStruct(reader, macho.fat_header);
if (fat_header.magic != macho.FAT_MAGIC) return 0;
@@ -44,12 +42,12 @@ pub fn getLibraryOffset(reader: anytype, arch: Arch) !u64 {
error.UnsupportedCpuArchitecture => continue,
else => |e| return e,
};
- if (lib_arch == arch) {
+ if (lib_arch == target.cpu.arch) {
// We have found a matching architecture!
return fat_arch.offset;
}
} else {
- log.err("Could not find matching cpu architecture in fat library: expected {s}", .{arch});
+ log.err("Could not find matching cpu architecture in fat library: expected {s}", .{target.cpu.arch});
return error.MismatchedCpuArchitecture;
}
}
diff --git a/src/main.zig b/src/main.zig
index 0987a46989..285b6d2316 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -830,7 +830,10 @@ fn buildOutputType(
} else if (mem.eql(u8, arg, "-D") or
mem.eql(u8, arg, "-isystem") or
mem.eql(u8, arg, "-I") or
- mem.eql(u8, arg, "-dirafter"))
+ mem.eql(u8, arg, "-dirafter") or
+ mem.eql(u8, arg, "-iwithsysroot") or
+ mem.eql(u8, arg, "-iframework") or
+ mem.eql(u8, arg, "-iframeworkwithsysroot"))
{
if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg});
i += 1;
@@ -873,6 +876,8 @@ fn buildOutputType(
if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg});
i += 1;
sysroot = args[i];
+ try clang_argv.append("-isysroot");
+ try clang_argv.append(args[i]);
} else if (mem.eql(u8, arg, "--libc")) {
if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg});
i += 1;
@@ -1673,7 +1678,9 @@ fn buildOutputType(
want_native_include_dirs = true;
}
- if (sysroot == null and cross_target.isNativeOs() and
+ const is_darwin_on_darwin = (comptime std.Target.current.isDarwin()) and cross_target.isDarwin();
+
+ if (sysroot == null and (cross_target.isNativeOs() or is_darwin_on_darwin) and
(system_libs.items.len != 0 or want_native_include_dirs))
{
const paths = std.zig.system.NativePaths.detect(arena, target_info) catch |err| {
@@ -1684,16 +1691,18 @@ fn buildOutputType(
}
const has_sysroot = if (comptime std.Target.current.isDarwin()) outer: {
- const min = target_info.target.os.getVersionRange().semver.min;
- const at_least_mojave = min.major >= 11 or (min.major >= 10 and min.minor >= 14);
- if (at_least_mojave) {
- const sdk_path = try std.zig.system.getSDKPath(arena);
+ const should_get_sdk_path = if (cross_target.isNativeOs() and target_info.target.os.tag == .macos) inner: {
+ const min = target_info.target.os.getVersionRange().semver.min;
+ const at_least_mojave = min.major >= 11 or (min.major >= 10 and min.minor >= 14);
+ break :inner at_least_mojave;
+ } else true;
+ if (!should_get_sdk_path) break :outer false;
+ if (try std.zig.system.darwin.getSDKPath(arena, target_info.target)) |sdk_path| {
try clang_argv.ensureCapacity(clang_argv.items.len + 2);
clang_argv.appendAssumeCapacity("-isysroot");
clang_argv.appendAssumeCapacity(sdk_path);
break :outer true;
- }
- break :outer false;
+ } else break :outer false;
} else false;
try clang_argv.ensureCapacity(clang_argv.items.len + paths.include_dirs.items.len * 2);