macho: when targeting simulator, match host dylibs too

otherwise, linking may fail as some libc functions are provided by
the host when simulating a different OS such iPhoneOS.
This commit is contained in:
Jakub Konka 2021-08-09 00:05:37 +02:00
parent 9ab8d065b6
commit 509fe33d10

View File

@ -352,6 +352,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;
@ -368,14 +404,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;
@ -386,7 +422,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| {
@ -405,7 +441,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| {
@ -433,11 +469,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)) {