authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-10 00:41:58-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-10 14:21:52-07:00
log14c8e270bb47c4e10ee3392661d4c62ab5c2f89d
treec74fe79e74d3fc6bff7dd61f372153906e29e040
parent58349b2c8ebc57718bbfbf939c30b586d5c85466

link: fix false positive crtbegin/crtend detection

Embrace the Path abstraction, doing more operations based on directory handles rather than absolute file paths. Most of the diff noise here comes from this one. Fix sorting of crtbegin/crtend atoms. Previously it would look at all path components for those strings. Make the C runtime path detection partially a pure function, and move some logic to glibc.zig where it belongs.

29 files changed, 937 insertions(+), 679 deletions(-)

lib/std/Build/Cache.zig+7
...@@ -398,12 +398,19 @@ pub const Manifest = struct {...@@ -398,12 +398,19 @@ pub const Manifest = struct {
398 return gop.index;398 return gop.index;
399 }399 }
400400
401 /// Deprecated, use `addOptionalFilePath`.
401 pub fn addOptionalFile(self: *Manifest, optional_file_path: ?[]const u8) !void {402 pub fn addOptionalFile(self: *Manifest, optional_file_path: ?[]const u8) !void {
402 self.hash.add(optional_file_path != null);403 self.hash.add(optional_file_path != null);
403 const file_path = optional_file_path orelse return;404 const file_path = optional_file_path orelse return;
404 _ = try self.addFile(file_path, null);405 _ = try self.addFile(file_path, null);
405 }406 }
406407
408 pub fn addOptionalFilePath(self: *Manifest, optional_file_path: ?Path) !void {
409 self.hash.add(optional_file_path != null);
410 const file_path = optional_file_path orelse return;
411 _ = try self.addFilePath(file_path, null);
412 }
413
407 pub fn addListOfFiles(self: *Manifest, list_of_files: []const []const u8) !void {414 pub fn addListOfFiles(self: *Manifest, list_of_files: []const []const u8) !void {
408 self.hash.add(list_of_files.len);415 self.hash.add(list_of_files.len);
409 for (list_of_files) |file_path| {416 for (list_of_files) |file_path| {
lib/std/Build/Cache/Path.zig+21-1
...@@ -11,7 +11,11 @@ pub fn clone(p: Path, arena: Allocator) Allocator.Error!Path {...@@ -11,7 +11,11 @@ pub fn clone(p: Path, arena: Allocator) Allocator.Error!Path {
11}11}
1212
13pub fn cwd() Path {13pub fn cwd() Path {
14 return .{ .root_dir = Cache.Directory.cwd() };14 return initCwd("");
15}
16
17pub fn initCwd(sub_path: []const u8) Path {
18 return .{ .root_dir = Cache.Directory.cwd(), .sub_path = sub_path };
15}19}
1620
17pub fn join(p: Path, arena: Allocator, sub_path: []const u8) Allocator.Error!Path {21pub fn join(p: Path, arena: Allocator, sub_path: []const u8) Allocator.Error!Path {
...@@ -126,6 +130,14 @@ pub fn makePath(p: Path, sub_path: []const u8) !void {...@@ -126,6 +130,14 @@ pub fn makePath(p: Path, sub_path: []const u8) !void {
126 return p.root_dir.handle.makePath(joined_path);130 return p.root_dir.handle.makePath(joined_path);
127}131}
128132
133pub fn toString(p: Path, allocator: Allocator) Allocator.Error![]u8 {
134 return std.fmt.allocPrint(allocator, "{}", .{p});
135}
136
137pub fn toStringZ(p: Path, allocator: Allocator) Allocator.Error![:0]u8 {
138 return std.fmt.allocPrintZ(allocator, "{}", .{p});
139}
140
129pub fn format(141pub fn format(
130 self: Path,142 self: Path,
131 comptime fmt_string: []const u8,143 comptime fmt_string: []const u8,
...@@ -182,6 +194,14 @@ pub fn subPathOrDot(self: Path) []const u8 {...@@ -182,6 +194,14 @@ pub fn subPathOrDot(self: Path) []const u8 {
182 return if (self.sub_path.len == 0) "." else self.sub_path;194 return if (self.sub_path.len == 0) "." else self.sub_path;
183}195}
184196
197pub fn stem(p: Path) []const u8 {
198 return fs.path.stem(p.sub_path);
199}
200
201pub fn basename(p: Path) []const u8 {
202 return fs.path.basename(p.sub_path);
203}
204
185/// Useful to make `Path` a key in `std.ArrayHashMap`.205/// Useful to make `Path` a key in `std.ArrayHashMap`.
186pub const TableAdapter = struct {206pub const TableAdapter = struct {
187 pub const Hash = std.hash.Wyhash;207 pub const Hash = std.hash.Wyhash;
lib/std/zig/LibCInstallation.zig+328
...@@ -690,12 +690,340 @@ fn appendCcExe(args: *std.ArrayList([]const u8), skip_cc_env_var: bool) !void {...@@ -690,12 +690,340 @@ fn appendCcExe(args: *std.ArrayList([]const u8), skip_cc_env_var: bool) !void {
690 }690 }
691}691}
692692
693/// These are basenames. This data is produced with a pure function. See also
694/// `CsuPaths`.
695pub const CrtBasenames = struct {
696 crt0: ?[]const u8 = null,
697 crti: ?[]const u8 = null,
698 crtbegin: ?[]const u8 = null,
699 crtend: ?[]const u8 = null,
700 crtn: ?[]const u8 = null,
701
702 pub const GetArgs = struct {
703 target: std.Target,
704 link_libc: bool,
705 output_mode: std.builtin.OutputMode,
706 link_mode: std.builtin.LinkMode,
707 pie: bool,
708 };
709
710 /// Determine file system path names of C runtime startup objects for supported
711 /// link modes.
712 pub fn get(args: GetArgs) CrtBasenames {
713 // crt objects are only required for libc.
714 if (!args.link_libc) return .{};
715
716 // Flatten crt cases.
717 const mode: enum {
718 dynamic_lib,
719 dynamic_exe,
720 dynamic_pie,
721 static_exe,
722 static_pie,
723 } = switch (args.output_mode) {
724 .Obj => return .{},
725 .Lib => switch (args.link_mode) {
726 .dynamic => .dynamic_lib,
727 .static => return .{},
728 },
729 .Exe => switch (args.link_mode) {
730 .dynamic => if (args.pie) .dynamic_pie else .dynamic_exe,
731 .static => if (args.pie) .static_pie else .static_exe,
732 },
733 };
734
735 const target = args.target;
736
737 if (target.isAndroid()) return switch (mode) {
738 .dynamic_lib => .{
739 .crtbegin = "crtbegin_so.o",
740 .crtend = "crtend_so.o",
741 },
742 .dynamic_exe, .dynamic_pie => .{
743 .crtbegin = "crtbegin_dynamic.o",
744 .crtend = "crtend_android.o",
745 },
746 .static_exe, .static_pie => .{
747 .crtbegin = "crtbegin_static.o",
748 .crtend = "crtend_android.o",
749 },
750 };
751
752 return switch (target.os.tag) {
753 .linux => switch (mode) {
754 .dynamic_lib => .{
755 .crti = "crti.o",
756 .crtn = "crtn.o",
757 },
758 .dynamic_exe => .{
759 .crt0 = "crt1.o",
760 .crti = "crti.o",
761 .crtn = "crtn.o",
762 },
763 .dynamic_pie => .{
764 .crt0 = "Scrt1.o",
765 .crti = "crti.o",
766 .crtn = "crtn.o",
767 },
768 .static_exe => .{
769 .crt0 = "crt1.o",
770 .crti = "crti.o",
771 .crtn = "crtn.o",
772 },
773 .static_pie => .{
774 .crt0 = "rcrt1.o",
775 .crti = "crti.o",
776 .crtn = "crtn.o",
777 },
778 },
779 .dragonfly => switch (mode) {
780 .dynamic_lib => .{
781 .crti = "crti.o",
782 .crtbegin = "crtbeginS.o",
783 .crtend = "crtendS.o",
784 .crtn = "crtn.o",
785 },
786 .dynamic_exe => .{
787 .crt0 = "crt1.o",
788 .crti = "crti.o",
789 .crtbegin = "crtbegin.o",
790 .crtend = "crtend.o",
791 .crtn = "crtn.o",
792 },
793 .dynamic_pie => .{
794 .crt0 = "Scrt1.o",
795 .crti = "crti.o",
796 .crtbegin = "crtbeginS.o",
797 .crtend = "crtendS.o",
798 .crtn = "crtn.o",
799 },
800 .static_exe => .{
801 .crt0 = "crt1.o",
802 .crti = "crti.o",
803 .crtbegin = "crtbegin.o",
804 .crtend = "crtend.o",
805 .crtn = "crtn.o",
806 },
807 .static_pie => .{
808 .crt0 = "Scrt1.o",
809 .crti = "crti.o",
810 .crtbegin = "crtbeginS.o",
811 .crtend = "crtendS.o",
812 .crtn = "crtn.o",
813 },
814 },
815 .freebsd => switch (mode) {
816 .dynamic_lib => .{
817 .crti = "crti.o",
818 .crtbegin = "crtbeginS.o",
819 .crtend = "crtendS.o",
820 .crtn = "crtn.o",
821 },
822 .dynamic_exe => .{
823 .crt0 = "crt1.o",
824 .crti = "crti.o",
825 .crtbegin = "crtbegin.o",
826 .crtend = "crtend.o",
827 .crtn = "crtn.o",
828 },
829 .dynamic_pie => .{
830 .crt0 = "Scrt1.o",
831 .crti = "crti.o",
832 .crtbegin = "crtbeginS.o",
833 .crtend = "crtendS.o",
834 .crtn = "crtn.o",
835 },
836 .static_exe => .{
837 .crt0 = "crt1.o",
838 .crti = "crti.o",
839 .crtbegin = "crtbeginT.o",
840 .crtend = "crtend.o",
841 .crtn = "crtn.o",
842 },
843 .static_pie => .{
844 .crt0 = "Scrt1.o",
845 .crti = "crti.o",
846 .crtbegin = "crtbeginS.o",
847 .crtend = "crtendS.o",
848 .crtn = "crtn.o",
849 },
850 },
851 .netbsd => switch (mode) {
852 .dynamic_lib => .{
853 .crti = "crti.o",
854 .crtbegin = "crtbeginS.o",
855 .crtend = "crtendS.o",
856 .crtn = "crtn.o",
857 },
858 .dynamic_exe => .{
859 .crt0 = "crt0.o",
860 .crti = "crti.o",
861 .crtbegin = "crtbegin.o",
862 .crtend = "crtend.o",
863 .crtn = "crtn.o",
864 },
865 .dynamic_pie => .{
866 .crt0 = "crt0.o",
867 .crti = "crti.o",
868 .crtbegin = "crtbeginS.o",
869 .crtend = "crtendS.o",
870 .crtn = "crtn.o",
871 },
872 .static_exe => .{
873 .crt0 = "crt0.o",
874 .crti = "crti.o",
875 .crtbegin = "crtbeginT.o",
876 .crtend = "crtend.o",
877 .crtn = "crtn.o",
878 },
879 .static_pie => .{
880 .crt0 = "crt0.o",
881 .crti = "crti.o",
882 .crtbegin = "crtbeginT.o",
883 .crtend = "crtendS.o",
884 .crtn = "crtn.o",
885 },
886 },
887 .openbsd => switch (mode) {
888 .dynamic_lib => .{
889 .crtbegin = "crtbeginS.o",
890 .crtend = "crtendS.o",
891 },
892 .dynamic_exe, .dynamic_pie => .{
893 .crt0 = "crt0.o",
894 .crtbegin = "crtbegin.o",
895 .crtend = "crtend.o",
896 },
897 .static_exe, .static_pie => .{
898 .crt0 = "rcrt0.o",
899 .crtbegin = "crtbegin.o",
900 .crtend = "crtend.o",
901 },
902 },
903 .haiku => switch (mode) {
904 .dynamic_lib => .{
905 .crti = "crti.o",
906 .crtbegin = "crtbeginS.o",
907 .crtend = "crtendS.o",
908 .crtn = "crtn.o",
909 },
910 .dynamic_exe => .{
911 .crt0 = "start_dyn.o",
912 .crti = "crti.o",
913 .crtbegin = "crtbegin.o",
914 .crtend = "crtend.o",
915 .crtn = "crtn.o",
916 },
917 .dynamic_pie => .{
918 .crt0 = "start_dyn.o",
919 .crti = "crti.o",
920 .crtbegin = "crtbeginS.o",
921 .crtend = "crtendS.o",
922 .crtn = "crtn.o",
923 },
924 .static_exe => .{
925 .crt0 = "start_dyn.o",
926 .crti = "crti.o",
927 .crtbegin = "crtbegin.o",
928 .crtend = "crtend.o",
929 .crtn = "crtn.o",
930 },
931 .static_pie => .{
932 .crt0 = "start_dyn.o",
933 .crti = "crti.o",
934 .crtbegin = "crtbeginS.o",
935 .crtend = "crtendS.o",
936 .crtn = "crtn.o",
937 },
938 },
939 .solaris, .illumos => switch (mode) {
940 .dynamic_lib => .{
941 .crti = "crti.o",
942 .crtn = "crtn.o",
943 },
944 .dynamic_exe, .dynamic_pie => .{
945 .crt0 = "crt1.o",
946 .crti = "crti.o",
947 .crtn = "crtn.o",
948 },
949 .static_exe, .static_pie => .{},
950 },
951 else => .{},
952 };
953 }
954};
955
956pub const CrtPaths = struct {
957 crt0: ?Path = null,
958 crti: ?Path = null,
959 crtbegin: ?Path = null,
960 crtend: ?Path = null,
961 crtn: ?Path = null,
962};
963
964pub fn resolveCrtPaths(
965 lci: LibCInstallation,
966 arena: Allocator,
967 crt_basenames: CrtBasenames,
968 target: std.Target,
969) error{ OutOfMemory, LibCInstallationMissingCrtDir }!CrtPaths {
970 const crt_dir_path: Path = .{
971 .root_dir = std.Build.Cache.Directory.cwd(),
972 .sub_path = lci.crt_dir orelse return error.LibCInstallationMissingCrtDir,
973 };
974 switch (target.os.tag) {
975 .dragonfly => {
976 const gccv: []const u8 = if (target.os.version_range.semver.isAtLeast(.{
977 .major = 5,
978 .minor = 4,
979 .patch = 0,
980 }) orelse true) "gcc80" else "gcc54";
981 return .{
982 .crt0 = if (crt_basenames.crt0) |basename| try crt_dir_path.join(arena, basename) else null,
983 .crti = if (crt_basenames.crti) |basename| try crt_dir_path.join(arena, basename) else null,
984 .crtbegin = if (crt_basenames.crtbegin) |basename| .{
985 .root_dir = crt_dir_path.root_dir,
986 .sub_path = try fs.path.join(arena, &.{ crt_dir_path.sub_path, gccv, basename }),
987 } else null,
988 .crtend = if (crt_basenames.crtend) |basename| .{
989 .root_dir = crt_dir_path.root_dir,
990 .sub_path = try fs.path.join(arena, &.{ crt_dir_path.sub_path, gccv, basename }),
991 } else null,
992 .crtn = if (crt_basenames.crtn) |basename| try crt_dir_path.join(arena, basename) else null,
993 };
994 },
995 .haiku => {
996 const gcc_dir_path: Path = .{
997 .root_dir = std.Build.Cache.Directory.cwd(),
998 .sub_path = lci.gcc_dir orelse return error.LibCInstallationMissingCrtDir,
999 };
1000 return .{
1001 .crt0 = if (crt_basenames.crt0) |basename| try crt_dir_path.join(arena, basename) else null,
1002 .crti = if (crt_basenames.crti) |basename| try crt_dir_path.join(arena, basename) else null,
1003 .crtbegin = if (crt_basenames.crtbegin) |basename| try gcc_dir_path.join(arena, basename) else null,
1004 .crtend = if (crt_basenames.crtend) |basename| try gcc_dir_path.join(arena, basename) else null,
1005 .crtn = if (crt_basenames.crtn) |basename| try crt_dir_path.join(arena, basename) else null,
1006 };
1007 },
1008 else => {
1009 return .{
1010 .crt0 = if (crt_basenames.crt0) |basename| try crt_dir_path.join(arena, basename) else null,
1011 .crti = if (crt_basenames.crti) |basename| try crt_dir_path.join(arena, basename) else null,
1012 .crtbegin = if (crt_basenames.crtbegin) |basename| try crt_dir_path.join(arena, basename) else null,
1013 .crtend = if (crt_basenames.crtend) |basename| try crt_dir_path.join(arena, basename) else null,
1014 .crtn = if (crt_basenames.crtn) |basename| try crt_dir_path.join(arena, basename) else null,
1015 };
1016 },
1017 }
1018}
1019
693const LibCInstallation = @This();1020const LibCInstallation = @This();
694const std = @import("std");1021const std = @import("std");
695const builtin = @import("builtin");1022const builtin = @import("builtin");
696const Target = std.Target;1023const Target = std.Target;
697const fs = std.fs;1024const fs = std.fs;
698const Allocator = std.mem.Allocator;1025const Allocator = std.mem.Allocator;
1026const Path = std.Build.Cache.Path;
6991027
700const is_darwin = builtin.target.isDarwin();1028const is_darwin = builtin.target.isDarwin();
701const is_windows = builtin.target.os.tag == .windows;1029const is_windows = builtin.target.os.tag == .windows;
src/Compilation.zig+93-62
...@@ -217,37 +217,37 @@ thread_pool: *ThreadPool,...@@ -217,37 +217,37 @@ thread_pool: *ThreadPool,
217217
218/// Populated when we build the libc++ static library. A Job to build this is placed in the queue218/// Populated when we build the libc++ static library. A Job to build this is placed in the queue
219/// and resolved before calling linker.flush().219/// and resolved before calling linker.flush().
220libcxx_static_lib: ?CRTFile = null,220libcxx_static_lib: ?CrtFile = null,
221/// Populated when we build the libc++abi static library. A Job to build this is placed in the queue221/// Populated when we build the libc++abi static library. A Job to build this is placed in the queue
222/// and resolved before calling linker.flush().222/// and resolved before calling linker.flush().
223libcxxabi_static_lib: ?CRTFile = null,223libcxxabi_static_lib: ?CrtFile = null,
224/// Populated when we build the libunwind static library. A Job to build this is placed in the queue224/// Populated when we build the libunwind static library. A Job to build this is placed in the queue
225/// and resolved before calling linker.flush().225/// and resolved before calling linker.flush().
226libunwind_static_lib: ?CRTFile = null,226libunwind_static_lib: ?CrtFile = null,
227/// Populated when we build the TSAN library. A Job to build this is placed in the queue227/// Populated when we build the TSAN library. A Job to build this is placed in the queue
228/// and resolved before calling linker.flush().228/// and resolved before calling linker.flush().
229tsan_lib: ?CRTFile = null,229tsan_lib: ?CrtFile = null,
230/// Populated when we build the libc static library. A Job to build this is placed in the queue230/// Populated when we build the libc static library. A Job to build this is placed in the queue
231/// and resolved before calling linker.flush().231/// and resolved before calling linker.flush().
232libc_static_lib: ?CRTFile = null,232libc_static_lib: ?CrtFile = null,
233/// Populated when we build the libcompiler_rt static library. A Job to build this is indicated233/// Populated when we build the libcompiler_rt static library. A Job to build this is indicated
234/// by setting `job_queued_compiler_rt_lib` and resolved before calling linker.flush().234/// by setting `job_queued_compiler_rt_lib` and resolved before calling linker.flush().
235compiler_rt_lib: ?CRTFile = null,235compiler_rt_lib: ?CrtFile = null,
236/// Populated when we build the compiler_rt_obj object. A Job to build this is indicated236/// Populated when we build the compiler_rt_obj object. A Job to build this is indicated
237/// by setting `job_queued_compiler_rt_obj` and resolved before calling linker.flush().237/// by setting `job_queued_compiler_rt_obj` and resolved before calling linker.flush().
238compiler_rt_obj: ?CRTFile = null,238compiler_rt_obj: ?CrtFile = null,
239/// Populated when we build the libfuzzer static library. A Job to build this239/// Populated when we build the libfuzzer static library. A Job to build this
240/// is indicated by setting `job_queued_fuzzer_lib` and resolved before240/// is indicated by setting `job_queued_fuzzer_lib` and resolved before
241/// calling linker.flush().241/// calling linker.flush().
242fuzzer_lib: ?CRTFile = null,242fuzzer_lib: ?CrtFile = null,
243243
244glibc_so_files: ?glibc.BuiltSharedObjects = null,244glibc_so_files: ?glibc.BuiltSharedObjects = null,
245wasi_emulated_libs: []const wasi_libc.CRTFile,245wasi_emulated_libs: []const wasi_libc.CrtFile,
246246
247/// For example `Scrt1.o` and `libc_nonshared.a`. These are populated after building libc from source,247/// For example `Scrt1.o` and `libc_nonshared.a`. These are populated after building libc from source,
248/// The set of needed CRT (C runtime) files differs depending on the target and compilation settings.248/// The set of needed CRT (C runtime) files differs depending on the target and compilation settings.
249/// The key is the basename, and the value is the absolute path to the completed build artifact.249/// The key is the basename, and the value is the absolute path to the completed build artifact.
250crt_files: std.StringHashMapUnmanaged(CRTFile) = .empty,250crt_files: std.StringHashMapUnmanaged(CrtFile) = .empty,
251251
252/// How many lines of reference trace should be included per compile error.252/// How many lines of reference trace should be included per compile error.
253/// Null means only show snippet on first error.253/// Null means only show snippet on first error.
...@@ -276,20 +276,20 @@ digest: ?[Cache.bin_digest_len]u8 = null,...@@ -276,20 +276,20 @@ digest: ?[Cache.bin_digest_len]u8 = null,
276pub const default_stack_protector_buffer_size = target_util.default_stack_protector_buffer_size;276pub const default_stack_protector_buffer_size = target_util.default_stack_protector_buffer_size;
277pub const SemaError = Zcu.SemaError;277pub const SemaError = Zcu.SemaError;
278278
279pub const CRTFile = struct {279pub const CrtFile = struct {
280 lock: Cache.Lock,280 lock: Cache.Lock,
281 full_object_path: []const u8,281 full_object_path: Path,
282282
283 pub fn isObject(cf: CRTFile) bool {283 pub fn isObject(cf: CrtFile) bool {
284 return switch (classifyFileExt(cf.full_object_path)) {284 return switch (classifyFileExt(cf.full_object_path.sub_path)) {
285 .object => true,285 .object => true,
286 else => false,286 else => false,
287 };287 };
288 }288 }
289289
290 pub fn deinit(self: *CRTFile, gpa: Allocator) void {290 pub fn deinit(self: *CrtFile, gpa: Allocator) void {
291 self.lock.release();291 self.lock.release();
292 gpa.free(self.full_object_path);292 gpa.free(self.full_object_path.sub_path);
293 self.* = undefined;293 self.* = undefined;
294 }294 }
295};295};
...@@ -369,13 +369,13 @@ const Job = union(enum) {...@@ -369,13 +369,13 @@ const Job = union(enum) {
369 resolve_type_fully: InternPool.Index,369 resolve_type_fully: InternPool.Index,
370370
371 /// one of the glibc static objects371 /// one of the glibc static objects
372 glibc_crt_file: glibc.CRTFile,372 glibc_crt_file: glibc.CrtFile,
373 /// all of the glibc shared objects373 /// all of the glibc shared objects
374 glibc_shared_objects,374 glibc_shared_objects,
375 /// one of the musl static objects375 /// one of the musl static objects
376 musl_crt_file: musl.CRTFile,376 musl_crt_file: musl.CrtFile,
377 /// one of the mingw-w64 static objects377 /// one of the mingw-w64 static objects
378 mingw_crt_file: mingw.CRTFile,378 mingw_crt_file: mingw.CrtFile,
379 /// libunwind.a, usually needed when linking libc379 /// libunwind.a, usually needed when linking libc
380 libunwind: void,380 libunwind: void,
381 libcxx: void,381 libcxx: void,
...@@ -385,7 +385,7 @@ const Job = union(enum) {...@@ -385,7 +385,7 @@ const Job = union(enum) {
385 /// calls to, for example, memcpy and memset.385 /// calls to, for example, memcpy and memset.
386 zig_libc: void,386 zig_libc: void,
387 /// one of WASI libc static objects387 /// one of WASI libc static objects
388 wasi_libc_crt_file: wasi_libc.CRTFile,388 wasi_libc_crt_file: wasi_libc.CrtFile,
389389
390 /// The value is the index into `system_libs`.390 /// The value is the index into `system_libs`.
391 windows_import_lib: usize,391 windows_import_lib: usize,
...@@ -422,8 +422,8 @@ pub const CObject = struct {...@@ -422,8 +422,8 @@ pub const CObject = struct {
422 status: union(enum) {422 status: union(enum) {
423 new,423 new,
424 success: struct {424 success: struct {
425 /// The outputted result. Owned by gpa.425 /// The outputted result. `sub_path` owned by gpa.
426 object_path: []u8,426 object_path: Path,
427 /// This is a file system lock on the cache hash manifest representing this427 /// This is a file system lock on the cache hash manifest representing this
428 /// object. It prevents other invocations of the Zig compiler from interfering428 /// object. It prevents other invocations of the Zig compiler from interfering
429 /// with this object until released.429 /// with this object until released.
...@@ -719,7 +719,7 @@ pub const CObject = struct {...@@ -719,7 +719,7 @@ pub const CObject = struct {
719 return true;719 return true;
720 },720 },
721 .success => |*success| {721 .success => |*success| {
722 gpa.free(success.object_path);722 gpa.free(success.object_path.sub_path);
723 success.lock.release();723 success.lock.release();
724 self.status = .new;724 self.status = .new;
725 return false;725 return false;
...@@ -1018,7 +1018,7 @@ const CacheUse = union(CacheMode) {...@@ -1018,7 +1018,7 @@ const CacheUse = union(CacheMode) {
1018};1018};
10191019
1020pub const LinkObject = struct {1020pub const LinkObject = struct {
1021 path: []const u8,1021 path: Path,
1022 must_link: bool = false,1022 must_link: bool = false,
1023 // When the library is passed via a positional argument, it will be1023 // When the library is passed via a positional argument, it will be
1024 // added as a full path. If it's `-l<lib>`, then just the basename.1024 // added as a full path. If it's `-l<lib>`, then just the basename.
...@@ -1027,7 +1027,7 @@ pub const LinkObject = struct {...@@ -1027,7 +1027,7 @@ pub const LinkObject = struct {
1027 loption: bool = false,1027 loption: bool = false,
10281028
1029 pub fn isObject(lo: LinkObject) bool {1029 pub fn isObject(lo: LinkObject) bool {
1030 return switch (classifyFileExt(lo.path)) {1030 return switch (classifyFileExt(lo.path.sub_path)) {
1031 .object => true,1031 .object => true,
1032 else => false,1032 else => false,
1033 };1033 };
...@@ -1095,7 +1095,7 @@ pub const CreateOptions = struct {...@@ -1095,7 +1095,7 @@ pub const CreateOptions = struct {
1095 /// * getpid1095 /// * getpid
1096 /// * mman1096 /// * mman
1097 /// * signal1097 /// * signal
1098 wasi_emulated_libs: []const wasi_libc.CRTFile = &.{},1098 wasi_emulated_libs: []const wasi_libc.CrtFile = &.{},
1099 /// This means that if the output mode is an executable it will be a1099 /// This means that if the output mode is an executable it will be a
1100 /// Position Independent Executable. If the output mode is not an1100 /// Position Independent Executable. If the output mode is not an
1101 /// executable this field is ignored.1101 /// executable this field is ignored.
...@@ -2578,7 +2578,7 @@ fn addNonIncrementalStuffToCacheManifest(...@@ -2578,7 +2578,7 @@ fn addNonIncrementalStuffToCacheManifest(
2578 }2578 }
25792579
2580 for (comp.objects) |obj| {2580 for (comp.objects) |obj| {
2581 _ = try man.addFile(obj.path, null);2581 _ = try man.addFilePath(obj.path, null);
2582 man.hash.add(obj.must_link);2582 man.hash.add(obj.must_link);
2583 man.hash.add(obj.loption);2583 man.hash.add(obj.loption);
2584 }2584 }
...@@ -2703,9 +2703,8 @@ fn emitOthers(comp: *Compilation) void {...@@ -2703,9 +2703,8 @@ fn emitOthers(comp: *Compilation) void {
2703 return;2703 return;
2704 }2704 }
2705 const obj_path = comp.c_object_table.keys()[0].status.success.object_path;2705 const obj_path = comp.c_object_table.keys()[0].status.success.object_path;
2706 const cwd = std.fs.cwd();2706 const ext = std.fs.path.extension(obj_path.sub_path);
2707 const ext = std.fs.path.extension(obj_path);2707 const dirname = obj_path.sub_path[0 .. obj_path.sub_path.len - ext.len];
2708 const basename = obj_path[0 .. obj_path.len - ext.len];
2709 // This obj path always ends with the object file extension, but if we change the2708 // This obj path always ends with the object file extension, but if we change the
2710 // extension to .ll, .bc, or .s, then it will be the path to those things.2709 // extension to .ll, .bc, or .s, then it will be the path to those things.
2711 const outs = [_]struct {2710 const outs = [_]struct {
...@@ -2720,13 +2719,13 @@ fn emitOthers(comp: *Compilation) void {...@@ -2720,13 +2719,13 @@ fn emitOthers(comp: *Compilation) void {
2720 if (out.emit) |loc| {2719 if (out.emit) |loc| {
2721 if (loc.directory) |directory| {2720 if (loc.directory) |directory| {
2722 const src_path = std.fmt.allocPrint(comp.gpa, "{s}{s}", .{2721 const src_path = std.fmt.allocPrint(comp.gpa, "{s}{s}", .{
2723 basename, out.ext,2722 dirname, out.ext,
2724 }) catch |err| {2723 }) catch |err| {
2725 log.err("unable to copy {s}{s}: {s}", .{ basename, out.ext, @errorName(err) });2724 log.err("unable to copy {s}{s}: {s}", .{ dirname, out.ext, @errorName(err) });
2726 continue;2725 continue;
2727 };2726 };
2728 defer comp.gpa.free(src_path);2727 defer comp.gpa.free(src_path);
2729 cwd.copyFile(src_path, directory.handle, loc.basename, .{}) catch |err| {2728 obj_path.root_dir.handle.copyFile(src_path, directory.handle, loc.basename, .{}) catch |err| {
2730 log.err("unable to copy {s}: {s}", .{ src_path, @errorName(err) });2729 log.err("unable to copy {s}: {s}", .{ src_path, @errorName(err) });
2731 };2730 };
2732 }2731 }
...@@ -3774,7 +3773,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre...@@ -3774,7 +3773,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
3774 const named_frame = tracy.namedFrame("glibc_crt_file");3773 const named_frame = tracy.namedFrame("glibc_crt_file");
3775 defer named_frame.end();3774 defer named_frame.end();
37763775
3777 glibc.buildCRTFile(comp, crt_file, prog_node) catch |err| {3776 glibc.buildCrtFile(comp, crt_file, prog_node) catch |err| {
3778 // TODO Surface more error details.3777 // TODO Surface more error details.
3779 comp.lockAndSetMiscFailure(.glibc_crt_file, "unable to build glibc CRT file: {s}", .{3778 comp.lockAndSetMiscFailure(.glibc_crt_file, "unable to build glibc CRT file: {s}", .{
3780 @errorName(err),3779 @errorName(err),
...@@ -3798,7 +3797,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre...@@ -3798,7 +3797,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
3798 const named_frame = tracy.namedFrame("musl_crt_file");3797 const named_frame = tracy.namedFrame("musl_crt_file");
3799 defer named_frame.end();3798 defer named_frame.end();
38003799
3801 musl.buildCRTFile(comp, crt_file, prog_node) catch |err| {3800 musl.buildCrtFile(comp, crt_file, prog_node) catch |err| {
3802 // TODO Surface more error details.3801 // TODO Surface more error details.
3803 comp.lockAndSetMiscFailure(3802 comp.lockAndSetMiscFailure(
3804 .musl_crt_file,3803 .musl_crt_file,
...@@ -3811,7 +3810,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre...@@ -3811,7 +3810,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
3811 const named_frame = tracy.namedFrame("mingw_crt_file");3810 const named_frame = tracy.namedFrame("mingw_crt_file");
3812 defer named_frame.end();3811 defer named_frame.end();
38133812
3814 mingw.buildCRTFile(comp, crt_file, prog_node) catch |err| {3813 mingw.buildCrtFile(comp, crt_file, prog_node) catch |err| {
3815 // TODO Surface more error details.3814 // TODO Surface more error details.
3816 comp.lockAndSetMiscFailure(3815 comp.lockAndSetMiscFailure(
3817 .mingw_crt_file,3816 .mingw_crt_file,
...@@ -3894,7 +3893,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre...@@ -3894,7 +3893,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
3894 const named_frame = tracy.namedFrame("wasi_libc_crt_file");3893 const named_frame = tracy.namedFrame("wasi_libc_crt_file");
3895 defer named_frame.end();3894 defer named_frame.end();
38963895
3897 wasi_libc.buildCRTFile(comp, crt_file, prog_node) catch |err| {3896 wasi_libc.buildCrtFile(comp, crt_file, prog_node) catch |err| {
3898 // TODO Surface more error details.3897 // TODO Surface more error details.
3899 comp.lockAndSetMiscFailure(3898 comp.lockAndSetMiscFailure(
3900 .wasi_libc_crt_file,3899 .wasi_libc_crt_file,
...@@ -4602,7 +4601,7 @@ fn buildRt(...@@ -4602,7 +4601,7 @@ fn buildRt(
4602 root_source_name: []const u8,4601 root_source_name: []const u8,
4603 misc_task: MiscTask,4602 misc_task: MiscTask,
4604 output_mode: std.builtin.OutputMode,4603 output_mode: std.builtin.OutputMode,
4605 out: *?CRTFile,4604 out: *?CrtFile,
4606 prog_node: std.Progress.Node,4605 prog_node: std.Progress.Node,
4607) void {4606) void {
4608 comp.buildOutputFromZig(4607 comp.buildOutputFromZig(
...@@ -4703,7 +4702,9 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr...@@ -4703,7 +4702,9 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
47034702
4704 log.debug("updating C object: {s}", .{c_object.src.src_path});4703 log.debug("updating C object: {s}", .{c_object.src.src_path});
47054704
4706 if (c_object.clearStatus(comp.gpa)) {4705 const gpa = comp.gpa;
4706
4707 if (c_object.clearStatus(gpa)) {
4707 // There was previous failure.4708 // There was previous failure.
4708 comp.mutex.lock();4709 comp.mutex.lock();
4709 defer comp.mutex.unlock();4710 defer comp.mutex.unlock();
...@@ -4722,7 +4723,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr...@@ -4722,7 +4723,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
47224723
4723 try cache_helpers.hashCSource(&man, c_object.src);4724 try cache_helpers.hashCSource(&man, c_object.src);
47244725
4725 var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);4726 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
4726 defer arena_allocator.deinit();4727 defer arena_allocator.deinit();
4727 const arena = arena_allocator.allocator();4728 const arena = arena_allocator.allocator();
47284729
...@@ -4744,7 +4745,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr...@@ -4744,7 +4745,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
4744 const target = comp.getTarget();4745 const target = comp.getTarget();
4745 const o_ext = target.ofmt.fileExt(target.cpu.arch);4746 const o_ext = target.ofmt.fileExt(target.cpu.arch);
4746 const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: {4747 const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: {
4747 var argv = std.ArrayList([]const u8).init(comp.gpa);4748 var argv = std.ArrayList([]const u8).init(gpa);
4748 defer argv.deinit();4749 defer argv.deinit();
47494750
4750 // In case we are doing passthrough mode, we need to detect -S and -emit-llvm.4751 // In case we are doing passthrough mode, we need to detect -S and -emit-llvm.
...@@ -4908,7 +4909,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr...@@ -4908,7 +4909,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
49084909
4909 switch (term) {4910 switch (term) {
4910 .Exited => |code| if (code != 0) if (out_diag_path) |diag_file_path| {4911 .Exited => |code| if (code != 0) if (out_diag_path) |diag_file_path| {
4911 const bundle = CObject.Diag.Bundle.parse(comp.gpa, diag_file_path) catch |err| {4912 const bundle = CObject.Diag.Bundle.parse(gpa, diag_file_path) catch |err| {
4912 log.err("{}: failed to parse clang diagnostics: {s}", .{ err, stderr });4913 log.err("{}: failed to parse clang diagnostics: {s}", .{ err, stderr });
4913 return comp.failCObj(c_object, "clang exited with code {d}", .{code});4914 return comp.failCObj(c_object, "clang exited with code {d}", .{code});
4914 };4915 };
...@@ -4982,9 +4983,10 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr...@@ -4982,9 +4983,10 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
49824983
4983 c_object.status = .{4984 c_object.status = .{
4984 .success = .{4985 .success = .{
4985 .object_path = try comp.local_cache_directory.join(comp.gpa, &[_][]const u8{4986 .object_path = .{
4986 "o", &digest, o_basename,4987 .root_dir = comp.local_cache_directory,
4987 }),4988 .sub_path = try std.fs.path.join(gpa, &.{ "o", &digest, o_basename }),
4989 },
4988 .lock = man.toOwnedLock(),4990 .lock = man.toOwnedLock(),
4989 },4991 },
4990 };4992 };
...@@ -6092,18 +6094,23 @@ test "classifyFileExt" {...@@ -6092,18 +6094,23 @@ test "classifyFileExt" {
6092 try std.testing.expectEqual(FileExt.zig, classifyFileExt("foo.zig"));6094 try std.testing.expectEqual(FileExt.zig, classifyFileExt("foo.zig"));
6093}6095}
60946096
6095pub fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const u8) ![]const u8 {6097pub fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const u8) !Path {
6096 if (comp.wantBuildGLibCFromSource() or6098 return (try crtFilePath(comp, basename)) orelse {
6097 comp.wantBuildMuslFromSource() or6099 const lci = comp.libc_installation orelse return error.LibCInstallationNotAvailable;
6098 comp.wantBuildMinGWFromSource() or6100 const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCrtDir;
6099 comp.wantBuildWasiLibcFromSource())6101 const full_path = try std.fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename });
6100 {6102 return Path.initCwd(full_path);
6101 return comp.crt_files.get(basename).?.full_object_path;6103 };
6102 }6104}
6103 const lci = comp.libc_installation orelse return error.LibCInstallationNotAvailable;6105
6104 const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCRTDir;6106pub fn crtFileAsString(comp: *Compilation, arena: Allocator, basename: []const u8) ![]const u8 {
6105 const full_path = try std.fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename });6107 const path = try get_libc_crt_file(comp, arena, basename);
6106 return full_path;6108 return path.toString(arena);
6109}
6110
6111pub fn crtFilePath(comp: *Compilation, basename: []const u8) Allocator.Error!?Path {
6112 const crt_file = comp.crt_files.get(basename) orelse return null;
6113 return crt_file.full_object_path;
6107}6114}
61086115
6109fn wantBuildLibCFromSource(comp: Compilation) bool {6116fn wantBuildLibCFromSource(comp: Compilation) bool {
...@@ -6314,7 +6321,7 @@ fn buildOutputFromZig(...@@ -6314,7 +6321,7 @@ fn buildOutputFromZig(
6314 comp: *Compilation,6321 comp: *Compilation,
6315 src_basename: []const u8,6322 src_basename: []const u8,
6316 output_mode: std.builtin.OutputMode,6323 output_mode: std.builtin.OutputMode,
6317 out: *?CRTFile,6324 out: *?CrtFile,
6318 misc_task_tag: MiscTask,6325 misc_task_tag: MiscTask,
6319 prog_node: std.Progress.Node,6326 prog_node: std.Progress.Node,
6320) !void {6327) !void {
...@@ -6542,15 +6549,39 @@ pub fn build_crt_file(...@@ -6542,15 +6549,39 @@ pub fn build_crt_file(
6542 comp.crt_files.putAssumeCapacityNoClobber(basename, try sub_compilation.toCrtFile());6549 comp.crt_files.putAssumeCapacityNoClobber(basename, try sub_compilation.toCrtFile());
6543}6550}
65446551
6545pub fn toCrtFile(comp: *Compilation) Allocator.Error!CRTFile {6552pub fn toCrtFile(comp: *Compilation) Allocator.Error!CrtFile {
6546 return .{6553 return .{
6547 .full_object_path = try comp.local_cache_directory.join(comp.gpa, &.{6554 .full_object_path = .{
6548 comp.cache_use.whole.bin_sub_path.?,6555 .root_dir = comp.local_cache_directory,
6549 }),6556 .sub_path = try comp.gpa.dupe(u8, comp.cache_use.whole.bin_sub_path.?),
6557 },
6550 .lock = comp.cache_use.whole.moveLock(),6558 .lock = comp.cache_use.whole.moveLock(),
6551 };6559 };
6552}6560}
65536561
6562pub fn getCrtPaths(
6563 comp: *Compilation,
6564 arena: Allocator,
6565) error{ OutOfMemory, LibCInstallationMissingCrtDir }!LibCInstallation.CrtPaths {
6566 const target = comp.root_mod.resolved_target.result;
6567 const basenames = LibCInstallation.CrtBasenames.get(.{
6568 .target = target,
6569 .link_libc = comp.config.link_libc,
6570 .output_mode = comp.config.output_mode,
6571 .link_mode = comp.config.link_mode,
6572 .pie = comp.config.pie,
6573 });
6574 if (comp.libc_installation) |lci| return lci.resolveCrtPaths(arena, basenames, target);
6575
6576 return .{
6577 .crt0 = if (basenames.crt0) |basename| try comp.crtFilePath(basename) else null,
6578 .crti = if (basenames.crti) |basename| try comp.crtFilePath(basename) else null,
6579 .crtbegin = if (basenames.crtbegin) |basename| try comp.crtFilePath(basename) else null,
6580 .crtend = if (basenames.crtend) |basename| try comp.crtFilePath(basename) else null,
6581 .crtn = if (basenames.crtn) |basename| try comp.crtFilePath(basename) else null,
6582 };
6583}
6584
6554pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void {6585pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void {
6555 // Avoid deadlocking on building import libs such as kernel32.lib6586 // Avoid deadlocking on building import libs such as kernel32.lib
6556 // This can happen when the user uses `build-exe foo.obj -lkernel32` and6587 // This can happen when the user uses `build-exe foo.obj -lkernel32` and
src/glibc.zig+4-3
...@@ -169,14 +169,14 @@ fn useElfInitFini(target: std.Target) bool {...@@ -169,14 +169,14 @@ fn useElfInitFini(target: std.Target) bool {
169 };169 };
170}170}
171171
172pub const CRTFile = enum {172pub const CrtFile = enum {
173 crti_o,173 crti_o,
174 crtn_o,174 crtn_o,
175 scrt1_o,175 scrt1_o,
176 libc_nonshared_a,176 libc_nonshared_a,
177};177};
178178
179pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: std.Progress.Node) !void {179pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progress.Node) !void {
180 if (!build_options.have_llvm) {180 if (!build_options.have_llvm) {
181 return error.ZigCompilerNotBuiltWithLLVMExtensions;181 return error.ZigCompilerNotBuiltWithLLVMExtensions;
182 }182 }
...@@ -292,7 +292,8 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: std.Progre...@@ -292,7 +292,8 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: std.Progre
292 .owner = undefined,292 .owner = undefined,
293 };293 };
294 var files = [_]Compilation.CSourceFile{ start_o, abi_note_o, init_o };294 var files = [_]Compilation.CSourceFile{ start_o, abi_note_o, init_o };
295 return comp.build_crt_file("Scrt1", .Obj, .@"glibc Scrt1.o", prog_node, &files);295 const basename = if (comp.config.output_mode == .Exe and !comp.config.pie) "crt1" else "Scrt1";
296 return comp.build_crt_file(basename, .Obj, .@"glibc Scrt1.o", prog_node, &files);
296 },297 },
297 .libc_nonshared_a => {298 .libc_nonshared_a => {
298 const s = path.sep_str;299 const s = path.sep_str;
src/link.zig+12-15
...@@ -11,7 +11,7 @@ const wasi_libc = @import("wasi_libc.zig");...@@ -11,7 +11,7 @@ const wasi_libc = @import("wasi_libc.zig");
11const Air = @import("Air.zig");11const Air = @import("Air.zig");
12const Allocator = std.mem.Allocator;12const Allocator = std.mem.Allocator;
13const Cache = std.Build.Cache;13const Cache = std.Build.Cache;
14const Path = Cache.Path;14const Path = std.Build.Cache.Path;
15const Compilation = @import("Compilation.zig");15const Compilation = @import("Compilation.zig");
16const LibCInstallation = std.zig.LibCInstallation;16const LibCInstallation = std.zig.LibCInstallation;
17const Liveness = @import("Liveness.zig");17const Liveness = @import("Liveness.zig");
...@@ -34,7 +34,7 @@ pub const SystemLib = struct {...@@ -34,7 +34,7 @@ pub const SystemLib = struct {
34 /// 1. Windows DLLs that zig ships such as advapi32.34 /// 1. Windows DLLs that zig ships such as advapi32.
35 /// 2. extern "foo" fn declarations where we find out about libraries too late35 /// 2. extern "foo" fn declarations where we find out about libraries too late
36 /// TODO: make this non-optional and resolve those two cases somehow.36 /// TODO: make this non-optional and resolve those two cases somehow.
37 path: ?[]const u8,37 path: ?Path,
38};38};
3939
40pub fn hashAddSystemLibs(40pub fn hashAddSystemLibs(
...@@ -46,7 +46,7 @@ pub fn hashAddSystemLibs(...@@ -46,7 +46,7 @@ pub fn hashAddSystemLibs(
46 for (hm.values()) |value| {46 for (hm.values()) |value| {
47 man.hash.add(value.needed);47 man.hash.add(value.needed);
48 man.hash.add(value.weak);48 man.hash.add(value.weak);
49 if (value.path) |p| _ = try man.addFile(p, null);49 if (value.path) |p| _ = try man.addFilePath(p, null);
50 }50 }
51}51}
5252
...@@ -551,7 +551,7 @@ pub const File = struct {...@@ -551,7 +551,7 @@ pub const File = struct {
551 LLDCrashed,551 LLDCrashed,
552 LLDReportedFailure,552 LLDReportedFailure,
553 LLD_LinkingIsTODO_ForSpirV,553 LLD_LinkingIsTODO_ForSpirV,
554 LibCInstallationMissingCRTDir,554 LibCInstallationMissingCrtDir,
555 LibCInstallationNotAvailable,555 LibCInstallationNotAvailable,
556 LinkingWithoutZigSourceUnimplemented,556 LinkingWithoutZigSourceUnimplemented,
557 MalformedArchive,557 MalformedArchive,
...@@ -606,18 +606,15 @@ pub const File = struct {...@@ -606,18 +606,15 @@ pub const File = struct {
606 const comp = base.comp;606 const comp = base.comp;
607 if (comp.clang_preprocessor_mode == .yes or comp.clang_preprocessor_mode == .pch) {607 if (comp.clang_preprocessor_mode == .yes or comp.clang_preprocessor_mode == .pch) {
608 dev.check(.clang_command);608 dev.check(.clang_command);
609 const gpa = comp.gpa;
610 const emit = base.emit;609 const emit = base.emit;
611 // TODO: avoid extra link step when it's just 1 object file (the `zig cc -c` case)610 // TODO: avoid extra link step when it's just 1 object file (the `zig cc -c` case)
612 // Until then, we do `lld -r -o output.o input.o` even though the output is the same611 // Until then, we do `lld -r -o output.o input.o` even though the output is the same
613 // as the input. For the preprocessing case (`zig cc -E -o foo`) we copy the file612 // as the input. For the preprocessing case (`zig cc -E -o foo`) we copy the file
614 // to the final location. See also the corresponding TODO in Coff linking.613 // to the final location. See also the corresponding TODO in Coff linking.
615 const full_out_path = try emit.root_dir.join(gpa, &[_][]const u8{emit.sub_path});
616 defer gpa.free(full_out_path);
617 assert(comp.c_object_table.count() == 1);614 assert(comp.c_object_table.count() == 1);
618 const the_key = comp.c_object_table.keys()[0];615 const the_key = comp.c_object_table.keys()[0];
619 const cached_pp_file_path = the_key.status.success.object_path;616 const cached_pp_file_path = the_key.status.success.object_path;
620 try fs.cwd().copyFile(cached_pp_file_path, fs.cwd(), full_out_path, .{});617 try cached_pp_file_path.root_dir.handle.copyFile(cached_pp_file_path.sub_path, emit.root_dir.handle, emit.sub_path, .{});
621 return;618 return;
622 }619 }
623620
...@@ -781,7 +778,7 @@ pub const File = struct {...@@ -781,7 +778,7 @@ pub const File = struct {
781778
782 log.debug("zcu_obj_path={s}", .{if (zcu_obj_path) |s| s else "(null)"});779 log.debug("zcu_obj_path={s}", .{if (zcu_obj_path) |s| s else "(null)"});
783780
784 const compiler_rt_path: ?[]const u8 = if (comp.include_compiler_rt)781 const compiler_rt_path: ?Path = if (comp.include_compiler_rt)
785 comp.compiler_rt_obj.?.full_object_path782 comp.compiler_rt_obj.?.full_object_path
786 else783 else
787 null;784 null;
...@@ -806,18 +803,18 @@ pub const File = struct {...@@ -806,18 +803,18 @@ pub const File = struct {
806 base.releaseLock();803 base.releaseLock();
807804
808 for (objects) |obj| {805 for (objects) |obj| {
809 _ = try man.addFile(obj.path, null);806 _ = try man.addFilePath(obj.path, null);
810 man.hash.add(obj.must_link);807 man.hash.add(obj.must_link);
811 man.hash.add(obj.loption);808 man.hash.add(obj.loption);
812 }809 }
813 for (comp.c_object_table.keys()) |key| {810 for (comp.c_object_table.keys()) |key| {
814 _ = try man.addFile(key.status.success.object_path, null);811 _ = try man.addFilePath(key.status.success.object_path, null);
815 }812 }
816 for (comp.win32_resource_table.keys()) |key| {813 for (comp.win32_resource_table.keys()) |key| {
817 _ = try man.addFile(key.status.success.res_path, null);814 _ = try man.addFile(key.status.success.res_path, null);
818 }815 }
819 try man.addOptionalFile(zcu_obj_path);816 try man.addOptionalFile(zcu_obj_path);
820 try man.addOptionalFile(compiler_rt_path);817 try man.addOptionalFilePath(compiler_rt_path);
821818
822 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.819 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
823 _ = try man.hit();820 _ = try man.hit();
...@@ -851,10 +848,10 @@ pub const File = struct {...@@ -851,10 +848,10 @@ pub const File = struct {
851 defer object_files.deinit();848 defer object_files.deinit();
852849
853 for (objects) |obj| {850 for (objects) |obj| {
854 object_files.appendAssumeCapacity(try arena.dupeZ(u8, obj.path));851 object_files.appendAssumeCapacity(try obj.path.toStringZ(arena));
855 }852 }
856 for (comp.c_object_table.keys()) |key| {853 for (comp.c_object_table.keys()) |key| {
857 object_files.appendAssumeCapacity(try arena.dupeZ(u8, key.status.success.object_path));854 object_files.appendAssumeCapacity(try key.status.success.object_path.toStringZ(arena));
858 }855 }
859 for (comp.win32_resource_table.keys()) |key| {856 for (comp.win32_resource_table.keys()) |key| {
860 object_files.appendAssumeCapacity(try arena.dupeZ(u8, key.status.success.res_path));857 object_files.appendAssumeCapacity(try arena.dupeZ(u8, key.status.success.res_path));
...@@ -863,7 +860,7 @@ pub const File = struct {...@@ -863,7 +860,7 @@ pub const File = struct {
863 object_files.appendAssumeCapacity(try arena.dupeZ(u8, p));860 object_files.appendAssumeCapacity(try arena.dupeZ(u8, p));
864 }861 }
865 if (compiler_rt_path) |p| {862 if (compiler_rt_path) |p| {
866 object_files.appendAssumeCapacity(try arena.dupeZ(u8, p));863 object_files.appendAssumeCapacity(try p.toStringZ(arena));
867 }864 }
868865
869 if (comp.verbose_link) {866 if (comp.verbose_link) {
src/link/Coff/lld.zig+25-22
...@@ -7,6 +7,7 @@ const fs = std.fs;...@@ -7,6 +7,7 @@ const fs = std.fs;
7const log = std.log.scoped(.link);7const log = std.log.scoped(.link);
8const mem = std.mem;8const mem = std.mem;
9const Cache = std.Build.Cache;9const Cache = std.Build.Cache;
10const Path = std.Build.Cache.Path;
1011
11const mingw = @import("../../mingw.zig");12const mingw = @import("../../mingw.zig");
12const link = @import("../../link.zig");13const link = @import("../../link.zig");
...@@ -74,11 +75,11 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -74,11 +75,11 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
74 comptime assert(Compilation.link_hash_implementation_version == 14);75 comptime assert(Compilation.link_hash_implementation_version == 14);
7576
76 for (comp.objects) |obj| {77 for (comp.objects) |obj| {
77 _ = try man.addFile(obj.path, null);78 _ = try man.addFilePath(obj.path, null);
78 man.hash.add(obj.must_link);79 man.hash.add(obj.must_link);
79 }80 }
80 for (comp.c_object_table.keys()) |key| {81 for (comp.c_object_table.keys()) |key| {
81 _ = try man.addFile(key.status.success.object_path, null);82 _ = try man.addFilePath(key.status.success.object_path, null);
82 }83 }
83 for (comp.win32_resource_table.keys()) |key| {84 for (comp.win32_resource_table.keys()) |key| {
84 _ = try man.addFile(key.status.success.res_path, null);85 _ = try man.addFile(key.status.success.res_path, null);
...@@ -154,17 +155,19 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -154,17 +155,19 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
154 break :blk comp.c_object_table.keys()[0].status.success.object_path;155 break :blk comp.c_object_table.keys()[0].status.success.object_path;
155156
156 if (module_obj_path) |p|157 if (module_obj_path) |p|
157 break :blk p;158 break :blk Path.initCwd(p);
158159
159 // TODO I think this is unreachable. Audit this situation when solving the above TODO160 // TODO I think this is unreachable. Audit this situation when solving the above TODO
160 // regarding eliding redundant object -> object transformations.161 // regarding eliding redundant object -> object transformations.
161 return error.NoObjectsToLink;162 return error.NoObjectsToLink;
162 };163 };
163 // This can happen when using --enable-cache and using the stage1 backend. In this case164 try std.fs.Dir.copyFile(
164 // we can skip the file copy.165 the_object_path.root_dir.handle,
165 if (!mem.eql(u8, the_object_path, full_out_path)) {166 the_object_path.sub_path,
166 try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});167 directory.handle,
167 }168 self.base.emit.sub_path,
169 .{},
170 );
168 } else {171 } else {
169 // Create an LLD command line and invoke it.172 // Create an LLD command line and invoke it.
170 var argv = std.ArrayList([]const u8).init(gpa);173 var argv = std.ArrayList([]const u8).init(gpa);
...@@ -270,14 +273,14 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -270,14 +273,14 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
270 try argv.ensureUnusedCapacity(comp.objects.len);273 try argv.ensureUnusedCapacity(comp.objects.len);
271 for (comp.objects) |obj| {274 for (comp.objects) |obj| {
272 if (obj.must_link) {275 if (obj.must_link) {
273 argv.appendAssumeCapacity(try allocPrint(arena, "-WHOLEARCHIVE:{s}", .{obj.path}));276 argv.appendAssumeCapacity(try allocPrint(arena, "-WHOLEARCHIVE:{}", .{@as(Path, obj.path)}));
274 } else {277 } else {
275 argv.appendAssumeCapacity(obj.path);278 argv.appendAssumeCapacity(try obj.path.toString(arena));
276 }279 }
277 }280 }
278281
279 for (comp.c_object_table.keys()) |key| {282 for (comp.c_object_table.keys()) |key| {
280 try argv.append(key.status.success.object_path);283 try argv.append(try key.status.success.object_path.toString(arena));
281 }284 }
282285
283 for (comp.win32_resource_table.keys()) |key| {286 for (comp.win32_resource_table.keys()) |key| {
...@@ -401,17 +404,17 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -401,17 +404,17 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
401 }404 }
402405
403 if (is_dyn_lib) {406 if (is_dyn_lib) {
404 try argv.append(try comp.get_libc_crt_file(arena, "dllcrt2.obj"));407 try argv.append(try comp.crtFileAsString(arena, "dllcrt2.obj"));
405 if (target.cpu.arch == .x86) {408 if (target.cpu.arch == .x86) {
406 try argv.append("-ALTERNATENAME:__DllMainCRTStartup@12=_DllMainCRTStartup@12");409 try argv.append("-ALTERNATENAME:__DllMainCRTStartup@12=_DllMainCRTStartup@12");
407 } else {410 } else {
408 try argv.append("-ALTERNATENAME:_DllMainCRTStartup=DllMainCRTStartup");411 try argv.append("-ALTERNATENAME:_DllMainCRTStartup=DllMainCRTStartup");
409 }412 }
410 } else {413 } else {
411 try argv.append(try comp.get_libc_crt_file(arena, "crt2.obj"));414 try argv.append(try comp.crtFileAsString(arena, "crt2.obj"));
412 }415 }
413416
414 try argv.append(try comp.get_libc_crt_file(arena, "mingw32.lib"));417 try argv.append(try comp.crtFileAsString(arena, "mingw32.lib"));
415 } else {418 } else {
416 const lib_str = switch (comp.config.link_mode) {419 const lib_str = switch (comp.config.link_mode) {
417 .dynamic => "",420 .dynamic => "",
...@@ -456,36 +459,36 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -456,36 +459,36 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
456459
457 // libc++ dep460 // libc++ dep
458 if (comp.config.link_libcpp) {461 if (comp.config.link_libcpp) {
459 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);462 try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena));
460 try argv.append(comp.libcxx_static_lib.?.full_object_path);463 try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena));
461 }464 }
462465
463 // libunwind dep466 // libunwind dep
464 if (comp.config.link_libunwind) {467 if (comp.config.link_libunwind) {
465 try argv.append(comp.libunwind_static_lib.?.full_object_path);468 try argv.append(try comp.libunwind_static_lib.?.full_object_path.toString(arena));
466 }469 }
467470
468 if (comp.config.any_fuzz) {471 if (comp.config.any_fuzz) {
469 try argv.append(comp.fuzzer_lib.?.full_object_path);472 try argv.append(try comp.fuzzer_lib.?.full_object_path.toString(arena));
470 }473 }
471474
472 if (is_exe_or_dyn_lib and !comp.skip_linker_dependencies) {475 if (is_exe_or_dyn_lib and !comp.skip_linker_dependencies) {
473 if (!comp.config.link_libc) {476 if (!comp.config.link_libc) {
474 if (comp.libc_static_lib) |lib| {477 if (comp.libc_static_lib) |lib| {
475 try argv.append(lib.full_object_path);478 try argv.append(try lib.full_object_path.toString(arena));
476 }479 }
477 }480 }
478 // MSVC compiler_rt is missing some stuff, so we build it unconditionally but481 // MSVC compiler_rt is missing some stuff, so we build it unconditionally but
479 // and rely on weak linkage to allow MSVC compiler_rt functions to override ours.482 // and rely on weak linkage to allow MSVC compiler_rt functions to override ours.
480 if (comp.compiler_rt_obj) |obj| try argv.append(obj.full_object_path);483 if (comp.compiler_rt_obj) |obj| try argv.append(try obj.full_object_path.toString(arena));
481 if (comp.compiler_rt_lib) |lib| try argv.append(lib.full_object_path);484 if (comp.compiler_rt_lib) |lib| try argv.append(try lib.full_object_path.toString(arena));
482 }485 }
483486
484 try argv.ensureUnusedCapacity(comp.system_libs.count());487 try argv.ensureUnusedCapacity(comp.system_libs.count());
485 for (comp.system_libs.keys()) |key| {488 for (comp.system_libs.keys()) |key| {
486 const lib_basename = try allocPrint(arena, "{s}.lib", .{key});489 const lib_basename = try allocPrint(arena, "{s}.lib", .{key});
487 if (comp.crt_files.get(lib_basename)) |crt_file| {490 if (comp.crt_files.get(lib_basename)) |crt_file| {
488 argv.appendAssumeCapacity(crt_file.full_object_path);491 argv.appendAssumeCapacity(try crt_file.full_object_path.toString(arena));
489 continue;492 continue;
490 }493 }
491 if (try findLib(arena, lib_basename, self.lib_dirs)) |full_path| {494 if (try findLib(arena, lib_basename, self.lib_dirs)) |full_path| {
src/link/Elf.zig+118-325
...@@ -383,9 +383,9 @@ pub fn createEmpty(...@@ -383,9 +383,9 @@ pub fn createEmpty(
383 const index: File.Index = @intCast(try self.files.addOne(gpa));383 const index: File.Index = @intCast(try self.files.addOne(gpa));
384 self.files.set(index, .{ .zig_object = .{384 self.files.set(index, .{ .zig_object = .{
385 .index = index,385 .index = index,
386 .path = try std.fmt.allocPrint(arena, "{s}.o", .{fs.path.stem(386 .basename = try std.fmt.allocPrint(arena, "{s}.o", .{
387 zcu.main_mod.root_src_path,387 fs.path.stem(zcu.main_mod.root_src_path),
388 )}),388 }),
389 } });389 } });
390 self.zig_object_index = index;390 self.zig_object_index = index;
391 try self.zigObjectPtr().?.init(self, .{391 try self.zigObjectPtr().?.init(self, .{
...@@ -742,13 +742,12 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -742,13 +742,12 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
742 const target = self.getTarget();742 const target = self.getTarget();
743 const link_mode = comp.config.link_mode;743 const link_mode = comp.config.link_mode;
744 const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.744 const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
745 const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {745 const module_obj_path: ?Path = if (self.base.zcu_object_sub_path) |path| .{
746 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});746 .root_dir = directory,
747 if (fs.path.dirname(full_out_path)) |dirname| {747 .sub_path = if (fs.path.dirname(self.base.emit.sub_path)) |dirname|
748 break :blk try fs.path.join(arena, &.{ dirname, path });748 try fs.path.join(arena, &.{ dirname, path })
749 } else {749 else
750 break :blk path;750 path,
751 }
752 } else null;751 } else null;
753752
754 // --verbose-link753 // --verbose-link
...@@ -758,7 +757,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -758,7 +757,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
758 if (self.base.isStaticLib()) return relocatable.flushStaticLib(self, comp, module_obj_path);757 if (self.base.isStaticLib()) return relocatable.flushStaticLib(self, comp, module_obj_path);
759 if (self.base.isObject()) return relocatable.flushObject(self, comp, module_obj_path);758 if (self.base.isObject()) return relocatable.flushObject(self, comp, module_obj_path);
760759
761 const csu = try CsuObjects.init(arena, comp);760 const csu = try comp.getCrtPaths(arena);
762761
763 // csu prelude762 // csu prelude
764 if (csu.crt0) |path| try parseObjectReportingFailure(self, path);763 if (csu.crt0) |path| try parseObjectReportingFailure(self, path);
...@@ -790,23 +789,22 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -790,23 +789,22 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
790 if (comp.libc_static_lib) |lib| try parseCrtFileReportingFailure(self, lib);789 if (comp.libc_static_lib) |lib| try parseCrtFileReportingFailure(self, lib);
791 }790 }
792791
793 var system_libs = std.ArrayList(SystemLib).init(arena);
794
795 try system_libs.ensureUnusedCapacity(comp.system_libs.values().len);
796 for (comp.system_libs.values()) |lib_info| {792 for (comp.system_libs.values()) |lib_info| {
797 system_libs.appendAssumeCapacity(.{ .needed = lib_info.needed, .path = lib_info.path.? });793 try self.parseLibraryReportingFailure(.{
794 .needed = lib_info.needed,
795 .path = lib_info.path.?,
796 }, false);
798 }797 }
799798
800 // libc++ dep799 // libc++ dep
801 if (comp.config.link_libcpp) {800 if (comp.config.link_libcpp) {
802 try system_libs.ensureUnusedCapacity(2);801 try self.parseLibraryReportingFailure(.{ .path = comp.libcxxabi_static_lib.?.full_object_path }, false);
803 system_libs.appendAssumeCapacity(.{ .path = comp.libcxxabi_static_lib.?.full_object_path });802 try self.parseLibraryReportingFailure(.{ .path = comp.libcxx_static_lib.?.full_object_path }, false);
804 system_libs.appendAssumeCapacity(.{ .path = comp.libcxx_static_lib.?.full_object_path });
805 }803 }
806804
807 // libunwind dep805 // libunwind dep
808 if (comp.config.link_libunwind) {806 if (comp.config.link_libunwind) {
809 try system_libs.append(.{ .path = comp.libunwind_static_lib.?.full_object_path });807 try self.parseLibraryReportingFailure(.{ .path = comp.libunwind_static_lib.?.full_object_path }, false);
810 }808 }
811809
812 // libc dep810 // libc dep
...@@ -814,7 +812,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -814,7 +812,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
814 if (comp.config.link_libc) {812 if (comp.config.link_libc) {
815 if (comp.libc_installation) |lc| {813 if (comp.libc_installation) |lc| {
816 const flags = target_util.libcFullLinkFlags(target);814 const flags = target_util.libcFullLinkFlags(target);
817 try system_libs.ensureUnusedCapacity(flags.len);
818815
819 var test_path = std.ArrayList(u8).init(arena);816 var test_path = std.ArrayList(u8).init(arena);
820 var checked_paths = std.ArrayList([]const u8).init(arena);817 var checked_paths = std.ArrayList([]const u8).init(arena);
...@@ -840,39 +837,34 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -840,39 +837,34 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
840 continue;837 continue;
841 }838 }
842839
843 const resolved_path = try arena.dupe(u8, test_path.items);840 const resolved_path = Path.initCwd(try arena.dupe(u8, test_path.items));
844 system_libs.appendAssumeCapacity(.{ .path = resolved_path });841 try self.parseLibraryReportingFailure(.{ .path = resolved_path }, false);
845 }842 }
846 } else if (target.isGnuLibC()) {843 } else if (target.isGnuLibC()) {
847 try system_libs.ensureUnusedCapacity(glibc.libs.len + 1);
848 for (glibc.libs) |lib| {844 for (glibc.libs) |lib| {
849 if (lib.removed_in) |rem_in| {845 if (lib.removed_in) |rem_in| {
850 if (target.os.version_range.linux.glibc.order(rem_in) != .lt) continue;846 if (target.os.version_range.linux.glibc.order(rem_in) != .lt) continue;
851 }847 }
852848
853 const lib_path = try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{849 const lib_path = Path.initCwd(try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{
854 comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,850 comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
855 });851 }));
856 system_libs.appendAssumeCapacity(.{ .path = lib_path });852 try self.parseLibraryReportingFailure(.{ .path = lib_path }, false);
857 }853 }
858 system_libs.appendAssumeCapacity(.{854 try self.parseLibraryReportingFailure(.{
859 .path = try comp.get_libc_crt_file(arena, "libc_nonshared.a"),855 .path = try comp.get_libc_crt_file(arena, "libc_nonshared.a"),
860 });856 }, false);
861 } else if (target.isMusl()) {857 } else if (target.isMusl()) {
862 const path = try comp.get_libc_crt_file(arena, switch (link_mode) {858 const path = try comp.get_libc_crt_file(arena, switch (link_mode) {
863 .static => "libc.a",859 .static => "libc.a",
864 .dynamic => "libc.so",860 .dynamic => "libc.so",
865 });861 });
866 try system_libs.append(.{ .path = path });862 try self.parseLibraryReportingFailure(.{ .path = path }, false);
867 } else {863 } else {
868 comp.link_error_flags.missing_libc = true;864 comp.link_error_flags.missing_libc = true;
869 }865 }
870 }866 }
871867
872 for (system_libs.items) |lib| {
873 try self.parseLibraryReportingFailure(lib, false);
874 }
875
876 // Finally, as the last input objects we add compiler_rt and CSU postlude (if any).868 // Finally, as the last input objects we add compiler_rt and CSU postlude (if any).
877869
878 // compiler-rt. Since compiler_rt exports symbols like `memset`, it needs870 // compiler-rt. Since compiler_rt exports symbols like `memset`, it needs
...@@ -1066,10 +1058,10 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1066,10 +1058,10 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1066 }1058 }
1067 } else null;1059 } else null;
10681060
1069 const csu = try CsuObjects.init(arena, comp);1061 const csu = try comp.getCrtPaths(arena);
1070 const compiler_rt_path: ?[]const u8 = blk: {1062 const compiler_rt_path: ?[]const u8 = blk: {
1071 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;1063 if (comp.compiler_rt_lib) |x| break :blk try x.full_object_path.toString(arena);
1072 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;1064 if (comp.compiler_rt_obj) |x| break :blk try x.full_object_path.toString(arena);
1073 break :blk null;1065 break :blk null;
1074 };1066 };
10751067
...@@ -1092,11 +1084,11 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1092,11 +1084,11 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
10921084
1093 if (self.base.isRelocatable()) {1085 if (self.base.isRelocatable()) {
1094 for (comp.objects) |obj| {1086 for (comp.objects) |obj| {
1095 try argv.append(obj.path);1087 try argv.append(try obj.path.toString(arena));
1096 }1088 }
10971089
1098 for (comp.c_object_table.keys()) |key| {1090 for (comp.c_object_table.keys()) |key| {
1099 try argv.append(key.status.success.object_path);1091 try argv.append(try key.status.success.object_path.toString(arena));
1100 }1092 }
11011093
1102 if (module_obj_path) |p| {1094 if (module_obj_path) |p| {
...@@ -1178,9 +1170,9 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1178,9 +1170,9 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1178 }1170 }
11791171
1180 // csu prelude1172 // csu prelude
1181 if (csu.crt0) |v| try argv.append(v);1173 if (csu.crt0) |path| try argv.append(try path.toString(arena));
1182 if (csu.crti) |v| try argv.append(v);1174 if (csu.crti) |path| try argv.append(try path.toString(arena));
1183 if (csu.crtbegin) |v| try argv.append(v);1175 if (csu.crtbegin) |path| try argv.append(try path.toString(arena));
11841176
1185 for (self.lib_dirs) |lib_dir| {1177 for (self.lib_dirs) |lib_dir| {
1186 try argv.append("-L");1178 try argv.append("-L");
...@@ -1205,10 +1197,9 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1205,10 +1197,9 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1205 }1197 }
12061198
1207 if (obj.loption) {1199 if (obj.loption) {
1208 assert(obj.path[0] == ':');
1209 try argv.append("-l");1200 try argv.append("-l");
1210 }1201 }
1211 try argv.append(obj.path);1202 try argv.append(try obj.path.toString(arena));
1212 }1203 }
1213 if (whole_archive) {1204 if (whole_archive) {
1214 try argv.append("-no-whole-archive");1205 try argv.append("-no-whole-archive");
...@@ -1216,7 +1207,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1216,7 +1207,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1216 }1207 }
12171208
1218 for (comp.c_object_table.keys()) |key| {1209 for (comp.c_object_table.keys()) |key| {
1219 try argv.append(key.status.success.object_path);1210 try argv.append(try key.status.success.object_path.toString(arena));
1220 }1211 }
12211212
1222 if (module_obj_path) |p| {1213 if (module_obj_path) |p| {
...@@ -1224,17 +1215,17 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1224,17 +1215,17 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1224 }1215 }
12251216
1226 if (comp.config.any_sanitize_thread) {1217 if (comp.config.any_sanitize_thread) {
1227 try argv.append(comp.tsan_lib.?.full_object_path);1218 try argv.append(try comp.tsan_lib.?.full_object_path.toString(arena));
1228 }1219 }
12291220
1230 if (comp.config.any_fuzz) {1221 if (comp.config.any_fuzz) {
1231 try argv.append(comp.fuzzer_lib.?.full_object_path);1222 try argv.append(try comp.fuzzer_lib.?.full_object_path.toString(arena));
1232 }1223 }
12331224
1234 // libc1225 // libc
1235 if (!comp.skip_linker_dependencies and !comp.config.link_libc) {1226 if (!comp.skip_linker_dependencies and !comp.config.link_libc) {
1236 if (comp.libc_static_lib) |lib| {1227 if (comp.libc_static_lib) |lib| {
1237 try argv.append(lib.full_object_path);1228 try argv.append(try lib.full_object_path.toString(arena));
1238 }1229 }
1239 }1230 }
12401231
...@@ -1258,7 +1249,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1258,7 +1249,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1258 as_needed = true;1249 as_needed = true;
1259 },1250 },
1260 }1251 }
1261 argv.appendAssumeCapacity(lib_info.path.?);1252 argv.appendAssumeCapacity(try lib_info.path.?.toString(arena));
1262 }1253 }
12631254
1264 if (!as_needed) {1255 if (!as_needed) {
...@@ -1268,13 +1259,13 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1268,13 +1259,13 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
12681259
1269 // libc++ dep1260 // libc++ dep
1270 if (comp.config.link_libcpp) {1261 if (comp.config.link_libcpp) {
1271 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);1262 try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena));
1272 try argv.append(comp.libcxx_static_lib.?.full_object_path);1263 try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena));
1273 }1264 }
12741265
1275 // libunwind dep1266 // libunwind dep
1276 if (comp.config.link_libunwind) {1267 if (comp.config.link_libunwind) {
1277 try argv.append(comp.libunwind_static_lib.?.full_object_path);1268 try argv.append(try comp.libunwind_static_lib.?.full_object_path.toString(arena));
1278 }1269 }
12791270
1280 // libc dep1271 // libc dep
...@@ -1295,9 +1286,9 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1295,9 +1286,9 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1295 });1286 });
1296 try argv.append(lib_path);1287 try argv.append(lib_path);
1297 }1288 }
1298 try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));1289 try argv.append(try comp.crtFileAsString(arena, "libc_nonshared.a"));
1299 } else if (target.isMusl()) {1290 } else if (target.isMusl()) {
1300 try argv.append(try comp.get_libc_crt_file(arena, switch (link_mode) {1291 try argv.append(try comp.crtFileAsString(arena, switch (link_mode) {
1301 .static => "libc.a",1292 .static => "libc.a",
1302 .dynamic => "libc.so",1293 .dynamic => "libc.so",
1303 }));1294 }));
...@@ -1310,8 +1301,8 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1310,8 +1301,8 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1310 }1301 }
13111302
1312 // crt postlude1303 // crt postlude
1313 if (csu.crtend) |v| try argv.append(v);1304 if (csu.crtend) |path| try argv.append(try path.toString(arena));
1314 if (csu.crtn) |v| try argv.append(v);1305 if (csu.crtn) |path| try argv.append(try path.toString(arena));
1315 }1306 }
13161307
1317 Compilation.dump_argv(argv.items);1308 Compilation.dump_argv(argv.items);
...@@ -1331,7 +1322,7 @@ pub const ParseError = error{...@@ -1331,7 +1322,7 @@ pub const ParseError = error{
1331 UnknownFileType,1322 UnknownFileType,
1332} || LdScript.Error || fs.Dir.AccessError || fs.File.SeekError || fs.File.OpenError || fs.File.ReadError;1323} || LdScript.Error || fs.Dir.AccessError || fs.File.SeekError || fs.File.OpenError || fs.File.ReadError;
13331324
1334fn parseCrtFileReportingFailure(self: *Elf, crt_file: Compilation.CRTFile) error{OutOfMemory}!void {1325fn parseCrtFileReportingFailure(self: *Elf, crt_file: Compilation.CrtFile) error{OutOfMemory}!void {
1335 if (crt_file.isObject()) {1326 if (crt_file.isObject()) {
1336 try parseObjectReportingFailure(self, crt_file.full_object_path);1327 try parseObjectReportingFailure(self, crt_file.full_object_path);
1337 } else {1328 } else {
...@@ -1339,7 +1330,7 @@ fn parseCrtFileReportingFailure(self: *Elf, crt_file: Compilation.CRTFile) error...@@ -1339,7 +1330,7 @@ fn parseCrtFileReportingFailure(self: *Elf, crt_file: Compilation.CRTFile) error
1339 }1330 }
1340}1331}
13411332
1342pub fn parseObjectReportingFailure(self: *Elf, path: []const u8) error{OutOfMemory}!void {1333pub fn parseObjectReportingFailure(self: *Elf, path: Path) error{OutOfMemory}!void {
1343 self.parseObject(path) catch |err| switch (err) {1334 self.parseObject(path) catch |err| switch (err) {
1344 error.LinkFailure => return, // already reported1335 error.LinkFailure => return, // already reported
1345 error.OutOfMemory => return error.OutOfMemory,1336 error.OutOfMemory => return error.OutOfMemory,
...@@ -1367,17 +1358,20 @@ fn parseLibrary(self: *Elf, lib: SystemLib, must_link: bool) ParseError!void {...@@ -1367,17 +1358,20 @@ fn parseLibrary(self: *Elf, lib: SystemLib, must_link: bool) ParseError!void {
1367 }1358 }
1368}1359}
13691360
1370fn parseObject(self: *Elf, path: []const u8) ParseError!void {1361fn parseObject(self: *Elf, path: Path) ParseError!void {
1371 const tracy = trace(@src());1362 const tracy = trace(@src());
1372 defer tracy.end();1363 defer tracy.end();
13731364
1374 const gpa = self.base.comp.gpa;1365 const gpa = self.base.comp.gpa;
1375 const handle = try fs.cwd().openFile(path, .{});1366 const handle = try path.root_dir.handle.openFile(path.sub_path, .{});
1376 const fh = try self.addFileHandle(handle);1367 const fh = try self.addFileHandle(handle);
13771368
1378 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));1369 const index: File.Index = @intCast(try self.files.addOne(gpa));
1379 self.files.set(index, .{ .object = .{1370 self.files.set(index, .{ .object = .{
1380 .path = try gpa.dupe(u8, path),1371 .path = .{
1372 .root_dir = path.root_dir,
1373 .sub_path = try gpa.dupe(u8, path.sub_path),
1374 },
1381 .file_handle = fh,1375 .file_handle = fh,
1382 .index = index,1376 .index = index,
1383 } });1377 } });
...@@ -1387,15 +1381,15 @@ fn parseObject(self: *Elf, path: []const u8) ParseError!void {...@@ -1387,15 +1381,15 @@ fn parseObject(self: *Elf, path: []const u8) ParseError!void {
1387 try object.parse(self);1381 try object.parse(self);
1388}1382}
13891383
1390fn parseArchive(self: *Elf, path: []const u8, must_link: bool) ParseError!void {1384fn parseArchive(self: *Elf, path: Path, must_link: bool) ParseError!void {
1391 const tracy = trace(@src());1385 const tracy = trace(@src());
1392 defer tracy.end();1386 defer tracy.end();
13931387
1394 const gpa = self.base.comp.gpa;1388 const gpa = self.base.comp.gpa;
1395 const handle = try fs.cwd().openFile(path, .{});1389 const handle = try path.root_dir.handle.openFile(path.sub_path, .{});
1396 const fh = try self.addFileHandle(handle);1390 const fh = try self.addFileHandle(handle);
13971391
1398 var archive = Archive{};1392 var archive: Archive = .{};
1399 defer archive.deinit(gpa);1393 defer archive.deinit(gpa);
1400 try archive.parse(self, path, fh);1394 try archive.parse(self, path, fh);
14011395
...@@ -1403,7 +1397,7 @@ fn parseArchive(self: *Elf, path: []const u8, must_link: bool) ParseError!void {...@@ -1403,7 +1397,7 @@ fn parseArchive(self: *Elf, path: []const u8, must_link: bool) ParseError!void {
1403 defer gpa.free(objects);1397 defer gpa.free(objects);
14041398
1405 for (objects) |extracted| {1399 for (objects) |extracted| {
1406 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));1400 const index: File.Index = @intCast(try self.files.addOne(gpa));
1407 self.files.set(index, .{ .object = extracted });1401 self.files.set(index, .{ .object = extracted });
1408 const object = &self.files.items(.data)[index].object;1402 const object = &self.files.items(.data)[index].object;
1409 object.index = index;1403 object.index = index;
...@@ -1418,12 +1412,15 @@ fn parseSharedObject(self: *Elf, lib: SystemLib) ParseError!void {...@@ -1418,12 +1412,15 @@ fn parseSharedObject(self: *Elf, lib: SystemLib) ParseError!void {
1418 defer tracy.end();1412 defer tracy.end();
14191413
1420 const gpa = self.base.comp.gpa;1414 const gpa = self.base.comp.gpa;
1421 const handle = try fs.cwd().openFile(lib.path, .{});1415 const handle = try lib.path.root_dir.handle.openFile(lib.path.sub_path, .{});
1422 defer handle.close();1416 defer handle.close();
14231417
1424 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));1418 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
1425 self.files.set(index, .{ .shared_object = .{1419 self.files.set(index, .{ .shared_object = .{
1426 .path = try gpa.dupe(u8, lib.path),1420 .path = .{
1421 .root_dir = lib.path.root_dir,
1422 .sub_path = try gpa.dupe(u8, lib.path.sub_path),
1423 },
1427 .index = index,1424 .index = index,
1428 .needed = lib.needed,1425 .needed = lib.needed,
1429 .alive = lib.needed,1426 .alive = lib.needed,
...@@ -1439,12 +1436,12 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {...@@ -1439,12 +1436,12 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
1439 defer tracy.end();1436 defer tracy.end();
14401437
1441 const gpa = self.base.comp.gpa;1438 const gpa = self.base.comp.gpa;
1442 const in_file = try fs.cwd().openFile(lib.path, .{});1439 const in_file = try lib.path.root_dir.handle.openFile(lib.path.sub_path, .{});
1443 defer in_file.close();1440 defer in_file.close();
1444 const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));1441 const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));
1445 defer gpa.free(data);1442 defer gpa.free(data);
14461443
1447 var script = LdScript{ .path = lib.path };1444 var script: LdScript = .{ .path = lib.path };
1448 defer script.deinit(gpa);1445 defer script.deinit(gpa);
1449 try script.parse(data, self);1446 try script.parse(data, self);
14501447
...@@ -1455,12 +1452,12 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {...@@ -1455,12 +1452,12 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
1455 var test_path = std.ArrayList(u8).init(arena);1452 var test_path = std.ArrayList(u8).init(arena);
1456 var checked_paths = std.ArrayList([]const u8).init(arena);1453 var checked_paths = std.ArrayList([]const u8).init(arena);
14571454
1458 for (script.args.items) |scr_obj| {1455 for (script.args.items) |script_arg| {
1459 checked_paths.clearRetainingCapacity();1456 checked_paths.clearRetainingCapacity();
14601457
1461 success: {1458 success: {
1462 if (mem.startsWith(u8, scr_obj.path, "-l")) {1459 if (mem.startsWith(u8, script_arg.path, "-l")) {
1463 const lib_name = scr_obj.path["-l".len..];1460 const lib_name = script_arg.path["-l".len..];
14641461
1465 // TODO I think technically we should re-use the mechanism used by the frontend here.1462 // TODO I think technically we should re-use the mechanism used by the frontend here.
1466 // Maybe we should hoist search-strategy all the way here?1463 // Maybe we should hoist search-strategy all the way here?
...@@ -1474,33 +1471,30 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {...@@ -1474,33 +1471,30 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
1474 }1471 }
1475 } else {1472 } else {
1476 var buffer: [fs.max_path_bytes]u8 = undefined;1473 var buffer: [fs.max_path_bytes]u8 = undefined;
1477 if (fs.realpath(scr_obj.path, &buffer)) |path| {1474 if (fs.realpath(script_arg.path, &buffer)) |path| {
1478 test_path.clearRetainingCapacity();1475 test_path.clearRetainingCapacity();
1479 try test_path.writer().writeAll(path);1476 try test_path.writer().writeAll(path);
1480 break :success;1477 break :success;
1481 } else |_| {}1478 } else |_| {}
14821479
1483 try checked_paths.append(try arena.dupe(u8, scr_obj.path));1480 try checked_paths.append(try arena.dupe(u8, script_arg.path));
1484 for (self.lib_dirs) |lib_dir| {1481 for (self.lib_dirs) |lib_dir| {
1485 if (try self.accessLibPath(arena, &test_path, &checked_paths, lib_dir, scr_obj.path, null))1482 if (try self.accessLibPath(arena, &test_path, &checked_paths, lib_dir, script_arg.path, null))
1486 break :success;1483 break :success;
1487 }1484 }
1488 }1485 }
14891486
1490 try self.reportMissingLibraryError(1487 try self.reportMissingLibraryError(
1491 checked_paths.items,1488 checked_paths.items,
1492 "missing library dependency: GNU ld script '{s}' requires '{s}', but file not found",1489 "missing library dependency: GNU ld script '{}' requires '{s}', but file not found",
1493 .{1490 .{ @as(Path, lib.path), script_arg.path },
1494 lib.path,
1495 scr_obj.path,
1496 },
1497 );1491 );
1498 continue;1492 continue;
1499 }1493 }
15001494
1501 const full_path = test_path.items;1495 const full_path = Path.initCwd(test_path.items);
1502 self.parseLibrary(.{1496 self.parseLibrary(.{
1503 .needed = scr_obj.needed,1497 .needed = script_arg.needed,
1504 .path = full_path,1498 .path = full_path,
1505 }, false) catch |err| switch (err) {1499 }, false) catch |err| switch (err) {
1506 error.LinkFailure => continue, // already reported1500 error.LinkFailure => continue, // already reported
...@@ -1841,7 +1835,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -1841,7 +1835,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
1841 const have_dynamic_linker = comp.config.link_libc and1835 const have_dynamic_linker = comp.config.link_libc and
1842 link_mode == .dynamic and is_exe_or_dyn_lib;1836 link_mode == .dynamic and is_exe_or_dyn_lib;
1843 const target = self.getTarget();1837 const target = self.getTarget();
1844 const compiler_rt_path: ?[]const u8 = blk: {1838 const compiler_rt_path: ?Path = blk: {
1845 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;1839 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
1846 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;1840 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;
1847 break :blk null;1841 break :blk null;
...@@ -1875,17 +1869,17 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -1875,17 +1869,17 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
1875 man.hash.add(self.allow_undefined_version);1869 man.hash.add(self.allow_undefined_version);
1876 man.hash.addOptional(self.enable_new_dtags);1870 man.hash.addOptional(self.enable_new_dtags);
1877 for (comp.objects) |obj| {1871 for (comp.objects) |obj| {
1878 _ = try man.addFile(obj.path, null);1872 _ = try man.addFilePath(obj.path, null);
1879 man.hash.add(obj.must_link);1873 man.hash.add(obj.must_link);
1880 man.hash.add(obj.loption);1874 man.hash.add(obj.loption);
1881 }1875 }
1882 for (comp.c_object_table.keys()) |key| {1876 for (comp.c_object_table.keys()) |key| {
1883 _ = try man.addFile(key.status.success.object_path, null);1877 _ = try man.addFilePath(key.status.success.object_path, null);
1884 }1878 }
1885 try man.addOptionalFile(module_obj_path);1879 try man.addOptionalFile(module_obj_path);
1886 try man.addOptionalFile(compiler_rt_path);1880 try man.addOptionalFilePath(compiler_rt_path);
1887 try man.addOptionalFile(if (comp.tsan_lib) |l| l.full_object_path else null);1881 try man.addOptionalFilePath(if (comp.tsan_lib) |l| l.full_object_path else null);
1888 try man.addOptionalFile(if (comp.fuzzer_lib) |l| l.full_object_path else null);1882 try man.addOptionalFilePath(if (comp.fuzzer_lib) |l| l.full_object_path else null);
18891883
1890 // We can skip hashing libc and libc++ components that we are in charge of building from Zig1884 // We can skip hashing libc and libc++ components that we are in charge of building from Zig
1891 // installation sources because they are always a product of the compiler version + target information.1885 // installation sources because they are always a product of the compiler version + target information.
...@@ -1982,17 +1976,19 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -1982,17 +1976,19 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
1982 break :blk comp.c_object_table.keys()[0].status.success.object_path;1976 break :blk comp.c_object_table.keys()[0].status.success.object_path;
19831977
1984 if (module_obj_path) |p|1978 if (module_obj_path) |p|
1985 break :blk p;1979 break :blk Path.initCwd(p);
19861980
1987 // TODO I think this is unreachable. Audit this situation when solving the above TODO1981 // TODO I think this is unreachable. Audit this situation when solving the above TODO
1988 // regarding eliding redundant object -> object transformations.1982 // regarding eliding redundant object -> object transformations.
1989 return error.NoObjectsToLink;1983 return error.NoObjectsToLink;
1990 };1984 };
1991 // This can happen when using --enable-cache and using the stage1 backend. In this case1985 try std.fs.Dir.copyFile(
1992 // we can skip the file copy.1986 the_object_path.root_dir.handle,
1993 if (!mem.eql(u8, the_object_path, full_out_path)) {1987 the_object_path.sub_path,
1994 try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});1988 directory.handle,
1995 }1989 self.base.emit.sub_path,
1990 .{},
1991 );
1996 } else {1992 } else {
1997 // Create an LLD command line and invoke it.1993 // Create an LLD command line and invoke it.
1998 var argv = std.ArrayList([]const u8).init(gpa);1994 var argv = std.ArrayList([]const u8).init(gpa);
...@@ -2177,10 +2173,10 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -2177,10 +2173,10 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
2177 try argv.append(full_out_path);2173 try argv.append(full_out_path);
21782174
2179 // csu prelude2175 // csu prelude
2180 const csu = try CsuObjects.init(arena, comp);2176 const csu = try comp.getCrtPaths(arena);
2181 if (csu.crt0) |v| try argv.append(v);2177 if (csu.crt0) |p| try argv.append(try p.toString(arena));
2182 if (csu.crti) |v| try argv.append(v);2178 if (csu.crti) |p| try argv.append(try p.toString(arena));
2183 if (csu.crtbegin) |v| try argv.append(v);2179 if (csu.crtbegin) |p| try argv.append(try p.toString(arena));
21842180
2185 for (self.rpath_table.keys()) |rpath| {2181 for (self.rpath_table.keys()) |rpath| {
2186 try argv.appendSlice(&.{ "-rpath", rpath });2182 try argv.appendSlice(&.{ "-rpath", rpath });
...@@ -2244,10 +2240,10 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -2244,10 +2240,10 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
2244 }2240 }
22452241
2246 if (obj.loption) {2242 if (obj.loption) {
2247 assert(obj.path[0] == ':');2243 assert(obj.path.sub_path[0] == ':');
2248 try argv.append("-l");2244 try argv.append("-l");
2249 }2245 }
2250 try argv.append(obj.path);2246 try argv.append(try obj.path.toString(arena));
2251 }2247 }
2252 if (whole_archive) {2248 if (whole_archive) {
2253 try argv.append("-no-whole-archive");2249 try argv.append("-no-whole-archive");
...@@ -2255,7 +2251,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -2255,7 +2251,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
2255 }2251 }
22562252
2257 for (comp.c_object_table.keys()) |key| {2253 for (comp.c_object_table.keys()) |key| {
2258 try argv.append(key.status.success.object_path);2254 try argv.append(try key.status.success.object_path.toString(arena));
2259 }2255 }
22602256
2261 if (module_obj_path) |p| {2257 if (module_obj_path) |p| {
...@@ -2264,12 +2260,12 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -2264,12 +2260,12 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
22642260
2265 if (comp.tsan_lib) |lib| {2261 if (comp.tsan_lib) |lib| {
2266 assert(comp.config.any_sanitize_thread);2262 assert(comp.config.any_sanitize_thread);
2267 try argv.append(lib.full_object_path);2263 try argv.append(try lib.full_object_path.toString(arena));
2268 }2264 }
22692265
2270 if (comp.fuzzer_lib) |lib| {2266 if (comp.fuzzer_lib) |lib| {
2271 assert(comp.config.any_fuzz);2267 assert(comp.config.any_fuzz);
2272 try argv.append(lib.full_object_path);2268 try argv.append(try lib.full_object_path.toString(arena));
2273 }2269 }
22742270
2275 // libc2271 // libc
...@@ -2278,7 +2274,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -2278,7 +2274,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
2278 !comp.config.link_libc)2274 !comp.config.link_libc)
2279 {2275 {
2280 if (comp.libc_static_lib) |lib| {2276 if (comp.libc_static_lib) |lib| {
2281 try argv.append(lib.full_object_path);2277 try argv.append(try lib.full_object_path.toString(arena));
2282 }2278 }
2283 }2279 }
22842280
...@@ -2311,7 +2307,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -2311,7 +2307,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
2311 // libraries and not static libraries (the check for that needs to be earlier),2307 // libraries and not static libraries (the check for that needs to be earlier),
2312 // but they could be full paths to .so files, in which case we2308 // but they could be full paths to .so files, in which case we
2313 // want to avoid prepending "-l".2309 // want to avoid prepending "-l".
2314 argv.appendAssumeCapacity(lib_info.path.?);2310 argv.appendAssumeCapacity(try lib_info.path.?.toString(arena));
2315 }2311 }
23162312
2317 if (!as_needed) {2313 if (!as_needed) {
...@@ -2321,13 +2317,13 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -2321,13 +2317,13 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
23212317
2322 // libc++ dep2318 // libc++ dep
2323 if (comp.config.link_libcpp) {2319 if (comp.config.link_libcpp) {
2324 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);2320 try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena));
2325 try argv.append(comp.libcxx_static_lib.?.full_object_path);2321 try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena));
2326 }2322 }
23272323
2328 // libunwind dep2324 // libunwind dep
2329 if (comp.config.link_libunwind) {2325 if (comp.config.link_libunwind) {
2330 try argv.append(comp.libunwind_static_lib.?.full_object_path);2326 try argv.append(try comp.libunwind_static_lib.?.full_object_path.toString(arena));
2331 }2327 }
23322328
2333 // libc dep2329 // libc dep
...@@ -2349,9 +2345,9 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -2349,9 +2345,9 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
2349 });2345 });
2350 try argv.append(lib_path);2346 try argv.append(lib_path);
2351 }2347 }
2352 try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));2348 try argv.append(try comp.crtFileAsString(arena, "libc_nonshared.a"));
2353 } else if (target.isMusl()) {2349 } else if (target.isMusl()) {
2354 try argv.append(try comp.get_libc_crt_file(arena, switch (link_mode) {2350 try argv.append(try comp.crtFileAsString(arena, switch (link_mode) {
2355 .static => "libc.a",2351 .static => "libc.a",
2356 .dynamic => "libc.so",2352 .dynamic => "libc.so",
2357 }));2353 }));
...@@ -2365,12 +2361,12 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -2365,12 +2361,12 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
2365 // to be after the shared libraries, so they are picked up from the shared2361 // to be after the shared libraries, so they are picked up from the shared
2366 // libraries, not libcompiler_rt.2362 // libraries, not libcompiler_rt.
2367 if (compiler_rt_path) |p| {2363 if (compiler_rt_path) |p| {
2368 try argv.append(p);2364 try argv.append(try p.toString(arena));
2369 }2365 }
23702366
2371 // crt postlude2367 // crt postlude
2372 if (csu.crtend) |v| try argv.append(v);2368 if (csu.crtend) |p| try argv.append(try p.toString(arena));
2373 if (csu.crtn) |v| try argv.append(v);2369 if (csu.crtn) |p| try argv.append(try p.toString(arena));
23742370
2375 if (self.base.allow_shlib_undefined) {2371 if (self.base.allow_shlib_undefined) {
2376 try argv.append("--allow-shlib-undefined");2372 try argv.append("--allow-shlib-undefined");
...@@ -3183,8 +3179,9 @@ fn sortInitFini(self: *Elf) !void {...@@ -3183,8 +3179,9 @@ fn sortInitFini(self: *Elf) !void {
3183 const object = atom_ptr.file(self).?.object;3179 const object = atom_ptr.file(self).?.object;
3184 const priority = blk: {3180 const priority = blk: {
3185 if (is_ctor_dtor) {3181 if (is_ctor_dtor) {
3186 if (mem.indexOf(u8, object.path, "crtbegin") != null) break :blk std.math.minInt(i32);3182 const basename = object.path.basename();
3187 if (mem.indexOf(u8, object.path, "crtend") != null) break :blk std.math.maxInt(i32);3183 if (mem.eql(u8, basename, "crtbegin.o")) break :blk std.math.minInt(i32);
3184 if (mem.eql(u8, basename, "crtend.o")) break :blk std.math.maxInt(i32);
3188 }3185 }
3189 const default: i32 = if (is_ctor_dtor) -1 else std.math.maxInt(i32);3186 const default: i32 = if (is_ctor_dtor) -1 else std.math.maxInt(i32);
3190 const name = atom_ptr.name(self);3187 const name = atom_ptr.name(self);
...@@ -4472,210 +4469,6 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {...@@ -4472,210 +4469,6 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
4472 return actual_size +| (actual_size / ideal_factor);4469 return actual_size +| (actual_size / ideal_factor);
4473}4470}
44744471
4475// Provide a blueprint of csu (c-runtime startup) objects for supported
4476// link modes.
4477//
4478// This is for cross-mode targets only. For host-mode targets the system
4479// compiler can be probed to produce a robust blueprint.
4480//
4481// Targets requiring a libc for which zig does not bundle a libc are
4482// host-mode targets. Unfortunately, host-mode probes are not yet
4483// implemented. For now the data is hard-coded here. Such targets are
4484// { freebsd, netbsd, openbsd, dragonfly }.
4485const CsuObjects = struct {
4486 crt0: ?[]const u8 = null,
4487 crti: ?[]const u8 = null,
4488 crtbegin: ?[]const u8 = null,
4489 crtend: ?[]const u8 = null,
4490 crtn: ?[]const u8 = null,
4491
4492 const InitArgs = struct {};
4493
4494 fn init(arena: Allocator, comp: *const Compilation) !CsuObjects {
4495 // crt objects are only required for libc.
4496 if (!comp.config.link_libc) return .{};
4497
4498 var result: CsuObjects = .{};
4499
4500 // Flatten crt cases.
4501 const mode: enum {
4502 dynamic_lib,
4503 dynamic_exe,
4504 dynamic_pie,
4505 static_exe,
4506 static_pie,
4507 } = switch (comp.config.output_mode) {
4508 .Obj => return CsuObjects{},
4509 .Lib => switch (comp.config.link_mode) {
4510 .dynamic => .dynamic_lib,
4511 .static => return CsuObjects{},
4512 },
4513 .Exe => switch (comp.config.link_mode) {
4514 .dynamic => if (comp.config.pie) .dynamic_pie else .dynamic_exe,
4515 .static => if (comp.config.pie) .static_pie else .static_exe,
4516 },
4517 };
4518
4519 const target = comp.root_mod.resolved_target.result;
4520
4521 if (target.isAndroid()) {
4522 switch (mode) {
4523 // zig fmt: off
4524 .dynamic_lib => result.set( null, null, "crtbegin_so.o", "crtend_so.o", null ),
4525 .dynamic_exe,
4526 .dynamic_pie => result.set( null, null, "crtbegin_dynamic.o", "crtend_android.o", null ),
4527 .static_exe,
4528 .static_pie => result.set( null, null, "crtbegin_static.o", "crtend_android.o", null ),
4529 // zig fmt: on
4530 }
4531 } else {
4532 switch (target.os.tag) {
4533 .linux => {
4534 switch (mode) {
4535 // zig fmt: off
4536 .dynamic_lib => result.set( null, "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
4537 .dynamic_exe => result.set( "crt1.o", "crti.o", "crtbegin.o", "crtend.o", "crtn.o" ),
4538 .dynamic_pie => result.set( "Scrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
4539 .static_exe => result.set( "crt1.o", "crti.o", "crtbeginT.o", "crtend.o", "crtn.o" ),
4540 .static_pie => result.set( "rcrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
4541 // zig fmt: on
4542 }
4543 if (comp.libc_installation) |_| {
4544 // hosted-glibc provides crtbegin/end objects in platform/compiler-specific dirs
4545 // and they are not known at comptime. For now null-out crtbegin/end objects;
4546 // there is no feature loss, zig has never linked those objects in before.
4547 result.crtbegin = null;
4548 result.crtend = null;
4549 } else {
4550 // Bundled glibc only has Scrt1.o .
4551 if (result.crt0 != null and target.isGnuLibC()) result.crt0 = "Scrt1.o";
4552 }
4553 },
4554 .dragonfly => switch (mode) {
4555 // zig fmt: off
4556 .dynamic_lib => result.set( null, "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
4557 .dynamic_exe => result.set( "crt1.o", "crti.o", "crtbegin.o", "crtend.o", "crtn.o" ),
4558 .dynamic_pie => result.set( "Scrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
4559 .static_exe => result.set( "crt1.o", "crti.o", "crtbegin.o", "crtend.o", "crtn.o" ),
4560 .static_pie => result.set( "Scrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
4561 // zig fmt: on
4562 },
4563 .freebsd => switch (mode) {
4564 // zig fmt: off
4565 .dynamic_lib => result.set( null, "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
4566 .dynamic_exe => result.set( "crt1.o", "crti.o", "crtbegin.o", "crtend.o", "crtn.o" ),
4567 .dynamic_pie => result.set( "Scrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
4568 .static_exe => result.set( "crt1.o", "crti.o", "crtbeginT.o", "crtend.o", "crtn.o" ),
4569 .static_pie => result.set( "Scrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
4570 // zig fmt: on
4571 },
4572 .netbsd => switch (mode) {
4573 // zig fmt: off
4574 .dynamic_lib => result.set( null, "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
4575 .dynamic_exe => result.set( "crt0.o", "crti.o", "crtbegin.o", "crtend.o", "crtn.o" ),
4576 .dynamic_pie => result.set( "crt0.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
4577 .static_exe => result.set( "crt0.o", "crti.o", "crtbeginT.o", "crtend.o", "crtn.o" ),
4578 .static_pie => result.set( "crt0.o", "crti.o", "crtbeginT.o", "crtendS.o", "crtn.o" ),
4579 // zig fmt: on
4580 },
4581 .openbsd => switch (mode) {
4582 // zig fmt: off
4583 .dynamic_lib => result.set( null, null, "crtbeginS.o", "crtendS.o", null ),
4584 .dynamic_exe,
4585 .dynamic_pie => result.set( "crt0.o", null, "crtbegin.o", "crtend.o", null ),
4586 .static_exe,
4587 .static_pie => result.set( "rcrt0.o", null, "crtbegin.o", "crtend.o", null ),
4588 // zig fmt: on
4589 },
4590 .haiku => switch (mode) {
4591 // zig fmt: off
4592 .dynamic_lib => result.set( null, "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
4593 .dynamic_exe => result.set( "start_dyn.o", "crti.o", "crtbegin.o", "crtend.o", "crtn.o" ),
4594 .dynamic_pie => result.set( "start_dyn.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
4595 .static_exe => result.set( "start_dyn.o", "crti.o", "crtbegin.o", "crtend.o", "crtn.o" ),
4596 .static_pie => result.set( "start_dyn.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
4597 // zig fmt: on
4598 },
4599 .solaris, .illumos => switch (mode) {
4600 // zig fmt: off
4601 .dynamic_lib => result.set( null, "crti.o", null, null, "crtn.o" ),
4602 .dynamic_exe,
4603 .dynamic_pie => result.set( "crt1.o", "crti.o", null, null, "crtn.o" ),
4604 .static_exe,
4605 .static_pie => result.set( null, null, null, null, null ),
4606 // zig fmt: on
4607 },
4608 else => {},
4609 }
4610 }
4611
4612 // Convert each object to a full pathname.
4613 if (comp.libc_installation) |lci| {
4614 const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCRTDir;
4615 switch (target.os.tag) {
4616 .dragonfly => {
4617 if (result.crt0) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
4618 if (result.crti) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
4619 if (result.crtn) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
4620
4621 var gccv: []const u8 = undefined;
4622 if (target.os.version_range.semver.isAtLeast(.{ .major = 5, .minor = 4, .patch = 0 }) orelse true) {
4623 gccv = "gcc80";
4624 } else {
4625 gccv = "gcc54";
4626 }
4627
4628 if (result.crtbegin) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, gccv, obj.* });
4629 if (result.crtend) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, gccv, obj.* });
4630 },
4631 .haiku => {
4632 const gcc_dir_path = lci.gcc_dir orelse return error.LibCInstallationMissingCRTDir;
4633 if (result.crt0) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
4634 if (result.crti) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
4635 if (result.crtn) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
4636
4637 if (result.crtbegin) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ gcc_dir_path, obj.* });
4638 if (result.crtend) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ gcc_dir_path, obj.* });
4639 },
4640 else => {
4641 inline for (std.meta.fields(@TypeOf(result))) |f| {
4642 if (@field(result, f.name)) |*obj| {
4643 obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
4644 }
4645 }
4646 },
4647 }
4648 } else {
4649 inline for (std.meta.fields(@TypeOf(result))) |f| {
4650 if (@field(result, f.name)) |*obj| {
4651 if (comp.crt_files.get(obj.*)) |crtf| {
4652 obj.* = crtf.full_object_path;
4653 } else {
4654 @field(result, f.name) = null;
4655 }
4656 }
4657 }
4658 }
4659
4660 return result;
4661 }
4662
4663 fn set(
4664 self: *CsuObjects,
4665 crt0: ?[]const u8,
4666 crti: ?[]const u8,
4667 crtbegin: ?[]const u8,
4668 crtend: ?[]const u8,
4669 crtn: ?[]const u8,
4670 ) void {
4671 self.crt0 = crt0;
4672 self.crti = crti;
4673 self.crtbegin = crtbegin;
4674 self.crtend = crtend;
4675 self.crtn = crtn;
4676 }
4677};
4678
4679/// If a target compiles other output modes as dynamic libraries,4472/// If a target compiles other output modes as dynamic libraries,
4680/// this function returns true for those too.4473/// this function returns true for those too.
4681pub fn isEffectivelyDynLib(self: Elf) bool {4474pub fn isEffectivelyDynLib(self: Elf) bool {
...@@ -5089,13 +4882,13 @@ fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void {...@@ -5089,13 +4882,13 @@ fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void {
50894882
5090pub fn addParseError(4883pub fn addParseError(
5091 self: *Elf,4884 self: *Elf,
5092 path: []const u8,4885 path: Path,
5093 comptime format: []const u8,4886 comptime format: []const u8,
5094 args: anytype,4887 args: anytype,
5095) error{OutOfMemory}!void {4888) error{OutOfMemory}!void {
5096 var err = try self.base.addErrorWithNotes(1);4889 var err = try self.base.addErrorWithNotes(1);
5097 try err.addMsg(format, args);4890 try err.addMsg(format, args);
5098 try err.addNote("while parsing {s}", .{path});4891 try err.addNote("while parsing {}", .{path});
5099}4892}
51004893
5101pub fn addFileError(4894pub fn addFileError(
...@@ -5121,7 +4914,7 @@ pub fn failFile(...@@ -5121,7 +4914,7 @@ pub fn failFile(
51214914
5122pub fn failParse(4915pub fn failParse(
5123 self: *Elf,4916 self: *Elf,
5124 path: []const u8,4917 path: Path,
5125 comptime format: []const u8,4918 comptime format: []const u8,
5126 args: anytype,4919 args: anytype,
5127) error{ OutOfMemory, LinkFailure } {4920) error{ OutOfMemory, LinkFailure } {
...@@ -5274,7 +5067,7 @@ fn fmtDumpState(...@@ -5274,7 +5067,7 @@ fn fmtDumpState(
5274 _ = options;5067 _ = options;
52755068
5276 if (self.zigObjectPtr()) |zig_object| {5069 if (self.zigObjectPtr()) |zig_object| {
5277 try writer.print("zig_object({d}) : {s}\n", .{ zig_object.index, zig_object.path });5070 try writer.print("zig_object({d}) : {s}\n", .{ zig_object.index, zig_object.basename });
5278 try writer.print("{}{}", .{5071 try writer.print("{}{}", .{
5279 zig_object.fmtAtoms(self),5072 zig_object.fmtAtoms(self),
5280 zig_object.fmtSymtab(self),5073 zig_object.fmtSymtab(self),
...@@ -5299,7 +5092,7 @@ fn fmtDumpState(...@@ -5299,7 +5092,7 @@ fn fmtDumpState(
5299 for (self.shared_objects.items) |index| {5092 for (self.shared_objects.items) |index| {
5300 const shared_object = self.file(index).?.shared_object;5093 const shared_object = self.file(index).?.shared_object;
5301 try writer.print("shared_object({d}) : ", .{index});5094 try writer.print("shared_object({d}) : ", .{index});
5302 try writer.print("{s}", .{shared_object.path});5095 try writer.print("{}", .{shared_object.path});
5303 try writer.print(" : needed({})", .{shared_object.needed});5096 try writer.print(" : needed({})", .{shared_object.needed});
5304 if (!shared_object.alive) try writer.writeAll(" : [*]");5097 if (!shared_object.alive) try writer.writeAll(" : [*]");
5305 try writer.writeByte('\n');5098 try writer.writeByte('\n');
...@@ -5482,7 +5275,7 @@ pub const null_shdr = elf.Elf64_Shdr{...@@ -5482,7 +5275,7 @@ pub const null_shdr = elf.Elf64_Shdr{
54825275
5483pub const SystemLib = struct {5276pub const SystemLib = struct {
5484 needed: bool = false,5277 needed: bool = false,
5485 path: []const u8,5278 path: Path,
5486};5279};
54875280
5488pub const Ref = struct {5281pub const Ref = struct {
src/link/Elf/Archive.zig+13-7
...@@ -1,8 +1,8 @@...@@ -1,8 +1,8 @@
1objects: std.ArrayListUnmanaged(Object) = .empty,1objects: std.ArrayListUnmanaged(Object) = .empty,
2strtab: std.ArrayListUnmanaged(u8) = .empty,2strtab: std.ArrayListUnmanaged(u8) = .empty,
33
4pub fn isArchive(path: []const u8) !bool {4pub fn isArchive(path: Path) !bool {
5 const file = try std.fs.cwd().openFile(path, .{});5 const file = try path.root_dir.handle.openFile(path.sub_path, .{});
6 defer file.close();6 defer file.close();
7 const reader = file.reader();7 const reader = file.reader();
8 const magic = reader.readBytesNoEof(elf.ARMAG.len) catch return false;8 const magic = reader.readBytesNoEof(elf.ARMAG.len) catch return false;
...@@ -15,7 +15,7 @@ pub fn deinit(self: *Archive, allocator: Allocator) void {...@@ -15,7 +15,7 @@ pub fn deinit(self: *Archive, allocator: Allocator) void {
15 self.strtab.deinit(allocator);15 self.strtab.deinit(allocator);
16}16}
1717
18pub fn parse(self: *Archive, elf_file: *Elf, path: []const u8, handle_index: File.HandleIndex) !void {18pub fn parse(self: *Archive, elf_file: *Elf, path: Path, handle_index: File.HandleIndex) !void {
19 const comp = elf_file.base.comp;19 const comp = elf_file.base.comp;
20 const gpa = comp.gpa;20 const gpa = comp.gpa;
21 const handle = elf_file.fileHandle(handle_index);21 const handle = elf_file.fileHandle(handle_index);
...@@ -59,19 +59,24 @@ pub fn parse(self: *Archive, elf_file: *Elf, path: []const u8, handle_index: Fil...@@ -59,19 +59,24 @@ pub fn parse(self: *Archive, elf_file: *Elf, path: []const u8, handle_index: Fil
59 else59 else
60 unreachable;60 unreachable;
6161
62 const object = Object{62 const object: Object = .{
63 .archive = .{63 .archive = .{
64 .path = try gpa.dupe(u8, path),64 .path = .{
65 .root_dir = path.root_dir,
66 .sub_path = try gpa.dupe(u8, path.sub_path),
67 },
65 .offset = pos,68 .offset = pos,
66 .size = obj_size,69 .size = obj_size,
67 },70 },
68 .path = try gpa.dupe(u8, name),71 .path = Path.initCwd(try gpa.dupe(u8, name)),
69 .file_handle = handle_index,72 .file_handle = handle_index,
70 .index = undefined,73 .index = undefined,
71 .alive = false,74 .alive = false,
72 };75 };
7376
74 log.debug("extracting object '{s}' from archive '{s}'", .{ object.path, path });77 log.debug("extracting object '{}' from archive '{}'", .{
78 @as(Path, object.path), @as(Path, path),
79 });
7580
76 try self.objects.append(gpa, object);81 try self.objects.append(gpa, object);
77 }82 }
...@@ -292,6 +297,7 @@ const elf = std.elf;...@@ -292,6 +297,7 @@ const elf = std.elf;
292const fs = std.fs;297const fs = std.fs;
293const log = std.log.scoped(.link);298const log = std.log.scoped(.link);
294const mem = std.mem;299const mem = std.mem;
300const Path = std.Build.Cache.Path;
295301
296const Allocator = mem.Allocator;302const Allocator = mem.Allocator;
297const Archive = @This();303const Archive = @This();
src/link/Elf/LdScript.zig+16-10
...@@ -1,6 +1,11 @@...@@ -1,6 +1,11 @@
1path: []const u8,1path: Path,
2cpu_arch: ?std.Target.Cpu.Arch = null,2cpu_arch: ?std.Target.Cpu.Arch = null,
3args: std.ArrayListUnmanaged(Elf.SystemLib) = .empty,3args: std.ArrayListUnmanaged(Arg) = .empty,
4
5pub const Arg = struct {
6 needed: bool = false,
7 path: []const u8,
8};
49
5pub fn deinit(scr: *LdScript, allocator: Allocator) void {10pub fn deinit(scr: *LdScript, allocator: Allocator) void {
6 scr.args.deinit(allocator);11 scr.args.deinit(allocator);
...@@ -47,7 +52,7 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {...@@ -47,7 +52,7 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
4752
48 var it = TokenIterator{ .tokens = tokens.items };53 var it = TokenIterator{ .tokens = tokens.items };
49 var parser = Parser{ .source = data, .it = &it };54 var parser = Parser{ .source = data, .it = &it };
50 var args = std.ArrayList(Elf.SystemLib).init(gpa);55 var args = std.ArrayList(Arg).init(gpa);
51 scr.doParse(.{56 scr.doParse(.{
52 .parser = &parser,57 .parser = &parser,
53 .args = &args,58 .args = &args,
...@@ -70,7 +75,7 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {...@@ -70,7 +75,7 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
7075
71fn doParse(scr: *LdScript, ctx: struct {76fn doParse(scr: *LdScript, ctx: struct {
72 parser: *Parser,77 parser: *Parser,
73 args: *std.ArrayList(Elf.SystemLib),78 args: *std.ArrayList(Arg),
74}) !void {79}) !void {
75 while (true) {80 while (true) {
76 ctx.parser.skipAny(&.{ .comment, .new_line });81 ctx.parser.skipAny(&.{ .comment, .new_line });
...@@ -142,7 +147,7 @@ const Parser = struct {...@@ -142,7 +147,7 @@ const Parser = struct {
142 return error.UnknownCpuArch;147 return error.UnknownCpuArch;
143 }148 }
144149
145 fn group(p: *Parser, args: *std.ArrayList(Elf.SystemLib)) !void {150 fn group(p: *Parser, args: *std.ArrayList(Arg)) !void {
146 if (!p.skip(&.{.lparen})) return error.UnexpectedToken;151 if (!p.skip(&.{.lparen})) return error.UnexpectedToken;
147152
148 while (true) {153 while (true) {
...@@ -162,7 +167,7 @@ const Parser = struct {...@@ -162,7 +167,7 @@ const Parser = struct {
162 _ = try p.require(.rparen);167 _ = try p.require(.rparen);
163 }168 }
164169
165 fn asNeeded(p: *Parser, args: *std.ArrayList(Elf.SystemLib)) !void {170 fn asNeeded(p: *Parser, args: *std.ArrayList(Arg)) !void {
166 if (!p.skip(&.{.lparen})) return error.UnexpectedToken;171 if (!p.skip(&.{.lparen})) return error.UnexpectedToken;
167172
168 while (p.maybe(.literal)) |tok_id| {173 while (p.maybe(.literal)) |tok_id| {
...@@ -239,7 +244,7 @@ const Token = struct {...@@ -239,7 +244,7 @@ const Token = struct {
239244
240 const Index = usize;245 const Index = usize;
241246
242 inline fn get(tok: Token, source: []const u8) []const u8 {247 fn get(tok: Token, source: []const u8) []const u8 {
243 return source[tok.start..tok.end];248 return source[tok.start..tok.end];
244 }249 }
245};250};
...@@ -399,11 +404,11 @@ const TokenIterator = struct {...@@ -399,11 +404,11 @@ const TokenIterator = struct {
399 return it.tokens[it.pos];404 return it.tokens[it.pos];
400 }405 }
401406
402 inline fn reset(it: *TokenIterator) void {407 fn reset(it: *TokenIterator) void {
403 it.pos = 0;408 it.pos = 0;
404 }409 }
405410
406 inline fn seekTo(it: *TokenIterator, pos: Token.Index) void {411 fn seekTo(it: *TokenIterator, pos: Token.Index) void {
407 it.pos = pos;412 it.pos = pos;
408 }413 }
409414
...@@ -416,7 +421,7 @@ const TokenIterator = struct {...@@ -416,7 +421,7 @@ const TokenIterator = struct {
416 }421 }
417 }422 }
418423
419 inline fn get(it: *TokenIterator, pos: Token.Index) Token {424 fn get(it: *TokenIterator, pos: Token.Index) Token {
420 assert(pos < it.tokens.len);425 assert(pos < it.tokens.len);
421 return it.tokens[pos];426 return it.tokens[pos];
422 }427 }
...@@ -426,6 +431,7 @@ const LdScript = @This();...@@ -426,6 +431,7 @@ const LdScript = @This();
426431
427const std = @import("std");432const std = @import("std");
428const assert = std.debug.assert;433const assert = std.debug.assert;
434const Path = std.Build.Cache.Path;
429435
430const Allocator = std.mem.Allocator;436const Allocator = std.mem.Allocator;
431const Elf = @import("../Elf.zig");437const Elf = @import("../Elf.zig");
src/link/Elf/Object.zig+14-13
...@@ -1,5 +1,7 @@...@@ -1,5 +1,7 @@
1archive: ?InArchive = null,1archive: ?InArchive = null,
2path: []const u8,2/// Archive files cannot contain subdirectories, so only the basename is needed
3/// for output. However, the full path is kept for error reporting.
4path: Path,
3file_handle: File.HandleIndex,5file_handle: File.HandleIndex,
4index: File.Index,6index: File.Index,
57
...@@ -36,8 +38,8 @@ output_symtab_ctx: Elf.SymtabCtx = .{},...@@ -36,8 +38,8 @@ output_symtab_ctx: Elf.SymtabCtx = .{},
36output_ar_state: Archive.ArState = .{},38output_ar_state: Archive.ArState = .{},
3739
38pub fn deinit(self: *Object, allocator: Allocator) void {40pub fn deinit(self: *Object, allocator: Allocator) void {
39 if (self.archive) |*ar| allocator.free(ar.path);41 if (self.archive) |*ar| allocator.free(ar.path.sub_path);
40 allocator.free(self.path);42 allocator.free(self.path.sub_path);
41 self.shdrs.deinit(allocator);43 self.shdrs.deinit(allocator);
42 self.symtab.deinit(allocator);44 self.symtab.deinit(allocator);
43 self.strtab.deinit(allocator);45 self.strtab.deinit(allocator);
...@@ -474,8 +476,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {...@@ -474,8 +476,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {
474 if (sym.type(elf_file) != elf.STT_FUNC)476 if (sym.type(elf_file) != elf.STT_FUNC)
475 // TODO convert into an error477 // TODO convert into an error
476 log.debug("{s}: {s}: CIE referencing external data reference", .{478 log.debug("{s}: {s}: CIE referencing external data reference", .{
477 self.fmtPath(),479 self.fmtPath(), sym.name(elf_file),
478 sym.name(elf_file),
479 });480 });
480 sym.flags.needs_plt = true;481 sym.flags.needs_plt = true;
481 }482 }
...@@ -996,7 +997,7 @@ pub fn updateArSize(self: *Object, elf_file: *Elf) !void {...@@ -996,7 +997,7 @@ pub fn updateArSize(self: *Object, elf_file: *Elf) !void {
996pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void {997pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void {
997 const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;998 const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;
998 const offset: u64 = if (self.archive) |ar| ar.offset else 0;999 const offset: u64 = if (self.archive) |ar| ar.offset else 0;
999 const name = self.path;1000 const name = std.fs.path.basename(self.path.sub_path);
1000 const hdr = Archive.setArHdr(.{1001 const hdr = Archive.setArHdr(.{
1001 .name = if (name.len <= Archive.max_member_name_len)1002 .name = if (name.len <= Archive.max_member_name_len)
1002 .{ .name = name }1003 .{ .name = name }
...@@ -1489,15 +1490,14 @@ fn formatPath(...@@ -1489,15 +1490,14 @@ fn formatPath(
1489 _ = unused_fmt_string;1490 _ = unused_fmt_string;
1490 _ = options;1491 _ = options;
1491 if (object.archive) |ar| {1492 if (object.archive) |ar| {
1492 try writer.writeAll(ar.path);1493 try writer.print("{}({})", .{ ar.path, object.path });
1493 try writer.writeByte('(');1494 } else {
1494 try writer.writeAll(object.path);1495 try writer.print("{}", .{object.path});
1495 try writer.writeByte(')');1496 }
1496 } else try writer.writeAll(object.path);
1497}1497}
14981498
1499const InArchive = struct {1499const InArchive = struct {
1500 path: []const u8,1500 path: Path,
1501 offset: u64,1501 offset: u64,
1502 size: u32,1502 size: u32,
1503};1503};
...@@ -1512,8 +1512,9 @@ const fs = std.fs;...@@ -1512,8 +1512,9 @@ const fs = std.fs;
1512const log = std.log.scoped(.link);1512const log = std.log.scoped(.link);
1513const math = std.math;1513const math = std.math;
1514const mem = std.mem;1514const mem = std.mem;
15151515const Path = std.Build.Cache.Path;
1516const Allocator = mem.Allocator;1516const Allocator = mem.Allocator;
1517
1517const Archive = @import("Archive.zig");1518const Archive = @import("Archive.zig");
1518const Atom = @import("Atom.zig");1519const Atom = @import("Atom.zig");
1519const AtomList = @import("AtomList.zig");1520const AtomList = @import("AtomList.zig");
src/link/Elf/SharedObject.zig+8-7
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1path: []const u8,1path: Path,
2index: File.Index,2index: File.Index,
33
4header: ?elf.Elf64_Ehdr = null,4header: ?elf.Elf64_Ehdr = null,
...@@ -22,8 +22,8 @@ alive: bool,...@@ -22,8 +22,8 @@ alive: bool,
2222
23output_symtab_ctx: Elf.SymtabCtx = .{},23output_symtab_ctx: Elf.SymtabCtx = .{},
2424
25pub fn isSharedObject(path: []const u8) !bool {25pub fn isSharedObject(path: Path) !bool {
26 const file = try std.fs.cwd().openFile(path, .{});26 const file = try path.root_dir.handle.openFile(path.sub_path, .{});
27 defer file.close();27 defer file.close();
28 const reader = file.reader();28 const reader = file.reader();
29 const header = reader.readStruct(elf.Elf64_Ehdr) catch return false;29 const header = reader.readStruct(elf.Elf64_Ehdr) catch return false;
...@@ -34,7 +34,7 @@ pub fn isSharedObject(path: []const u8) !bool {...@@ -34,7 +34,7 @@ pub fn isSharedObject(path: []const u8) !bool {
34}34}
3535
36pub fn deinit(self: *SharedObject, allocator: Allocator) void {36pub fn deinit(self: *SharedObject, allocator: Allocator) void {
37 allocator.free(self.path);37 allocator.free(self.path.sub_path);
38 self.shdrs.deinit(allocator);38 self.shdrs.deinit(allocator);
39 self.symtab.deinit(allocator);39 self.symtab.deinit(allocator);
40 self.strtab.deinit(allocator);40 self.strtab.deinit(allocator);
...@@ -319,7 +319,7 @@ pub fn asFile(self: *SharedObject) File {...@@ -319,7 +319,7 @@ pub fn asFile(self: *SharedObject) File {
319319
320fn verdefNum(self: *SharedObject) u32 {320fn verdefNum(self: *SharedObject) u32 {
321 for (self.dynamic_table.items) |entry| switch (entry.d_tag) {321 for (self.dynamic_table.items) |entry| switch (entry.d_tag) {
322 elf.DT_VERDEFNUM => return @as(u32, @intCast(entry.d_val)),322 elf.DT_VERDEFNUM => return @intCast(entry.d_val),
323 else => {},323 else => {},
324 };324 };
325 return 0;325 return 0;
...@@ -327,10 +327,10 @@ fn verdefNum(self: *SharedObject) u32 {...@@ -327,10 +327,10 @@ fn verdefNum(self: *SharedObject) u32 {
327327
328pub fn soname(self: *SharedObject) []const u8 {328pub fn soname(self: *SharedObject) []const u8 {
329 for (self.dynamic_table.items) |entry| switch (entry.d_tag) {329 for (self.dynamic_table.items) |entry| switch (entry.d_tag) {
330 elf.DT_SONAME => return self.getString(@as(u32, @intCast(entry.d_val))),330 elf.DT_SONAME => return self.getString(@intCast(entry.d_val)),
331 else => {},331 else => {},
332 };332 };
333 return std.fs.path.basename(self.path);333 return std.fs.path.basename(self.path.sub_path);
334}334}
335335
336pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {336pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {
...@@ -508,6 +508,7 @@ const assert = std.debug.assert;...@@ -508,6 +508,7 @@ const assert = std.debug.assert;
508const elf = std.elf;508const elf = std.elf;
509const log = std.log.scoped(.elf);509const log = std.log.scoped(.elf);
510const mem = std.mem;510const mem = std.mem;
511const Path = std.Build.Cache.Path;
511512
512const Allocator = mem.Allocator;513const Allocator = mem.Allocator;
513const Elf = @import("../Elf.zig");514const Elf = @import("../Elf.zig");
src/link/Elf/ZigObject.zig+4-4
...@@ -5,7 +5,7 @@...@@ -5,7 +5,7 @@
55
6data: std.ArrayListUnmanaged(u8) = .empty,6data: std.ArrayListUnmanaged(u8) = .empty,
7/// Externally owned memory.7/// Externally owned memory.
8path: []const u8,8basename: []const u8,
9index: File.Index,9index: File.Index,
1010
11symtab: std.MultiArrayList(ElfSym) = .{},11symtab: std.MultiArrayList(ElfSym) = .{},
...@@ -88,7 +88,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {...@@ -88,7 +88,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
88 try self.strtab.buffer.append(gpa, 0);88 try self.strtab.buffer.append(gpa, 0);
8989
90 {90 {
91 const name_off = try self.strtab.insert(gpa, self.path);91 const name_off = try self.strtab.insert(gpa, self.basename);
92 const symbol_index = try self.newLocalSymbol(gpa, name_off);92 const symbol_index = try self.newLocalSymbol(gpa, name_off);
93 const sym = self.symbol(symbol_index);93 const sym = self.symbol(symbol_index);
94 const esym = &self.symtab.items(.elf_sym)[sym.esym_index];94 const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
...@@ -774,7 +774,7 @@ pub fn updateArSize(self: *ZigObject) void {...@@ -774,7 +774,7 @@ pub fn updateArSize(self: *ZigObject) void {
774}774}
775775
776pub fn writeAr(self: ZigObject, writer: anytype) !void {776pub fn writeAr(self: ZigObject, writer: anytype) !void {
777 const name = self.path;777 const name = self.basename;
778 const hdr = Archive.setArHdr(.{778 const hdr = Archive.setArHdr(.{
779 .name = if (name.len <= Archive.max_member_name_len)779 .name = if (name.len <= Archive.max_member_name_len)
780 .{ .name = name }780 .{ .name = name }
...@@ -2384,9 +2384,9 @@ const relocation = @import("relocation.zig");...@@ -2384,9 +2384,9 @@ const relocation = @import("relocation.zig");
2384const target_util = @import("../../target.zig");2384const target_util = @import("../../target.zig");
2385const trace = @import("../../tracy.zig").trace;2385const trace = @import("../../tracy.zig").trace;
2386const std = @import("std");2386const std = @import("std");
2387const Allocator = std.mem.Allocator;
23872388
2388const Air = @import("../../Air.zig");2389const Air = @import("../../Air.zig");
2389const Allocator = std.mem.Allocator;
2390const Archive = @import("Archive.zig");2390const Archive = @import("Archive.zig");
2391const Atom = @import("Atom.zig");2391const Atom = @import("Atom.zig");
2392const Dwarf = @import("../Dwarf.zig");2392const Dwarf = @import("../Dwarf.zig");
src/link/Elf/file.zig+20-18
...@@ -23,10 +23,10 @@ pub const File = union(enum) {...@@ -23,10 +23,10 @@ pub const File = union(enum) {
23 _ = unused_fmt_string;23 _ = unused_fmt_string;
24 _ = options;24 _ = options;
25 switch (file) {25 switch (file) {
26 .zig_object => |x| try writer.print("{s}", .{x.path}),26 .zig_object => |zo| try writer.writeAll(zo.basename),
27 .linker_defined => try writer.writeAll("(linker defined)"),27 .linker_defined => try writer.writeAll("(linker defined)"),
28 .object => |x| try writer.print("{}", .{x.fmtPath()}),28 .object => |x| try writer.print("{}", .{x.fmtPath()}),
29 .shared_object => |x| try writer.writeAll(x.path),29 .shared_object => |x| try writer.print("{}", .{@as(Path, x.path)}),
30 }30 }
31 }31 }
3232
...@@ -240,30 +240,31 @@ pub const File = union(enum) {...@@ -240,30 +240,31 @@ pub const File = union(enum) {
240 return switch (file) {240 return switch (file) {
241 .zig_object => |x| x.updateArSymtab(ar_symtab, elf_file),241 .zig_object => |x| x.updateArSymtab(ar_symtab, elf_file),
242 .object => |x| x.updateArSymtab(ar_symtab, elf_file),242 .object => |x| x.updateArSymtab(ar_symtab, elf_file),
243 inline else => unreachable,243 else => unreachable,
244 };244 };
245 }245 }
246246
247 pub fn updateArStrtab(file: File, allocator: Allocator, ar_strtab: *Archive.ArStrtab) !void {247 pub fn updateArStrtab(file: File, allocator: Allocator, ar_strtab: *Archive.ArStrtab) !void {
248 const path = switch (file) {248 switch (file) {
249 .zig_object => |x| x.path,249 .zig_object => |zo| {
250 .object => |x| x.path,250 const basename = zo.basename;
251 inline else => unreachable,251 if (basename.len <= Archive.max_member_name_len) return;
252 };252 zo.output_ar_state.name_off = try ar_strtab.insert(allocator, basename);
253 const state = switch (file) {253 },
254 .zig_object => |x| &x.output_ar_state,254 .object => |o| {
255 .object => |x| &x.output_ar_state,255 const basename = std.fs.path.basename(o.path.sub_path);
256 inline else => unreachable,256 if (basename.len <= Archive.max_member_name_len) return;
257 };257 o.output_ar_state.name_off = try ar_strtab.insert(allocator, basename);
258 if (path.len <= Archive.max_member_name_len) return;258 },
259 state.name_off = try ar_strtab.insert(allocator, path);259 else => unreachable,
260 }
260 }261 }
261262
262 pub fn updateArSize(file: File, elf_file: *Elf) !void {263 pub fn updateArSize(file: File, elf_file: *Elf) !void {
263 return switch (file) {264 return switch (file) {
264 .zig_object => |x| x.updateArSize(),265 .zig_object => |x| x.updateArSize(),
265 .object => |x| x.updateArSize(elf_file),266 .object => |x| x.updateArSize(elf_file),
266 inline else => unreachable,267 else => unreachable,
267 };268 };
268 }269 }
269270
...@@ -271,7 +272,7 @@ pub const File = union(enum) {...@@ -271,7 +272,7 @@ pub const File = union(enum) {
271 return switch (file) {272 return switch (file) {
272 .zig_object => |x| x.writeAr(writer),273 .zig_object => |x| x.writeAr(writer),
273 .object => |x| x.writeAr(elf_file, writer),274 .object => |x| x.writeAr(elf_file, writer),
274 inline else => unreachable,275 else => unreachable,
275 };276 };
276 }277 }
277278
...@@ -292,8 +293,9 @@ pub const File = union(enum) {...@@ -292,8 +293,9 @@ pub const File = union(enum) {
292const std = @import("std");293const std = @import("std");
293const elf = std.elf;294const elf = std.elf;
294const log = std.log.scoped(.link);295const log = std.log.scoped(.link);
295296const Path = std.Build.Cache.Path;
296const Allocator = std.mem.Allocator;297const Allocator = std.mem.Allocator;
298
297const Archive = @import("Archive.zig");299const Archive = @import("Archive.zig");
298const Atom = @import("Atom.zig");300const Atom = @import("Atom.zig");
299const Cie = @import("eh_frame.zig").Cie;301const Cie = @import("eh_frame.zig").Cie;
src/link/Elf/relocatable.zig+15-11
...@@ -1,8 +1,8 @@...@@ -1,8 +1,8 @@
1pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {1pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) link.File.FlushError!void {
2 const gpa = comp.gpa;2 const gpa = comp.gpa;
33
4 for (comp.objects) |obj| {4 for (comp.objects) |obj| {
5 switch (Compilation.classifyFileExt(obj.path)) {5 switch (Compilation.classifyFileExt(obj.path.sub_path)) {
6 .object => try parseObjectStaticLibReportingFailure(elf_file, obj.path),6 .object => try parseObjectStaticLibReportingFailure(elf_file, obj.path),
7 .static_library => try parseArchiveStaticLibReportingFailure(elf_file, obj.path),7 .static_library => try parseArchiveStaticLibReportingFailure(elf_file, obj.path),
8 else => try elf_file.addParseError(obj.path, "unrecognized file extension", .{}),8 else => try elf_file.addParseError(obj.path, "unrecognized file extension", .{}),
...@@ -140,7 +140,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co...@@ -140,7 +140,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co
140 if (elf_file.base.hasErrors()) return error.FlushFailure;140 if (elf_file.base.hasErrors()) return error.FlushFailure;
141}141}
142142
143pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {143pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) link.File.FlushError!void {
144 for (comp.objects) |obj| {144 for (comp.objects) |obj| {
145 if (obj.isObject()) {145 if (obj.isObject()) {
146 try elf_file.parseObjectReportingFailure(obj.path);146 try elf_file.parseObjectReportingFailure(obj.path);
...@@ -198,7 +198,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const...@@ -198,7 +198,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const
198 if (elf_file.base.hasErrors()) return error.FlushFailure;198 if (elf_file.base.hasErrors()) return error.FlushFailure;
199}199}
200200
201fn parseObjectStaticLibReportingFailure(elf_file: *Elf, path: []const u8) error{OutOfMemory}!void {201fn parseObjectStaticLibReportingFailure(elf_file: *Elf, path: Path) error{OutOfMemory}!void {
202 parseObjectStaticLib(elf_file, path) catch |err| switch (err) {202 parseObjectStaticLib(elf_file, path) catch |err| switch (err) {
203 error.LinkFailure => return,203 error.LinkFailure => return,
204 error.OutOfMemory => return error.OutOfMemory,204 error.OutOfMemory => return error.OutOfMemory,
...@@ -206,7 +206,7 @@ fn parseObjectStaticLibReportingFailure(elf_file: *Elf, path: []const u8) error{...@@ -206,7 +206,7 @@ fn parseObjectStaticLibReportingFailure(elf_file: *Elf, path: []const u8) error{
206 };206 };
207}207}
208208
209fn parseArchiveStaticLibReportingFailure(elf_file: *Elf, path: []const u8) error{OutOfMemory}!void {209fn parseArchiveStaticLibReportingFailure(elf_file: *Elf, path: Path) error{OutOfMemory}!void {
210 parseArchiveStaticLib(elf_file, path) catch |err| switch (err) {210 parseArchiveStaticLib(elf_file, path) catch |err| switch (err) {
211 error.LinkFailure => return,211 error.LinkFailure => return,
212 error.OutOfMemory => return error.OutOfMemory,212 error.OutOfMemory => return error.OutOfMemory,
...@@ -214,14 +214,17 @@ fn parseArchiveStaticLibReportingFailure(elf_file: *Elf, path: []const u8) error...@@ -214,14 +214,17 @@ fn parseArchiveStaticLibReportingFailure(elf_file: *Elf, path: []const u8) error
214 };214 };
215}215}
216216
217fn parseObjectStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void {217fn parseObjectStaticLib(elf_file: *Elf, path: Path) Elf.ParseError!void {
218 const gpa = elf_file.base.comp.gpa;218 const gpa = elf_file.base.comp.gpa;
219 const handle = try std.fs.cwd().openFile(path, .{});219 const handle = try path.root_dir.handle.openFile(path.sub_path, .{});
220 const fh = try elf_file.addFileHandle(handle);220 const fh = try elf_file.addFileHandle(handle);
221221
222 const index = @as(File.Index, @intCast(try elf_file.files.addOne(gpa)));222 const index: File.Index = @intCast(try elf_file.files.addOne(gpa));
223 elf_file.files.set(index, .{ .object = .{223 elf_file.files.set(index, .{ .object = .{
224 .path = try gpa.dupe(u8, path),224 .path = .{
225 .root_dir = path.root_dir,
226 .sub_path = try gpa.dupe(u8, path.sub_path),
227 },
225 .file_handle = fh,228 .file_handle = fh,
226 .index = index,229 .index = index,
227 } });230 } });
...@@ -231,9 +234,9 @@ fn parseObjectStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void {...@@ -231,9 +234,9 @@ fn parseObjectStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
231 try object.parseAr(elf_file);234 try object.parseAr(elf_file);
232}235}
233236
234fn parseArchiveStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void {237fn parseArchiveStaticLib(elf_file: *Elf, path: Path) Elf.ParseError!void {
235 const gpa = elf_file.base.comp.gpa;238 const gpa = elf_file.base.comp.gpa;
236 const handle = try std.fs.cwd().openFile(path, .{});239 const handle = try path.root_dir.handle.openFile(path.sub_path, .{});
237 const fh = try elf_file.addFileHandle(handle);240 const fh = try elf_file.addFileHandle(handle);
238241
239 var archive = Archive{};242 var archive = Archive{};
...@@ -531,6 +534,7 @@ const log = std.log.scoped(.link);...@@ -531,6 +534,7 @@ const log = std.log.scoped(.link);
531const math = std.math;534const math = std.math;
532const mem = std.mem;535const mem = std.mem;
533const state_log = std.log.scoped(.link_state);536const state_log = std.log.scoped(.link_state);
537const Path = std.Build.Cache.Path;
534const std = @import("std");538const std = @import("std");
535539
536const Archive = @import("Archive.zig");540const Archive = @import("Archive.zig");
src/link/MachO.zig+57-47
...@@ -144,14 +144,14 @@ hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{},...@@ -144,14 +144,14 @@ hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{},
144pub const Framework = struct {144pub const Framework = struct {
145 needed: bool = false,145 needed: bool = false,
146 weak: bool = false,146 weak: bool = false,
147 path: []const u8,147 path: Path,
148};148};
149149
150pub fn hashAddFrameworks(man: *Cache.Manifest, hm: []const Framework) !void {150pub fn hashAddFrameworks(man: *Cache.Manifest, hm: []const Framework) !void {
151 for (hm) |value| {151 for (hm) |value| {
152 man.hash.add(value.needed);152 man.hash.add(value.needed);
153 man.hash.add(value.weak);153 man.hash.add(value.weak);
154 _ = try man.addFile(value.path, null);154 _ = try man.addFilePath(value.path, null);
155 }155 }
156}156}
157157
...@@ -239,9 +239,9 @@ pub fn createEmpty(...@@ -239,9 +239,9 @@ pub fn createEmpty(
239 const index: File.Index = @intCast(try self.files.addOne(gpa));239 const index: File.Index = @intCast(try self.files.addOne(gpa));
240 self.files.set(index, .{ .zig_object = .{240 self.files.set(index, .{ .zig_object = .{
241 .index = index,241 .index = index,
242 .path = try std.fmt.allocPrint(arena, "{s}.o", .{fs.path.stem(242 .basename = try std.fmt.allocPrint(arena, "{s}.o", .{
243 zcu.main_mod.root_src_path,243 fs.path.stem(zcu.main_mod.root_src_path),
244 )}),244 }),
245 } });245 } });
246 self.zig_object = index;246 self.zig_object = index;
247 const zo = self.getZigObject().?;247 const zo = self.getZigObject().?;
...@@ -356,13 +356,12 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -356,13 +356,12 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
356 defer sub_prog_node.end();356 defer sub_prog_node.end();
357357
358 const directory = self.base.emit.root_dir;358 const directory = self.base.emit.root_dir;
359 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});359 const module_obj_path: ?Path = if (self.base.zcu_object_sub_path) |path| .{
360 const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {360 .root_dir = directory,
361 if (fs.path.dirname(full_out_path)) |dirname| {361 .sub_path = if (fs.path.dirname(self.base.emit.sub_path)) |dirname|
362 break :blk try fs.path.join(arena, &.{ dirname, path });362 try fs.path.join(arena, &.{ dirname, path })
363 } else {363 else
364 break :blk path;364 path,
365 }
366 } else null;365 } else null;
367366
368 // --verbose-link367 // --verbose-link
...@@ -455,7 +454,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -455,7 +454,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
455 }454 }
456455
457 // Finally, link against compiler_rt.456 // Finally, link against compiler_rt.
458 const compiler_rt_path: ?[]const u8 = blk: {457 const compiler_rt_path: ?Path = blk: {
459 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;458 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
460 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;459 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;
461 break :blk null;460 break :blk null;
...@@ -567,7 +566,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -567,7 +566,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
567 // The most important here is to have the correct vm and filesize of the __LINKEDIT segment566 // The most important here is to have the correct vm and filesize of the __LINKEDIT segment
568 // where the code signature goes into.567 // where the code signature goes into.
569 var codesig = CodeSignature.init(self.getPageSize());568 var codesig = CodeSignature.init(self.getPageSize());
570 codesig.code_directory.ident = fs.path.basename(full_out_path);569 codesig.code_directory.ident = fs.path.basename(self.base.emit.sub_path);
571 if (self.entitlements) |path| try codesig.addEntitlements(gpa, path);570 if (self.entitlements) |path| try codesig.addEntitlements(gpa, path);
572 try self.writeCodeSignaturePadding(&codesig);571 try self.writeCodeSignaturePadding(&codesig);
573 break :blk codesig;572 break :blk codesig;
...@@ -625,11 +624,11 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {...@@ -625,11 +624,11 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
625624
626 if (self.base.isRelocatable()) {625 if (self.base.isRelocatable()) {
627 for (comp.objects) |obj| {626 for (comp.objects) |obj| {
628 try argv.append(obj.path);627 try argv.append(try obj.path.toString(arena));
629 }628 }
630629
631 for (comp.c_object_table.keys()) |key| {630 for (comp.c_object_table.keys()) |key| {
632 try argv.append(key.status.success.object_path);631 try argv.append(try key.status.success.object_path.toString(arena));
633 }632 }
634633
635 if (module_obj_path) |p| {634 if (module_obj_path) |p| {
...@@ -711,11 +710,11 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {...@@ -711,11 +710,11 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
711 if (obj.must_link) {710 if (obj.must_link) {
712 try argv.append("-force_load");711 try argv.append("-force_load");
713 }712 }
714 try argv.append(obj.path);713 try argv.append(try obj.path.toString(arena));
715 }714 }
716715
717 for (comp.c_object_table.keys()) |key| {716 for (comp.c_object_table.keys()) |key| {
718 try argv.append(key.status.success.object_path);717 try argv.append(try key.status.success.object_path.toString(arena));
719 }718 }
720719
721 if (module_obj_path) |p| {720 if (module_obj_path) |p| {
...@@ -723,13 +722,12 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {...@@ -723,13 +722,12 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
723 }722 }
724723
725 if (comp.config.any_sanitize_thread) {724 if (comp.config.any_sanitize_thread) {
726 const path = comp.tsan_lib.?.full_object_path;725 const path = try comp.tsan_lib.?.full_object_path.toString(arena);
727 try argv.append(path);726 try argv.appendSlice(&.{ path, "-rpath", std.fs.path.dirname(path) orelse "." });
728 try argv.appendSlice(&.{ "-rpath", std.fs.path.dirname(path) orelse "." });
729 }727 }
730728
731 if (comp.config.any_fuzz) {729 if (comp.config.any_fuzz) {
732 try argv.append(comp.fuzzer_lib.?.full_object_path);730 try argv.append(try comp.fuzzer_lib.?.full_object_path.toString(arena));
733 }731 }
734732
735 for (self.lib_dirs) |lib_dir| {733 for (self.lib_dirs) |lib_dir| {
...@@ -754,7 +752,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {...@@ -754,7 +752,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
754 }752 }
755753
756 for (self.frameworks) |framework| {754 for (self.frameworks) |framework| {
757 const name = fs.path.stem(framework.path);755 const name = framework.path.stem();
758 const arg = if (framework.needed)756 const arg = if (framework.needed)
759 try std.fmt.allocPrint(arena, "-needed_framework {s}", .{name})757 try std.fmt.allocPrint(arena, "-needed_framework {s}", .{name})
760 else if (framework.weak)758 else if (framework.weak)
...@@ -765,14 +763,16 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {...@@ -765,14 +763,16 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
765 }763 }
766764
767 if (comp.config.link_libcpp) {765 if (comp.config.link_libcpp) {
768 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);766 try argv.appendSlice(&.{
769 try argv.append(comp.libcxx_static_lib.?.full_object_path);767 try comp.libcxxabi_static_lib.?.full_object_path.toString(arena),
768 try comp.libcxx_static_lib.?.full_object_path.toString(arena),
769 });
770 }770 }
771771
772 try argv.append("-lSystem");772 try argv.append("-lSystem");
773773
774 if (comp.compiler_rt_lib) |lib| try argv.append(lib.full_object_path);774 if (comp.compiler_rt_lib) |lib| try argv.append(try lib.full_object_path.toString(arena));
775 if (comp.compiler_rt_obj) |obj| try argv.append(obj.full_object_path);775 if (comp.compiler_rt_obj) |obj| try argv.append(try obj.full_object_path.toString(arena));
776 }776 }
777777
778 Compilation.dump_argv(argv.items);778 Compilation.dump_argv(argv.items);
...@@ -807,20 +807,20 @@ pub fn resolveLibSystem(...@@ -807,20 +807,20 @@ pub fn resolveLibSystem(
807 return error.MissingLibSystem;807 return error.MissingLibSystem;
808 }808 }
809809
810 const libsystem_path = try arena.dupe(u8, test_path.items);810 const libsystem_path = Path.initCwd(try arena.dupe(u8, test_path.items));
811 try out_libs.append(.{811 try out_libs.append(.{
812 .needed = true,812 .needed = true,
813 .path = libsystem_path,813 .path = libsystem_path,
814 });814 });
815}815}
816816
817pub fn classifyInputFile(self: *MachO, path: []const u8, lib: SystemLib, must_link: bool) !void {817pub fn classifyInputFile(self: *MachO, path: Path, lib: SystemLib, must_link: bool) !void {
818 const tracy = trace(@src());818 const tracy = trace(@src());
819 defer tracy.end();819 defer tracy.end();
820820
821 log.debug("classifying input file {s}", .{path});821 log.debug("classifying input file {}", .{path});
822822
823 const file = try std.fs.cwd().openFile(path, .{});823 const file = try path.root_dir.handle.openFile(path.sub_path, .{});
824 const fh = try self.addFileHandle(file);824 const fh = try self.addFileHandle(file);
825 var buffer: [Archive.SARMAG]u8 = undefined;825 var buffer: [Archive.SARMAG]u8 = undefined;
826826
...@@ -844,7 +844,7 @@ pub fn classifyInputFile(self: *MachO, path: []const u8, lib: SystemLib, must_li...@@ -844,7 +844,7 @@ pub fn classifyInputFile(self: *MachO, path: []const u8, lib: SystemLib, must_li
844 _ = try self.addTbd(lib, true, fh);844 _ = try self.addTbd(lib, true, fh);
845}845}
846846
847fn parseFatFile(self: *MachO, file: std.fs.File, path: []const u8) !?fat.Arch {847fn parseFatFile(self: *MachO, file: std.fs.File, path: Path) !?fat.Arch {
848 const fat_h = fat.readFatHeader(file) catch return null;848 const fat_h = fat.readFatHeader(file) catch return null;
849 if (fat_h.magic != macho.FAT_MAGIC and fat_h.magic != macho.FAT_MAGIC_64) return null;849 if (fat_h.magic != macho.FAT_MAGIC and fat_h.magic != macho.FAT_MAGIC_64) return null;
850 var fat_archs_buffer: [2]fat.Arch = undefined;850 var fat_archs_buffer: [2]fat.Arch = undefined;
...@@ -873,7 +873,7 @@ pub fn readArMagic(file: std.fs.File, offset: usize, buffer: *[Archive.SARMAG]u8...@@ -873,7 +873,7 @@ pub fn readArMagic(file: std.fs.File, offset: usize, buffer: *[Archive.SARMAG]u8
873 return buffer[0..Archive.SARMAG];873 return buffer[0..Archive.SARMAG];
874}874}
875875
876fn addObject(self: *MachO, path: []const u8, handle: File.HandleIndex, offset: u64) !void {876fn addObject(self: *MachO, path: Path, handle: File.HandleIndex, offset: u64) !void {
877 const tracy = trace(@src());877 const tracy = trace(@src());
878 defer tracy.end();878 defer tracy.end();
879879
...@@ -886,7 +886,10 @@ fn addObject(self: *MachO, path: []const u8, handle: File.HandleIndex, offset: u...@@ -886,7 +886,10 @@ fn addObject(self: *MachO, path: []const u8, handle: File.HandleIndex, offset: u
886 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));886 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
887 self.files.set(index, .{ .object = .{887 self.files.set(index, .{ .object = .{
888 .offset = offset,888 .offset = offset,
889 .path = try gpa.dupe(u8, path),889 .path = .{
890 .root_dir = path.root_dir,
891 .sub_path = try gpa.dupe(u8, path.sub_path),
892 },
890 .file_handle = handle,893 .file_handle = handle,
891 .mtime = mtime,894 .mtime = mtime,
892 .index = index,895 .index = index,
...@@ -937,7 +940,7 @@ fn addArchive(self: *MachO, lib: SystemLib, must_link: bool, handle: File.Handle...@@ -937,7 +940,7 @@ fn addArchive(self: *MachO, lib: SystemLib, must_link: bool, handle: File.Handle
937940
938 const gpa = self.base.comp.gpa;941 const gpa = self.base.comp.gpa;
939942
940 var archive = Archive{};943 var archive: Archive = .{};
941 defer archive.deinit(gpa);944 defer archive.deinit(gpa);
942 try archive.unpack(self, lib.path, handle, fat_arch);945 try archive.unpack(self, lib.path, handle, fat_arch);
943946
...@@ -963,7 +966,10 @@ fn addDylib(self: *MachO, lib: SystemLib, explicit: bool, handle: File.HandleInd...@@ -963,7 +966,10 @@ fn addDylib(self: *MachO, lib: SystemLib, explicit: bool, handle: File.HandleInd
963 .offset = offset,966 .offset = offset,
964 .file_handle = handle,967 .file_handle = handle,
965 .tag = .dylib,968 .tag = .dylib,
966 .path = try gpa.dupe(u8, lib.path),969 .path = .{
970 .root_dir = lib.path.root_dir,
971 .sub_path = try gpa.dupe(u8, lib.path.sub_path),
972 },
967 .index = index,973 .index = index,
968 .needed = lib.needed,974 .needed = lib.needed,
969 .weak = lib.weak,975 .weak = lib.weak,
...@@ -986,7 +992,10 @@ fn addTbd(self: *MachO, lib: SystemLib, explicit: bool, handle: File.HandleIndex...@@ -986,7 +992,10 @@ fn addTbd(self: *MachO, lib: SystemLib, explicit: bool, handle: File.HandleIndex
986 .offset = 0,992 .offset = 0,
987 .file_handle = handle,993 .file_handle = handle,
988 .tag = .tbd,994 .tag = .tbd,
989 .path = try gpa.dupe(u8, lib.path),995 .path = .{
996 .root_dir = lib.path.root_dir,
997 .sub_path = try gpa.dupe(u8, lib.path.sub_path),
998 },
990 .index = index,999 .index = index,
991 .needed = lib.needed,1000 .needed = lib.needed,
992 .weak = lib.weak,1001 .weak = lib.weak,
...@@ -1175,11 +1184,11 @@ fn parseDependentDylibs(self: *MachO) !void {...@@ -1175,11 +1184,11 @@ fn parseDependentDylibs(self: *MachO) !void {
1175 continue;1184 continue;
1176 }1185 }
1177 };1186 };
1178 const lib = SystemLib{1187 const lib: SystemLib = .{
1179 .path = full_path,1188 .path = Path.initCwd(full_path),
1180 .weak = is_weak,1189 .weak = is_weak,
1181 };1190 };
1182 const file = try std.fs.cwd().openFile(lib.path, .{});1191 const file = try lib.path.root_dir.handle.openFile(lib.path.sub_path, .{});
1183 const fh = try self.addFileHandle(file);1192 const fh = try self.addFileHandle(file);
1184 const fat_arch = try self.parseFatFile(file, lib.path);1193 const fat_arch = try self.parseFatFile(file, lib.path);
1185 const offset = if (fat_arch) |fa| fa.offset else 0;1194 const offset = if (fat_arch) |fa| fa.offset else 0;
...@@ -2865,7 +2874,8 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {...@@ -2865,7 +2874,8 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
2865 ncmds += 1;2874 ncmds += 1;
2866 }2875 }
2867 if (comp.config.any_sanitize_thread) {2876 if (comp.config.any_sanitize_thread) {
2868 const path = comp.tsan_lib.?.full_object_path;2877 const path = try comp.tsan_lib.?.full_object_path.toString(gpa);
2878 defer gpa.free(path);
2869 const rpath = std.fs.path.dirname(path) orelse ".";2879 const rpath = std.fs.path.dirname(path) orelse ".";
2870 try load_commands.writeRpathLC(rpath, writer);2880 try load_commands.writeRpathLC(rpath, writer);
2871 ncmds += 1;2881 ncmds += 1;
...@@ -3758,13 +3768,13 @@ pub fn eatPrefix(path: []const u8, prefix: []const u8) ?[]const u8 {...@@ -3758,13 +3768,13 @@ pub fn eatPrefix(path: []const u8, prefix: []const u8) ?[]const u8 {
37583768
3759pub fn reportParseError(3769pub fn reportParseError(
3760 self: *MachO,3770 self: *MachO,
3761 path: []const u8,3771 path: Path,
3762 comptime format: []const u8,3772 comptime format: []const u8,
3763 args: anytype,3773 args: anytype,
3764) error{OutOfMemory}!void {3774) error{OutOfMemory}!void {
3765 var err = try self.base.addErrorWithNotes(1);3775 var err = try self.base.addErrorWithNotes(1);
3766 try err.addMsg(format, args);3776 try err.addMsg(format, args);
3767 try err.addNote("while parsing {s}", .{path});3777 try err.addNote("while parsing {}", .{path});
3768}3778}
37693779
3770pub fn reportParseError2(3780pub fn reportParseError2(
...@@ -3913,7 +3923,7 @@ fn fmtDumpState(...@@ -3913,7 +3923,7 @@ fn fmtDumpState(
3913 _ = options;3923 _ = options;
3914 _ = unused_fmt_string;3924 _ = unused_fmt_string;
3915 if (self.getZigObject()) |zo| {3925 if (self.getZigObject()) |zo| {
3916 try writer.print("zig_object({d}) : {s}\n", .{ zo.index, zo.path });3926 try writer.print("zig_object({d}) : {s}\n", .{ zo.index, zo.basename });
3917 try writer.print("{}{}\n", .{3927 try writer.print("{}{}\n", .{
3918 zo.fmtAtoms(self),3928 zo.fmtAtoms(self),
3919 zo.fmtSymtab(self),3929 zo.fmtSymtab(self),
...@@ -3938,9 +3948,9 @@ fn fmtDumpState(...@@ -3938,9 +3948,9 @@ fn fmtDumpState(
3938 }3948 }
3939 for (self.dylibs.items) |index| {3949 for (self.dylibs.items) |index| {
3940 const dylib = self.getFile(index).?.dylib;3950 const dylib = self.getFile(index).?.dylib;
3941 try writer.print("dylib({d}) : {s} : needed({}) : weak({})", .{3951 try writer.print("dylib({d}) : {} : needed({}) : weak({})", .{
3942 index,3952 index,
3943 dylib.path,3953 @as(Path, dylib.path),
3944 dylib.needed,3954 dylib.needed,
3945 dylib.weak,3955 dylib.weak,
3946 });3956 });
...@@ -4442,7 +4452,7 @@ pub const default_pagezero_size: u64 = 0x100000000;...@@ -4442,7 +4452,7 @@ pub const default_pagezero_size: u64 = 0x100000000;
4442pub const default_headerpad_size: u32 = 0x1000;4452pub const default_headerpad_size: u32 = 0x1000;
44434453
4444const SystemLib = struct {4454const SystemLib = struct {
4445 path: []const u8,4455 path: Path,
4446 needed: bool = false,4456 needed: bool = false,
4447 weak: bool = false,4457 weak: bool = false,
4448 hidden: bool = false,4458 hidden: bool = false,
src/link/MachO/Archive.zig+10-6
...@@ -4,7 +4,7 @@ pub fn deinit(self: *Archive, allocator: Allocator) void {...@@ -4,7 +4,7 @@ pub fn deinit(self: *Archive, allocator: Allocator) void {
4 self.objects.deinit(allocator);4 self.objects.deinit(allocator);
5}5}
66
7pub fn unpack(self: *Archive, macho_file: *MachO, path: []const u8, handle_index: File.HandleIndex, fat_arch: ?fat.Arch) !void {7pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File.HandleIndex, fat_arch: ?fat.Arch) !void {
8 const gpa = macho_file.base.comp.gpa;8 const gpa = macho_file.base.comp.gpa;
99
10 var arena = std.heap.ArenaAllocator.init(gpa);10 var arena = std.heap.ArenaAllocator.init(gpa);
...@@ -55,20 +55,23 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: []const u8, handle_index...@@ -55,20 +55,23 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: []const u8, handle_index
55 mem.eql(u8, name, SYMDEF_SORTED) or55 mem.eql(u8, name, SYMDEF_SORTED) or
56 mem.eql(u8, name, SYMDEF64_SORTED)) continue;56 mem.eql(u8, name, SYMDEF64_SORTED)) continue;
5757
58 const object = Object{58 const object: Object = .{
59 .offset = pos,59 .offset = pos,
60 .in_archive = .{60 .in_archive = .{
61 .path = try gpa.dupe(u8, path),61 .path = .{
62 .root_dir = path.root_dir,
63 .sub_path = try gpa.dupe(u8, path.sub_path),
64 },
62 .size = hdr_size,65 .size = hdr_size,
63 },66 },
64 .path = try gpa.dupe(u8, name),67 .path = Path.initCwd(try gpa.dupe(u8, name)),
65 .file_handle = handle_index,68 .file_handle = handle_index,
66 .index = undefined,69 .index = undefined,
67 .alive = false,70 .alive = false,
68 .mtime = hdr.date() catch 0,71 .mtime = hdr.date() catch 0,
69 };72 };
7073
71 log.debug("extracting object '{s}' from archive '{s}'", .{ object.path, path });74 log.debug("extracting object '{}' from archive '{}'", .{ object.path, path });
7275
73 try self.objects.append(gpa, object);76 try self.objects.append(gpa, object);
74 }77 }
...@@ -301,8 +304,9 @@ const log = std.log.scoped(.link);...@@ -301,8 +304,9 @@ const log = std.log.scoped(.link);
301const macho = std.macho;304const macho = std.macho;
302const mem = std.mem;305const mem = std.mem;
303const std = @import("std");306const std = @import("std");
304
305const Allocator = mem.Allocator;307const Allocator = mem.Allocator;
308const Path = std.Build.Cache.Path;
309
306const Archive = @This();310const Archive = @This();
307const File = @import("file.zig").File;311const File = @import("file.zig").File;
308const MachO = @import("../MachO.zig");312const MachO = @import("../MachO.zig");
src/link/MachO/Dylib.zig+6-5
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1/// Non-zero for fat dylibs1/// Non-zero for fat dylibs
2offset: u64,2offset: u64,
3path: []const u8,3path: Path,
4index: File.Index,4index: File.Index,
5file_handle: File.HandleIndex,5file_handle: File.HandleIndex,
6tag: enum { dylib, tbd },6tag: enum { dylib, tbd },
...@@ -28,7 +28,7 @@ referenced: bool = false,...@@ -28,7 +28,7 @@ referenced: bool = false,
28output_symtab_ctx: MachO.SymtabCtx = .{},28output_symtab_ctx: MachO.SymtabCtx = .{},
2929
30pub fn deinit(self: *Dylib, allocator: Allocator) void {30pub fn deinit(self: *Dylib, allocator: Allocator) void {
31 allocator.free(self.path);31 allocator.free(self.path.sub_path);
32 self.exports.deinit(allocator);32 self.exports.deinit(allocator);
33 self.strtab.deinit(allocator);33 self.strtab.deinit(allocator);
34 if (self.id) |*id| id.deinit(allocator);34 if (self.id) |*id| id.deinit(allocator);
...@@ -61,7 +61,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {...@@ -61,7 +61,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {
61 const file = macho_file.getFileHandle(self.file_handle);61 const file = macho_file.getFileHandle(self.file_handle);
62 const offset = self.offset;62 const offset = self.offset;
6363
64 log.debug("parsing dylib from binary: {s}", .{self.path});64 log.debug("parsing dylib from binary: {}", .{@as(Path, self.path)});
6565
66 var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;66 var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;
67 {67 {
...@@ -267,7 +267,7 @@ fn parseTbd(self: *Dylib, macho_file: *MachO) !void {...@@ -267,7 +267,7 @@ fn parseTbd(self: *Dylib, macho_file: *MachO) !void {
267267
268 const gpa = macho_file.base.comp.gpa;268 const gpa = macho_file.base.comp.gpa;
269269
270 log.debug("parsing dylib from stub: {s}", .{self.path});270 log.debug("parsing dylib from stub: {}", .{self.path});
271271
272 const file = macho_file.getFileHandle(self.file_handle);272 const file = macho_file.getFileHandle(self.file_handle);
273 var lib_stub = LibStub.loadFromFile(gpa, file) catch |err| {273 var lib_stub = LibStub.loadFromFile(gpa, file) catch |err| {
...@@ -959,8 +959,9 @@ const mem = std.mem;...@@ -959,8 +959,9 @@ const mem = std.mem;
959const tapi = @import("../tapi.zig");959const tapi = @import("../tapi.zig");
960const trace = @import("../../tracy.zig").trace;960const trace = @import("../../tracy.zig").trace;
961const std = @import("std");961const std = @import("std");
962
963const Allocator = mem.Allocator;962const Allocator = mem.Allocator;
963const Path = std.Build.Cache.Path;
964
964const Dylib = @This();965const Dylib = @This();
965const File = @import("file.zig").File;966const File = @import("file.zig").File;
966const LibStub = tapi.LibStub;967const LibStub = tapi.LibStub;
src/link/MachO/Object.zig+45-18
...@@ -1,6 +1,8 @@...@@ -1,6 +1,8 @@
1/// Non-zero for fat object files or archives1/// Non-zero for fat object files or archives
2offset: u64,2offset: u64,
3path: []const u8,3/// Archive files cannot contain subdirectories, so only the basename is needed
4/// for output. However, the full path is kept for error reporting.
5path: Path,
4file_handle: File.HandleIndex,6file_handle: File.HandleIndex,
5mtime: u64,7mtime: u64,
6index: File.Index,8index: File.Index,
...@@ -39,8 +41,8 @@ output_symtab_ctx: MachO.SymtabCtx = .{},...@@ -39,8 +41,8 @@ output_symtab_ctx: MachO.SymtabCtx = .{},
39output_ar_state: Archive.ArState = .{},41output_ar_state: Archive.ArState = .{},
4042
41pub fn deinit(self: *Object, allocator: Allocator) void {43pub fn deinit(self: *Object, allocator: Allocator) void {
42 if (self.in_archive) |*ar| allocator.free(ar.path);44 if (self.in_archive) |*ar| allocator.free(ar.path.sub_path);
43 allocator.free(self.path);45 allocator.free(self.path.sub_path);
44 for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| {46 for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| {
45 relocs.deinit(allocator);47 relocs.deinit(allocator);
46 sub.deinit(allocator);48 sub.deinit(allocator);
...@@ -1723,7 +1725,8 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void {...@@ -1723,7 +1725,8 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void {
1723pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void {1725pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void {
1724 // Header1726 // Header
1725 const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;1727 const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;
1726 try Archive.writeHeader(self.path, size, ar_format, writer);1728 const basename = std.fs.path.basename(self.path.sub_path);
1729 try Archive.writeHeader(basename, size, ar_format, writer);
1727 // Data1730 // Data
1728 const file = macho_file.getFileHandle(self.file_handle);1731 const file = macho_file.getFileHandle(self.file_handle);
1729 // TODO try using copyRangeAll1732 // TODO try using copyRangeAll
...@@ -1774,6 +1777,11 @@ pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void {...@@ -1774,6 +1777,11 @@ pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void {
1774 self.calcStabsSize(macho_file);1777 self.calcStabsSize(macho_file);
1775}1778}
17761779
1780fn pathLen(path: Path) usize {
1781 // +1 for the path separator
1782 return (if (path.root_dir.path) |p| p.len + @intFromBool(path.sub_path.len != 0) else 0) + path.sub_path.len;
1783}
1784
1777pub fn calcStabsSize(self: *Object, macho_file: *MachO) void {1785pub fn calcStabsSize(self: *Object, macho_file: *MachO) void {
1778 if (self.compile_unit) |cu| {1786 if (self.compile_unit) |cu| {
1779 const comp_dir = cu.getCompDir(self.*);1787 const comp_dir = cu.getCompDir(self.*);
...@@ -1784,9 +1792,9 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) void {...@@ -1784,9 +1792,9 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) void {
1784 self.output_symtab_ctx.strsize += @as(u32, @intCast(tu_name.len + 1)); // tu_name1792 self.output_symtab_ctx.strsize += @as(u32, @intCast(tu_name.len + 1)); // tu_name
17851793
1786 if (self.in_archive) |ar| {1794 if (self.in_archive) |ar| {
1787 self.output_symtab_ctx.strsize += @as(u32, @intCast(ar.path.len + 1 + self.path.len + 1 + 1));1795 self.output_symtab_ctx.strsize += @intCast(pathLen(ar.path) + 1 + self.path.basename().len + 1 + 1);
1788 } else {1796 } else {
1789 self.output_symtab_ctx.strsize += @as(u32, @intCast(self.path.len + 1));1797 self.output_symtab_ctx.strsize += @intCast(pathLen(self.path) + 1);
1790 }1798 }
17911799
1792 for (self.symbols.items, 0..) |sym, i| {1800 for (self.symbols.items, 0..) |sym, i| {
...@@ -2118,19 +2126,36 @@ pub fn writeStabs(self: Object, stroff: u32, macho_file: *MachO, ctx: anytype) v...@@ -2118,19 +2126,36 @@ pub fn writeStabs(self: Object, stroff: u32, macho_file: *MachO, ctx: anytype) v
2118 };2126 };
2119 index += 1;2127 index += 1;
2120 if (self.in_archive) |ar| {2128 if (self.in_archive) |ar| {
2121 @memcpy(ctx.strtab.items[n_strx..][0..ar.path.len], ar.path);2129 if (ar.path.root_dir.path) |p| {
2122 n_strx += @intCast(ar.path.len);2130 @memcpy(ctx.strtab.items[n_strx..][0..p.len], p);
2131 n_strx += @intCast(p.len);
2132 if (ar.path.sub_path.len != 0) {
2133 ctx.strtab.items[n_strx] = '/';
2134 n_strx += 1;
2135 }
2136 }
2137 @memcpy(ctx.strtab.items[n_strx..][0..ar.path.sub_path.len], ar.path.sub_path);
2138 n_strx += @intCast(ar.path.sub_path.len);
2123 ctx.strtab.items[n_strx] = '(';2139 ctx.strtab.items[n_strx] = '(';
2124 n_strx += 1;2140 n_strx += 1;
2125 @memcpy(ctx.strtab.items[n_strx..][0..self.path.len], self.path);2141 const basename = self.path.basename();
2126 n_strx += @intCast(self.path.len);2142 @memcpy(ctx.strtab.items[n_strx..][0..basename.len], basename);
2143 n_strx += @intCast(basename.len);
2127 ctx.strtab.items[n_strx] = ')';2144 ctx.strtab.items[n_strx] = ')';
2128 n_strx += 1;2145 n_strx += 1;
2129 ctx.strtab.items[n_strx] = 0;2146 ctx.strtab.items[n_strx] = 0;
2130 n_strx += 1;2147 n_strx += 1;
2131 } else {2148 } else {
2132 @memcpy(ctx.strtab.items[n_strx..][0..self.path.len], self.path);2149 if (self.path.root_dir.path) |p| {
2133 n_strx += @intCast(self.path.len);2150 @memcpy(ctx.strtab.items[n_strx..][0..p.len], p);
2151 n_strx += @intCast(p.len);
2152 if (self.path.sub_path.len != 0) {
2153 ctx.strtab.items[n_strx] = '/';
2154 n_strx += 1;
2155 }
2156 }
2157 @memcpy(ctx.strtab.items[n_strx..][0..self.path.sub_path.len], self.path.sub_path);
2158 n_strx += @intCast(self.path.sub_path.len);
2134 ctx.strtab.items[n_strx] = 0;2159 ctx.strtab.items[n_strx] = 0;
2135 n_strx += 1;2160 n_strx += 1;
2136 }2161 }
...@@ -2666,11 +2691,12 @@ fn formatPath(...@@ -2666,11 +2691,12 @@ fn formatPath(
2666 _ = unused_fmt_string;2691 _ = unused_fmt_string;
2667 _ = options;2692 _ = options;
2668 if (object.in_archive) |ar| {2693 if (object.in_archive) |ar| {
2669 try writer.writeAll(ar.path);2694 try writer.print("{}({s})", .{
2670 try writer.writeByte('(');2695 @as(Path, ar.path), object.path.basename(),
2671 try writer.writeAll(object.path);2696 });
2672 try writer.writeByte(')');2697 } else {
2673 } else try writer.writeAll(object.path);2698 try writer.print("{}", .{@as(Path, object.path)});
2699 }
2674}2700}
26752701
2676const Section = struct {2702const Section = struct {
...@@ -2777,7 +2803,7 @@ const CompileUnit = struct {...@@ -2777,7 +2803,7 @@ const CompileUnit = struct {
2777};2803};
27782804
2779const InArchive = struct {2805const InArchive = struct {
2780 path: []const u8,2806 path: Path,
2781 size: u32,2807 size: u32,
2782};2808};
27832809
...@@ -3170,6 +3196,7 @@ const math = std.math;...@@ -3170,6 +3196,7 @@ const math = std.math;
3170const mem = std.mem;3196const mem = std.mem;
3171const trace = @import("../../tracy.zig").trace;3197const trace = @import("../../tracy.zig").trace;
3172const std = @import("std");3198const std = @import("std");
3199const Path = std.Build.Cache.Path;
31733200
3174const Allocator = mem.Allocator;3201const Allocator = mem.Allocator;
3175const Archive = @import("Archive.zig");3202const Archive = @import("Archive.zig");
src/link/MachO/ZigObject.zig+2-2
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1data: std.ArrayListUnmanaged(u8) = .empty,1data: std.ArrayListUnmanaged(u8) = .empty,
2/// Externally owned memory.2/// Externally owned memory.
3path: []const u8,3basename: []const u8,
4index: File.Index,4index: File.Index,
55
6symtab: std.MultiArrayList(Nlist) = .{},6symtab: std.MultiArrayList(Nlist) = .{},
...@@ -317,7 +317,7 @@ pub fn updateArSize(self: *ZigObject) void {...@@ -317,7 +317,7 @@ pub fn updateArSize(self: *ZigObject) void {
317pub fn writeAr(self: ZigObject, ar_format: Archive.Format, writer: anytype) !void {317pub fn writeAr(self: ZigObject, ar_format: Archive.Format, writer: anytype) !void {
318 // Header318 // Header
319 const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;319 const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;
320 try Archive.writeHeader(self.path, size, ar_format, writer);320 try Archive.writeHeader(self.basename, size, ar_format, writer);
321 // Data321 // Data
322 try writer.writeAll(self.data.items);322 try writer.writeAll(self.data.items);
323}323}
src/link/MachO/file.zig+6-5
...@@ -23,10 +23,10 @@ pub const File = union(enum) {...@@ -23,10 +23,10 @@ pub const File = union(enum) {
23 _ = unused_fmt_string;23 _ = unused_fmt_string;
24 _ = options;24 _ = options;
25 switch (file) {25 switch (file) {
26 .zig_object => |x| try writer.writeAll(x.path),26 .zig_object => |zo| try writer.writeAll(zo.basename),
27 .internal => try writer.writeAll("internal"),27 .internal => try writer.writeAll("internal"),
28 .object => |x| try writer.print("{}", .{x.fmtPath()}),28 .object => |x| try writer.print("{}", .{x.fmtPath()}),
29 .dylib => |x| try writer.writeAll(x.path),29 .dylib => |dl| try writer.print("{}", .{@as(Path, dl.path)}),
30 }30 }
31 }31 }
3232
...@@ -373,13 +373,14 @@ pub const File = union(enum) {...@@ -373,13 +373,14 @@ pub const File = union(enum) {
373 pub const HandleIndex = Index;373 pub const HandleIndex = Index;
374};374};
375375
376const std = @import("std");
376const assert = std.debug.assert;377const assert = std.debug.assert;
377const log = std.log.scoped(.link);378const log = std.log.scoped(.link);
378const macho = std.macho;379const macho = std.macho;
379const std = @import("std");
380const trace = @import("../../tracy.zig").trace;
381
382const Allocator = std.mem.Allocator;380const Allocator = std.mem.Allocator;
381const Path = std.Build.Cache.Path;
382
383const trace = @import("../../tracy.zig").trace;
383const Archive = @import("Archive.zig");384const Archive = @import("Archive.zig");
384const Atom = @import("Atom.zig");385const Atom = @import("Atom.zig");
385const InternalObject = @import("InternalObject.zig");386const InternalObject = @import("InternalObject.zig");
src/link/MachO/load_commands.zig+2-1
...@@ -72,7 +72,8 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32...@@ -72,7 +72,8 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32
72 }72 }
7373
74 if (comp.config.any_sanitize_thread) {74 if (comp.config.any_sanitize_thread) {
75 const path = comp.tsan_lib.?.full_object_path;75 const path = try comp.tsan_lib.?.full_object_path.toString(gpa);
76 defer gpa.free(path);
76 const rpath = std.fs.path.dirname(path) orelse ".";77 const rpath = std.fs.path.dirname(path) orelse ".";
77 sizeofcmds += calcInstallNameLen(78 sizeofcmds += calcInstallNameLen(
78 @sizeOf(macho.rpath_command),79 @sizeOf(macho.rpath_command),
src/link/MachO/relocatable.zig+23-17
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {1pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Path) link.File.FlushError!void {
2 const gpa = macho_file.base.comp.gpa;2 const gpa = macho_file.base.comp.gpa;
33
4 // TODO: "positional arguments" is a CLI concept, not a linker concept. Delete this unnecessary array list.
4 var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);5 var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);
5 defer positionals.deinit();6 defer positionals.deinit();
6 try positionals.ensureUnusedCapacity(comp.objects.len);7 try positionals.ensureUnusedCapacity(comp.objects.len);
...@@ -19,7 +20,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]c...@@ -19,7 +20,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]c
19 // TODO: in the future, when we implement `dsymutil` alternative directly in the Zig20 // TODO: in the future, when we implement `dsymutil` alternative directly in the Zig
20 // compiler, investigate if we can get rid of this `if` prong here.21 // compiler, investigate if we can get rid of this `if` prong here.
21 const path = positionals.items[0].path;22 const path = positionals.items[0].path;
22 const in_file = try std.fs.cwd().openFile(path, .{});23 const in_file = try path.root_dir.handle.openFile(path.sub_path, .{});
23 const stat = try in_file.stat();24 const stat = try in_file.stat();
24 const amt = try in_file.copyRangeAll(0, macho_file.base.file.?, 0, stat.size);25 const amt = try in_file.copyRangeAll(0, macho_file.base.file.?, 0, stat.size);
25 if (amt != stat.size) return error.InputOutput; // TODO: report an actual user error26 if (amt != stat.size) return error.InputOutput; // TODO: report an actual user error
...@@ -72,7 +73,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]c...@@ -72,7 +73,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]c
72 try writeHeader(macho_file, ncmds, sizeofcmds);73 try writeHeader(macho_file, ncmds, sizeofcmds);
73}74}
7475
75pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {76pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Path) link.File.FlushError!void {
76 const gpa = comp.gpa;77 const gpa = comp.gpa;
7778
78 var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);79 var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);
...@@ -173,21 +174,25 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -173,21 +174,25 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
173174
174 for (files.items) |index| {175 for (files.items) |index| {
175 const file = macho_file.getFile(index).?;176 const file = macho_file.getFile(index).?;
176 const state = switch (file) {177 switch (file) {
177 .zig_object => |x| &x.output_ar_state,178 .zig_object => |zo| {
178 .object => |x| &x.output_ar_state,179 const state = &zo.output_ar_state;
180 pos = mem.alignForward(usize, pos, 2);
181 state.file_off = pos;
182 pos += @sizeOf(Archive.ar_hdr);
183 pos += mem.alignForward(usize, zo.basename.len + 1, ptr_width);
184 pos += math.cast(usize, state.size) orelse return error.Overflow;
185 },
186 .object => |o| {
187 const state = &o.output_ar_state;
188 pos = mem.alignForward(usize, pos, 2);
189 state.file_off = pos;
190 pos += @sizeOf(Archive.ar_hdr);
191 pos += mem.alignForward(usize, o.path.basename().len + 1, ptr_width);
192 pos += math.cast(usize, state.size) orelse return error.Overflow;
193 },
179 else => unreachable,194 else => unreachable,
180 };195 }
181 const path = switch (file) {
182 .zig_object => |x| x.path,
183 .object => |x| x.path,
184 else => unreachable,
185 };
186 pos = mem.alignForward(usize, pos, 2);
187 state.file_off = pos;
188 pos += @sizeOf(Archive.ar_hdr);
189 pos += mem.alignForward(usize, path.len + 1, ptr_width);
190 pos += math.cast(usize, state.size) orelse return error.Overflow;
191 }196 }
192197
193 break :blk pos;198 break :blk pos;
...@@ -777,6 +782,7 @@ const mem = std.mem;...@@ -777,6 +782,7 @@ const mem = std.mem;
777const state_log = std.log.scoped(.link_state);782const state_log = std.log.scoped(.link_state);
778const std = @import("std");783const std = @import("std");
779const trace = @import("../../tracy.zig").trace;784const trace = @import("../../tracy.zig").trace;
785const Path = std.Build.Cache.Path;
780786
781const Archive = @import("Archive.zig");787const Archive = @import("Archive.zig");
782const Atom = @import("Atom.zig");788const Atom = @import("Atom.zig");
src/link/StringTable.zig+1-1
...@@ -15,7 +15,7 @@ pub fn insert(self: *Self, gpa: Allocator, string: []const u8) !u32 {...@@ -15,7 +15,7 @@ pub fn insert(self: *Self, gpa: Allocator, string: []const u8) !u32 {
15 if (gop.found_existing) return gop.key_ptr.*;15 if (gop.found_existing) return gop.key_ptr.*;
1616
17 try self.buffer.ensureUnusedCapacity(gpa, string.len + 1);17 try self.buffer.ensureUnusedCapacity(gpa, string.len + 1);
18 const new_off = @as(u32, @intCast(self.buffer.items.len));18 const new_off: u32 = @intCast(self.buffer.items.len);
1919
20 self.buffer.appendSliceAssumeCapacity(string);20 self.buffer.appendSliceAssumeCapacity(string);
21 self.buffer.appendAssumeCapacity(0);21 self.buffer.appendAssumeCapacity(0);
src/link/Wasm.zig+31-28
...@@ -2507,6 +2507,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -2507,6 +2507,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
2507 } else null;2507 } else null;
25082508
2509 // Positional arguments to the linker such as object files and static archives.2509 // Positional arguments to the linker such as object files and static archives.
2510 // TODO: "positional arguments" is a CLI concept, not a linker concept. Delete this unnecessary array list.
2510 var positionals = std.ArrayList([]const u8).init(arena);2511 var positionals = std.ArrayList([]const u8).init(arena);
2511 try positionals.ensureUnusedCapacity(comp.objects.len);2512 try positionals.ensureUnusedCapacity(comp.objects.len);
25122513
...@@ -2527,23 +2528,23 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -2527,23 +2528,23 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
2527 (output_mode == .Lib and link_mode == .dynamic);2528 (output_mode == .Lib and link_mode == .dynamic);
2528 if (is_exe_or_dyn_lib) {2529 if (is_exe_or_dyn_lib) {
2529 for (comp.wasi_emulated_libs) |crt_file| {2530 for (comp.wasi_emulated_libs) |crt_file| {
2530 try positionals.append(try comp.get_libc_crt_file(2531 try positionals.append(try comp.crtFileAsString(
2531 arena,2532 arena,
2532 wasi_libc.emulatedLibCRFileLibName(crt_file),2533 wasi_libc.emulatedLibCRFileLibName(crt_file),
2533 ));2534 ));
2534 }2535 }
25352536
2536 if (link_libc) {2537 if (link_libc) {
2537 try positionals.append(try comp.get_libc_crt_file(2538 try positionals.append(try comp.crtFileAsString(
2538 arena,2539 arena,
2539 wasi_libc.execModelCrtFileFullName(wasi_exec_model),2540 wasi_libc.execModelCrtFileFullName(wasi_exec_model),
2540 ));2541 ));
2541 try positionals.append(try comp.get_libc_crt_file(arena, "libc.a"));2542 try positionals.append(try comp.crtFileAsString(arena, "libc.a"));
2542 }2543 }
25432544
2544 if (link_libcpp) {2545 if (link_libcpp) {
2545 try positionals.append(comp.libcxx_static_lib.?.full_object_path);2546 try positionals.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena));
2546 try positionals.append(comp.libcxxabi_static_lib.?.full_object_path);2547 try positionals.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena));
2547 }2548 }
2548 }2549 }
2549 }2550 }
...@@ -2553,15 +2554,15 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no...@@ -2553,15 +2554,15 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
2553 }2554 }
25542555
2555 for (comp.objects) |object| {2556 for (comp.objects) |object| {
2556 try positionals.append(object.path);2557 try positionals.append(try object.path.toString(arena));
2557 }2558 }
25582559
2559 for (comp.c_object_table.keys()) |c_object| {2560 for (comp.c_object_table.keys()) |c_object| {
2560 try positionals.append(c_object.status.success.object_path);2561 try positionals.append(try c_object.status.success.object_path.toString(arena));
2561 }2562 }
25622563
2563 if (comp.compiler_rt_lib) |lib| try positionals.append(lib.full_object_path);2564 if (comp.compiler_rt_lib) |lib| try positionals.append(try lib.full_object_path.toString(arena));
2564 if (comp.compiler_rt_obj) |obj| try positionals.append(obj.full_object_path);2565 if (comp.compiler_rt_obj) |obj| try positionals.append(try obj.full_object_path.toString(arena));
25652566
2566 try wasm.parseInputFiles(positionals.items);2567 try wasm.parseInputFiles(positionals.items);
25672568
...@@ -3365,7 +3366,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:...@@ -3365,7 +3366,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
3365 defer sub_prog_node.end();3366 defer sub_prog_node.end();
33663367
3367 const is_obj = comp.config.output_mode == .Obj;3368 const is_obj = comp.config.output_mode == .Obj;
3368 const compiler_rt_path: ?[]const u8 = blk: {3369 const compiler_rt_path: ?Path = blk: {
3369 if (comp.compiler_rt_lib) |lib| break :blk lib.full_object_path;3370 if (comp.compiler_rt_lib) |lib| break :blk lib.full_object_path;
3370 if (comp.compiler_rt_obj) |obj| break :blk obj.full_object_path;3371 if (comp.compiler_rt_obj) |obj| break :blk obj.full_object_path;
3371 break :blk null;3372 break :blk null;
...@@ -3387,14 +3388,14 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:...@@ -3387,14 +3388,14 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
3387 comptime assert(Compilation.link_hash_implementation_version == 14);3388 comptime assert(Compilation.link_hash_implementation_version == 14);
33883389
3389 for (comp.objects) |obj| {3390 for (comp.objects) |obj| {
3390 _ = try man.addFile(obj.path, null);3391 _ = try man.addFilePath(obj.path, null);
3391 man.hash.add(obj.must_link);3392 man.hash.add(obj.must_link);
3392 }3393 }
3393 for (comp.c_object_table.keys()) |key| {3394 for (comp.c_object_table.keys()) |key| {
3394 _ = try man.addFile(key.status.success.object_path, null);3395 _ = try man.addFilePath(key.status.success.object_path, null);
3395 }3396 }
3396 try man.addOptionalFile(module_obj_path);3397 try man.addOptionalFile(module_obj_path);
3397 try man.addOptionalFile(compiler_rt_path);3398 try man.addOptionalFilePath(compiler_rt_path);
3398 man.hash.addOptionalBytes(wasm.entry_name);3399 man.hash.addOptionalBytes(wasm.entry_name);
3399 man.hash.add(wasm.base.stack_size);3400 man.hash.add(wasm.base.stack_size);
3400 man.hash.add(wasm.base.build_id);3401 man.hash.add(wasm.base.build_id);
...@@ -3450,17 +3451,19 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:...@@ -3450,17 +3451,19 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
3450 break :blk comp.c_object_table.keys()[0].status.success.object_path;3451 break :blk comp.c_object_table.keys()[0].status.success.object_path;
34513452
3452 if (module_obj_path) |p|3453 if (module_obj_path) |p|
3453 break :blk p;3454 break :blk Path.initCwd(p);
34543455
3455 // TODO I think this is unreachable. Audit this situation when solving the above TODO3456 // TODO I think this is unreachable. Audit this situation when solving the above TODO
3456 // regarding eliding redundant object -> object transformations.3457 // regarding eliding redundant object -> object transformations.
3457 return error.NoObjectsToLink;3458 return error.NoObjectsToLink;
3458 };3459 };
3459 // This can happen when using --enable-cache and using the stage1 backend. In this case3460 try std.fs.Dir.copyFile(
3460 // we can skip the file copy.3461 the_object_path.root_dir.handle,
3461 if (!mem.eql(u8, the_object_path, full_out_path)) {3462 the_object_path.sub_path,
3462 try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});3463 directory.handle,
3463 }3464 wasm.base.emit.sub_path,
3465 .{},
3466 );
3464 } else {3467 } else {
3465 // Create an LLD command line and invoke it.3468 // Create an LLD command line and invoke it.
3466 var argv = std.ArrayList([]const u8).init(gpa);3469 var argv = std.ArrayList([]const u8).init(gpa);
...@@ -3581,23 +3584,23 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:...@@ -3581,23 +3584,23 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
3581 (comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic);3584 (comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic);
3582 if (is_exe_or_dyn_lib) {3585 if (is_exe_or_dyn_lib) {
3583 for (comp.wasi_emulated_libs) |crt_file| {3586 for (comp.wasi_emulated_libs) |crt_file| {
3584 try argv.append(try comp.get_libc_crt_file(3587 try argv.append(try comp.crtFileAsString(
3585 arena,3588 arena,
3586 wasi_libc.emulatedLibCRFileLibName(crt_file),3589 wasi_libc.emulatedLibCRFileLibName(crt_file),
3587 ));3590 ));
3588 }3591 }
35893592
3590 if (comp.config.link_libc) {3593 if (comp.config.link_libc) {
3591 try argv.append(try comp.get_libc_crt_file(3594 try argv.append(try comp.crtFileAsString(
3592 arena,3595 arena,
3593 wasi_libc.execModelCrtFileFullName(comp.config.wasi_exec_model),3596 wasi_libc.execModelCrtFileFullName(comp.config.wasi_exec_model),
3594 ));3597 ));
3595 try argv.append(try comp.get_libc_crt_file(arena, "libc.a"));3598 try argv.append(try comp.crtFileAsString(arena, "libc.a"));
3596 }3599 }
35973600
3598 if (comp.config.link_libcpp) {3601 if (comp.config.link_libcpp) {
3599 try argv.append(comp.libcxx_static_lib.?.full_object_path);3602 try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena));
3600 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);3603 try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena));
3601 }3604 }
3602 }3605 }
3603 }3606 }
...@@ -3612,7 +3615,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:...@@ -3612,7 +3615,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
3612 try argv.append("-no-whole-archive");3615 try argv.append("-no-whole-archive");
3613 whole_archive = false;3616 whole_archive = false;
3614 }3617 }
3615 try argv.append(obj.path);3618 try argv.append(try obj.path.toString(arena));
3616 }3619 }
3617 if (whole_archive) {3620 if (whole_archive) {
3618 try argv.append("-no-whole-archive");3621 try argv.append("-no-whole-archive");
...@@ -3620,7 +3623,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:...@@ -3620,7 +3623,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
3620 }3623 }
36213624
3622 for (comp.c_object_table.keys()) |key| {3625 for (comp.c_object_table.keys()) |key| {
3623 try argv.append(key.status.success.object_path);3626 try argv.append(try key.status.success.object_path.toString(arena));
3624 }3627 }
3625 if (module_obj_path) |p| {3628 if (module_obj_path) |p| {
3626 try argv.append(p);3629 try argv.append(p);
...@@ -3630,11 +3633,11 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:...@@ -3630,11 +3633,11 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
3630 !comp.skip_linker_dependencies and3633 !comp.skip_linker_dependencies and
3631 !comp.config.link_libc)3634 !comp.config.link_libc)
3632 {3635 {
3633 try argv.append(comp.libc_static_lib.?.full_object_path);3636 try argv.append(try comp.libc_static_lib.?.full_object_path.toString(arena));
3634 }3637 }
36353638
3636 if (compiler_rt_path) |p| {3639 if (compiler_rt_path) |p| {
3637 try argv.append(p);3640 try argv.append(try p.toString(arena));
3638 }3641 }
36393642
3640 if (comp.verbose_link) {3643 if (comp.verbose_link) {
src/main.zig+24-23
...@@ -13,6 +13,12 @@ const warn = std.log.warn;...@@ -13,6 +13,12 @@ const warn = std.log.warn;
13const ThreadPool = std.Thread.Pool;13const ThreadPool = std.Thread.Pool;
14const cleanExit = std.process.cleanExit;14const cleanExit = std.process.cleanExit;
15const native_os = builtin.os.tag;15const native_os = builtin.os.tag;
16const Cache = std.Build.Cache;
17const Path = std.Build.Cache.Path;
18const EnvVar = std.zig.EnvVar;
19const LibCInstallation = std.zig.LibCInstallation;
20const AstGen = std.zig.AstGen;
21const Server = std.zig.Server;
1622
17const tracy = @import("tracy.zig");23const tracy = @import("tracy.zig");
18const Compilation = @import("Compilation.zig");24const Compilation = @import("Compilation.zig");
...@@ -20,16 +26,11 @@ const link = @import("link.zig");...@@ -20,16 +26,11 @@ const link = @import("link.zig");
20const Package = @import("Package.zig");26const Package = @import("Package.zig");
21const build_options = @import("build_options");27const build_options = @import("build_options");
22const introspect = @import("introspect.zig");28const introspect = @import("introspect.zig");
23const EnvVar = std.zig.EnvVar;
24const LibCInstallation = std.zig.LibCInstallation;
25const wasi_libc = @import("wasi_libc.zig");29const wasi_libc = @import("wasi_libc.zig");
26const Cache = std.Build.Cache;
27const target_util = @import("target.zig");30const target_util = @import("target.zig");
28const crash_report = @import("crash_report.zig");31const crash_report = @import("crash_report.zig");
29const Zcu = @import("Zcu.zig");32const Zcu = @import("Zcu.zig");
30const AstGen = std.zig.AstGen;
31const mingw = @import("mingw.zig");33const mingw = @import("mingw.zig");
32const Server = std.zig.Server;
33const dev = @import("dev.zig");34const dev = @import("dev.zig");
3435
35pub const std_options = .{36pub const std_options = .{
...@@ -1724,14 +1725,14 @@ fn buildOutputType(...@@ -1724,14 +1725,14 @@ fn buildOutputType(
1724 }1725 }
1725 } else switch (file_ext orelse Compilation.classifyFileExt(arg)) {1726 } else switch (file_ext orelse Compilation.classifyFileExt(arg)) {
1726 .shared_library => {1727 .shared_library => {
1727 try create_module.link_objects.append(arena, .{ .path = arg });1728 try create_module.link_objects.append(arena, .{ .path = Path.initCwd(arg) });
1728 create_module.opts.any_dyn_libs = true;1729 create_module.opts.any_dyn_libs = true;
1729 },1730 },
1730 .object, .static_library => {1731 .object, .static_library => {
1731 try create_module.link_objects.append(arena, .{ .path = arg });1732 try create_module.link_objects.append(arena, .{ .path = Path.initCwd(arg) });
1732 },1733 },
1733 .res => {1734 .res => {
1734 try create_module.link_objects.append(arena, .{ .path = arg });1735 try create_module.link_objects.append(arena, .{ .path = Path.initCwd(arg) });
1735 contains_res_file = true;1736 contains_res_file = true;
1736 },1737 },
1737 .manifest => {1738 .manifest => {
...@@ -1845,20 +1846,20 @@ fn buildOutputType(...@@ -1845,20 +1846,20 @@ fn buildOutputType(
1845 },1846 },
1846 .shared_library => {1847 .shared_library => {
1847 try create_module.link_objects.append(arena, .{1848 try create_module.link_objects.append(arena, .{
1848 .path = it.only_arg,1849 .path = Path.initCwd(it.only_arg),
1849 .must_link = must_link,1850 .must_link = must_link,
1850 });1851 });
1851 create_module.opts.any_dyn_libs = true;1852 create_module.opts.any_dyn_libs = true;
1852 },1853 },
1853 .unknown, .object, .static_library => {1854 .unknown, .object, .static_library => {
1854 try create_module.link_objects.append(arena, .{1855 try create_module.link_objects.append(arena, .{
1855 .path = it.only_arg,1856 .path = Path.initCwd(it.only_arg),
1856 .must_link = must_link,1857 .must_link = must_link,
1857 });1858 });
1858 },1859 },
1859 .res => {1860 .res => {
1860 try create_module.link_objects.append(arena, .{1861 try create_module.link_objects.append(arena, .{
1861 .path = it.only_arg,1862 .path = Path.initCwd(it.only_arg),
1862 .must_link = must_link,1863 .must_link = must_link,
1863 });1864 });
1864 contains_res_file = true;1865 contains_res_file = true;
...@@ -1894,7 +1895,7 @@ fn buildOutputType(...@@ -1894,7 +1895,7 @@ fn buildOutputType(
1894 // binary: no extra rpaths and DSO filename exactly1895 // binary: no extra rpaths and DSO filename exactly
1895 // as provided. Hello, Go.1896 // as provided. Hello, Go.
1896 try create_module.link_objects.append(arena, .{1897 try create_module.link_objects.append(arena, .{
1897 .path = it.only_arg,1898 .path = Path.initCwd(it.only_arg),
1898 .must_link = must_link,1899 .must_link = must_link,
1899 .loption = true,1900 .loption = true,
1900 });1901 });
...@@ -2532,7 +2533,7 @@ fn buildOutputType(...@@ -2532,7 +2533,7 @@ fn buildOutputType(
2532 install_name = linker_args_it.nextOrFatal();2533 install_name = linker_args_it.nextOrFatal();
2533 } else if (mem.eql(u8, arg, "-force_load")) {2534 } else if (mem.eql(u8, arg, "-force_load")) {
2534 try create_module.link_objects.append(arena, .{2535 try create_module.link_objects.append(arena, .{
2535 .path = linker_args_it.nextOrFatal(),2536 .path = Path.initCwd(linker_args_it.nextOrFatal()),
2536 .must_link = true,2537 .must_link = true,
2537 });2538 });
2538 } else if (mem.eql(u8, arg, "-hash-style") or2539 } else if (mem.eql(u8, arg, "-hash-style") or
...@@ -2707,7 +2708,7 @@ fn buildOutputType(...@@ -2707,7 +2708,7 @@ fn buildOutputType(
2707 break :b create_module.c_source_files.items[0].src_path;2708 break :b create_module.c_source_files.items[0].src_path;
27082709
2709 if (create_module.link_objects.items.len >= 1)2710 if (create_module.link_objects.items.len >= 1)
2710 break :b create_module.link_objects.items[0].path;2711 break :b create_module.link_objects.items[0].path.sub_path;
27112712
2712 if (emit_bin == .yes)2713 if (emit_bin == .yes)
2713 break :b emit_bin.yes;2714 break :b emit_bin.yes;
...@@ -2963,7 +2964,7 @@ fn buildOutputType(...@@ -2963,7 +2964,7 @@ fn buildOutputType(
2963 framework_dir_path,2964 framework_dir_path,
2964 framework_name,2965 framework_name,
2965 )) {2966 )) {
2966 const path = try arena.dupe(u8, test_path.items);2967 const path = Path.initCwd(try arena.dupe(u8, test_path.items));
2967 try resolved_frameworks.append(.{2968 try resolved_frameworks.append(.{
2968 .needed = info.needed,2969 .needed = info.needed,
2969 .weak = info.weak,2970 .weak = info.weak,
...@@ -3635,7 +3636,7 @@ const CreateModule = struct {...@@ -3635,7 +3636,7 @@ const CreateModule = struct {
3635 name: []const u8,3636 name: []const u8,
3636 lib: Compilation.SystemLib,3637 lib: Compilation.SystemLib,
3637 }),3638 }),
3638 wasi_emulated_libs: std.ArrayListUnmanaged(wasi_libc.CRTFile),3639 wasi_emulated_libs: std.ArrayListUnmanaged(wasi_libc.CrtFile),
36393640
3640 c_source_files: std.ArrayListUnmanaged(Compilation.CSourceFile),3641 c_source_files: std.ArrayListUnmanaged(Compilation.CSourceFile),
3641 rc_source_files: std.ArrayListUnmanaged(Compilation.RcSourceFile),3642 rc_source_files: std.ArrayListUnmanaged(Compilation.RcSourceFile),
...@@ -3808,7 +3809,7 @@ fn createModule(...@@ -3808,7 +3809,7 @@ fn createModule(
3808 }3809 }
38093810
3810 if (target.os.tag == .wasi) {3811 if (target.os.tag == .wasi) {
3811 if (wasi_libc.getEmulatedLibCRTFile(lib_name)) |crt_file| {3812 if (wasi_libc.getEmulatedLibCrtFile(lib_name)) |crt_file| {
3812 try create_module.wasi_emulated_libs.append(arena, crt_file);3813 try create_module.wasi_emulated_libs.append(arena, crt_file);
3813 continue;3814 continue;
3814 }3815 }
...@@ -3929,7 +3930,7 @@ fn createModule(...@@ -3929,7 +3930,7 @@ fn createModule(
3929 target,3930 target,
3930 info.preferred_mode,3931 info.preferred_mode,
3931 )) {3932 )) {
3932 const path = try arena.dupe(u8, test_path.items);3933 const path = Path.initCwd(try arena.dupe(u8, test_path.items));
3933 switch (info.preferred_mode) {3934 switch (info.preferred_mode) {
3934 .static => try create_module.link_objects.append(arena, .{ .path = path }),3935 .static => try create_module.link_objects.append(arena, .{ .path = path }),
3935 .dynamic => try create_module.resolved_system_libs.append(arena, .{3936 .dynamic => try create_module.resolved_system_libs.append(arena, .{
...@@ -3963,7 +3964,7 @@ fn createModule(...@@ -3963,7 +3964,7 @@ fn createModule(
3963 target,3964 target,
3964 info.fallbackMode(),3965 info.fallbackMode(),
3965 )) {3966 )) {
3966 const path = try arena.dupe(u8, test_path.items);3967 const path = Path.initCwd(try arena.dupe(u8, test_path.items));
3967 switch (info.fallbackMode()) {3968 switch (info.fallbackMode()) {
3968 .static => try create_module.link_objects.append(arena, .{ .path = path }),3969 .static => try create_module.link_objects.append(arena, .{ .path = path }),
3969 .dynamic => try create_module.resolved_system_libs.append(arena, .{3970 .dynamic => try create_module.resolved_system_libs.append(arena, .{
...@@ -3997,7 +3998,7 @@ fn createModule(...@@ -3997,7 +3998,7 @@ fn createModule(
3997 target,3998 target,
3998 info.preferred_mode,3999 info.preferred_mode,
3999 )) {4000 )) {
4000 const path = try arena.dupe(u8, test_path.items);4001 const path = Path.initCwd(try arena.dupe(u8, test_path.items));
4001 switch (info.preferred_mode) {4002 switch (info.preferred_mode) {
4002 .static => try create_module.link_objects.append(arena, .{ .path = path }),4003 .static => try create_module.link_objects.append(arena, .{ .path = path }),
4003 .dynamic => try create_module.resolved_system_libs.append(arena, .{4004 .dynamic => try create_module.resolved_system_libs.append(arena, .{
...@@ -4021,7 +4022,7 @@ fn createModule(...@@ -4021,7 +4022,7 @@ fn createModule(
4021 target,4022 target,
4022 info.fallbackMode(),4023 info.fallbackMode(),
4023 )) {4024 )) {
4024 const path = try arena.dupe(u8, test_path.items);4025 const path = Path.initCwd(try arena.dupe(u8, test_path.items));
4025 switch (info.fallbackMode()) {4026 switch (info.fallbackMode()) {
4026 .static => try create_module.link_objects.append(arena, .{ .path = path }),4027 .static => try create_module.link_objects.append(arena, .{ .path = path }),
4027 .dynamic => try create_module.resolved_system_libs.append(arena, .{4028 .dynamic => try create_module.resolved_system_libs.append(arena, .{
...@@ -6163,7 +6164,7 @@ fn cmdAstCheck(...@@ -6163,7 +6164,7 @@ fn cmdAstCheck(
6163 }6164 }
61646165
6165 file.mod = try Package.Module.createLimited(arena, .{6166 file.mod = try Package.Module.createLimited(arena, .{
6166 .root = Cache.Path.cwd(),6167 .root = Path.cwd(),
6167 .root_src_path = file.sub_file_path,6168 .root_src_path = file.sub_file_path,
6168 .fully_qualified_name = "root",6169 .fully_qualified_name = "root",
6169 });6170 });
...@@ -6523,7 +6524,7 @@ fn cmdChangelist(...@@ -6523,7 +6524,7 @@ fn cmdChangelist(
6523 };6524 };
65246525
6525 file.mod = try Package.Module.createLimited(arena, .{6526 file.mod = try Package.Module.createLimited(arena, .{
6526 .root = Cache.Path.cwd(),6527 .root = Path.cwd(),
6527 .root_src_path = file.sub_file_path,6528 .root_src_path = file.sub_file_path,
6528 .fully_qualified_name = "root",6529 .fully_qualified_name = "root",
6529 });6530 });
src/mingw.zig+23-19
...@@ -11,13 +11,13 @@ const build_options = @import("build_options");...@@ -11,13 +11,13 @@ const build_options = @import("build_options");
11const Cache = std.Build.Cache;11const Cache = std.Build.Cache;
12const dev = @import("dev.zig");12const dev = @import("dev.zig");
1313
14pub const CRTFile = enum {14pub const CrtFile = enum {
15 crt2_o,15 crt2_o,
16 dllcrt2_o,16 dllcrt2_o,
17 mingw32_lib,17 mingw32_lib,
18};18};
1919
20pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: std.Progress.Node) !void {20pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progress.Node) !void {
21 if (!build_options.have_llvm) {21 if (!build_options.have_llvm) {
22 return error.ZigCompilerNotBuiltWithLLVMExtensions;22 return error.ZigCompilerNotBuiltWithLLVMExtensions;
23 }23 }
...@@ -160,7 +160,9 @@ fn add_cc_args(...@@ -160,7 +160,9 @@ fn add_cc_args(
160pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {160pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
161 dev.check(.build_import_lib);161 dev.check(.build_import_lib);
162162
163 var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);163 const gpa = comp.gpa;
164
165 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
164 defer arena_allocator.deinit();166 defer arena_allocator.deinit();
165 const arena = arena_allocator.allocator();167 const arena = arena_allocator.allocator();
166168
...@@ -178,7 +180,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {...@@ -178,7 +180,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
178180
179 // Use the global cache directory.181 // Use the global cache directory.
180 var cache: Cache = .{182 var cache: Cache = .{
181 .gpa = comp.gpa,183 .gpa = gpa,
182 .manifest_dir = try comp.global_cache_directory.handle.makeOpenPath("h", .{}),184 .manifest_dir = try comp.global_cache_directory.handle.makeOpenPath("h", .{}),
183 };185 };
184 cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });186 cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });
...@@ -195,17 +197,18 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {...@@ -195,17 +197,18 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
195197
196 _ = try man.addFile(def_file_path, null);198 _ = try man.addFile(def_file_path, null);
197199
198 const final_lib_basename = try std.fmt.allocPrint(comp.gpa, "{s}.lib", .{lib_name});200 const final_lib_basename = try std.fmt.allocPrint(gpa, "{s}.lib", .{lib_name});
199 errdefer comp.gpa.free(final_lib_basename);201 errdefer gpa.free(final_lib_basename);
200202
201 if (try man.hit()) {203 if (try man.hit()) {
202 const digest = man.final();204 const digest = man.final();
203205
204 try comp.crt_files.ensureUnusedCapacity(comp.gpa, 1);206 try comp.crt_files.ensureUnusedCapacity(gpa, 1);
205 comp.crt_files.putAssumeCapacityNoClobber(final_lib_basename, .{207 comp.crt_files.putAssumeCapacityNoClobber(final_lib_basename, .{
206 .full_object_path = try comp.global_cache_directory.join(comp.gpa, &[_][]const u8{208 .full_object_path = .{
207 "o", &digest, final_lib_basename,209 .root_dir = comp.global_cache_directory,
208 }),210 .sub_path = try std.fs.path.join(gpa, &.{ "o", &digest, final_lib_basename }),
211 },
209 .lock = man.toOwnedLock(),212 .lock = man.toOwnedLock(),
210 });213 });
211 return;214 return;
...@@ -230,7 +233,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {...@@ -230,7 +233,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
230 };233 };
231234
232 const aro = @import("aro");235 const aro = @import("aro");
233 var aro_comp = aro.Compilation.init(comp.gpa, std.fs.cwd());236 var aro_comp = aro.Compilation.init(gpa, std.fs.cwd());
234 defer aro_comp.deinit();237 defer aro_comp.deinit();
235238
236 const include_dir = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "mingw", "def-include" });239 const include_dir = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "mingw", "def-include" });
...@@ -244,7 +247,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {...@@ -244,7 +247,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
244 nosuspend stderr.print("output path: {s}\n", .{def_final_path}) catch break :print;247 nosuspend stderr.print("output path: {s}\n", .{def_final_path}) catch break :print;
245 }248 }
246249
247 try aro_comp.include_dirs.append(comp.gpa, include_dir);250 try aro_comp.include_dirs.append(gpa, include_dir);
248251
249 const builtin_macros = try aro_comp.generateBuiltinMacros(.include_system_defines);252 const builtin_macros = try aro_comp.generateBuiltinMacros(.include_system_defines);
250 const user_macros = try aro_comp.addSourceFromBuffer("<command line>", target_defines);253 const user_macros = try aro_comp.addSourceFromBuffer("<command line>", target_defines);
...@@ -271,17 +274,15 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {...@@ -271,17 +274,15 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
271 try pp.prettyPrintTokens(def_final_file.writer(), .result_only);274 try pp.prettyPrintTokens(def_final_file.writer(), .result_only);
272 }275 }
273276
274 const lib_final_path = try comp.global_cache_directory.join(comp.gpa, &[_][]const u8{277 const lib_final_path = try std.fs.path.join(gpa, &.{ "o", &digest, final_lib_basename });
275 "o", &digest, final_lib_basename,278 errdefer gpa.free(lib_final_path);
276 });
277 errdefer comp.gpa.free(lib_final_path);
278279
279 if (!build_options.have_llvm) return error.ZigCompilerNotBuiltWithLLVMExtensions;280 if (!build_options.have_llvm) return error.ZigCompilerNotBuiltWithLLVMExtensions;
280 const llvm_bindings = @import("codegen/llvm/bindings.zig");281 const llvm_bindings = @import("codegen/llvm/bindings.zig");
281 const llvm = @import("codegen/llvm.zig");282 const llvm = @import("codegen/llvm.zig");
282 const arch_tag = llvm.targetArch(target.cpu.arch);283 const arch_tag = llvm.targetArch(target.cpu.arch);
283 const def_final_path_z = try arena.dupeZ(u8, def_final_path);284 const def_final_path_z = try arena.dupeZ(u8, def_final_path);
284 const lib_final_path_z = try arena.dupeZ(u8, lib_final_path);285 const lib_final_path_z = try comp.global_cache_directory.joinZ(arena, &.{lib_final_path});
285 if (llvm_bindings.WriteImportLibrary(def_final_path_z.ptr, arch_tag, lib_final_path_z.ptr, true)) {286 if (llvm_bindings.WriteImportLibrary(def_final_path_z.ptr, arch_tag, lib_final_path_z.ptr, true)) {
286 // TODO surface a proper error here287 // TODO surface a proper error here
287 log.err("unable to turn {s}.def into {s}.lib", .{ lib_name, lib_name });288 log.err("unable to turn {s}.def into {s}.lib", .{ lib_name, lib_name });
...@@ -292,8 +293,11 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {...@@ -292,8 +293,11 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
292 log.warn("failed to write cache manifest for DLL import {s}.lib: {s}", .{ lib_name, @errorName(err) });293 log.warn("failed to write cache manifest for DLL import {s}.lib: {s}", .{ lib_name, @errorName(err) });
293 };294 };
294295
295 try comp.crt_files.putNoClobber(comp.gpa, final_lib_basename, .{296 try comp.crt_files.putNoClobber(gpa, final_lib_basename, .{
296 .full_object_path = lib_final_path,297 .full_object_path = .{
298 .root_dir = comp.global_cache_directory,
299 .sub_path = lib_final_path,
300 },
297 .lock = man.toOwnedLock(),301 .lock = man.toOwnedLock(),
298 });302 });
299}303}
src/musl.zig+2-2
...@@ -9,7 +9,7 @@ const archName = std.zig.target.muslArchName;...@@ -9,7 +9,7 @@ const archName = std.zig.target.muslArchName;
9const Compilation = @import("Compilation.zig");9const Compilation = @import("Compilation.zig");
10const build_options = @import("build_options");10const build_options = @import("build_options");
1111
12pub const CRTFile = enum {12pub const CrtFile = enum {
13 crti_o,13 crti_o,
14 crtn_o,14 crtn_o,
15 crt1_o,15 crt1_o,
...@@ -19,7 +19,7 @@ pub const CRTFile = enum {...@@ -19,7 +19,7 @@ pub const CRTFile = enum {
19 libc_so,19 libc_so,
20};20};
2121
22pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: std.Progress.Node) !void {22pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progress.Node) !void {
23 if (!build_options.have_llvm) {23 if (!build_options.have_llvm) {
24 return error.ZigCompilerNotBuiltWithLLVMExtensions;24 return error.ZigCompilerNotBuiltWithLLVMExtensions;
25 }25 }
src/wasi_libc.zig+7-7
...@@ -6,7 +6,7 @@ const Allocator = std.mem.Allocator;...@@ -6,7 +6,7 @@ const Allocator = std.mem.Allocator;
6const Compilation = @import("Compilation.zig");6const Compilation = @import("Compilation.zig");
7const build_options = @import("build_options");7const build_options = @import("build_options");
88
9pub const CRTFile = enum {9pub const CrtFile = enum {
10 crt1_reactor_o,10 crt1_reactor_o,
11 crt1_command_o,11 crt1_command_o,
12 libc_a,12 libc_a,
...@@ -16,7 +16,7 @@ pub const CRTFile = enum {...@@ -16,7 +16,7 @@ pub const CRTFile = enum {
16 libwasi_emulated_signal_a,16 libwasi_emulated_signal_a,
17};17};
1818
19pub fn getEmulatedLibCRTFile(lib_name: []const u8) ?CRTFile {19pub fn getEmulatedLibCrtFile(lib_name: []const u8) ?CrtFile {
20 if (mem.eql(u8, lib_name, "wasi-emulated-process-clocks")) {20 if (mem.eql(u8, lib_name, "wasi-emulated-process-clocks")) {
21 return .libwasi_emulated_process_clocks_a;21 return .libwasi_emulated_process_clocks_a;
22 }22 }
...@@ -32,7 +32,7 @@ pub fn getEmulatedLibCRTFile(lib_name: []const u8) ?CRTFile {...@@ -32,7 +32,7 @@ pub fn getEmulatedLibCRTFile(lib_name: []const u8) ?CRTFile {
32 return null;32 return null;
33}33}
3434
35pub fn emulatedLibCRFileLibName(crt_file: CRTFile) []const u8 {35pub fn emulatedLibCRFileLibName(crt_file: CrtFile) []const u8 {
36 return switch (crt_file) {36 return switch (crt_file) {
37 .libwasi_emulated_process_clocks_a => "libwasi-emulated-process-clocks.a",37 .libwasi_emulated_process_clocks_a => "libwasi-emulated-process-clocks.a",
38 .libwasi_emulated_getpid_a => "libwasi-emulated-getpid.a",38 .libwasi_emulated_getpid_a => "libwasi-emulated-getpid.a",
...@@ -42,10 +42,10 @@ pub fn emulatedLibCRFileLibName(crt_file: CRTFile) []const u8 {...@@ -42,10 +42,10 @@ pub fn emulatedLibCRFileLibName(crt_file: CRTFile) []const u8 {
42 };42 };
43}43}
4444
45pub fn execModelCrtFile(wasi_exec_model: std.builtin.WasiExecModel) CRTFile {45pub fn execModelCrtFile(wasi_exec_model: std.builtin.WasiExecModel) CrtFile {
46 return switch (wasi_exec_model) {46 return switch (wasi_exec_model) {
47 .reactor => CRTFile.crt1_reactor_o,47 .reactor => CrtFile.crt1_reactor_o,
48 .command => CRTFile.crt1_command_o,48 .command => CrtFile.crt1_command_o,
49 };49 };
50}50}
5151
...@@ -57,7 +57,7 @@ pub fn execModelCrtFileFullName(wasi_exec_model: std.builtin.WasiExecModel) []co...@@ -57,7 +57,7 @@ pub fn execModelCrtFileFullName(wasi_exec_model: std.builtin.WasiExecModel) []co
57 };57 };
58}58}
5959
60pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: std.Progress.Node) !void {60pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progress.Node) !void {
61 if (!build_options.have_llvm) {61 if (!build_options.have_llvm) {
62 return error.ZigCompilerNotBuiltWithLLVMExtensions;62 return error.ZigCompilerNotBuiltWithLLVMExtensions;
63 }63 }