diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2021-06-30 00:03:55 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-06-30 00:03:55 +0200 |
| commit | 81bf05bf6c1249c39273b494d3e337d300b4ddd5 (patch) | |
| tree | 9b53744d1d3a31ac82e153173bb9abe7bb52c999 /src | |
| parent | 37fbf5b0d3b0be131903e4895ee3703393b32d8f (diff) | |
| parent | 0e15205521b9a8c95db3c1714dffe3be1df5cda1 (diff) | |
| download | zig-81bf05bf6c1249c39273b494d3e337d300b4ddd5.tar.gz zig-81bf05bf6c1249c39273b494d3e337d300b4ddd5.zip | |
Merge pull request #9266 from ziglang/zld-dylibs
zig ld can create dylibs now; remove system linker hack and any mention of ld64.lld from the codebase
Diffstat (limited to 'src')
| -rw-r--r-- | src/Compilation.zig | 15 | ||||
| -rw-r--r-- | src/codegen/llvm/bindings.zig | 2 | ||||
| -rw-r--r-- | src/link.zig | 3 | ||||
| -rw-r--r-- | src/link/MachO.zig | 611 | ||||
| -rw-r--r-- | src/link/MachO/Trie.zig | 5 | ||||
| -rw-r--r-- | src/link/MachO/Zld.zig | 191 | ||||
| -rw-r--r-- | src/main.zig | 4 | ||||
| -rw-r--r-- | src/zig_llvm.cpp | 5 | ||||
| -rw-r--r-- | src/zig_llvm.h | 1 |
9 files changed, 303 insertions, 534 deletions
diff --git a/src/Compilation.zig b/src/Compilation.zig index 10b2a9af11..890100b996 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -879,24 +879,16 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { break :blk false; }; - const darwin_can_use_system_linker_and_sdk = + const darwin_can_use_system_sdk = // comptime conditions ((build_options.have_llvm and comptime std.Target.current.isDarwin()) and // runtime conditions (use_lld and std.builtin.os.tag == .macos and options.target.isDarwin())); - const darwin_system_linker_hack = blk: { - if (darwin_can_use_system_linker_and_sdk) { - break :blk std.os.getenv("ZIG_SYSTEM_LINKER_HACK") != null; - } else { - break :blk false; - } - }; - const sysroot = blk: { if (options.sysroot) |sysroot| { break :blk sysroot; - } else if (darwin_can_use_system_linker_and_sdk) { + } else if (darwin_can_use_system_sdk) { // TODO Revisit this targeting versions lower than macOS 11 when LLVM 12 is out. // See https://github.com/ziglang/zig/issues/6996 const at_least_big_sur = options.target.os.getVersionRange().semver.min.major >= 11; @@ -915,8 +907,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { break :blk false; } else if (options.c_source_files.len == 0) { break :blk false; - } else if (darwin_system_linker_hack) { - break :blk false; } else switch (options.output_mode) { .Lib, .Obj => break :blk false, .Exe => switch (options.optimize_mode) { @@ -1295,7 +1285,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { .optimize_mode = options.optimize_mode, .use_lld = use_lld, .use_llvm = use_llvm, - .system_linker_hack = darwin_system_linker_hack, .link_libc = link_libc, .link_libcpp = link_libcpp, .link_libunwind = link_libunwind, diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index 364b059a87..f3a1a72f3d 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -496,12 +496,10 @@ fn LLVMInitializeAllAsmParsers() callconv(.C) void { extern fn ZigLLDLinkCOFF(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int; extern fn ZigLLDLinkELF(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int; -extern fn ZigLLDLinkMachO(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int; extern fn ZigLLDLinkWasm(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int; pub const LinkCOFF = ZigLLDLinkCOFF; pub const LinkELF = ZigLLDLinkELF; -pub const LinkMachO = ZigLLDLinkMachO; pub const LinkWasm = ZigLLDLinkWasm; pub const ObjectFormatType = enum(c_int) { diff --git a/src/link.zig b/src/link.zig index c26feb10fd..3bbd542a15 100644 --- a/src/link.zig +++ b/src/link.zig @@ -61,9 +61,6 @@ pub const Options = struct { /// other objects. /// Otherwise (depending on `use_lld`) this link code directly outputs and updates the final binary. use_llvm: bool, - /// Darwin-only. If this is true, `use_llvm` is true, and `is_native_os` is true, this link code will - /// use system linker `ld` instead of the LLD. - system_linker_hack: bool, link_libc: bool, link_libcpp: bool, link_libunwind: bool, diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 45e7bbe519..ba9999730e 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -430,7 +430,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*MachO { pub fn flush(self: *MachO, comp: *Compilation) !void { if (build_options.have_llvm and self.base.options.use_lld) { - return self.linkWithLLD(comp); + return self.linkWithZld(comp); } else { switch (self.base.options.effectiveOutputMode()) { .Exe, .Obj => {}, @@ -593,7 +593,7 @@ fn resolveFramework( return null; } -fn linkWithLLD(self: *MachO, comp: *Compilation) !void { +fn linkWithZld(self: *MachO, comp: *Compilation) !void { const tracy = trace(@src()); defer tracy.end(); @@ -631,7 +631,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { const stack_size = self.base.options.stack_size_override orelse 0; const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os; - const id_symlink_basename = "lld.id"; + const id_symlink_basename = "zld.id"; var man: Cache.Manifest = undefined; defer if (!self.base.options.disable_lld_caching) man.deinit(); @@ -669,7 +669,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { man.hash.addStringSet(self.base.options.system_libs); man.hash.add(allow_shlib_undefined); man.hash.add(self.base.options.bind_global_refs_locally); - man.hash.add(self.base.options.system_linker_hack); man.hash.addOptionalBytes(self.base.options.sysroot); // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. @@ -682,17 +681,17 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { id_symlink_basename, &prev_digest_buf, ) catch |err| blk: { - log.debug("MachO LLD new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) }); + log.debug("MachO Zld new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) }); // Handle this as a cache miss. break :blk prev_digest_buf[0..0]; }; if (mem.eql(u8, prev_digest, &digest)) { - log.debug("MachO LLD digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)}); + log.debug("MachO Zld digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)}); // Hot diggity dog! The output binary is already there. self.base.lock = man.toOwnedLock(); return; } - log.debug("MachO LLD prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) }); + log.debug("MachO Zld prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) }); // We are about to change the output file to be different, so we invalidate the build hash now. directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) { @@ -726,495 +725,227 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { if (!mem.eql(u8, the_object_path, full_out_path)) { try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{}); } - } else outer: { - const use_zld = blk: { - if (self.base.options.is_native_os and self.base.options.system_linker_hack) { - // If the user forces the use of ld64, make sure we are running native! - break :blk false; - } - - if (self.base.options.target.cpu.arch == .aarch64) { - // On aarch64, always use zld. - break :blk true; - } - - if (self.base.options.output_mode == .Lib or - self.base.options.linker_script != null) - { - // Fallback to LLD in this handful of cases on x86_64 only. - break :blk false; - } + } else { + var zld = Zld.init(self.base.allocator); + defer { + zld.closeFiles(); + zld.deinit(); + } + zld.target = target; + zld.stack_size = stack_size; - break :blk true; - }; + // Positional arguments to the linker such as object files and static archives. + var positionals = std.ArrayList([]const u8).init(arena); - if (use_zld) { - var zld = Zld.init(self.base.allocator); - defer { - zld.closeFiles(); - zld.deinit(); - } - zld.arch = target.cpu.arch; - zld.stack_size = stack_size; + try positionals.appendSlice(self.base.options.objects); - // Positional arguments to the linker such as object files and static archives. - var positionals = std.ArrayList([]const u8).init(arena); + for (comp.c_object_table.keys()) |key| { + try positionals.append(key.status.success.object_path); + } - try positionals.appendSlice(self.base.options.objects); + if (module_obj_path) |p| { + try positionals.append(p); + } - for (comp.c_object_table.keys()) |key| { - try positionals.append(key.status.success.object_path); - } + try positionals.append(comp.compiler_rt_static_lib.?.full_object_path); - if (module_obj_path) |p| { - try positionals.append(p); - } + // libc++ dep + if (self.base.options.link_libcpp) { + try positionals.append(comp.libcxxabi_static_lib.?.full_object_path); + try positionals.append(comp.libcxx_static_lib.?.full_object_path); + } - try positionals.append(comp.compiler_rt_static_lib.?.full_object_path); + // Shared and static libraries passed via `-l` flag. + var search_lib_names = std.ArrayList([]const u8).init(arena); - // libc++ dep - if (self.base.options.link_libcpp) { - try positionals.append(comp.libcxxabi_static_lib.?.full_object_path); - try positionals.append(comp.libcxx_static_lib.?.full_object_path); + const system_libs = self.base.options.system_libs.keys(); + for (system_libs) |link_lib| { + // By this time, we depend on these libs being dynamically linked libraries and not static libraries + // (the check for that needs to be earlier), but they could be full paths to .dylib files, in which + // case we want to avoid prepending "-l". + if (Compilation.classifyFileExt(link_lib) == .shared_library) { + try positionals.append(link_lib); + continue; } - // Shared and static libraries passed via `-l` flag. - var search_lib_names = std.ArrayList([]const u8).init(arena); - - const system_libs = self.base.options.system_libs.keys(); - for (system_libs) |link_lib| { - // By this time, we depend on these libs being dynamically linked libraries and not static libraries - // (the check for that needs to be earlier), but they could be full paths to .dylib files, in which - // case we want to avoid prepending "-l". - if (Compilation.classifyFileExt(link_lib) == .shared_library) { - try positionals.append(link_lib); - continue; - } + try search_lib_names.append(link_lib); + } - try search_lib_names.append(link_lib); + var lib_dirs = std.ArrayList([]const u8).init(arena); + for (self.base.options.lib_dirs) |dir| { + if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| { + try lib_dirs.append(search_dir); + } else { + log.warn("directory not found for '-L{s}'", .{dir}); } + } - var lib_dirs = std.ArrayList([]const u8).init(arena); - for (self.base.options.lib_dirs) |dir| { - if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| { - try lib_dirs.append(search_dir); - } else { - log.warn("directory not found for '-L{s}'", .{dir}); + var libs = std.ArrayList([]const u8).init(arena); + var lib_not_found = false; + for (search_lib_names.items) |lib_name| { + // Assume ld64 default: -search_paths_first + // Look in each directory for a dylib (stub first), and then for archive + // TODO implement alternative: -search_dylibs_first + for (&[_][]const u8{ ".tbd", ".dylib", ".a" }) |ext| { + if (try resolveLib(arena, lib_dirs.items, lib_name, ext)) |full_path| { + try libs.append(full_path); + break; } + } else { + log.warn("library not found for '-l{s}'", .{lib_name}); + lib_not_found = true; } + } - var libs = std.ArrayList([]const u8).init(arena); - var lib_not_found = false; - for (search_lib_names.items) |lib_name| { - // Assume ld64 default: -search_paths_first - // Look in each directory for a dylib (stub first), and then for archive - // TODO implement alternative: -search_dylibs_first - for (&[_][]const u8{ ".tbd", ".dylib", ".a" }) |ext| { - if (try resolveLib(arena, lib_dirs.items, lib_name, ext)) |full_path| { - try libs.append(full_path); - break; - } - } else { - log.warn("library not found for '-l{s}'", .{lib_name}); - lib_not_found = true; - } + if (lib_not_found) { + log.warn("Library search paths:", .{}); + for (lib_dirs.items) |dir| { + log.warn(" {s}", .{dir}); } + } - if (lib_not_found) { - log.warn("Library search paths:", .{}); - for (lib_dirs.items) |dir| { - log.warn(" {s}", .{dir}); - } + // If we're compiling native and we can find libSystem.B.{dylib, tbd}, + // we link against that instead of embedded libSystem.B.tbd file. + var native_libsystem_available = false; + if (self.base.options.is_native_os) blk: { + // Try stub file first. If we hit it, then we're done as the stub file + // re-exports every single symbol definition. + if (try resolveLib(arena, lib_dirs.items, "System", ".tbd")) |full_path| { + try libs.append(full_path); + native_libsystem_available = true; + break :blk; } - - // If we're compiling native and we can find libSystem.B.{dylib, tbd}, - // we link against that instead of embedded libSystem.B.tbd file. - var native_libsystem_available = false; - if (self.base.options.is_native_os) blk: { - // Try stub file first. If we hit it, then we're done as the stub file - // re-exports every single symbol definition. - if (try resolveLib(arena, lib_dirs.items, "System", ".tbd")) |full_path| { - try libs.append(full_path); + // If we didn't hit the stub file, try .dylib next. However, libSystem.dylib + // doesn't export libc.dylib which we'll need to resolve subsequently also. + if (try resolveLib(arena, lib_dirs.items, "System", ".dylib")) |libsystem_path| { + if (try resolveLib(arena, lib_dirs.items, "c", ".dylib")) |libc_path| { + try libs.append(libsystem_path); + try libs.append(libc_path); native_libsystem_available = true; break :blk; } - // If we didn't hit the stub file, try .dylib next. However, libSystem.dylib - // doesn't export libc.dylib which we'll need to resolve subsequently also. - if (try resolveLib(arena, lib_dirs.items, "System", ".dylib")) |libsystem_path| { - if (try resolveLib(arena, lib_dirs.items, "c", ".dylib")) |libc_path| { - try libs.append(libsystem_path); - try libs.append(libc_path); - native_libsystem_available = true; - break :blk; - } - } } - if (!native_libsystem_available) { - const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", "darwin", "libSystem.B.tbd", - }); - try libs.append(full_path); - } - - // frameworks - var framework_dirs = std.ArrayList([]const u8).init(arena); - for (self.base.options.framework_dirs) |dir| { - if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| { - try framework_dirs.append(search_dir); - } else { - log.warn("directory not found for '-F{s}'", .{dir}); - } - } - - var framework_not_found = false; - for (self.base.options.frameworks) |framework| { - for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| { - if (try resolveFramework(arena, framework_dirs.items, framework, ext)) |full_path| { - try libs.append(full_path); - break; - } - } else { - log.warn("framework not found for '-f{s}'", .{framework}); - framework_not_found = true; - } - } - - if (framework_not_found) { - log.warn("Framework search paths:", .{}); - for (framework_dirs.items) |dir| { - log.warn(" {s}", .{dir}); - } - } - - // 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.keys()) |*key| { - rpaths.appendAssumeCapacity(key.*); - } - - if (self.base.options.verbose_link) { - var argv = std.ArrayList([]const u8).init(arena); - - try argv.append("zig"); - try argv.append("ld"); - - if (self.base.options.sysroot) |syslibroot| { - try argv.append("-syslibroot"); - 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"); - try argv.append(full_out_path); - - if (native_libsystem_available) { - try argv.append("-lSystem"); - try argv.append("-lc"); - } - - for (search_lib_names.items) |l_name| { - try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{l_name})); - } - - for (self.base.options.lib_dirs) |lib_dir| { - try argv.append(try std.fmt.allocPrint(arena, "-L{s}", .{lib_dir})); - } - - Compilation.dump_argv(argv.items); - } - - try zld.link(positionals.items, full_out_path, .{ - .syslibroot = self.base.options.sysroot, - .libs = libs.items, - .rpaths = rpaths.items, + } + if (!native_libsystem_available) { + const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", "darwin", "libSystem.B.tbd", }); - - break :outer; + try libs.append(full_path); } - // Create an LLD command line and invoke it. - var argv = std.ArrayList([]const u8).init(self.base.allocator); - defer argv.deinit(); - - // TODO https://github.com/ziglang/zig/issues/6971 - // Note that there is no need to check if running natively since we do that already - // when setting `system_linker_hack` in Compilation struct. - if (self.base.options.system_linker_hack) { - try argv.append("ld"); - } else { - // We will invoke ourselves as a child process to gain access to LLD. - // This is necessary because LLD does not behave properly as a library - - // it calls exit() and does not reset all global data between invocations. - try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, "ld64.lld" }); - - try argv.append("-error-limit"); - try argv.append("0"); + // frameworks + var framework_dirs = std.ArrayList([]const u8).init(arena); + for (self.base.options.framework_dirs) |dir| { + if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| { + try framework_dirs.append(search_dir); + } else { + log.warn("directory not found for '-F{s}'", .{dir}); + } } - if (self.base.options.lto) { - switch (self.base.options.optimize_mode) { - .Debug => {}, - .ReleaseSmall => try argv.append("-O2"), - .ReleaseFast, .ReleaseSafe => try argv.append("-O3"), + var framework_not_found = false; + for (self.base.options.frameworks) |framework| { + for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| { + if (try resolveFramework(arena, framework_dirs.items, framework, ext)) |full_path| { + try libs.append(full_path); + break; + } + } else { + log.warn("framework not found for '-f{s}'", .{framework}); + framework_not_found = true; } } - try argv.append("-demangle"); - if (self.base.options.rdynamic and !self.base.options.system_linker_hack) { - try argv.append("--export-dynamic"); + if (framework_not_found) { + log.warn("Framework search paths:", .{}); + for (framework_dirs.items) |dir| { + log.warn(" {s}", .{dir}); + } } - try argv.appendSlice(self.base.options.extra_lld_args); - - if (self.base.options.z_nodelete) { - try argv.append("-z"); - try argv.append("nodelete"); - } - if (self.base.options.z_defs) { - try argv.append("-z"); - try argv.append("defs"); + // 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, {}); } - if (is_exe_or_dyn_lib) { - try argv.append("-dynamic"); + var rpaths = std.ArrayList([]const u8).init(arena); + try rpaths.ensureCapacity(rpath_table.count()); + for (rpath_table.keys()) |*key| { + rpaths.appendAssumeCapacity(key.*); } - if (is_dyn_lib) { - try argv.append("-dylib"); - - if (self.base.options.version) |ver| { - const compat_vers = try std.fmt.allocPrint(arena, "{d}.0.0", .{ver.major}); - try argv.append("-compatibility_version"); - try argv.append(compat_vers); - - const cur_vers = try std.fmt.allocPrint(arena, "{d}.{d}.{d}", .{ ver.major, ver.minor, ver.patch }); - try argv.append("-current_version"); - try argv.append(cur_vers); + const output: Zld.Output = output: { + if (is_dyn_lib) { + const install_name = try std.fmt.allocPrint(arena, "@rpath/{s}", .{ + self.base.options.emit.?.sub_path, + }); + break :output .{ + .tag = .dylib, + .path = full_out_path, + .install_name = install_name, + }; } + break :output .{ + .tag = .exe, + .path = full_out_path, + }; + }; - const dylib_install_name = try std.fmt.allocPrint(arena, "@rpath/{s}", .{self.base.options.emit.?.sub_path}); - try argv.append("-install_name"); - try argv.append(dylib_install_name); - } + if (self.base.options.verbose_link) { + var argv = std.ArrayList([]const u8).init(arena); - try argv.append("-arch"); - try argv.append(darwinArchString(target.cpu.arch)); + try argv.append("zig"); + try argv.append("ld"); - switch (target.os.tag) { - .macos => { - try argv.append("-macosx_version_min"); - }, - .ios, .tvos, .watchos => switch (target.cpu.arch) { - .i386, .x86_64 => { - try argv.append("-ios_simulator_version_min"); - }, - else => { - try argv.append("-iphoneos_version_min"); - }, - }, - else => unreachable, - } - const ver = target.os.version_range.semver.min; - const version_string = try std.fmt.allocPrint(arena, "{d}.{d}.{d}", .{ ver.major, ver.minor, ver.patch }); - try argv.append(version_string); + if (is_exe_or_dyn_lib) { + try argv.append("-dynamic"); + } - try argv.append("-sdk_version"); - try argv.append(version_string); + if (is_dyn_lib) { + try argv.append("-dylib"); - if (target_util.requiresPIE(target) and self.base.options.output_mode == .Exe) { - try argv.append("-pie"); - } + try argv.append("-install_name"); + try argv.append(output.install_name.?); + } - try argv.append("-o"); - try argv.append(full_out_path); + if (self.base.options.sysroot) |syslibroot| { + try argv.append("-syslibroot"); + try argv.append(syslibroot); + } - // rpaths - var rpath_table = std.StringHashMap(void).init(self.base.allocator); - defer rpath_table.deinit(); - for (self.base.options.rpath_list) |rpath| { - if ((try rpath_table.fetchPut(rpath, {})) == null) { + for (rpaths.items) |rpath| { try argv.append("-rpath"); try argv.append(rpath); } - } - if (is_dyn_lib) { - if ((try rpath_table.fetchPut(full_out_path, {})) == null) { - try argv.append("-rpath"); - try argv.append(full_out_path); - } - } - - if (self.base.options.sysroot) |dir| { - try argv.append("-syslibroot"); - try argv.append(dir); - } - - for (self.base.options.lib_dirs) |lib_dir| { - try argv.append("-L"); - try argv.append(lib_dir); - } - - // Positional arguments to the linker such as object files. - try argv.appendSlice(self.base.options.objects); - - for (comp.c_object_table.keys()) |key| { - try argv.append(key.status.success.object_path); - } - if (module_obj_path) |p| { - try argv.append(p); - } - // compiler_rt on darwin is missing some stuff, so we still build it and rely on LinkOnce - if (is_exe_or_dyn_lib and !self.base.options.skip_linker_dependencies) { - try argv.append(comp.compiler_rt_static_lib.?.full_object_path); - } + try argv.appendSlice(positionals.items); - // Shared libraries. - const system_libs = self.base.options.system_libs.keys(); - try argv.ensureCapacity(argv.items.len + system_libs.len); - for (system_libs) |link_lib| { - // By this time, we depend on these libs being dynamically linked libraries and not static libraries - // (the check for that needs to be earlier), but they could be full paths to .dylib files, in which - // case we want to avoid prepending "-l". - const ext = Compilation.classifyFileExt(link_lib); - const arg = if (ext == .shared_library) link_lib else try std.fmt.allocPrint(arena, "-l{s}", .{link_lib}); - argv.appendAssumeCapacity(arg); - } - - // libc++ dep - if (self.base.options.link_libcpp) { - try argv.append(comp.libcxxabi_static_lib.?.full_object_path); - try argv.append(comp.libcxx_static_lib.?.full_object_path); - } + try argv.append("-o"); + try argv.append(output.path); - // On Darwin, libSystem has libc in it, but also you have to use it - // to make syscalls because the syscall numbers are not documented - // and change between versions. So we always link against libSystem. - // LLD craps out if you do -lSystem cross compiling, so until that - // codebase gets some love from the new maintainers we're left with - // this dirty hack. - if (self.base.options.is_native_os) { - try argv.append("-lSystem"); - } - - for (self.base.options.framework_dirs) |framework_dir| { - try argv.append("-F"); - try argv.append(framework_dir); - } - for (self.base.options.frameworks) |framework| { - try argv.append("-framework"); - try argv.append(framework); - } - - if (allow_shlib_undefined) { - try argv.append("-undefined"); - try argv.append("dynamic_lookup"); - } - if (self.base.options.bind_global_refs_locally) { - try argv.append("-Bsymbolic"); - } - - if (self.base.options.verbose_link) { - // Potentially skip over our own name so that the LLD linker name is the first argv item. - const adjusted_argv = if (self.base.options.system_linker_hack) argv.items else argv.items[1..]; - Compilation.dump_argv(adjusted_argv); - } - - // TODO https://github.com/ziglang/zig/issues/6971 - // Note that there is no need to check if running natively since we do that already - // when setting `system_linker_hack` in Compilation struct. - if (self.base.options.system_linker_hack) { - const result = try std.ChildProcess.exec(.{ .allocator = self.base.allocator, .argv = argv.items }); - defer { - self.base.allocator.free(result.stdout); - self.base.allocator.free(result.stderr); + if (native_libsystem_available) { + try argv.append("-lSystem"); + try argv.append("-lc"); } - if (result.stdout.len != 0) { - log.warn("unexpected LD stdout: {s}", .{result.stdout}); - } - if (result.stderr.len != 0) { - log.warn("unexpected LD stderr: {s}", .{result.stderr}); - } - if (result.term != .Exited or result.term.Exited != 0) { - // TODO parse this output and surface with the Compilation API rather than - // directly outputting to stderr here. - log.err("{s}", .{result.stderr}); - return error.LDReportedFailure; - } - } else { - // Sadly, we must run LLD as a child process because it does not behave - // properly as a library. - const child = try std.ChildProcess.init(argv.items, arena); - defer child.deinit(); - - if (comp.clang_passthrough_mode) { - child.stdin_behavior = .Inherit; - child.stdout_behavior = .Inherit; - child.stderr_behavior = .Inherit; - - const term = child.spawnAndWait() catch |err| { - log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); - return error.UnableToSpawnSelf; - }; - switch (term) { - .Exited => |code| { - if (code != 0) { - // TODO https://github.com/ziglang/zig/issues/6342 - std.process.exit(1); - } - }, - else => { - log.err("{s} terminated", .{argv.items[0]}); - return error.LLDCrashed; - }, - } - } else { - child.stdin_behavior = .Ignore; - child.stdout_behavior = .Ignore; - child.stderr_behavior = .Pipe; - - try child.spawn(); - - const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024); - const term = child.wait() catch |err| { - log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); - return error.UnableToSpawnSelf; - }; - - switch (term) { - .Exited => |code| { - if (code != 0) { - // TODO parse this output and surface with the Compilation API rather than - // directly outputting to stderr here. - std.debug.print("{s}", .{stderr}); - return error.LLDReportedFailure; - } - }, - else => { - log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); - return error.LLDCrashed; - }, - } + for (search_lib_names.items) |l_name| { + try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{l_name})); + } - if (stderr.len != 0) { - log.warn("unexpected LLD stderr:\n{s}", .{stderr}); - } + for (self.base.options.lib_dirs) |lib_dir| { + try argv.append(try std.fmt.allocPrint(arena, "-L{s}", .{lib_dir})); } + + Compilation.dump_argv(argv.items); } + + try zld.link(positionals.items, output, .{ + .syslibroot = self.base.options.sysroot, + .libs = libs.items, + .rpaths = rpaths.items, + }); } if (!self.base.options.disable_lld_caching) { diff --git a/src/link/MachO/Trie.zig b/src/link/MachO/Trie.zig index 9ef1e486e1..8aa2262bff 100644 --- a/src/link/MachO/Trie.zig +++ b/src/link/MachO/Trie.zig @@ -334,8 +334,9 @@ pub fn finalize(self: *Trie) !void { self.ordered_nodes.shrinkRetainingCapacity(0); try self.ordered_nodes.ensureCapacity(self.allocator, self.node_count); - const Fifo = std.fifo.LinearFifo(*Node, .{ .Static = std.math.maxInt(u8) }); - var fifo = Fifo.init(); + var fifo = std.fifo.LinearFifo(*Node, .Dynamic).init(self.allocator); + defer fifo.deinit(); + try fifo.writeItem(self.root.?); while (fifo.readItem()) |next| { diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index 59c09aacef..454b5dbcfe 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -25,10 +25,10 @@ usingnamespace @import("bind.zig"); allocator: *Allocator, -arch: ?std.Target.Cpu.Arch = null, +target: ?std.Target = null, page_size: ?u16 = null, file: ?fs.File = null, -out_path: ?[]const u8 = null, +output: ?Output = null, // TODO these args will become obselete once Zld is coalesced with incremental // linker. @@ -54,6 +54,7 @@ dylinker_cmd_index: ?u16 = null, data_in_code_cmd_index: ?u16 = null, function_starts_cmd_index: ?u16 = null, main_cmd_index: ?u16 = null, +dylib_id_cmd_index: ?u16 = null, version_min_cmd_index: ?u16 = null, source_version_cmd_index: ?u16 = null, uuid_cmd_index: ?u16 = null, @@ -118,6 +119,12 @@ got_entries: std.ArrayListUnmanaged(*Symbol) = .{}, stub_helper_stubs_start_off: ?u64 = null, +pub const Output = struct { + tag: enum { exe, dylib }, + path: []const u8, + install_name: ?[]const u8 = null, +}; + const TlvOffset = struct { source_addr: u64, offset: u64, @@ -200,36 +207,17 @@ const LinkArgs = struct { rpaths: []const []const u8, }; -pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: LinkArgs) !void { +pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArgs) !void { if (files.len == 0) return error.NoInputFiles; - if (out_path.len == 0) return error.EmptyOutputPath; - - if (self.arch == null) { - // Try inferring the arch from the object files. - self.arch = blk: { - const file = try fs.cwd().openFile(files[0], .{}); - defer file.close(); - var reader = file.reader(); - const header = try reader.readStruct(macho.mach_header_64); - const arch: std.Target.Cpu.Arch = switch (header.cputype) { - macho.CPU_TYPE_X86_64 => .x86_64, - macho.CPU_TYPE_ARM64 => .aarch64, - else => |value| { - log.err("unsupported cpu architecture 0x{x}", .{value}); - return error.UnsupportedCpuArchitecture; - }, - }; - break :blk arch; - }; - } + if (output.path.len == 0) return error.EmptyOutputPath; - self.page_size = switch (self.arch.?) { + self.page_size = switch (self.target.?.cpu.arch) { .aarch64 => 0x4000, .x86_64 => 0x1000, else => unreachable, }; - self.out_path = out_path; - self.file = try fs.cwd().createFile(out_path, .{ + self.output = output; + self.file = try fs.cwd().createFile(self.output.?.path, .{ .truncate = true, .read = true, .mode = if (std.Target.current.os.tag == .windows) 0 else 0o777, @@ -263,19 +251,19 @@ fn parseInputFiles(self: *Zld, files: []const []const u8, syslibroot: ?[]const u break :full_path try self.allocator.dupe(u8, path); }; - if (try Object.createAndParseFromPath(self.allocator, self.arch.?, full_path)) |object| { + if (try Object.createAndParseFromPath(self.allocator, self.target.?.cpu.arch, full_path)) |object| { try self.objects.append(self.allocator, object); continue; } - if (try Archive.createAndParseFromPath(self.allocator, self.arch.?, full_path)) |archive| { + if (try Archive.createAndParseFromPath(self.allocator, self.target.?.cpu.arch, full_path)) |archive| { try self.archives.append(self.allocator, archive); continue; } if (try Dylib.createAndParseFromPath( self.allocator, - self.arch.?, + self.target.?.cpu.arch, full_path, .{ .syslibroot = syslibroot }, )) |dylibs| { @@ -292,7 +280,7 @@ fn parseLibs(self: *Zld, libs: []const []const u8, syslibroot: ?[]const u8) !voi for (libs) |lib| { if (try Dylib.createAndParseFromPath( self.allocator, - self.arch.?, + self.target.?.cpu.arch, lib, .{ .syslibroot = syslibroot }, )) |dylibs| { @@ -301,7 +289,7 @@ fn parseLibs(self: *Zld, libs: []const []const u8, syslibroot: ?[]const u8) !voi continue; } - if (try Archive.createAndParseFromPath(self.allocator, self.arch.?, lib)) |archive| { + if (try Archive.createAndParseFromPath(self.allocator, self.target.?.cpu.arch, lib)) |archive| { try self.archives.append(self.allocator, archive); continue; } @@ -989,7 +977,7 @@ fn allocateTextSegment(self: *Zld) !void { const stub_helper = &seg.sections.items[self.stub_helper_section_index.?]; stubs.size += nstubs * stubs.reserved2; - const stub_size: u4 = switch (self.arch.?) { + const stub_size: u4 = switch (self.target.?.cpu.arch) { .x86_64 => 10, .aarch64 => 3 * @sizeOf(u32), else => unreachable, @@ -1226,7 +1214,7 @@ fn writeStubHelperCommon(self: *Zld) !void { const data = &data_segment.sections.items[self.data_section_index.?]; self.stub_helper_stubs_start_off = blk: { - switch (self.arch.?) { + switch (self.target.?.cpu.arch) { .x86_64 => { const code_size = 15; var code: [code_size]u8 = undefined; @@ -1358,7 +1346,7 @@ fn writeLazySymbolPointer(self: *Zld, index: u32) !void { const data_segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment; const la_symbol_ptr = data_segment.sections.items[self.la_symbol_ptr_section_index.?]; - const stub_size: u4 = switch (self.arch.?) { + const stub_size: u4 = switch (self.target.?.cpu.arch) { .x86_64 => 10, .aarch64 => 3 * @sizeOf(u32), else => unreachable, @@ -1384,7 +1372,7 @@ fn writeStub(self: *Zld, index: u32) !void { log.debug("writing stub at 0x{x}", .{stub_off}); var code = try self.allocator.alloc(u8, stubs.reserved2); defer self.allocator.free(code); - switch (self.arch.?) { + switch (self.target.?.cpu.arch) { .x86_64 => { assert(la_ptr_addr >= stub_addr + stubs.reserved2); const displacement = try math.cast(u32, la_ptr_addr - stub_addr - stubs.reserved2); @@ -1447,7 +1435,7 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void { const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; const stub_helper = text_segment.sections.items[self.stub_helper_section_index.?]; - const stub_size: u4 = switch (self.arch.?) { + const stub_size: u4 = switch (self.target.?.cpu.arch) { .x86_64 => 10, .aarch64 => 3 * @sizeOf(u32), else => unreachable, @@ -1455,7 +1443,7 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void { const stub_off = self.stub_helper_stubs_start_off.? + index * stub_size; var code = try self.allocator.alloc(u8, stub_size); defer self.allocator.free(code); - switch (self.arch.?) { + switch (self.target.?.cpu.arch) { .x86_64 => { const displacement = try math.cast( i32, @@ -1999,7 +1987,7 @@ fn populateMetadata(self: *Zld) !void { if (self.text_section_index == null) { const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; self.text_section_index = @intCast(u16, text_seg.sections.items.len); - const alignment: u2 = switch (self.arch.?) { + const alignment: u2 = switch (self.target.?.cpu.arch) { .x86_64 => 0, .aarch64 => 2, else => unreachable, // unhandled architecture type @@ -2013,12 +2001,12 @@ fn populateMetadata(self: *Zld) !void { if (self.stubs_section_index == null) { const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; self.stubs_section_index = @intCast(u16, text_seg.sections.items.len); - const alignment: u2 = switch (self.arch.?) { + const alignment: u2 = switch (self.target.?.cpu.arch) { .x86_64 => 0, .aarch64 => 2, else => unreachable, // unhandled architecture type }; - const stub_size: u4 = switch (self.arch.?) { + const stub_size: u4 = switch (self.target.?.cpu.arch) { .x86_64 => 6, .aarch64 => 3 * @sizeOf(u32), else => unreachable, // unhandled architecture type @@ -2033,12 +2021,12 @@ fn populateMetadata(self: *Zld) !void { if (self.stub_helper_section_index == null) { const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; self.stub_helper_section_index = @intCast(u16, text_seg.sections.items.len); - const alignment: u2 = switch (self.arch.?) { + const alignment: u2 = switch (self.target.?.cpu.arch) { .x86_64 => 0, .aarch64 => 2, else => unreachable, // unhandled architecture type }; - const stub_helper_size: u6 = switch (self.arch.?) { + const stub_helper_size: u6 = switch (self.target.?.cpu.arch) { .x86_64 => 15, .aarch64 => 6 * @sizeOf(u32), else => unreachable, @@ -2187,7 +2175,7 @@ fn populateMetadata(self: *Zld) !void { try self.load_commands.append(self.allocator, .{ .Dylinker = dylinker_cmd }); } - if (self.main_cmd_index == null) { + if (self.main_cmd_index == null and self.output.?.tag == .exe) { self.main_cmd_index = @intCast(u16, self.load_commands.items.len); try self.load_commands.append(self.allocator, .{ .Main = .{ @@ -2199,6 +2187,41 @@ fn populateMetadata(self: *Zld) !void { }); } + if (self.dylib_id_cmd_index == null and self.output.?.tag == .dylib) { + self.dylib_id_cmd_index = @intCast(u16, self.load_commands.items.len); + var dylib_cmd = try createLoadDylibCommand( + self.allocator, + self.output.?.install_name.?, + 2, + 0x10000, // TODO forward user-provided versions + 0x10000, + ); + errdefer dylib_cmd.deinit(self.allocator); + dylib_cmd.inner.cmd = macho.LC_ID_DYLIB; + try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd }); + } + + if (self.version_min_cmd_index == null) { + self.version_min_cmd_index = @intCast(u16, self.load_commands.items.len); + const cmd: u32 = switch (self.target.?.os.tag) { + .macos => macho.LC_VERSION_MIN_MACOSX, + .ios => macho.LC_VERSION_MIN_IPHONEOS, + .tvos => macho.LC_VERSION_MIN_TVOS, + .watchos => macho.LC_VERSION_MIN_WATCHOS, + else => unreachable, // wrong OS + }; + const ver = self.target.?.os.version_range.semver.min; + const version = ver.major << 16 | ver.minor << 8 | ver.patch; + try self.load_commands.append(self.allocator, .{ + .VersionMin = .{ + .cmd = cmd, + .cmdsize = @sizeOf(macho.version_min_command), + .version = version, + .sdk = version, + }, + }); + } + if (self.source_version_cmd_index == null) { self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len); try self.load_commands.append(self.allocator, .{ @@ -2237,7 +2260,7 @@ fn addDataInCodeLC(self: *Zld) !void { } fn addCodeSignatureLC(self: *Zld) !void { - if (self.code_signature_cmd_index == null and self.arch.? == .aarch64) { + if (self.code_signature_cmd_index == null and self.target.?.cpu.arch == .aarch64) { self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); try self.load_commands.append(self.allocator, .{ .LinkeditData = .{ @@ -2355,19 +2378,20 @@ fn flush(self: *Zld) !void { seg.inner.vmsize = mem.alignForwardGeneric(u64, seg.inner.filesize, self.page_size.?); } - if (self.arch.? == .aarch64) { + if (self.target.?.cpu.arch == .aarch64) { try self.writeCodeSignaturePadding(); } try self.writeLoadCommands(); try self.writeHeader(); - if (self.arch.? == .aarch64) { + if (self.target.?.cpu.arch == .aarch64) { try self.writeCodeSignature(); } if (comptime std.Target.current.isDarwin() and std.Target.current.cpu.arch == .aarch64) { - try fs.cwd().copyFile(self.out_path.?, fs.cwd(), self.out_path.?, .{}); + const out_path = self.output.?.path; + try fs.cwd().copyFile(out_path, fs.cwd(), out_path, .{}); } } @@ -2392,6 +2416,8 @@ fn writeGotEntries(self: *Zld) !void { } fn setEntryPoint(self: *Zld) !void { + if (self.output.?.tag != .exe) return; + // TODO we should respect the -entry flag passed in by the user to set a custom // entrypoint. For now, assume default of `_main`. const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; @@ -2636,12 +2662,12 @@ fn populateLazyBindOffsetsInStubHelper(self: *Zld, buffer: []const u8) !void { } assert(self.stubs.items.len <= offsets.items.len); - const stub_size: u4 = switch (self.arch.?) { + const stub_size: u4 = switch (self.target.?.cpu.arch) { .x86_64 => 10, .aarch64 => 3 * @sizeOf(u32), else => unreachable, }; - const off: u4 = switch (self.arch.?) { + const off: u4 = switch (self.target.?.cpu.arch) { .x86_64 => 1, .aarch64 => 2 * @sizeOf(u32), else => unreachable, @@ -2660,17 +2686,40 @@ fn writeExportInfo(self: *Zld) !void { defer trie.deinit(); const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; + const base_address = text_segment.inner.vmaddr; - // TODO export items for dylibs - const sym = self.globals.get("_main") orelse return error.MissingMainEntrypoint; - const reg = sym.cast(Symbol.Regular) orelse unreachable; - assert(reg.address >= text_segment.inner.vmaddr); + // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER. + log.debug("writing export trie", .{}); - try trie.put(.{ - .name = sym.name, - .vmaddr_offset = reg.address - text_segment.inner.vmaddr, - .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR, - }); + const Sorter = struct { + fn lessThan(_: void, a: []const u8, b: []const u8) bool { + return mem.lessThan(u8, a, b); + } + }; + + var sorted_globals = std.ArrayList([]const u8).init(self.allocator); + defer sorted_globals.deinit(); + + for (self.globals.values()) |sym| { + const reg = sym.cast(Symbol.Regular) orelse continue; + if (reg.linkage != .global) continue; + try sorted_globals.append(sym.name); + } + + std.sort.sort([]const u8, sorted_globals.items, {}, Sorter.lessThan); + + for (sorted_globals.items) |sym_name| { + const sym = self.globals.get(sym_name) orelse unreachable; + const reg = sym.cast(Symbol.Regular) orelse unreachable; + + log.debug(" | putting '{s}' defined at 0x{x}", .{ reg.base.name, reg.address }); + + try trie.put(.{ + .name = sym.name, + .vmaddr_offset = reg.address - base_address, + .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR, + }); + } try trie.finalize(); @@ -2975,7 +3024,7 @@ fn writeStringTable(self: *Zld) !void { try self.file.?.pwriteAll(self.strtab.items, symtab.stroff); - if (symtab.strsize > self.strtab.items.len and self.arch.? == .x86_64) { + if (symtab.strsize > self.strtab.items.len and self.target.?.cpu.arch == .x86_64) { // This is the last section, so we need to pad it out. try self.file.?.pwriteAll(&[_]u8{0}, seg.inner.fileoff + seg.inner.filesize - 1); } @@ -3023,7 +3072,7 @@ fn writeCodeSignaturePadding(self: *Zld) !void { const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData; const fileoff = seg.inner.fileoff + seg.inner.filesize; const needed_size = CodeSignature.calcCodeSignaturePaddingSize( - self.out_path.?, + self.output.?.path, fileoff, self.page_size.?, ); @@ -3049,7 +3098,7 @@ fn writeCodeSignature(self: *Zld) !void { defer code_sig.deinit(); try code_sig.calcAdhocSignature( self.file.?, - self.out_path.?, + self.output.?.path, text_seg.inner, code_sig_cmd, .Exe, @@ -3091,7 +3140,7 @@ fn writeHeader(self: *Zld) !void { cpu_subtype: macho.cpu_subtype_t, }; - const cpu_info: CpuInfo = switch (self.arch.?) { + const cpu_info: CpuInfo = switch (self.target.?.cpu.arch) { .aarch64 => .{ .cpu_type = macho.CPU_TYPE_ARM64, .cpu_subtype = macho.CPU_SUBTYPE_ARM_ALL, @@ -3104,8 +3153,22 @@ fn writeHeader(self: *Zld) !void { }; header.cputype = cpu_info.cpu_type; header.cpusubtype = cpu_info.cpu_subtype; - header.filetype = macho.MH_EXECUTE; - header.flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL; + + switch (self.output.?.tag) { + .exe => { + header.filetype = macho.MH_EXECUTE; + header.flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL; + }, + .dylib => { + header.filetype = macho.MH_DYLIB; + header.flags = macho.MH_NOUNDEFS | + macho.MH_DYLDLINK | + macho.MH_PIE | + macho.MH_TWOLEVEL | + macho.MH_NO_REEXPORTED_DYLIBS; + }, + } + header.reserved = 0; if (self.tlv_section_index) |_| diff --git a/src/main.zig b/src/main.zig index 86995c5b9f..192f6d853c 100644 --- a/src/main.zig +++ b/src/main.zig @@ -226,7 +226,6 @@ pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v { return punt_to_clang(arena, args); } else if (mem.eql(u8, cmd, "ld.lld") or - mem.eql(u8, cmd, "ld64.lld") or mem.eql(u8, cmd, "lld-link") or mem.eql(u8, cmd, "wasm-ld")) { @@ -3384,7 +3383,6 @@ fn punt_to_llvm_ar(arena: *Allocator, args: []const []const u8) error{OutOfMemor /// The first argument determines which backend is invoked. The options are: /// * `ld.lld` - ELF -/// * `ld64.lld` - Mach-O /// * `lld-link` - COFF /// * `wasm-ld` - WebAssembly /// TODO https://github.com/ziglang/zig/issues/3257 @@ -3402,8 +3400,6 @@ pub fn punt_to_lld(arena: *Allocator, args: []const []const u8) error{OutOfMemor const argc = @intCast(c_int, argv.len); if (mem.eql(u8, args[1], "ld.lld")) { break :rc llvm.LinkELF(argc, argv.ptr, true); - } else if (mem.eql(u8, args[1], "ld64.lld")) { - break :rc llvm.LinkMachO(argc, argv.ptr, true); } else if (mem.eql(u8, args[1], "lld-link")) { break :rc llvm.LinkCOFF(argc, argv.ptr, true); } else if (mem.eql(u8, args[1], "wasm-ld")) { diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index 8c54af4bb4..6d40f4089a 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -1187,11 +1187,6 @@ int ZigLLDLinkELF(int argc, const char **argv, bool can_exit_early) { return lld::elf::link(args, can_exit_early, llvm::outs(), llvm::errs()); } -int ZigLLDLinkMachO(int argc, const char **argv, bool can_exit_early) { - std::vector<const char *> args(argv, argv + argc); - return lld::mach_o::link(args, can_exit_early, llvm::outs(), llvm::errs()); -} - int ZigLLDLinkWasm(int argc, const char **argv, bool can_exit_early) { std::vector<const char *> args(argv, argv + argc); return lld::wasm::link(args, can_exit_early, llvm::outs(), llvm::errs()); diff --git a/src/zig_llvm.h b/src/zig_llvm.h index 32a969f70e..a2b3c6b92e 100644 --- a/src/zig_llvm.h +++ b/src/zig_llvm.h @@ -514,7 +514,6 @@ ZIG_EXTERN_C const char *ZigLLVMGetEnvironmentTypeName(enum ZigLLVM_EnvironmentT ZIG_EXTERN_C int ZigLLDLinkCOFF(int argc, const char **argv, bool can_exit_early); ZIG_EXTERN_C int ZigLLDLinkELF(int argc, const char **argv, bool can_exit_early); -ZIG_EXTERN_C int ZigLLDLinkMachO(int argc, const char **argv, bool can_exit_early); ZIG_EXTERN_C int ZigLLDLinkWasm(int argc, const char **argv, bool can_exit_early); ZIG_EXTERN_C bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size_t file_name_count, |
