diff --git a/lib/std/build.zig b/lib/std/build.zig index b78df48daf..b7785b214f 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -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| { diff --git a/src/Compilation.zig b/src/Compilation.zig index b3c2608c05..861771def4 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -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.* = .{ diff --git a/src/link.zig b/src/link.zig index 17083a915f..70e360d373 100644 --- a/src/link.zig +++ b/src/link.zig @@ -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; } diff --git a/src/link/MachO.zig b/src/link/MachO.zig index efc1330597..7dc6c52372 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -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 diff --git a/src/main.zig b/src/main.zig index e3221ecc67..61b4ebb7e9 100644 --- a/src/main.zig +++ b/src/main.zig @@ -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;