mirror of
https://github.com/ziglang/zig.git
synced 2024-11-17 01:23:54 +00:00
zld: support -Wl,-force_load=archive_path flag
This actually enables using `zig cc` as a linker for `cargo test` with `serde_derive`.
This commit is contained in:
parent
f9f792ab70
commit
16c55b15cb
@ -699,6 +699,7 @@ pub const InitOptions = struct {
|
||||
rpath_list: []const []const u8 = &[0][]const u8{},
|
||||
c_source_files: []const CSourceFile = &[0]CSourceFile{},
|
||||
link_objects: []const []const u8 = &[0][]const u8{},
|
||||
must_link_objects: []const []const u8 = &[0][]const u8{},
|
||||
framework_dirs: []const []const u8 = &[0][]const u8{},
|
||||
frameworks: []const []const u8 = &[0][]const u8{},
|
||||
system_lib_names: []const []const u8 = &.{},
|
||||
@ -1535,6 +1536,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
|
||||
.link_libcpp = link_libcpp,
|
||||
.link_libunwind = link_libunwind,
|
||||
.objects = options.link_objects,
|
||||
.must_link_objects = options.must_link_objects,
|
||||
.frameworks = options.frameworks,
|
||||
.framework_dirs = options.framework_dirs,
|
||||
.system_libs = system_libs,
|
||||
|
@ -156,6 +156,7 @@ pub const Options = struct {
|
||||
llvm_cpu_features: ?[*:0]const u8,
|
||||
|
||||
objects: []const []const u8,
|
||||
must_link_objects: []const []const u8,
|
||||
framework_dirs: []const []const u8,
|
||||
frameworks: []const []const u8,
|
||||
system_libs: std.StringArrayHashMapUnmanaged(SystemLib),
|
||||
|
@ -679,10 +679,20 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
|
||||
// the relocatable object files.
|
||||
self.invalidate_relocs = true;
|
||||
|
||||
// Unpack must-link archives
|
||||
var must_link_archives = std.StringArrayHashMap(void).init(arena);
|
||||
try must_link_archives.ensureTotalCapacity(@intCast(u32, self.base.options.must_link_objects.len));
|
||||
for (self.base.options.must_link_objects) |lib| {
|
||||
_ = must_link_archives.getOrPutAssumeCapacity(lib);
|
||||
}
|
||||
|
||||
// Positional arguments to the linker such as object files and static archives.
|
||||
var positionals = std.ArrayList([]const u8).init(arena);
|
||||
|
||||
try positionals.appendSlice(self.base.options.objects);
|
||||
try positionals.ensureUnusedCapacity(self.base.options.objects.len);
|
||||
for (self.base.options.objects) |obj| {
|
||||
if (must_link_archives.contains(obj)) continue;
|
||||
_ = positionals.appendAssumeCapacity(obj);
|
||||
}
|
||||
|
||||
for (comp.c_object_table.keys()) |key| {
|
||||
try positionals.append(key.status.success.object_path);
|
||||
@ -889,12 +899,17 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
|
||||
try argv.append("dynamic_lookup");
|
||||
}
|
||||
|
||||
for (self.base.options.must_link_objects) |lib| {
|
||||
try argv.append(try std.fmt.allocPrint(arena, "-force_load {s}", .{lib}));
|
||||
}
|
||||
|
||||
Compilation.dump_argv(argv.items);
|
||||
}
|
||||
|
||||
var dependent_libs = std.fifo.LinearFifo(Dylib.Id, .Dynamic).init(self.base.allocator);
|
||||
defer dependent_libs.deinit();
|
||||
try self.parseInputFiles(positionals.items, self.base.options.sysroot, &dependent_libs);
|
||||
try self.parseAndForceLoadStaticArchives(must_link_archives.keys());
|
||||
try self.parseLibs(libs.items, self.base.options.sysroot, &dependent_libs);
|
||||
try self.parseDependentLibs(self.base.options.sysroot, &dependent_libs);
|
||||
}
|
||||
@ -1203,7 +1218,7 @@ fn parseObject(self: *MachO, path: []const u8) !bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
fn parseArchive(self: *MachO, path: []const u8) !bool {
|
||||
fn parseArchive(self: *MachO, path: []const u8, force_load: bool) !bool {
|
||||
const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
|
||||
error.FileNotFound => return false,
|
||||
else => |e| return e,
|
||||
@ -1226,7 +1241,23 @@ fn parseArchive(self: *MachO, path: []const u8) !bool {
|
||||
else => |e| return e,
|
||||
};
|
||||
|
||||
try self.archives.append(self.base.allocator, archive);
|
||||
if (force_load) {
|
||||
defer archive.deinit(self.base.allocator);
|
||||
// Get all offsets from the ToC
|
||||
var offsets = std.AutoArrayHashMap(u32, void).init(self.base.allocator);
|
||||
defer offsets.deinit();
|
||||
for (archive.toc.values()) |offs| {
|
||||
for (offs.items) |off| {
|
||||
_ = try offsets.getOrPut(off);
|
||||
}
|
||||
}
|
||||
for (offsets.keys()) |off| {
|
||||
const object = try self.objects.addOne(self.base.allocator);
|
||||
object.* = try archive.parseObject(self.base.allocator, self.base.options.target, off);
|
||||
}
|
||||
} else {
|
||||
try self.archives.append(self.base.allocator, archive);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1311,7 +1342,7 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const
|
||||
log.debug("parsing input file path '{s}'", .{full_path});
|
||||
|
||||
if (try self.parseObject(full_path)) continue;
|
||||
if (try self.parseArchive(full_path)) continue;
|
||||
if (try self.parseArchive(full_path, false)) continue;
|
||||
if (try self.parseDylib(full_path, .{
|
||||
.syslibroot = syslibroot,
|
||||
.dependent_libs = dependent_libs,
|
||||
@ -1321,6 +1352,21 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const
|
||||
}
|
||||
}
|
||||
|
||||
fn parseAndForceLoadStaticArchives(self: *MachO, files: []const []const u8) !void {
|
||||
for (files) |file_name| {
|
||||
const full_path = full_path: {
|
||||
var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
|
||||
const path = try fs.realpath(file_name, &buffer);
|
||||
break :full_path try self.base.allocator.dupe(u8, path);
|
||||
};
|
||||
defer self.base.allocator.free(full_path);
|
||||
log.debug("parsing and force loading static archive '{s}'", .{full_path});
|
||||
|
||||
if (try self.parseArchive(full_path, true)) continue;
|
||||
log.warn("unknown filetype: expected static archive: '{s}'", .{file_name});
|
||||
}
|
||||
}
|
||||
|
||||
fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8, dependent_libs: anytype) !void {
|
||||
for (libs) |lib| {
|
||||
log.debug("parsing lib path '{s}'", .{lib});
|
||||
@ -1328,7 +1374,7 @@ fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8, de
|
||||
.syslibroot = syslibroot,
|
||||
.dependent_libs = dependent_libs,
|
||||
})) continue;
|
||||
if (try self.parseArchive(lib)) continue;
|
||||
if (try self.parseArchive(lib, false)) continue;
|
||||
|
||||
log.warn("unknown filetype for a library: '{s}'", .{lib});
|
||||
}
|
||||
|
10
src/main.zig
10
src/main.zig
@ -708,6 +708,9 @@ fn buildOutputType(
|
||||
var link_objects = std.ArrayList([]const u8).init(gpa);
|
||||
defer link_objects.deinit();
|
||||
|
||||
var must_link_objects = std.ArrayList([]const u8).init(gpa);
|
||||
defer must_link_objects.deinit();
|
||||
|
||||
var framework_dirs = std.ArrayList([]const u8).init(gpa);
|
||||
defer framework_dirs.deinit();
|
||||
|
||||
@ -1748,6 +1751,12 @@ fn buildOutputType(
|
||||
fatal("expected linker arg after '{s}'", .{arg});
|
||||
}
|
||||
install_name = linker_args.items[i];
|
||||
} else if (mem.eql(u8, arg, "-force_load")) {
|
||||
i += 1;
|
||||
if (i >= linker_args.items.len) {
|
||||
fatal("expected linker arg after '{s}'", .{arg});
|
||||
}
|
||||
try must_link_objects.append(linker_args.items[i]);
|
||||
} else {
|
||||
warn("unsupported linker arg: {s}", .{arg});
|
||||
}
|
||||
@ -2438,6 +2447,7 @@ fn buildOutputType(
|
||||
.rpath_list = rpath_list.items,
|
||||
.c_source_files = c_source_files.items,
|
||||
.link_objects = link_objects.items,
|
||||
.must_link_objects = must_link_objects.items,
|
||||
.framework_dirs = framework_dirs.items,
|
||||
.frameworks = frameworks.items,
|
||||
.system_lib_names = system_libs.keys(),
|
||||
|
Loading…
Reference in New Issue
Block a user