Skip to content

Commit

Permalink
macho: when targeting simulator, match host dylibs too
Browse files Browse the repository at this point in the history
otherwise, linking may fail as some libc functions are provided by
the host when simulating a different OS such iPhoneOS.
  • Loading branch information
kubkon committed Aug 8, 2021
1 parent f8436af commit 83f1203
Showing 1 changed file with 43 additions and 7 deletions.
50 changes: 43 additions & 7 deletions src/link/MachO/Dylib.zig
Expand Up @@ -350,6 +350,42 @@ fn targetToAppleString(allocator: *Allocator, target: std.Target) ![]const u8 {
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;

Expand All @@ -366,14 +402,14 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, target: std.Target, li
}
self.id = id;

const target_string = try targetToAppleString(allocator, target);
defer allocator.free(target_string);
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;
Expand All @@ -384,7 +420,7 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, target: std.Target, li

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| {
Expand All @@ -403,7 +439,7 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, target: std.Target, li

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| {
Expand Down Expand Up @@ -431,11 +467,11 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, target: std.Target, li

// 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)) {
Expand Down

0 comments on commit 83f1203

Please sign in to comment.