authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-29 07:59:46+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-29 07:59:46+02:00
log75a13a456b2cec9a81b9dabf54014f0e2a072c67
tree3ba86161bae27e232c206e13a37552d7884e44c1
parent2c385e58f96ea080bd6c732de422f84c6c38c2a2

zld: remove system linker hack and lld hooks


3 files changed, 149 insertions(+), 460 deletions(-)

src/Compilation.zig+2-13
......@@ -880,24 +880,16 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
880880 break :blk false;
881881 };
882882
883 const darwin_can_use_system_linker_and_sdk =
883 const darwin_can_use_system_sdk =
884884 // comptime conditions
885885 ((build_options.have_llvm and comptime std.Target.current.isDarwin()) and
886886 // runtime conditions
887887 (use_lld and std.builtin.os.tag == .macos and options.target.isDarwin()));
888888
889 const darwin_system_linker_hack = blk: {
890 if (darwin_can_use_system_linker_and_sdk) {
891 break :blk std.os.getenv("ZIG_SYSTEM_LINKER_HACK") != null;
892 } else {
893 break :blk false;
894 }
895 };
896
897889 const sysroot = blk: {
898890 if (options.sysroot) |sysroot| {
899891 break :blk sysroot;
900 } else if (darwin_can_use_system_linker_and_sdk) {
892 } else if (darwin_can_use_system_sdk) {
901893 // TODO Revisit this targeting versions lower than macOS 11 when LLVM 12 is out.
902894 // See https://github.com/ziglang/zig/issues/6996
903895 const at_least_big_sur = options.target.os.getVersionRange().semver.min.major >= 11;
......@@ -916,8 +908,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
916908 break :blk false;
917909 } else if (options.c_source_files.len == 0) {
918910 break :blk false;
919 } else if (darwin_system_linker_hack) {
920 break :blk false;
921911 } else switch (options.output_mode) {
922912 .Lib, .Obj => break :blk false,
923913 .Exe => switch (options.optimize_mode) {
......@@ -1296,7 +1286,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
12961286 .optimize_mode = options.optimize_mode,
12971287 .use_lld = use_lld,
12981288 .use_llvm = use_llvm,
1299 .system_linker_hack = darwin_system_linker_hack,
13001289 .link_libc = link_libc,
13011290 .link_libcpp = link_libcpp,
13021291 .link_libunwind = link_libunwind,
src/link.zig-3
......@@ -61,9 +61,6 @@ pub const Options = struct {
6161 /// other objects.
6262 /// Otherwise (depending on `use_lld`) this link code directly outputs and updates the final binary.
6363 use_llvm: bool,
64 /// Darwin-only. If this is true, `use_llvm` is true, and `is_native_os` is true, this link code will
65 /// use system linker `ld` instead of the LLD.
66 system_linker_hack: bool,
6764 link_libc: bool,
6865 link_libcpp: bool,
6966 link_libunwind: bool,
src/link/MachO.zig+147-444
......@@ -430,7 +430,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*MachO {
430430
431431pub fn flush(self: *MachO, comp: *Compilation) !void {
432432 if (build_options.have_llvm and self.base.options.use_lld) {
433 return self.linkWithLLD(comp);
433 return self.linkWithZld(comp);
434434 } else {
435435 switch (self.base.options.effectiveOutputMode()) {
436436 .Exe, .Obj => {},
......@@ -593,7 +593,7 @@ fn resolveFramework(
593593 return null;
594594}
595595
596fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
596fn linkWithZld(self: *MachO, comp: *Compilation) !void {
597597 const tracy = trace(@src());
598598 defer tracy.end();
599599
......@@ -626,7 +626,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
626626
627627 const is_lib = self.base.options.output_mode == .Lib;
628628 const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;
629 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
629 // const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
630630 const target = self.base.options.target;
631631 const stack_size = self.base.options.stack_size_override orelse 0;
632632 const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os;
......@@ -669,7 +669,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
669669 man.hash.addStringSet(self.base.options.system_libs);
670670 man.hash.add(allow_shlib_undefined);
671671 man.hash.add(self.base.options.bind_global_refs_locally);
672 man.hash.add(self.base.options.system_linker_hack);
673672 man.hash.addOptionalBytes(self.base.options.sysroot);
674673
675674 // 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 {
682681 id_symlink_basename,
683682 &prev_digest_buf,
684683 ) catch |err| blk: {
685 log.debug("MachO LLD new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) });
684 log.debug("MachO Zld new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) });
686685 // Handle this as a cache miss.
687686 break :blk prev_digest_buf[0..0];
688687 };
689688 if (mem.eql(u8, prev_digest, &digest)) {
690 log.debug("MachO LLD digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)});
689 log.debug("MachO Zld digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)});
691690 // Hot diggity dog! The output binary is already there.
692691 self.base.lock = man.toOwnedLock();
693692 return;
694693 }
695 log.debug("MachO LLD prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) });
694 log.debug("MachO Zld prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) });
696695
697696 // We are about to change the output file to be different, so we invalidate the build hash now.
698697 directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {
......@@ -726,495 +725,199 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
726725 if (!mem.eql(u8, the_object_path, full_out_path)) {
727726 try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});
728727 }
729 } else outer: {
730 const use_zld = blk: {
731 if (self.base.options.is_native_os and self.base.options.system_linker_hack) {
732 // If the user forces the use of ld64, make sure we are running native!
733 break :blk false;
734 }
735
736 if (self.base.options.target.cpu.arch == .aarch64) {
737 // On aarch64, always use zld.
738 break :blk true;
739 }
740
741 if (self.base.options.output_mode == .Lib or
742 self.base.options.linker_script != null)
743 {
744 // Fallback to LLD in this handful of cases on x86_64 only.
745 break :blk false;
746 }
728 } else {
729 var zld = Zld.init(self.base.allocator);
730 defer {
731 zld.closeFiles();
732 zld.deinit();
733 }
734 zld.arch = target.cpu.arch;
735 zld.stack_size = stack_size;
747736
748 break :blk true;
749 };
737 // Positional arguments to the linker such as object files and static archives.
738 var positionals = std.ArrayList([]const u8).init(arena);
750739
751 if (use_zld) {
752 var zld = Zld.init(self.base.allocator);
753 defer {
754 zld.closeFiles();
755 zld.deinit();
756 }
757 zld.arch = target.cpu.arch;
758 zld.stack_size = stack_size;
740 try positionals.appendSlice(self.base.options.objects);
759741
760 // Positional arguments to the linker such as object files and static archives.
761 var positionals = std.ArrayList([]const u8).init(arena);
742 for (comp.c_object_table.keys()) |key| {
743 try positionals.append(key.status.success.object_path);
744 }
762745
763 try positionals.appendSlice(self.base.options.objects);
746 if (module_obj_path) |p| {
747 try positionals.append(p);
748 }
764749
765 for (comp.c_object_table.keys()) |key| {
766 try positionals.append(key.status.success.object_path);
767 }
750 try positionals.append(comp.compiler_rt_static_lib.?.full_object_path);
768751
769 if (module_obj_path) |p| {
770 try positionals.append(p);
771 }
752 // libc++ dep
753 if (self.base.options.link_libcpp) {
754 try positionals.append(comp.libcxxabi_static_lib.?.full_object_path);
755 try positionals.append(comp.libcxx_static_lib.?.full_object_path);
756 }
772757
773 try positionals.append(comp.compiler_rt_static_lib.?.full_object_path);
758 // Shared and static libraries passed via `-l` flag.
759 var search_lib_names = std.ArrayList([]const u8).init(arena);
774760
775 // libc++ dep
776 if (self.base.options.link_libcpp) {
777 try positionals.append(comp.libcxxabi_static_lib.?.full_object_path);
778 try positionals.append(comp.libcxx_static_lib.?.full_object_path);
761 const system_libs = self.base.options.system_libs.keys();
762 for (system_libs) |link_lib| {
763 // By this time, we depend on these libs being dynamically linked libraries and not static libraries
764 // (the check for that needs to be earlier), but they could be full paths to .dylib files, in which
765 // case we want to avoid prepending "-l".
766 if (Compilation.classifyFileExt(link_lib) == .shared_library) {
767 try positionals.append(link_lib);
768 continue;
779769 }
780770
781 // Shared and static libraries passed via `-l` flag.
782 var search_lib_names = std.ArrayList([]const u8).init(arena);
783
784 const system_libs = self.base.options.system_libs.keys();
785 for (system_libs) |link_lib| {
786 // By this time, we depend on these libs being dynamically linked libraries and not static libraries
787 // (the check for that needs to be earlier), but they could be full paths to .dylib files, in which
788 // case we want to avoid prepending "-l".
789 if (Compilation.classifyFileExt(link_lib) == .shared_library) {
790 try positionals.append(link_lib);
791 continue;
792 }
771 try search_lib_names.append(link_lib);
772 }
793773
794 try search_lib_names.append(link_lib);
774 var lib_dirs = std.ArrayList([]const u8).init(arena);
775 for (self.base.options.lib_dirs) |dir| {
776 if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| {
777 try lib_dirs.append(search_dir);
778 } else {
779 log.warn("directory not found for '-L{s}'", .{dir});
795780 }
781 }
796782
797 var lib_dirs = std.ArrayList([]const u8).init(arena);
798 for (self.base.options.lib_dirs) |dir| {
799 if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| {
800 try lib_dirs.append(search_dir);
801 } else {
802 log.warn("directory not found for '-L{s}'", .{dir});
783 var libs = std.ArrayList([]const u8).init(arena);
784 var lib_not_found = false;
785 for (search_lib_names.items) |lib_name| {
786 // Assume ld64 default: -search_paths_first
787 // Look in each directory for a dylib (stub first), and then for archive
788 // TODO implement alternative: -search_dylibs_first
789 for (&[_][]const u8{ ".tbd", ".dylib", ".a" }) |ext| {
790 if (try resolveLib(arena, lib_dirs.items, lib_name, ext)) |full_path| {
791 try libs.append(full_path);
792 break;
803793 }
794 } else {
795 log.warn("library not found for '-l{s}'", .{lib_name});
796 lib_not_found = true;
804797 }
798 }
805799
806 var libs = std.ArrayList([]const u8).init(arena);
807 var lib_not_found = false;
808 for (search_lib_names.items) |lib_name| {
809 // Assume ld64 default: -search_paths_first
810 // Look in each directory for a dylib (stub first), and then for archive
811 // TODO implement alternative: -search_dylibs_first
812 for (&[_][]const u8{ ".tbd", ".dylib", ".a" }) |ext| {
813 if (try resolveLib(arena, lib_dirs.items, lib_name, ext)) |full_path| {
814 try libs.append(full_path);
815 break;
816 }
817 } else {
818 log.warn("library not found for '-l{s}'", .{lib_name});
819 lib_not_found = true;
820 }
800 if (lib_not_found) {
801 log.warn("Library search paths:", .{});
802 for (lib_dirs.items) |dir| {
803 log.warn(" {s}", .{dir});
821804 }
805 }
822806
823 if (lib_not_found) {
824 log.warn("Library search paths:", .{});
825 for (lib_dirs.items) |dir| {
826 log.warn(" {s}", .{dir});
827 }
807 // If we're compiling native and we can find libSystem.B.{dylib, tbd},
808 // we link against that instead of embedded libSystem.B.tbd file.
809 var native_libsystem_available = false;
810 if (self.base.options.is_native_os) blk: {
811 // Try stub file first. If we hit it, then we're done as the stub file
812 // re-exports every single symbol definition.
813 if (try resolveLib(arena, lib_dirs.items, "System", ".tbd")) |full_path| {
814 try libs.append(full_path);
815 native_libsystem_available = true;
816 break :blk;
828817 }
829
830 // If we're compiling native and we can find libSystem.B.{dylib, tbd},
831 // we link against that instead of embedded libSystem.B.tbd file.
832 var native_libsystem_available = false;
833 if (self.base.options.is_native_os) blk: {
834 // Try stub file first. If we hit it, then we're done as the stub file
835 // re-exports every single symbol definition.
836 if (try resolveLib(arena, lib_dirs.items, "System", ".tbd")) |full_path| {
837 try libs.append(full_path);
818 // If we didn't hit the stub file, try .dylib next. However, libSystem.dylib
819 // doesn't export libc.dylib which we'll need to resolve subsequently also.
820 if (try resolveLib(arena, lib_dirs.items, "System", ".dylib")) |libsystem_path| {
821 if (try resolveLib(arena, lib_dirs.items, "c", ".dylib")) |libc_path| {
822 try libs.append(libsystem_path);
823 try libs.append(libc_path);
838824 native_libsystem_available = true;
839825 break :blk;
840826 }
841 // If we didn't hit the stub file, try .dylib next. However, libSystem.dylib
842 // doesn't export libc.dylib which we'll need to resolve subsequently also.
843 if (try resolveLib(arena, lib_dirs.items, "System", ".dylib")) |libsystem_path| {
844 if (try resolveLib(arena, lib_dirs.items, "c", ".dylib")) |libc_path| {
845 try libs.append(libsystem_path);
846 try libs.append(libc_path);
847 native_libsystem_available = true;
848 break :blk;
849 }
850 }
851827 }
852 if (!native_libsystem_available) {
853 const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
854 "libc", "darwin", "libSystem.B.tbd",
855 });
856 try libs.append(full_path);
857 }
858
859 // frameworks
860 var framework_dirs = std.ArrayList([]const u8).init(arena);
861 for (self.base.options.framework_dirs) |dir| {
862 if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| {
863 try framework_dirs.append(search_dir);
864 } else {
865 log.warn("directory not found for '-F{s}'", .{dir});
866 }
867 }
868
869 var framework_not_found = false;
870 for (self.base.options.frameworks) |framework| {
871 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
872 if (try resolveFramework(arena, framework_dirs.items, framework, ext)) |full_path| {
873 try libs.append(full_path);
874 break;
875 }
876 } else {
877 log.warn("framework not found for '-f{s}'", .{framework});
878 framework_not_found = true;
879 }
880 }
881
882 if (framework_not_found) {
883 log.warn("Framework search paths:", .{});
884 for (framework_dirs.items) |dir| {
885 log.warn(" {s}", .{dir});
886 }
887 }
888
889 // rpaths
890 var rpath_table = std.StringArrayHashMap(void).init(arena);
891 for (self.base.options.rpath_list) |rpath| {
892 if (rpath_table.contains(rpath)) continue;
893 try rpath_table.putNoClobber(rpath, {});
894 }
895
896 var rpaths = std.ArrayList([]const u8).init(arena);
897 try rpaths.ensureCapacity(rpath_table.count());
898 for (rpath_table.keys()) |*key| {
899 rpaths.appendAssumeCapacity(key.*);
900 }
901
902 if (self.base.options.verbose_link) {
903 var argv = std.ArrayList([]const u8).init(arena);
904
905 try argv.append("zig");
906 try argv.append("ld");
907
908 if (self.base.options.sysroot) |syslibroot| {
909 try argv.append("-syslibroot");
910 try argv.append(syslibroot);
911 }
912
913 for (rpaths.items) |rpath| {
914 try argv.append("-rpath");
915 try argv.append(rpath);
916 }
917
918 try argv.appendSlice(positionals.items);
919
920 try argv.append("-o");
921 try argv.append(full_out_path);
922
923 if (native_libsystem_available) {
924 try argv.append("-lSystem");
925 try argv.append("-lc");
926 }
927
928 for (search_lib_names.items) |l_name| {
929 try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{l_name}));
930 }
931
932 for (self.base.options.lib_dirs) |lib_dir| {
933 try argv.append(try std.fmt.allocPrint(arena, "-L{s}", .{lib_dir}));
934 }
935
936 Compilation.dump_argv(argv.items);
937 }
938
939 try zld.link(positionals.items, full_out_path, .{
940 .syslibroot = self.base.options.sysroot,
941 .libs = libs.items,
942 .rpaths = rpaths.items,
828 }
829 if (!native_libsystem_available) {
830 const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
831 "libc", "darwin", "libSystem.B.tbd",
943832 });
944
945 break :outer;
833 try libs.append(full_path);
946834 }
947835
948 // Create an LLD command line and invoke it.
949 var argv = std.ArrayList([]const u8).init(self.base.allocator);
950 defer argv.deinit();
951
952 // TODO https://github.com/ziglang/zig/issues/6971
953 // Note that there is no need to check if running natively since we do that already
954 // when setting `system_linker_hack` in Compilation struct.
955 if (self.base.options.system_linker_hack) {
956 try argv.append("ld");
957 } else {
958 // We will invoke ourselves as a child process to gain access to LLD.
959 // This is necessary because LLD does not behave properly as a library -
960 // it calls exit() and does not reset all global data between invocations.
961 try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, "ld64.lld" });
962
963 try argv.append("-error-limit");
964 try argv.append("0");
836 // frameworks
837 var framework_dirs = std.ArrayList([]const u8).init(arena);
838 for (self.base.options.framework_dirs) |dir| {
839 if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| {
840 try framework_dirs.append(search_dir);
841 } else {
842 log.warn("directory not found for '-F{s}'", .{dir});
843 }
965844 }
966845
967 if (self.base.options.lto) {
968 switch (self.base.options.optimize_mode) {
969 .Debug => {},
970 .ReleaseSmall => try argv.append("-O2"),
971 .ReleaseFast, .ReleaseSafe => try argv.append("-O3"),
846 var framework_not_found = false;
847 for (self.base.options.frameworks) |framework| {
848 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
849 if (try resolveFramework(arena, framework_dirs.items, framework, ext)) |full_path| {
850 try libs.append(full_path);
851 break;
852 }
853 } else {
854 log.warn("framework not found for '-f{s}'", .{framework});
855 framework_not_found = true;
972856 }
973857 }
974 try argv.append("-demangle");
975858
976 if (self.base.options.rdynamic and !self.base.options.system_linker_hack) {
977 try argv.append("--export-dynamic");
859 if (framework_not_found) {
860 log.warn("Framework search paths:", .{});
861 for (framework_dirs.items) |dir| {
862 log.warn(" {s}", .{dir});
863 }
978864 }
979865
980 try argv.appendSlice(self.base.options.extra_lld_args);
981
982 if (self.base.options.z_nodelete) {
983 try argv.append("-z");
984 try argv.append("nodelete");
985 }
986 if (self.base.options.z_defs) {
987 try argv.append("-z");
988 try argv.append("defs");
866 // rpaths
867 var rpath_table = std.StringArrayHashMap(void).init(arena);
868 for (self.base.options.rpath_list) |rpath| {
869 if (rpath_table.contains(rpath)) continue;
870 try rpath_table.putNoClobber(rpath, {});
989871 }
990872
991 if (is_exe_or_dyn_lib) {
992 try argv.append("-dynamic");
873 var rpaths = std.ArrayList([]const u8).init(arena);
874 try rpaths.ensureCapacity(rpath_table.count());
875 for (rpath_table.keys()) |*key| {
876 rpaths.appendAssumeCapacity(key.*);
993877 }
994878
995 if (is_dyn_lib) {
996 try argv.append("-dylib");
879 if (self.base.options.verbose_link) {
880 var argv = std.ArrayList([]const u8).init(arena);
997881
998 if (self.base.options.version) |ver| {
999 const compat_vers = try std.fmt.allocPrint(arena, "{d}.0.0", .{ver.major});
1000 try argv.append("-compatibility_version");
1001 try argv.append(compat_vers);
882 try argv.append("zig");
883 try argv.append("ld");
1002884
1003 const cur_vers = try std.fmt.allocPrint(arena, "{d}.{d}.{d}", .{ ver.major, ver.minor, ver.patch });
1004 try argv.append("-current_version");
1005 try argv.append(cur_vers);
885 if (self.base.options.sysroot) |syslibroot| {
886 try argv.append("-syslibroot");
887 try argv.append(syslibroot);
1006888 }
1007889
1008 const dylib_install_name = try std.fmt.allocPrint(arena, "@rpath/{s}", .{self.base.options.emit.?.sub_path});
1009 try argv.append("-install_name");
1010 try argv.append(dylib_install_name);
1011 }
1012
1013 try argv.append("-arch");
1014 try argv.append(darwinArchString(target.cpu.arch));
1015
1016 switch (target.os.tag) {
1017 .macos => {
1018 try argv.append("-macosx_version_min");
1019 },
1020 .ios, .tvos, .watchos => switch (target.cpu.arch) {
1021 .i386, .x86_64 => {
1022 try argv.append("-ios_simulator_version_min");
1023 },
1024 else => {
1025 try argv.append("-iphoneos_version_min");
1026 },
1027 },
1028 else => unreachable,
1029 }
1030 const ver = target.os.version_range.semver.min;
1031 const version_string = try std.fmt.allocPrint(arena, "{d}.{d}.{d}", .{ ver.major, ver.minor, ver.patch });
1032 try argv.append(version_string);
1033
1034 try argv.append("-sdk_version");
1035 try argv.append(version_string);
1036
1037 if (target_util.requiresPIE(target) and self.base.options.output_mode == .Exe) {
1038 try argv.append("-pie");
1039 }
1040
1041 try argv.append("-o");
1042 try argv.append(full_out_path);
1043
1044 // rpaths
1045 var rpath_table = std.StringHashMap(void).init(self.base.allocator);
1046 defer rpath_table.deinit();
1047 for (self.base.options.rpath_list) |rpath| {
1048 if ((try rpath_table.fetchPut(rpath, {})) == null) {
890 for (rpaths.items) |rpath| {
1049891 try argv.append("-rpath");
1050892 try argv.append(rpath);
1051893 }
1052 }
1053 if (is_dyn_lib) {
1054 if ((try rpath_table.fetchPut(full_out_path, {})) == null) {
1055 try argv.append("-rpath");
1056 try argv.append(full_out_path);
1057 }
1058 }
1059
1060 if (self.base.options.sysroot) |dir| {
1061 try argv.append("-syslibroot");
1062 try argv.append(dir);
1063 }
1064
1065 for (self.base.options.lib_dirs) |lib_dir| {
1066 try argv.append("-L");
1067 try argv.append(lib_dir);
1068 }
1069
1070 // Positional arguments to the linker such as object files.
1071 try argv.appendSlice(self.base.options.objects);
1072
1073 for (comp.c_object_table.keys()) |key| {
1074 try argv.append(key.status.success.object_path);
1075 }
1076 if (module_obj_path) |p| {
1077 try argv.append(p);
1078 }
1079
1080 // compiler_rt on darwin is missing some stuff, so we still build it and rely on LinkOnce
1081 if (is_exe_or_dyn_lib and !self.base.options.skip_linker_dependencies) {
1082 try argv.append(comp.compiler_rt_static_lib.?.full_object_path);
1083 }
1084894
1085 // Shared libraries.
1086 const system_libs = self.base.options.system_libs.keys();
1087 try argv.ensureCapacity(argv.items.len + system_libs.len);
1088 for (system_libs) |link_lib| {
1089 // By this time, we depend on these libs being dynamically linked libraries and not static libraries
1090 // (the check for that needs to be earlier), but they could be full paths to .dylib files, in which
1091 // case we want to avoid prepending "-l".
1092 const ext = Compilation.classifyFileExt(link_lib);
1093 const arg = if (ext == .shared_library) link_lib else try std.fmt.allocPrint(arena, "-l{s}", .{link_lib});
1094 argv.appendAssumeCapacity(arg);
1095 }
895 try argv.appendSlice(positionals.items);
1096896
1097 // libc++ dep
1098 if (self.base.options.link_libcpp) {
1099 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
1100 try argv.append(comp.libcxx_static_lib.?.full_object_path);
1101 }
897 try argv.append("-o");
898 try argv.append(full_out_path);
1102899
1103 // On Darwin, libSystem has libc in it, but also you have to use it
1104 // to make syscalls because the syscall numbers are not documented
1105 // and change between versions. So we always link against libSystem.
1106 // LLD craps out if you do -lSystem cross compiling, so until that
1107 // codebase gets some love from the new maintainers we're left with
1108 // this dirty hack.
1109 if (self.base.options.is_native_os) {
1110 try argv.append("-lSystem");
1111 }
1112
1113 for (self.base.options.framework_dirs) |framework_dir| {
1114 try argv.append("-F");
1115 try argv.append(framework_dir);
1116 }
1117 for (self.base.options.frameworks) |framework| {
1118 try argv.append("-framework");
1119 try argv.append(framework);
1120 }
1121
1122 if (allow_shlib_undefined) {
1123 try argv.append("-undefined");
1124 try argv.append("dynamic_lookup");
1125 }
1126 if (self.base.options.bind_global_refs_locally) {
1127 try argv.append("-Bsymbolic");
1128 }
1129
1130 if (self.base.options.verbose_link) {
1131 // Potentially skip over our own name so that the LLD linker name is the first argv item.
1132 const adjusted_argv = if (self.base.options.system_linker_hack) argv.items else argv.items[1..];
1133 Compilation.dump_argv(adjusted_argv);
1134 }
1135
1136 // TODO https://github.com/ziglang/zig/issues/6971
1137 // Note that there is no need to check if running natively since we do that already
1138 // when setting `system_linker_hack` in Compilation struct.
1139 if (self.base.options.system_linker_hack) {
1140 const result = try std.ChildProcess.exec(.{ .allocator = self.base.allocator, .argv = argv.items });
1141 defer {
1142 self.base.allocator.free(result.stdout);
1143 self.base.allocator.free(result.stderr);
1144 }
1145 if (result.stdout.len != 0) {
1146 log.warn("unexpected LD stdout: {s}", .{result.stdout});
900 if (native_libsystem_available) {
901 try argv.append("-lSystem");
902 try argv.append("-lc");
1147903 }
1148 if (result.stderr.len != 0) {
1149 log.warn("unexpected LD stderr: {s}", .{result.stderr});
1150 }
1151 if (result.term != .Exited or result.term.Exited != 0) {
1152 // TODO parse this output and surface with the Compilation API rather than
1153 // directly outputting to stderr here.
1154 log.err("{s}", .{result.stderr});
1155 return error.LDReportedFailure;
1156 }
1157 } else {
1158 // Sadly, we must run LLD as a child process because it does not behave
1159 // properly as a library.
1160 const child = try std.ChildProcess.init(argv.items, arena);
1161 defer child.deinit();
1162
1163 if (comp.clang_passthrough_mode) {
1164 child.stdin_behavior = .Inherit;
1165 child.stdout_behavior = .Inherit;
1166 child.stderr_behavior = .Inherit;
1167
1168 const term = child.spawnAndWait() catch |err| {
1169 log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
1170 return error.UnableToSpawnSelf;
1171 };
1172 switch (term) {
1173 .Exited => |code| {
1174 if (code != 0) {
1175 // TODO https://github.com/ziglang/zig/issues/6342
1176 std.process.exit(1);
1177 }
1178 },
1179 else => {
1180 log.err("{s} terminated", .{argv.items[0]});
1181 return error.LLDCrashed;
1182 },
1183 }
1184 } else {
1185 child.stdin_behavior = .Ignore;
1186 child.stdout_behavior = .Ignore;
1187 child.stderr_behavior = .Pipe;
1188
1189 try child.spawn();
1190
1191 const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024);
1192904
1193 const term = child.wait() catch |err| {
1194 log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
1195 return error.UnableToSpawnSelf;
1196 };
1197
1198 switch (term) {
1199 .Exited => |code| {
1200 if (code != 0) {
1201 // TODO parse this output and surface with the Compilation API rather than
1202 // directly outputting to stderr here.
1203 std.debug.print("{s}", .{stderr});
1204 return error.LLDReportedFailure;
1205 }
1206 },
1207 else => {
1208 log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr });
1209 return error.LLDCrashed;
1210 },
1211 }
905 for (search_lib_names.items) |l_name| {
906 try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{l_name}));
907 }
1212908
1213 if (stderr.len != 0) {
1214 log.warn("unexpected LLD stderr:\n{s}", .{stderr});
1215 }
909 for (self.base.options.lib_dirs) |lib_dir| {
910 try argv.append(try std.fmt.allocPrint(arena, "-L{s}", .{lib_dir}));
1216911 }
912
913 Compilation.dump_argv(argv.items);
1217914 }
915
916 try zld.link(positionals.items, full_out_path, .{
917 .syslibroot = self.base.options.sysroot,
918 .libs = libs.items,
919 .rpaths = rpaths.items,
920 });
1218921 }
1219922
1220923 if (!self.base.options.disable_lld_caching) {