mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
zld: parse dylibs as positionals
* add preliminary rpath support * enable shared_library test on x86_64 macOS
This commit is contained in:
parent
ca772735c3
commit
1dac5f5214
@ -516,6 +516,19 @@ pub const dylib = extern struct {
|
||||
compatibility_version: u32,
|
||||
};
|
||||
|
||||
/// The rpath_command contains a path which at runtime should be added to the current
|
||||
/// run path used to find @rpath prefixed dylibs.
|
||||
pub const rpath_command = extern struct {
|
||||
/// LC_RPATH
|
||||
cmd: u32,
|
||||
|
||||
/// includes string
|
||||
cmdsize: u32,
|
||||
|
||||
/// path to add to run path
|
||||
path: u32,
|
||||
};
|
||||
|
||||
/// The segment load command indicates that a part of this file is to be
|
||||
/// mapped into the task's address space. The size of this segment in memory,
|
||||
/// vmsize, maybe equal to or larger than the amount to map from this file,
|
||||
|
||||
@ -756,6 +756,19 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
|
||||
}
|
||||
}
|
||||
|
||||
// rpaths
|
||||
var rpath_table = std.StringArrayHashMap(void).init(arena);
|
||||
for (self.base.options.rpath_list) |rpath| {
|
||||
if (rpath_table.contains(rpath)) continue;
|
||||
try rpath_table.putNoClobber(rpath, {});
|
||||
}
|
||||
|
||||
var rpaths = std.ArrayList([]const u8) .init(arena);
|
||||
try rpaths.ensureCapacity(rpath_table.count());
|
||||
for (rpath_table.items()) |entry| {
|
||||
rpaths.appendAssumeCapacity(entry.key);
|
||||
}
|
||||
|
||||
if (self.base.options.verbose_link) {
|
||||
var argv = std.ArrayList([]const u8).init(arena);
|
||||
|
||||
@ -767,6 +780,11 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
|
||||
try argv.append(syslibroot);
|
||||
}
|
||||
|
||||
for (rpaths.items) |rpath| {
|
||||
try argv.append("-rpath");
|
||||
try argv.append(rpath);
|
||||
}
|
||||
|
||||
try argv.appendSlice(positionals.items);
|
||||
|
||||
try argv.append("-o");
|
||||
@ -783,7 +801,10 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
|
||||
Compilation.dump_argv(argv.items);
|
||||
}
|
||||
|
||||
try zld.link(positionals.items, shared_libs.items, full_out_path);
|
||||
try zld.link(positionals.items, full_out_path, .{
|
||||
.shared_libs = shared_libs.items,
|
||||
.rpaths = rpaths.items,
|
||||
});
|
||||
|
||||
break :outer;
|
||||
}
|
||||
|
||||
@ -186,7 +186,12 @@ pub fn closeFiles(self: Zld) void {
|
||||
if (self.file) |f| f.close();
|
||||
}
|
||||
|
||||
pub fn link(self: *Zld, files: []const []const u8, shared_libs: []const []const u8, out_path: []const u8) !void {
|
||||
const LinkArgs = struct {
|
||||
shared_libs: []const []const u8,
|
||||
rpaths: []const []const u8,
|
||||
};
|
||||
|
||||
pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: LinkArgs) !void {
|
||||
if (files.len == 0) return error.NoInputFiles;
|
||||
if (out_path.len == 0) return error.EmptyOutputPath;
|
||||
|
||||
@ -222,8 +227,9 @@ pub fn link(self: *Zld, files: []const []const u8, shared_libs: []const []const
|
||||
});
|
||||
|
||||
try self.populateMetadata();
|
||||
try self.addRpaths(args.rpaths);
|
||||
try self.parseInputFiles(files);
|
||||
try self.parseDylibs(shared_libs);
|
||||
try self.parseDylibs(args.shared_libs);
|
||||
try self.resolveSymbols();
|
||||
try self.resolveStubsAndGotEntries();
|
||||
try self.updateMetadata();
|
||||
@ -241,6 +247,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
|
||||
kind: enum {
|
||||
object,
|
||||
archive,
|
||||
dylib,
|
||||
},
|
||||
file: fs.File,
|
||||
name: []const u8,
|
||||
@ -248,7 +255,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
|
||||
var classified = std.ArrayList(Input).init(self.allocator);
|
||||
defer classified.deinit();
|
||||
|
||||
// First, classify input files as either object or archive.
|
||||
// First, classify input files: object, archive or dylib.
|
||||
for (files) |file_name| {
|
||||
const file = try fs.cwd().openFile(file_name, .{});
|
||||
const full_path = full_path: {
|
||||
@ -289,6 +296,22 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
|
||||
continue;
|
||||
}
|
||||
|
||||
try_dylib: {
|
||||
const header = try file.reader().readStruct(macho.mach_header_64);
|
||||
if (header.filetype != macho.MH_DYLIB) {
|
||||
try file.seekTo(0);
|
||||
break :try_dylib;
|
||||
}
|
||||
|
||||
try file.seekTo(0);
|
||||
try classified.append(.{
|
||||
.kind = .dylib,
|
||||
.file = file,
|
||||
.name = full_path,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
log.debug("unexpected input file of unknown type '{s}'", .{file_name});
|
||||
}
|
||||
|
||||
@ -317,6 +340,35 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
|
||||
try archive.parse();
|
||||
try self.archives.append(self.allocator, archive);
|
||||
},
|
||||
.dylib => {
|
||||
const dylib = try self.allocator.create(Dylib);
|
||||
errdefer self.allocator.destroy(dylib);
|
||||
|
||||
dylib.* = Dylib.init(self.allocator);
|
||||
dylib.arch = self.arch.?;
|
||||
dylib.name = input.name;
|
||||
dylib.file = input.file;
|
||||
|
||||
const ordinal = @intCast(u16, self.dylibs.items.len);
|
||||
dylib.ordinal = ordinal + 2; // TODO +2 since 1 is reserved for libSystem
|
||||
|
||||
// TODO Defer parsing of the dylibs until they are actually needed
|
||||
try dylib.parse();
|
||||
try self.dylibs.append(self.allocator, dylib);
|
||||
|
||||
// Add LC_LOAD_DYLIB command
|
||||
const dylib_id = dylib.id orelse unreachable;
|
||||
var dylib_cmd = try createLoadDylibCommand(
|
||||
self.allocator,
|
||||
dylib_id.name,
|
||||
dylib_id.timestamp,
|
||||
dylib_id.current_version,
|
||||
dylib_id.compatibility_version,
|
||||
);
|
||||
errdefer dylib_cmd.deinit(self.allocator);
|
||||
|
||||
try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd });
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2117,6 +2169,25 @@ fn populateMetadata(self: *Zld) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn addRpaths(self: *Zld, rpaths: []const []const u8) !void {
|
||||
for (rpaths) |rpath| {
|
||||
const cmdsize = @intCast(u32, mem.alignForwardGeneric(
|
||||
u64,
|
||||
@sizeOf(macho.rpath_command) + rpath.len,
|
||||
@sizeOf(u64),
|
||||
));
|
||||
var rpath_cmd = emptyGenericCommandWithData(macho.rpath_command{
|
||||
.cmd = macho.LC_RPATH,
|
||||
.cmdsize = cmdsize,
|
||||
.path = @sizeOf(macho.rpath_command),
|
||||
});
|
||||
rpath_cmd.data = try self.allocator.alloc(u8, cmdsize - rpath_cmd.inner.path);
|
||||
mem.set(u8, rpath_cmd.data, 0);
|
||||
mem.copy(u8, rpath_cmd.data, rpath);
|
||||
try self.load_commands.append(self.allocator, .{ .Rpath = rpath_cmd });
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(self: *Zld) !void {
|
||||
try self.writeStubHelperCommon();
|
||||
try self.resolveRelocsAndWriteSections();
|
||||
|
||||
@ -24,6 +24,7 @@ pub const LoadCommand = union(enum) {
|
||||
SourceVersion: macho.source_version_command,
|
||||
Uuid: macho.uuid_command,
|
||||
LinkeditData: macho.linkedit_data_command,
|
||||
Rpath: GenericCommandWithData(macho.rpath_command),
|
||||
Unknown: GenericCommandWithData(macho.load_command),
|
||||
|
||||
pub fn read(allocator: *Allocator, reader: anytype) !LoadCommand {
|
||||
@ -84,6 +85,9 @@ pub const LoadCommand = union(enum) {
|
||||
=> LoadCommand{
|
||||
.LinkeditData = try stream.reader().readStruct(macho.linkedit_data_command),
|
||||
},
|
||||
macho.LC_RPATH => LoadCommand{
|
||||
.Rpath = try GenericCommandWithData(macho.rpath_command).read(allocator, stream.reader()),
|
||||
},
|
||||
else => LoadCommand{
|
||||
.Unknown = try GenericCommandWithData(macho.load_command).read(allocator, stream.reader()),
|
||||
},
|
||||
@ -103,6 +107,7 @@ pub const LoadCommand = union(enum) {
|
||||
.Segment => |x| x.write(writer),
|
||||
.Dylinker => |x| x.write(writer),
|
||||
.Dylib => |x| x.write(writer),
|
||||
.Rpath => |x| x.write(writer),
|
||||
.Unknown => |x| x.write(writer),
|
||||
};
|
||||
}
|
||||
@ -120,6 +125,7 @@ pub const LoadCommand = union(enum) {
|
||||
.Segment => |x| x.inner.cmd,
|
||||
.Dylinker => |x| x.inner.cmd,
|
||||
.Dylib => |x| x.inner.cmd,
|
||||
.Rpath => |x| x.inner.cmd,
|
||||
.Unknown => |x| x.inner.cmd,
|
||||
};
|
||||
}
|
||||
@ -137,6 +143,7 @@ pub const LoadCommand = union(enum) {
|
||||
.Segment => |x| x.inner.cmdsize,
|
||||
.Dylinker => |x| x.inner.cmdsize,
|
||||
.Dylib => |x| x.inner.cmdsize,
|
||||
.Rpath => |x| x.inner.cmdsize,
|
||||
.Unknown => |x| x.inner.cmdsize,
|
||||
};
|
||||
}
|
||||
@ -146,6 +153,7 @@ pub const LoadCommand = union(enum) {
|
||||
.Segment => |*x| x.deinit(allocator),
|
||||
.Dylinker => |*x| x.deinit(allocator),
|
||||
.Dylib => |*x| x.deinit(allocator),
|
||||
.Rpath => |*x| x.deinit(allocator),
|
||||
.Unknown => |*x| x.deinit(allocator),
|
||||
else => {},
|
||||
};
|
||||
@ -169,6 +177,7 @@ pub const LoadCommand = union(enum) {
|
||||
.Segment => |x| x.eql(other.Segment),
|
||||
.Dylinker => |x| x.eql(other.Dylinker),
|
||||
.Dylib => |x| x.eql(other.Dylib),
|
||||
.Rpath => |x| x.eql(other.Rpath),
|
||||
.Unknown => |x| x.eql(other.Unknown),
|
||||
};
|
||||
}
|
||||
|
||||
@ -9,10 +9,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
|
||||
cases.add("test/standalone/main_return_error/error_u8.zig");
|
||||
cases.add("test/standalone/main_return_error/error_u8_non_zero.zig");
|
||||
cases.addBuildFile("test/standalone/main_pkg_path/build.zig");
|
||||
if (std.Target.current.os.tag != .macos) {
|
||||
// TODO zld cannot link shared libraries yet.
|
||||
cases.addBuildFile("test/standalone/shared_library/build.zig");
|
||||
}
|
||||
cases.addBuildFile("test/standalone/shared_library/build.zig");
|
||||
cases.addBuildFile("test/standalone/mix_o_files/build.zig");
|
||||
cases.addBuildFile("test/standalone/global_linkage/build.zig");
|
||||
cases.addBuildFile("test/standalone/static_c_lib/build.zig");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user