Commit f2bf1390a2

Jakub Konka <kubkon@jakubkonka.com>
2021-08-09 22:44:57
macho: fix linking of dylibs and frameworks
Previously, I have incorrectly assumed that with two-level namespace we only need to link in dylibs/frameworks that actually export symbols which are undefined in the linked image. Turns out, regardless of whether we link with two-level namespace (default on macOS) or a flat namespace (more common on other platforms), we always need to put the dylibs/frameworks as specified by the user from the linker line into the final linked image.
1 parent 2ccd023
Changed files (5)
src
test
standalone
link_frameworks
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();
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;
         }
 
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", .{});