macho: handle -install_name option for dylibs/MachO

The status quo for the `build.zig` build system is preserved in
the sense that, if the user does not explicitly override
`dylib.setInstallName(...);` in their build script, the default
of `@rpath/libname.dylib` applies. However, should they want to
override the default behaviour, they can either:

1) unset it with

```dylib.setIntallName(null);```

2) set it to an explicit string with

```dylib.setInstallName("somename.dylib");```

When it comes to the command line however, the default is not to
use `@rpath` for the install name when creating a dylib. The user
will now be required to explicitly specify the `@rpath` as part
of the desired install name should they choose so like so:

1) with `build-lib`

```
zig build-lib -dynamic foo.zig -install_name @rpath/libfoo.dylib
```

2) with `cc`

```
zig cc -shared foo.c -o libfoo.dylib -Wl,"-install_name=@rpath/libfoo.dylib"
```
This commit is contained in:
Jakub Konka 2021-12-17 00:18:45 +01:00 committed by Andrew Kelley
parent 9a8fdbe0a0
commit a08137330c
5 changed files with 38 additions and 9 deletions

View file

@ -1537,6 +1537,9 @@ pub const LibExeObjStep = struct {
/// Permit read-only relocations in read-only segments. Disallowed by default.
link_z_notext: bool = false,
/// (Darwin) Install name for the dylib
install_name: ?[]const u8 = null,
/// Position Independent Code
force_pic: ?bool = null,
@ -2451,6 +2454,16 @@ pub const LibExeObjStep = struct {
zig_args.append("--version") catch unreachable;
zig_args.append(builder.fmt("{}", .{version})) catch unreachable;
}
if (self.target.isDarwin()) {
const install_name = self.install_name orelse builder.fmt("@rpath/{s}{s}{s}", .{
self.target.libPrefix(),
self.name,
self.target.dynamicLibSuffix(),
});
try zig_args.append("-install_name");
try zig_args.append(install_name);
}
}
if (self.bundle_compiler_rt) |x| {

View file

@ -780,6 +780,8 @@ pub const InitOptions = struct {
enable_link_snapshots: bool = false,
/// (Darwin) Path and version of the native SDK if detected.
native_darwin_sdk: ?std.zig.system.darwin.DarwinSDK = null,
/// (Darwin) Install name of the dylib
install_name: ?[]const u8 = null,
};
fn addPackageTableToCacheHash(
@ -1509,6 +1511,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
.use_stage1 = use_stage1,
.enable_link_snapshots = options.enable_link_snapshots,
.native_darwin_sdk = options.native_darwin_sdk,
.install_name = options.install_name,
});
errdefer bin_file.destroy();
comp.* = .{

View file

@ -157,6 +157,9 @@ pub const Options = struct {
/// (Darwin) Path and version of the native SDK if detected.
native_darwin_sdk: ?std.zig.system.darwin.DarwinSDK = null,
/// (Darwin) Install name for the dylib
install_name: ?[]const u8 = null,
pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode {
return if (options.use_lld) .Obj else options.output_mode;
}

View file

@ -479,6 +479,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
man.hash.addListOfBytes(self.base.options.frameworks);
man.hash.addListOfBytes(self.base.options.rpath_list);
if (is_dyn_lib) {
man.hash.addOptionalBytes(self.base.options.install_name);
man.hash.addOptional(self.base.options.version);
}
link.hashAddSystemLibs(&man.hash, self.base.options.system_libs);
@ -811,11 +812,10 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
if (is_dyn_lib) {
try argv.append("-dylib");
const install_name = try std.fmt.allocPrint(arena, "@rpath/{s}", .{
self.base.options.emit.?.sub_path,
});
try argv.append("-install_name");
try argv.append(install_name);
if (self.base.options.install_name) |install_name| {
try argv.append("-install_name");
try argv.append(install_name);
}
}
if (self.base.options.sysroot) |syslibroot| {
@ -4336,10 +4336,7 @@ fn populateMissingMetadata(self: *MachO) !void {
if (self.dylib_id_cmd_index == null and self.base.options.output_mode == .Lib) {
self.dylib_id_cmd_index = @intCast(u16, self.load_commands.items.len);
const install_name = try std.fmt.allocPrint(self.base.allocator, "@rpath/{s}", .{
self.base.options.emit.?.sub_path,
});
defer self.base.allocator.free(install_name);
const install_name = self.base.options.install_name orelse self.base.options.emit.?.sub_path;
const current_version = self.base.options.version orelse
std.builtin.Version{ .major = 1, .minor = 0, .patch = 0 };
const compat_version = self.base.options.compatibility_version orelse

View file

@ -430,6 +430,7 @@ const usage_build_generic =
\\ --image-base [addr] Set base address for executable image
\\ -framework [name] (Darwin) link against framework
\\ -F[dir] (Darwin) add search path for frameworks
\\ -install_name=[value] (Darwin) add dylib's install name
\\ --import-memory (WebAssembly) import memory from the environment
\\ --initial-memory=[bytes] (WebAssembly) initial size of the linear memory
\\ --max-memory=[bytes] (WebAssembly) maximum size of the linear memory
@ -668,6 +669,7 @@ fn buildOutputType(
var wasi_exec_model: ?std.builtin.WasiExecModel = null;
var enable_link_snapshots: bool = false;
var native_darwin_sdk: ?std.zig.system.darwin.DarwinSDK = null;
var install_name: ?[]const u8 = null;
// e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names.
// This array is populated by zig cc frontend and then has to be converted to zig-style
@ -873,6 +875,10 @@ fn buildOutputType(
if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg});
i += 1;
try frameworks.append(args[i]);
} else if (mem.eql(u8, arg, "-install_name")) {
if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg});
i += 1;
install_name = args[i];
} else if (mem.eql(u8, arg, "-T") or mem.eql(u8, arg, "--script")) {
if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg});
i += 1;
@ -1721,6 +1727,12 @@ fn buildOutputType(
} else {
fatal("unsupported -undefined option '{s}'", .{linker_args.items[i]});
}
} else if (mem.eql(u8, arg, "-install_name")) {
i += 1;
if (i >= linker_args.items.len) {
fatal("expected linker arg after '{s}'", .{arg});
}
install_name = linker_args.items[i];
} else {
warn("unsupported linker arg: {s}", .{arg});
}
@ -2495,6 +2507,7 @@ fn buildOutputType(
.debug_compile_errors = debug_compile_errors,
.enable_link_snapshots = enable_link_snapshots,
.native_darwin_sdk = native_darwin_sdk,
.install_name = install_name,
}) catch |err| switch (err) {
error.LibCUnavailable => {
const target = target_info.target;