authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-12 17:21:10+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-13 20:02:11+01:00
log16c55b15cb227067bf8146226139608edddd8e8c
tree71e6db987f9d628db752556a746e330bce5dab37
parentf9f792ab701a8aa3e3fb7b7b47b2b7c50b1bc9a2

zld: support -Wl,-force_load=archive_path flag

This actually enables using `zig cc` as a linker for `cargo test` with `serde_derive`.

4 files changed, 65 insertions(+), 6 deletions(-)

src/Compilation.zig+2
...@@ -699,6 +699,7 @@ pub const InitOptions = struct {...@@ -699,6 +699,7 @@ pub const InitOptions = struct {
699 rpath_list: []const []const u8 = &[0][]const u8{},699 rpath_list: []const []const u8 = &[0][]const u8{},
700 c_source_files: []const CSourceFile = &[0]CSourceFile{},700 c_source_files: []const CSourceFile = &[0]CSourceFile{},
701 link_objects: []const []const u8 = &[0][]const u8{},701 link_objects: []const []const u8 = &[0][]const u8{},
702 must_link_objects: []const []const u8 = &[0][]const u8{},
702 framework_dirs: []const []const u8 = &[0][]const u8{},703 framework_dirs: []const []const u8 = &[0][]const u8{},
703 frameworks: []const []const u8 = &[0][]const u8{},704 frameworks: []const []const u8 = &[0][]const u8{},
704 system_lib_names: []const []const u8 = &.{},705 system_lib_names: []const []const u8 = &.{},
...@@ -1535,6 +1536,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1535,6 +1536,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1535 .link_libcpp = link_libcpp,1536 .link_libcpp = link_libcpp,
1536 .link_libunwind = link_libunwind,1537 .link_libunwind = link_libunwind,
1537 .objects = options.link_objects,1538 .objects = options.link_objects,
1539 .must_link_objects = options.must_link_objects,
1538 .frameworks = options.frameworks,1540 .frameworks = options.frameworks,
1539 .framework_dirs = options.framework_dirs,1541 .framework_dirs = options.framework_dirs,
1540 .system_libs = system_libs,1542 .system_libs = system_libs,
src/link.zig+1
...@@ -156,6 +156,7 @@ pub const Options = struct {...@@ -156,6 +156,7 @@ pub const Options = struct {
156 llvm_cpu_features: ?[*:0]const u8,156 llvm_cpu_features: ?[*:0]const u8,
157157
158 objects: []const []const u8,158 objects: []const []const u8,
159 must_link_objects: []const []const u8,
159 framework_dirs: []const []const u8,160 framework_dirs: []const []const u8,
160 frameworks: []const []const u8,161 frameworks: []const []const u8,
161 system_libs: std.StringArrayHashMapUnmanaged(SystemLib),162 system_libs: std.StringArrayHashMapUnmanaged(SystemLib),
src/link/MachO.zig+52-6
...@@ -679,10 +679,20 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -679,10 +679,20 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
679 // the relocatable object files.679 // the relocatable object files.
680 self.invalidate_relocs = true;680 self.invalidate_relocs = true;
681681
682 // Unpack must-link archives
683 var must_link_archives = std.StringArrayHashMap(void).init(arena);
684 try must_link_archives.ensureTotalCapacity(@intCast(u32, self.base.options.must_link_objects.len));
685 for (self.base.options.must_link_objects) |lib| {
686 _ = must_link_archives.getOrPutAssumeCapacity(lib);
687 }
688
682 // Positional arguments to the linker such as object files and static archives.689 // Positional arguments to the linker such as object files and static archives.
683 var positionals = std.ArrayList([]const u8).init(arena);690 var positionals = std.ArrayList([]const u8).init(arena);
684691 try positionals.ensureUnusedCapacity(self.base.options.objects.len);
685 try positionals.appendSlice(self.base.options.objects);692 for (self.base.options.objects) |obj| {
693 if (must_link_archives.contains(obj)) continue;
694 _ = positionals.appendAssumeCapacity(obj);
695 }
686696
687 for (comp.c_object_table.keys()) |key| {697 for (comp.c_object_table.keys()) |key| {
688 try positionals.append(key.status.success.object_path);698 try positionals.append(key.status.success.object_path);
...@@ -889,12 +899,17 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -889,12 +899,17 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
889 try argv.append("dynamic_lookup");899 try argv.append("dynamic_lookup");
890 }900 }
891901
902 for (self.base.options.must_link_objects) |lib| {
903 try argv.append(try std.fmt.allocPrint(arena, "-force_load {s}", .{lib}));
904 }
905
892 Compilation.dump_argv(argv.items);906 Compilation.dump_argv(argv.items);
893 }907 }
894908
895 var dependent_libs = std.fifo.LinearFifo(Dylib.Id, .Dynamic).init(self.base.allocator);909 var dependent_libs = std.fifo.LinearFifo(Dylib.Id, .Dynamic).init(self.base.allocator);
896 defer dependent_libs.deinit();910 defer dependent_libs.deinit();
897 try self.parseInputFiles(positionals.items, self.base.options.sysroot, &dependent_libs);911 try self.parseInputFiles(positionals.items, self.base.options.sysroot, &dependent_libs);
912 try self.parseAndForceLoadStaticArchives(must_link_archives.keys());
898 try self.parseLibs(libs.items, self.base.options.sysroot, &dependent_libs);913 try self.parseLibs(libs.items, self.base.options.sysroot, &dependent_libs);
899 try self.parseDependentLibs(self.base.options.sysroot, &dependent_libs);914 try self.parseDependentLibs(self.base.options.sysroot, &dependent_libs);
900 }915 }
...@@ -1203,7 +1218,7 @@ fn parseObject(self: *MachO, path: []const u8) !bool {...@@ -1203,7 +1218,7 @@ fn parseObject(self: *MachO, path: []const u8) !bool {
1203 return true;1218 return true;
1204}1219}
12051220
1206fn parseArchive(self: *MachO, path: []const u8) !bool {1221fn parseArchive(self: *MachO, path: []const u8, force_load: bool) !bool {
1207 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {1222 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
1208 error.FileNotFound => return false,1223 error.FileNotFound => return false,
1209 else => |e| return e,1224 else => |e| return e,
...@@ -1226,7 +1241,23 @@ fn parseArchive(self: *MachO, path: []const u8) !bool {...@@ -1226,7 +1241,23 @@ fn parseArchive(self: *MachO, path: []const u8) !bool {
1226 else => |e| return e,1241 else => |e| return e,
1227 };1242 };
12281243
1229 try self.archives.append(self.base.allocator, archive);1244 if (force_load) {
1245 defer archive.deinit(self.base.allocator);
1246 // Get all offsets from the ToC
1247 var offsets = std.AutoArrayHashMap(u32, void).init(self.base.allocator);
1248 defer offsets.deinit();
1249 for (archive.toc.values()) |offs| {
1250 for (offs.items) |off| {
1251 _ = try offsets.getOrPut(off);
1252 }
1253 }
1254 for (offsets.keys()) |off| {
1255 const object = try self.objects.addOne(self.base.allocator);
1256 object.* = try archive.parseObject(self.base.allocator, self.base.options.target, off);
1257 }
1258 } else {
1259 try self.archives.append(self.base.allocator, archive);
1260 }
12301261
1231 return true;1262 return true;
1232}1263}
...@@ -1311,7 +1342,7 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const...@@ -1311,7 +1342,7 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const
1311 log.debug("parsing input file path '{s}'", .{full_path});1342 log.debug("parsing input file path '{s}'", .{full_path});
13121343
1313 if (try self.parseObject(full_path)) continue;1344 if (try self.parseObject(full_path)) continue;
1314 if (try self.parseArchive(full_path)) continue;1345 if (try self.parseArchive(full_path, false)) continue;
1315 if (try self.parseDylib(full_path, .{1346 if (try self.parseDylib(full_path, .{
1316 .syslibroot = syslibroot,1347 .syslibroot = syslibroot,
1317 .dependent_libs = dependent_libs,1348 .dependent_libs = dependent_libs,
...@@ -1321,6 +1352,21 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const...@@ -1321,6 +1352,21 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const
1321 }1352 }
1322}1353}
13231354
1355fn parseAndForceLoadStaticArchives(self: *MachO, files: []const []const u8) !void {
1356 for (files) |file_name| {
1357 const full_path = full_path: {
1358 var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
1359 const path = try fs.realpath(file_name, &buffer);
1360 break :full_path try self.base.allocator.dupe(u8, path);
1361 };
1362 defer self.base.allocator.free(full_path);
1363 log.debug("parsing and force loading static archive '{s}'", .{full_path});
1364
1365 if (try self.parseArchive(full_path, true)) continue;
1366 log.warn("unknown filetype: expected static archive: '{s}'", .{file_name});
1367 }
1368}
1369
1324fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8, dependent_libs: anytype) !void {1370fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8, dependent_libs: anytype) !void {
1325 for (libs) |lib| {1371 for (libs) |lib| {
1326 log.debug("parsing lib path '{s}'", .{lib});1372 log.debug("parsing lib path '{s}'", .{lib});
...@@ -1328,7 +1374,7 @@ fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8, de...@@ -1328,7 +1374,7 @@ fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8, de
1328 .syslibroot = syslibroot,1374 .syslibroot = syslibroot,
1329 .dependent_libs = dependent_libs,1375 .dependent_libs = dependent_libs,
1330 })) continue;1376 })) continue;
1331 if (try self.parseArchive(lib)) continue;1377 if (try self.parseArchive(lib, false)) continue;
13321378
1333 log.warn("unknown filetype for a library: '{s}'", .{lib});1379 log.warn("unknown filetype for a library: '{s}'", .{lib});
1334 }1380 }
src/main.zig+10
...@@ -708,6 +708,9 @@ fn buildOutputType(...@@ -708,6 +708,9 @@ fn buildOutputType(
708 var link_objects = std.ArrayList([]const u8).init(gpa);708 var link_objects = std.ArrayList([]const u8).init(gpa);
709 defer link_objects.deinit();709 defer link_objects.deinit();
710710
711 var must_link_objects = std.ArrayList([]const u8).init(gpa);
712 defer must_link_objects.deinit();
713
711 var framework_dirs = std.ArrayList([]const u8).init(gpa);714 var framework_dirs = std.ArrayList([]const u8).init(gpa);
712 defer framework_dirs.deinit();715 defer framework_dirs.deinit();
713716
...@@ -1748,6 +1751,12 @@ fn buildOutputType(...@@ -1748,6 +1751,12 @@ fn buildOutputType(
1748 fatal("expected linker arg after '{s}'", .{arg});1751 fatal("expected linker arg after '{s}'", .{arg});
1749 }1752 }
1750 install_name = linker_args.items[i];1753 install_name = linker_args.items[i];
1754 } else if (mem.eql(u8, arg, "-force_load")) {
1755 i += 1;
1756 if (i >= linker_args.items.len) {
1757 fatal("expected linker arg after '{s}'", .{arg});
1758 }
1759 try must_link_objects.append(linker_args.items[i]);
1751 } else {1760 } else {
1752 warn("unsupported linker arg: {s}", .{arg});1761 warn("unsupported linker arg: {s}", .{arg});
1753 }1762 }
...@@ -2438,6 +2447,7 @@ fn buildOutputType(...@@ -2438,6 +2447,7 @@ fn buildOutputType(
2438 .rpath_list = rpath_list.items,2447 .rpath_list = rpath_list.items,
2439 .c_source_files = c_source_files.items,2448 .c_source_files = c_source_files.items,
2440 .link_objects = link_objects.items,2449 .link_objects = link_objects.items,
2450 .must_link_objects = must_link_objects.items,
2441 .framework_dirs = framework_dirs.items,2451 .framework_dirs = framework_dirs.items,
2442 .frameworks = frameworks.items,2452 .frameworks = frameworks.items,
2443 .system_lib_names = system_libs.keys(),2453 .system_lib_names = system_libs.keys(),