diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 36d5bc6a87..5d9b0e6fe1 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -1013,7 +1013,12 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const .syslibroot = syslibroot, })) |dylibs| { defer self.base.allocator.free(dylibs); + const dylib_id = @intCast(u16, self.dylibs.items.len); try self.dylibs.appendSlice(self.base.allocator, dylibs); + // We always have to add the dylib that was on the linker line. + if (!self.referenced_dylibs.contains(dylib_id)) { + try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {}); + } continue; } @@ -1028,7 +1033,12 @@ fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8) !v .syslibroot = syslibroot, })) |dylibs| { defer self.base.allocator.free(dylibs); + const dylib_id = @intCast(u16, self.dylibs.items.len); try self.dylibs.appendSlice(self.base.allocator, dylibs); + // We always have to add the dylib that was on the linker line. + if (!self.referenced_dylibs.contains(dylib_id)) { + try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {}); + } continue; } diff --git a/src/link/MachO/Dylib.zig b/src/link/MachO/Dylib.zig index 4763203c3b..71301ccbbf 100644 --- a/src/link/MachO/Dylib.zig +++ b/src/link/MachO/Dylib.zig @@ -193,6 +193,8 @@ pub fn createAndParseFromPath( defer dylibs.deinit(); 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); return dylibs.toOwnedSlice(); diff --git a/test/standalone.zig b/test/standalone.zig index 9a32701ddd..85957923b7 100644 --- a/test/standalone.zig +++ b/test/standalone.zig @@ -16,6 +16,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void { cases.addBuildFile("test/standalone/link_interdependent_static_c_libs/build.zig", .{}); cases.addBuildFile("test/standalone/link_static_lib_as_system_lib/build.zig", .{}); cases.addBuildFile("test/standalone/link_common_symbols/build.zig", .{}); + cases.addBuildFile("test/standalone/link_frameworks/build.zig", .{ .requires_macos_sdk = true }); cases.addBuildFile("test/standalone/issue_339/build.zig", .{}); cases.addBuildFile("test/standalone/issue_8550/build.zig", .{}); cases.addBuildFile("test/standalone/issue_794/build.zig", .{}); diff --git a/test/standalone/link_frameworks/build.zig b/test/standalone/link_frameworks/build.zig new file mode 100644 index 0000000000..460e1675e0 --- /dev/null +++ b/test/standalone/link_frameworks/build.zig @@ -0,0 +1,34 @@ +const std = @import("std"); +const Builder = std.build.Builder; +const CrossTarget = std.zig.CrossTarget; + +fn isRunnableTarget(t: CrossTarget) bool { + // TODO I think we might be able to run this on Linux via Darling. + // Add a check for that here, and return true if Darling is available. + if (t.isNative() and t.getOsTag() == .macos) + return true + else + return false; +} + +pub fn build(b: *Builder) void { + const mode = b.standardReleaseOptions(); + const target = b.standardTargetOptions(.{}); + + const test_step = b.step("test", "Test the program"); + + const exe = b.addExecutable("test", null); + b.default_step.dependOn(&exe.step); + exe.addCSourceFile("main.c", &[0][]const u8{}); + exe.setBuildMode(mode); + exe.setTarget(target); + exe.linkLibC(); + // TODO when we figure out how to ship framework stubs for cross-compilation, + // populate paths to the sysroot here. + exe.linkFramework("Cocoa"); + + if (isRunnableTarget(target)) { + const run_cmd = exe.run(); + test_step.dependOn(&run_cmd.step); + } +} diff --git a/test/standalone/link_frameworks/main.c b/test/standalone/link_frameworks/main.c new file mode 100644 index 0000000000..b9dab990b2 --- /dev/null +++ b/test/standalone/link_frameworks/main.c @@ -0,0 +1,7 @@ +#include +#include + +int main() { + assert(objc_getClass("NSObject") > 0); + assert(objc_getClass("NSApplication") > 0); +}