aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2021-08-11 19:36:21 +0200
committerGitHub <noreply@github.com>2021-08-11 19:36:21 +0200
commit60a5552d414ffedf84117df57963fd5bf099c2ea (patch)
tree586178dc0f24bf9875e58a830af1e2fdde51af2f /src
parentf2bf1390a29a9decaa5ca49d3ae720b360583b35 (diff)
parent509fe33d10e4e89a351678f4d466f30a7870ebcf (diff)
downloadzig-60a5552d414ffedf84117df57963fd5bf099c2ea.tar.gz
zig-60a5552d414ffedf84117df57963fd5bf099c2ea.zip
Merge pull request #9532 from ziglang/basic-ios-support
Add minimal support to Zig toolchain to support building iOS binaries
Diffstat (limited to 'src')
-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
8 files changed, 203 insertions, 120 deletions
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);