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 {
398398 return gop.index;
399399 }
400400
401 /// Deprecated, use `addOptionalFilePath`.
401402 pub fn addOptionalFile(self: *Manifest, optional_file_path: ?[]const u8) !void {
402403 self.hash.add(optional_file_path != null);
403404 const file_path = optional_file_path orelse return;
404405 _ = try self.addFile(file_path, null);
405406 }
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
407414 pub fn addListOfFiles(self: *Manifest, list_of_files: []const []const u8) !void {
408415 self.hash.add(list_of_files.len);
409416 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 {
1111}
1212
1313pub 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 };
1519}
1620
1721pub 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 {
126130 return p.root_dir.handle.makePath(joined_path);
127131}
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
129141pub fn format(
130142 self: Path,
131143 comptime fmt_string: []const u8,
......@@ -182,6 +194,14 @@ pub fn subPathOrDot(self: Path) []const u8 {
182194 return if (self.sub_path.len == 0) "." else self.sub_path;
183195}
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
185205/// Useful to make `Path` a key in `std.ArrayHashMap`.
186206pub const TableAdapter = struct {
187207 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 {
690690 }
691691}
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
6931020const LibCInstallation = @This();
6941021const std = @import("std");
6951022const builtin = @import("builtin");
6961023const Target = std.Target;
6971024const fs = std.fs;
6981025const Allocator = std.mem.Allocator;
1026const Path = std.Build.Cache.Path;
6991027
7001028const is_darwin = builtin.target.isDarwin();
7011029const is_windows = builtin.target.os.tag == .windows;
src/Compilation.zig+93-62
......@@ -217,37 +217,37 @@ thread_pool: *ThreadPool,
217217
218218/// Populated when we build the libc++ static library. A Job to build this is placed in the queue
219219/// and resolved before calling linker.flush().
220libcxx_static_lib: ?CRTFile = null,
220libcxx_static_lib: ?CrtFile = null,
221221/// Populated when we build the libc++abi static library. A Job to build this is placed in the queue
222222/// and resolved before calling linker.flush().
223libcxxabi_static_lib: ?CRTFile = null,
223libcxxabi_static_lib: ?CrtFile = null,
224224/// Populated when we build the libunwind static library. A Job to build this is placed in the queue
225225/// and resolved before calling linker.flush().
226libunwind_static_lib: ?CRTFile = null,
226libunwind_static_lib: ?CrtFile = null,
227227/// Populated when we build the TSAN library. A Job to build this is placed in the queue
228228/// and resolved before calling linker.flush().
229tsan_lib: ?CRTFile = null,
229tsan_lib: ?CrtFile = null,
230230/// Populated when we build the libc static library. A Job to build this is placed in the queue
231231/// and resolved before calling linker.flush().
232libc_static_lib: ?CRTFile = null,
232libc_static_lib: ?CrtFile = null,
233233/// Populated when we build the libcompiler_rt static library. A Job to build this is indicated
234234/// by setting `job_queued_compiler_rt_lib` and resolved before calling linker.flush().
235compiler_rt_lib: ?CRTFile = null,
235compiler_rt_lib: ?CrtFile = null,
236236/// Populated when we build the compiler_rt_obj object. A Job to build this is indicated
237237/// by setting `job_queued_compiler_rt_obj` and resolved before calling linker.flush().
238compiler_rt_obj: ?CRTFile = null,
238compiler_rt_obj: ?CrtFile = null,
239239/// Populated when we build the libfuzzer static library. A Job to build this
240240/// is indicated by setting `job_queued_fuzzer_lib` and resolved before
241241/// calling linker.flush().
242fuzzer_lib: ?CRTFile = null,
242fuzzer_lib: ?CrtFile = null,
243243
244244glibc_so_files: ?glibc.BuiltSharedObjects = null,
245wasi_emulated_libs: []const wasi_libc.CRTFile,
245wasi_emulated_libs: []const wasi_libc.CrtFile,
246246
247247/// For example `Scrt1.o` and `libc_nonshared.a`. These are populated after building libc from source,
248248/// The set of needed CRT (C runtime) files differs depending on the target and compilation settings.
249249/// 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
252252/// How many lines of reference trace should be included per compile error.
253253/// Null means only show snippet on first error.
......@@ -276,20 +276,20 @@ digest: ?[Cache.bin_digest_len]u8 = null,
276276pub const default_stack_protector_buffer_size = target_util.default_stack_protector_buffer_size;
277277pub const SemaError = Zcu.SemaError;
278278
279pub const CRTFile = struct {
279pub const CrtFile = struct {
280280 lock: Cache.Lock,
281 full_object_path: []const u8,
281 full_object_path: Path,
282282
283 pub fn isObject(cf: CRTFile) bool {
284 return switch (classifyFileExt(cf.full_object_path)) {
283 pub fn isObject(cf: CrtFile) bool {
284 return switch (classifyFileExt(cf.full_object_path.sub_path)) {
285285 .object => true,
286286 else => false,
287287 };
288288 }
289289
290 pub fn deinit(self: *CRTFile, gpa: Allocator) void {
290 pub fn deinit(self: *CrtFile, gpa: Allocator) void {
291291 self.lock.release();
292 gpa.free(self.full_object_path);
292 gpa.free(self.full_object_path.sub_path);
293293 self.* = undefined;
294294 }
295295};
......@@ -369,13 +369,13 @@ const Job = union(enum) {
369369 resolve_type_fully: InternPool.Index,
370370
371371 /// one of the glibc static objects
372 glibc_crt_file: glibc.CRTFile,
372 glibc_crt_file: glibc.CrtFile,
373373 /// all of the glibc shared objects
374374 glibc_shared_objects,
375375 /// one of the musl static objects
376 musl_crt_file: musl.CRTFile,
376 musl_crt_file: musl.CrtFile,
377377 /// one of the mingw-w64 static objects
378 mingw_crt_file: mingw.CRTFile,
378 mingw_crt_file: mingw.CrtFile,
379379 /// libunwind.a, usually needed when linking libc
380380 libunwind: void,
381381 libcxx: void,
......@@ -385,7 +385,7 @@ const Job = union(enum) {
385385 /// calls to, for example, memcpy and memset.
386386 zig_libc: void,
387387 /// one of WASI libc static objects
388 wasi_libc_crt_file: wasi_libc.CRTFile,
388 wasi_libc_crt_file: wasi_libc.CrtFile,
389389
390390 /// The value is the index into `system_libs`.
391391 windows_import_lib: usize,
......@@ -422,8 +422,8 @@ pub const CObject = struct {
422422 status: union(enum) {
423423 new,
424424 success: struct {
425 /// The outputted result. Owned by gpa.
426 object_path: []u8,
425 /// The outputted result. `sub_path` owned by gpa.
426 object_path: Path,
427427 /// This is a file system lock on the cache hash manifest representing this
428428 /// object. It prevents other invocations of the Zig compiler from interfering
429429 /// with this object until released.
......@@ -719,7 +719,7 @@ pub const CObject = struct {
719719 return true;
720720 },
721721 .success => |*success| {
722 gpa.free(success.object_path);
722 gpa.free(success.object_path.sub_path);
723723 success.lock.release();
724724 self.status = .new;
725725 return false;
......@@ -1018,7 +1018,7 @@ const CacheUse = union(CacheMode) {
10181018};
10191019
10201020pub const LinkObject = struct {
1021 path: []const u8,
1021 path: Path,
10221022 must_link: bool = false,
10231023 // When the library is passed via a positional argument, it will be
10241024 // added as a full path. If it's `-l<lib>`, then just the basename.
......@@ -1027,7 +1027,7 @@ pub const LinkObject = struct {
10271027 loption: bool = false,
10281028
10291029 pub fn isObject(lo: LinkObject) bool {
1030 return switch (classifyFileExt(lo.path)) {
1030 return switch (classifyFileExt(lo.path.sub_path)) {
10311031 .object => true,
10321032 else => false,
10331033 };
......@@ -1095,7 +1095,7 @@ pub const CreateOptions = struct {
10951095 /// * getpid
10961096 /// * mman
10971097 /// * signal
1098 wasi_emulated_libs: []const wasi_libc.CRTFile = &.{},
1098 wasi_emulated_libs: []const wasi_libc.CrtFile = &.{},
10991099 /// This means that if the output mode is an executable it will be a
11001100 /// Position Independent Executable. If the output mode is not an
11011101 /// executable this field is ignored.
......@@ -2578,7 +2578,7 @@ fn addNonIncrementalStuffToCacheManifest(
25782578 }
25792579
25802580 for (comp.objects) |obj| {
2581 _ = try man.addFile(obj.path, null);
2581 _ = try man.addFilePath(obj.path, null);
25822582 man.hash.add(obj.must_link);
25832583 man.hash.add(obj.loption);
25842584 }
......@@ -2703,9 +2703,8 @@ fn emitOthers(comp: *Compilation) void {
27032703 return;
27042704 }
27052705 const obj_path = comp.c_object_table.keys()[0].status.success.object_path;
2706 const cwd = std.fs.cwd();
2707 const ext = std.fs.path.extension(obj_path);
2708 const basename = obj_path[0 .. obj_path.len - ext.len];
2706 const ext = std.fs.path.extension(obj_path.sub_path);
2707 const dirname = obj_path.sub_path[0 .. obj_path.sub_path.len - ext.len];
27092708 // This obj path always ends with the object file extension, but if we change the
27102709 // extension to .ll, .bc, or .s, then it will be the path to those things.
27112710 const outs = [_]struct {
......@@ -2720,13 +2719,13 @@ fn emitOthers(comp: *Compilation) void {
27202719 if (out.emit) |loc| {
27212720 if (loc.directory) |directory| {
27222721 const src_path = std.fmt.allocPrint(comp.gpa, "{s}{s}", .{
2723 basename, out.ext,
2722 dirname, out.ext,
27242723 }) 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) });
27262725 continue;
27272726 };
27282727 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| {
27302729 log.err("unable to copy {s}: {s}", .{ src_path, @errorName(err) });
27312730 };
27322731 }
......@@ -3774,7 +3773,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
37743773 const named_frame = tracy.namedFrame("glibc_crt_file");
37753774 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| {
37783777 // TODO Surface more error details.
37793778 comp.lockAndSetMiscFailure(.glibc_crt_file, "unable to build glibc CRT file: {s}", .{
37803779 @errorName(err),
......@@ -3798,7 +3797,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
37983797 const named_frame = tracy.namedFrame("musl_crt_file");
37993798 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| {
38023801 // TODO Surface more error details.
38033802 comp.lockAndSetMiscFailure(
38043803 .musl_crt_file,
......@@ -3811,7 +3810,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
38113810 const named_frame = tracy.namedFrame("mingw_crt_file");
38123811 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| {
38153814 // TODO Surface more error details.
38163815 comp.lockAndSetMiscFailure(
38173816 .mingw_crt_file,
......@@ -3894,7 +3893,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
38943893 const named_frame = tracy.namedFrame("wasi_libc_crt_file");
38953894 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| {
38983897 // TODO Surface more error details.
38993898 comp.lockAndSetMiscFailure(
39003899 .wasi_libc_crt_file,
......@@ -4602,7 +4601,7 @@ fn buildRt(
46024601 root_source_name: []const u8,
46034602 misc_task: MiscTask,
46044603 output_mode: std.builtin.OutputMode,
4605 out: *?CRTFile,
4604 out: *?CrtFile,
46064605 prog_node: std.Progress.Node,
46074606) void {
46084607 comp.buildOutputFromZig(
......@@ -4703,7 +4702,9 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
47034702
47044703 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)) {
47074708 // There was previous failure.
47084709 comp.mutex.lock();
47094710 defer comp.mutex.unlock();
......@@ -4722,7 +4723,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
47224723
47234724 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);
47264727 defer arena_allocator.deinit();
47274728 const arena = arena_allocator.allocator();
47284729
......@@ -4744,7 +4745,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
47444745 const target = comp.getTarget();
47454746 const o_ext = target.ofmt.fileExt(target.cpu.arch);
47464747 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);
47484749 defer argv.deinit();
47494750
47504751 // 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
49084909
49094910 switch (term) {
49104911 .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| {
49124913 log.err("{}: failed to parse clang diagnostics: {s}", .{ err, stderr });
49134914 return comp.failCObj(c_object, "clang exited with code {d}", .{code});
49144915 };
......@@ -4982,9 +4983,10 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
49824983
49834984 c_object.status = .{
49844985 .success = .{
4985 .object_path = try comp.local_cache_directory.join(comp.gpa, &[_][]const u8{
4986 "o", &digest, o_basename,
4987 }),
4986 .object_path = .{
4987 .root_dir = comp.local_cache_directory,
4988 .sub_path = try std.fs.path.join(gpa, &.{ "o", &digest, o_basename }),
4989 },
49884990 .lock = man.toOwnedLock(),
49894991 },
49904992 };
......@@ -6092,18 +6094,23 @@ test "classifyFileExt" {
60926094 try std.testing.expectEqual(FileExt.zig, classifyFileExt("foo.zig"));
60936095}
60946096
6095pub fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const u8) ![]const u8 {
6096 if (comp.wantBuildGLibCFromSource() or
6097 comp.wantBuildMuslFromSource() or
6098 comp.wantBuildMinGWFromSource() or
6099 comp.wantBuildWasiLibcFromSource())
6100 {
6101 return comp.crt_files.get(basename).?.full_object_path;
6102 }
6103 const lci = comp.libc_installation orelse return error.LibCInstallationNotAvailable;
6104 const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCRTDir;
6105 const full_path = try std.fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename });
6106 return full_path;
6097pub fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const u8) !Path {
6098 return (try crtFilePath(comp, basename)) orelse {
6099 const lci = comp.libc_installation orelse return error.LibCInstallationNotAvailable;
6100 const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCrtDir;
6101 const full_path = try std.fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename });
6102 return Path.initCwd(full_path);
6103 };
6104}
6105
6106pub fn crtFileAsString(comp: *Compilation, arena: Allocator, basename: []const u8) ![]const u8 {
6107 const path = try get_libc_crt_file(comp, arena, basename);
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;
61076114}
61086115
61096116fn wantBuildLibCFromSource(comp: Compilation) bool {
......@@ -6314,7 +6321,7 @@ fn buildOutputFromZig(
63146321 comp: *Compilation,
63156322 src_basename: []const u8,
63166323 output_mode: std.builtin.OutputMode,
6317 out: *?CRTFile,
6324 out: *?CrtFile,
63186325 misc_task_tag: MiscTask,
63196326 prog_node: std.Progress.Node,
63206327) !void {
......@@ -6542,15 +6549,39 @@ pub fn build_crt_file(
65426549 comp.crt_files.putAssumeCapacityNoClobber(basename, try sub_compilation.toCrtFile());
65436550}
65446551
6545pub fn toCrtFile(comp: *Compilation) Allocator.Error!CRTFile {
6552pub fn toCrtFile(comp: *Compilation) Allocator.Error!CrtFile {
65466553 return .{
6547 .full_object_path = try comp.local_cache_directory.join(comp.gpa, &.{
6548 comp.cache_use.whole.bin_sub_path.?,
6549 }),
6554 .full_object_path = .{
6555 .root_dir = comp.local_cache_directory,
6556 .sub_path = try comp.gpa.dupe(u8, comp.cache_use.whole.bin_sub_path.?),
6557 },
65506558 .lock = comp.cache_use.whole.moveLock(),
65516559 };
65526560}
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
65546585pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void {
65556586 // Avoid deadlocking on building import libs such as kernel32.lib
65566587 // 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 {
169169 };
170170}
171171
172pub const CRTFile = enum {
172pub const CrtFile = enum {
173173 crti_o,
174174 crtn_o,
175175 scrt1_o,
176176 libc_nonshared_a,
177177};
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 {
180180 if (!build_options.have_llvm) {
181181 return error.ZigCompilerNotBuiltWithLLVMExtensions;
182182 }
......@@ -292,7 +292,8 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: std.Progre
292292 .owner = undefined,
293293 };
294294 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);
296297 },
297298 .libc_nonshared_a => {
298299 const s = path.sep_str;
src/link.zig+12-15
......@@ -11,7 +11,7 @@ const wasi_libc = @import("wasi_libc.zig");
1111const Air = @import("Air.zig");
1212const Allocator = std.mem.Allocator;
1313const Cache = std.Build.Cache;
14const Path = Cache.Path;
14const Path = std.Build.Cache.Path;
1515const Compilation = @import("Compilation.zig");
1616const LibCInstallation = std.zig.LibCInstallation;
1717const Liveness = @import("Liveness.zig");
......@@ -34,7 +34,7 @@ pub const SystemLib = struct {
3434 /// 1. Windows DLLs that zig ships such as advapi32.
3535 /// 2. extern "foo" fn declarations where we find out about libraries too late
3636 /// TODO: make this non-optional and resolve those two cases somehow.
37 path: ?[]const u8,
37 path: ?Path,
3838};
3939
4040pub fn hashAddSystemLibs(
......@@ -46,7 +46,7 @@ pub fn hashAddSystemLibs(
4646 for (hm.values()) |value| {
4747 man.hash.add(value.needed);
4848 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);
5050 }
5151}
5252
......@@ -551,7 +551,7 @@ pub const File = struct {
551551 LLDCrashed,
552552 LLDReportedFailure,
553553 LLD_LinkingIsTODO_ForSpirV,
554 LibCInstallationMissingCRTDir,
554 LibCInstallationMissingCrtDir,
555555 LibCInstallationNotAvailable,
556556 LinkingWithoutZigSourceUnimplemented,
557557 MalformedArchive,
......@@ -606,18 +606,15 @@ pub const File = struct {
606606 const comp = base.comp;
607607 if (comp.clang_preprocessor_mode == .yes or comp.clang_preprocessor_mode == .pch) {
608608 dev.check(.clang_command);
609 const gpa = comp.gpa;
610609 const emit = base.emit;
611610 // TODO: avoid extra link step when it's just 1 object file (the `zig cc -c` case)
612611 // Until then, we do `lld -r -o output.o input.o` even though the output is the same
613612 // as the input. For the preprocessing case (`zig cc -E -o foo`) we copy the file
614613 // 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);
617614 assert(comp.c_object_table.count() == 1);
618615 const the_key = comp.c_object_table.keys()[0];
619616 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, .{});
621618 return;
622619 }
623620
......@@ -781,7 +778,7 @@ pub const File = struct {
781778
782779 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)
785782 comp.compiler_rt_obj.?.full_object_path
786783 else
787784 null;
......@@ -806,18 +803,18 @@ pub const File = struct {
806803 base.releaseLock();
807804
808805 for (objects) |obj| {
809 _ = try man.addFile(obj.path, null);
806 _ = try man.addFilePath(obj.path, null);
810807 man.hash.add(obj.must_link);
811808 man.hash.add(obj.loption);
812809 }
813810 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);
815812 }
816813 for (comp.win32_resource_table.keys()) |key| {
817814 _ = try man.addFile(key.status.success.res_path, null);
818815 }
819816 try man.addOptionalFile(zcu_obj_path);
820 try man.addOptionalFile(compiler_rt_path);
817 try man.addOptionalFilePath(compiler_rt_path);
821818
822819 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
823820 _ = try man.hit();
......@@ -851,10 +848,10 @@ pub const File = struct {
851848 defer object_files.deinit();
852849
853850 for (objects) |obj| {
854 object_files.appendAssumeCapacity(try arena.dupeZ(u8, obj.path));
851 object_files.appendAssumeCapacity(try obj.path.toStringZ(arena));
855852 }
856853 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));
858855 }
859856 for (comp.win32_resource_table.keys()) |key| {
860857 object_files.appendAssumeCapacity(try arena.dupeZ(u8, key.status.success.res_path));
......@@ -863,7 +860,7 @@ pub const File = struct {
863860 object_files.appendAssumeCapacity(try arena.dupeZ(u8, p));
864861 }
865862 if (compiler_rt_path) |p| {
866 object_files.appendAssumeCapacity(try arena.dupeZ(u8, p));
863 object_files.appendAssumeCapacity(try p.toStringZ(arena));
867864 }
868865
869866 if (comp.verbose_link) {
src/link/Coff/lld.zig+25-22
......@@ -7,6 +7,7 @@ const fs = std.fs;
77const log = std.log.scoped(.link);
88const mem = std.mem;
99const Cache = std.Build.Cache;
10const Path = std.Build.Cache.Path;
1011
1112const mingw = @import("../../mingw.zig");
1213const link = @import("../../link.zig");
......@@ -74,11 +75,11 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
7475 comptime assert(Compilation.link_hash_implementation_version == 14);
7576
7677 for (comp.objects) |obj| {
77 _ = try man.addFile(obj.path, null);
78 _ = try man.addFilePath(obj.path, null);
7879 man.hash.add(obj.must_link);
7980 }
8081 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);
8283 }
8384 for (comp.win32_resource_table.keys()) |key| {
8485 _ = 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
154155 break :blk comp.c_object_table.keys()[0].status.success.object_path;
155156
156157 if (module_obj_path) |p|
157 break :blk p;
158 break :blk Path.initCwd(p);
158159
159160 // TODO I think this is unreachable. Audit this situation when solving the above TODO
160161 // regarding eliding redundant object -> object transformations.
161162 return error.NoObjectsToLink;
162163 };
163 // This can happen when using --enable-cache and using the stage1 backend. In this case
164 // we can skip the file copy.
165 if (!mem.eql(u8, the_object_path, full_out_path)) {
166 try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});
167 }
164 try std.fs.Dir.copyFile(
165 the_object_path.root_dir.handle,
166 the_object_path.sub_path,
167 directory.handle,
168 self.base.emit.sub_path,
169 .{},
170 );
168171 } else {
169172 // Create an LLD command line and invoke it.
170173 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
270273 try argv.ensureUnusedCapacity(comp.objects.len);
271274 for (comp.objects) |obj| {
272275 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)}));
274277 } else {
275 argv.appendAssumeCapacity(obj.path);
278 argv.appendAssumeCapacity(try obj.path.toString(arena));
276279 }
277280 }
278281
279282 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));
281284 }
282285
283286 for (comp.win32_resource_table.keys()) |key| {
......@@ -401,17 +404,17 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
401404 }
402405
403406 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"));
405408 if (target.cpu.arch == .x86) {
406409 try argv.append("-ALTERNATENAME:__DllMainCRTStartup@12=_DllMainCRTStartup@12");
407410 } else {
408411 try argv.append("-ALTERNATENAME:_DllMainCRTStartup=DllMainCRTStartup");
409412 }
410413 } else {
411 try argv.append(try comp.get_libc_crt_file(arena, "crt2.obj"));
414 try argv.append(try comp.crtFileAsString(arena, "crt2.obj"));
412415 }
413416
414 try argv.append(try comp.get_libc_crt_file(arena, "mingw32.lib"));
417 try argv.append(try comp.crtFileAsString(arena, "mingw32.lib"));
415418 } else {
416419 const lib_str = switch (comp.config.link_mode) {
417420 .dynamic => "",
......@@ -456,36 +459,36 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
456459
457460 // libc++ dep
458461 if (comp.config.link_libcpp) {
459 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
460 try argv.append(comp.libcxx_static_lib.?.full_object_path);
462 try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena));
463 try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena));
461464 }
462465
463466 // libunwind dep
464467 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));
466469 }
467470
468471 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));
470473 }
471474
472475 if (is_exe_or_dyn_lib and !comp.skip_linker_dependencies) {
473476 if (!comp.config.link_libc) {
474477 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));
476479 }
477480 }
478481 // MSVC compiler_rt is missing some stuff, so we build it unconditionally but
479482 // 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);
481 if (comp.compiler_rt_lib) |lib| try argv.append(lib.full_object_path);
483 if (comp.compiler_rt_obj) |obj| try argv.append(try obj.full_object_path.toString(arena));
484 if (comp.compiler_rt_lib) |lib| try argv.append(try lib.full_object_path.toString(arena));
482485 }
483486
484487 try argv.ensureUnusedCapacity(comp.system_libs.count());
485488 for (comp.system_libs.keys()) |key| {
486489 const lib_basename = try allocPrint(arena, "{s}.lib", .{key});
487490 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));
489492 continue;
490493 }
491494 if (try findLib(arena, lib_basename, self.lib_dirs)) |full_path| {
src/link/Elf.zig+118-325
......@@ -383,9 +383,9 @@ pub fn createEmpty(
383383 const index: File.Index = @intCast(try self.files.addOne(gpa));
384384 self.files.set(index, .{ .zig_object = .{
385385 .index = index,
386 .path = try std.fmt.allocPrint(arena, "{s}.o", .{fs.path.stem(
387 zcu.main_mod.root_src_path,
388 )}),
386 .basename = try std.fmt.allocPrint(arena, "{s}.o", .{
387 fs.path.stem(zcu.main_mod.root_src_path),
388 }),
389389 } });
390390 self.zig_object_index = index;
391391 try self.zigObjectPtr().?.init(self, .{
......@@ -742,13 +742,12 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
742742 const target = self.getTarget();
743743 const link_mode = comp.config.link_mode;
744744 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: {
746 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
747 if (fs.path.dirname(full_out_path)) |dirname| {
748 break :blk try fs.path.join(arena, &.{ dirname, path });
749 } else {
750 break :blk path;
751 }
745 const module_obj_path: ?Path = if (self.base.zcu_object_sub_path) |path| .{
746 .root_dir = directory,
747 .sub_path = if (fs.path.dirname(self.base.emit.sub_path)) |dirname|
748 try fs.path.join(arena, &.{ dirname, path })
749 else
750 path,
752751 } else null;
753752
754753 // --verbose-link
......@@ -758,7 +757,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
758757 if (self.base.isStaticLib()) return relocatable.flushStaticLib(self, comp, module_obj_path);
759758 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
763762 // csu prelude
764763 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
790789 if (comp.libc_static_lib) |lib| try parseCrtFileReportingFailure(self, lib);
791790 }
792791
793 var system_libs = std.ArrayList(SystemLib).init(arena);
794
795 try system_libs.ensureUnusedCapacity(comp.system_libs.values().len);
796792 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);
798797 }
799798
800799 // libc++ dep
801800 if (comp.config.link_libcpp) {
802 try system_libs.ensureUnusedCapacity(2);
803 system_libs.appendAssumeCapacity(.{ .path = comp.libcxxabi_static_lib.?.full_object_path });
804 system_libs.appendAssumeCapacity(.{ .path = comp.libcxx_static_lib.?.full_object_path });
801 try self.parseLibraryReportingFailure(.{ .path = comp.libcxxabi_static_lib.?.full_object_path }, false);
802 try self.parseLibraryReportingFailure(.{ .path = comp.libcxx_static_lib.?.full_object_path }, false);
805803 }
806804
807805 // libunwind dep
808806 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);
810808 }
811809
812810 // libc dep
......@@ -814,7 +812,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
814812 if (comp.config.link_libc) {
815813 if (comp.libc_installation) |lc| {
816814 const flags = target_util.libcFullLinkFlags(target);
817 try system_libs.ensureUnusedCapacity(flags.len);
818815
819816 var test_path = std.ArrayList(u8).init(arena);
820817 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
840837 continue;
841838 }
842839
843 const resolved_path = try arena.dupe(u8, test_path.items);
844 system_libs.appendAssumeCapacity(.{ .path = resolved_path });
840 const resolved_path = Path.initCwd(try arena.dupe(u8, test_path.items));
841 try self.parseLibraryReportingFailure(.{ .path = resolved_path }, false);
845842 }
846843 } else if (target.isGnuLibC()) {
847 try system_libs.ensureUnusedCapacity(glibc.libs.len + 1);
848844 for (glibc.libs) |lib| {
849845 if (lib.removed_in) |rem_in| {
850846 if (target.os.version_range.linux.glibc.order(rem_in) != .lt) continue;
851847 }
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}", .{
854850 comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
855 });
856 system_libs.appendAssumeCapacity(.{ .path = lib_path });
851 }));
852 try self.parseLibraryReportingFailure(.{ .path = lib_path }, false);
857853 }
858 system_libs.appendAssumeCapacity(.{
854 try self.parseLibraryReportingFailure(.{
859855 .path = try comp.get_libc_crt_file(arena, "libc_nonshared.a"),
860 });
856 }, false);
861857 } else if (target.isMusl()) {
862858 const path = try comp.get_libc_crt_file(arena, switch (link_mode) {
863859 .static => "libc.a",
864860 .dynamic => "libc.so",
865861 });
866 try system_libs.append(.{ .path = path });
862 try self.parseLibraryReportingFailure(.{ .path = path }, false);
867863 } else {
868864 comp.link_error_flags.missing_libc = true;
869865 }
870866 }
871867
872 for (system_libs.items) |lib| {
873 try self.parseLibraryReportingFailure(lib, false);
874 }
875
876868 // Finally, as the last input objects we add compiler_rt and CSU postlude (if any).
877869
878870 // compiler-rt. Since compiler_rt exports symbols like `memset`, it needs
......@@ -1066,10 +1058,10 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
10661058 }
10671059 } else null;
10681060
1069 const csu = try CsuObjects.init(arena, comp);
1061 const csu = try comp.getCrtPaths(arena);
10701062 const compiler_rt_path: ?[]const u8 = blk: {
1071 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
1072 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;
1063 if (comp.compiler_rt_lib) |x| break :blk try x.full_object_path.toString(arena);
1064 if (comp.compiler_rt_obj) |x| break :blk try x.full_object_path.toString(arena);
10731065 break :blk null;
10741066 };
10751067
......@@ -1092,11 +1084,11 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
10921084
10931085 if (self.base.isRelocatable()) {
10941086 for (comp.objects) |obj| {
1095 try argv.append(obj.path);
1087 try argv.append(try obj.path.toString(arena));
10961088 }
10971089
10981090 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));
11001092 }
11011093
11021094 if (module_obj_path) |p| {
......@@ -1178,9 +1170,9 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
11781170 }
11791171
11801172 // csu prelude
1181 if (csu.crt0) |v| try argv.append(v);
1182 if (csu.crti) |v| try argv.append(v);
1183 if (csu.crtbegin) |v| try argv.append(v);
1173 if (csu.crt0) |path| try argv.append(try path.toString(arena));
1174 if (csu.crti) |path| try argv.append(try path.toString(arena));
1175 if (csu.crtbegin) |path| try argv.append(try path.toString(arena));
11841176
11851177 for (self.lib_dirs) |lib_dir| {
11861178 try argv.append("-L");
......@@ -1205,10 +1197,9 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
12051197 }
12061198
12071199 if (obj.loption) {
1208 assert(obj.path[0] == ':');
12091200 try argv.append("-l");
12101201 }
1211 try argv.append(obj.path);
1202 try argv.append(try obj.path.toString(arena));
12121203 }
12131204 if (whole_archive) {
12141205 try argv.append("-no-whole-archive");
......@@ -1216,7 +1207,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
12161207 }
12171208
12181209 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));
12201211 }
12211212
12221213 if (module_obj_path) |p| {
......@@ -1224,17 +1215,17 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
12241215 }
12251216
12261217 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));
12281219 }
12291220
12301221 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));
12321223 }
12331224
12341225 // libc
12351226 if (!comp.skip_linker_dependencies and !comp.config.link_libc) {
12361227 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));
12381229 }
12391230 }
12401231
......@@ -1258,7 +1249,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
12581249 as_needed = true;
12591250 },
12601251 }
1261 argv.appendAssumeCapacity(lib_info.path.?);
1252 argv.appendAssumeCapacity(try lib_info.path.?.toString(arena));
12621253 }
12631254
12641255 if (!as_needed) {
......@@ -1268,13 +1259,13 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
12681259
12691260 // libc++ dep
12701261 if (comp.config.link_libcpp) {
1271 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
1272 try argv.append(comp.libcxx_static_lib.?.full_object_path);
1262 try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena));
1263 try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena));
12731264 }
12741265
12751266 // libunwind dep
12761267 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));
12781269 }
12791270
12801271 // libc dep
......@@ -1295,9 +1286,9 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
12951286 });
12961287 try argv.append(lib_path);
12971288 }
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"));
12991290 } 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) {
13011292 .static => "libc.a",
13021293 .dynamic => "libc.so",
13031294 }));
......@@ -1310,8 +1301,8 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
13101301 }
13111302
13121303 // crt postlude
1313 if (csu.crtend) |v| try argv.append(v);
1314 if (csu.crtn) |v| try argv.append(v);
1304 if (csu.crtend) |path| try argv.append(try path.toString(arena));
1305 if (csu.crtn) |path| try argv.append(try path.toString(arena));
13151306 }
13161307
13171308 Compilation.dump_argv(argv.items);
......@@ -1331,7 +1322,7 @@ pub const ParseError = error{
13311322 UnknownFileType,
13321323} || 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 {
13351326 if (crt_file.isObject()) {
13361327 try parseObjectReportingFailure(self, crt_file.full_object_path);
13371328 } else {
......@@ -1339,7 +1330,7 @@ fn parseCrtFileReportingFailure(self: *Elf, crt_file: Compilation.CRTFile) error
13391330 }
13401331}
13411332
1342pub fn parseObjectReportingFailure(self: *Elf, path: []const u8) error{OutOfMemory}!void {
1333pub fn parseObjectReportingFailure(self: *Elf, path: Path) error{OutOfMemory}!void {
13431334 self.parseObject(path) catch |err| switch (err) {
13441335 error.LinkFailure => return, // already reported
13451336 error.OutOfMemory => return error.OutOfMemory,
......@@ -1367,17 +1358,20 @@ fn parseLibrary(self: *Elf, lib: SystemLib, must_link: bool) ParseError!void {
13671358 }
13681359}
13691360
1370fn parseObject(self: *Elf, path: []const u8) ParseError!void {
1361fn parseObject(self: *Elf, path: Path) ParseError!void {
13711362 const tracy = trace(@src());
13721363 defer tracy.end();
13731364
13741365 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, .{});
13761367 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));
13791370 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 },
13811375 .file_handle = fh,
13821376 .index = index,
13831377 } });
......@@ -1387,15 +1381,15 @@ fn parseObject(self: *Elf, path: []const u8) ParseError!void {
13871381 try object.parse(self);
13881382}
13891383
1390fn parseArchive(self: *Elf, path: []const u8, must_link: bool) ParseError!void {
1384fn parseArchive(self: *Elf, path: Path, must_link: bool) ParseError!void {
13911385 const tracy = trace(@src());
13921386 defer tracy.end();
13931387
13941388 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, .{});
13961390 const fh = try self.addFileHandle(handle);
13971391
1398 var archive = Archive{};
1392 var archive: Archive = .{};
13991393 defer archive.deinit(gpa);
14001394 try archive.parse(self, path, fh);
14011395
......@@ -1403,7 +1397,7 @@ fn parseArchive(self: *Elf, path: []const u8, must_link: bool) ParseError!void {
14031397 defer gpa.free(objects);
14041398
14051399 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));
14071401 self.files.set(index, .{ .object = extracted });
14081402 const object = &self.files.items(.data)[index].object;
14091403 object.index = index;
......@@ -1418,12 +1412,15 @@ fn parseSharedObject(self: *Elf, lib: SystemLib) ParseError!void {
14181412 defer tracy.end();
14191413
14201414 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, .{});
14221416 defer handle.close();
14231417
14241418 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
14251419 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 },
14271424 .index = index,
14281425 .needed = lib.needed,
14291426 .alive = lib.needed,
......@@ -1439,12 +1436,12 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
14391436 defer tracy.end();
14401437
14411438 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, .{});
14431440 defer in_file.close();
14441441 const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));
14451442 defer gpa.free(data);
14461443
1447 var script = LdScript{ .path = lib.path };
1444 var script: LdScript = .{ .path = lib.path };
14481445 defer script.deinit(gpa);
14491446 try script.parse(data, self);
14501447
......@@ -1455,12 +1452,12 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
14551452 var test_path = std.ArrayList(u8).init(arena);
14561453 var checked_paths = std.ArrayList([]const u8).init(arena);
14571454
1458 for (script.args.items) |scr_obj| {
1455 for (script.args.items) |script_arg| {
14591456 checked_paths.clearRetainingCapacity();
14601457
14611458 success: {
1462 if (mem.startsWith(u8, scr_obj.path, "-l")) {
1463 const lib_name = scr_obj.path["-l".len..];
1459 if (mem.startsWith(u8, script_arg.path, "-l")) {
1460 const lib_name = script_arg.path["-l".len..];
14641461
14651462 // TODO I think technically we should re-use the mechanism used by the frontend here.
14661463 // Maybe we should hoist search-strategy all the way here?
......@@ -1474,33 +1471,30 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
14741471 }
14751472 } else {
14761473 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| {
14781475 test_path.clearRetainingCapacity();
14791476 try test_path.writer().writeAll(path);
14801477 break :success;
14811478 } 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));
14841481 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))
14861483 break :success;
14871484 }
14881485 }
14891486
14901487 try self.reportMissingLibraryError(
14911488 checked_paths.items,
1492 "missing library dependency: GNU ld script '{s}' requires '{s}', but file not found",
1493 .{
1494 lib.path,
1495 scr_obj.path,
1496 },
1489 "missing library dependency: GNU ld script '{}' requires '{s}', but file not found",
1490 .{ @as(Path, lib.path), script_arg.path },
14971491 );
14981492 continue;
14991493 }
15001494
1501 const full_path = test_path.items;
1495 const full_path = Path.initCwd(test_path.items);
15021496 self.parseLibrary(.{
1503 .needed = scr_obj.needed,
1497 .needed = script_arg.needed,
15041498 .path = full_path,
15051499 }, false) catch |err| switch (err) {
15061500 error.LinkFailure => continue, // already reported
......@@ -1841,7 +1835,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
18411835 const have_dynamic_linker = comp.config.link_libc and
18421836 link_mode == .dynamic and is_exe_or_dyn_lib;
18431837 const target = self.getTarget();
1844 const compiler_rt_path: ?[]const u8 = blk: {
1838 const compiler_rt_path: ?Path = blk: {
18451839 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
18461840 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;
18471841 break :blk null;
......@@ -1875,17 +1869,17 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
18751869 man.hash.add(self.allow_undefined_version);
18761870 man.hash.addOptional(self.enable_new_dtags);
18771871 for (comp.objects) |obj| {
1878 _ = try man.addFile(obj.path, null);
1872 _ = try man.addFilePath(obj.path, null);
18791873 man.hash.add(obj.must_link);
18801874 man.hash.add(obj.loption);
18811875 }
18821876 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);
18841878 }
18851879 try man.addOptionalFile(module_obj_path);
1886 try man.addOptionalFile(compiler_rt_path);
1887 try man.addOptionalFile(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);
1880 try man.addOptionalFilePath(compiler_rt_path);
1881 try man.addOptionalFilePath(if (comp.tsan_lib) |l| l.full_object_path else null);
1882 try man.addOptionalFilePath(if (comp.fuzzer_lib) |l| l.full_object_path else null);
18891883
18901884 // We can skip hashing libc and libc++ components that we are in charge of building from Zig
18911885 // 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
19821976 break :blk comp.c_object_table.keys()[0].status.success.object_path;
19831977
19841978 if (module_obj_path) |p|
1985 break :blk p;
1979 break :blk Path.initCwd(p);
19861980
19871981 // TODO I think this is unreachable. Audit this situation when solving the above TODO
19881982 // regarding eliding redundant object -> object transformations.
19891983 return error.NoObjectsToLink;
19901984 };
1991 // This can happen when using --enable-cache and using the stage1 backend. In this case
1992 // we can skip the file copy.
1993 if (!mem.eql(u8, the_object_path, full_out_path)) {
1994 try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});
1995 }
1985 try std.fs.Dir.copyFile(
1986 the_object_path.root_dir.handle,
1987 the_object_path.sub_path,
1988 directory.handle,
1989 self.base.emit.sub_path,
1990 .{},
1991 );
19961992 } else {
19971993 // Create an LLD command line and invoke it.
19981994 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
21772173 try argv.append(full_out_path);
21782174
21792175 // csu prelude
2180 const csu = try CsuObjects.init(arena, comp);
2181 if (csu.crt0) |v| try argv.append(v);
2182 if (csu.crti) |v| try argv.append(v);
2183 if (csu.crtbegin) |v| try argv.append(v);
2176 const csu = try comp.getCrtPaths(arena);
2177 if (csu.crt0) |p| try argv.append(try p.toString(arena));
2178 if (csu.crti) |p| try argv.append(try p.toString(arena));
2179 if (csu.crtbegin) |p| try argv.append(try p.toString(arena));
21842180
21852181 for (self.rpath_table.keys()) |rpath| {
21862182 try argv.appendSlice(&.{ "-rpath", rpath });
......@@ -2244,10 +2240,10 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
22442240 }
22452241
22462242 if (obj.loption) {
2247 assert(obj.path[0] == ':');
2243 assert(obj.path.sub_path[0] == ':');
22482244 try argv.append("-l");
22492245 }
2250 try argv.append(obj.path);
2246 try argv.append(try obj.path.toString(arena));
22512247 }
22522248 if (whole_archive) {
22532249 try argv.append("-no-whole-archive");
......@@ -2255,7 +2251,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
22552251 }
22562252
22572253 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));
22592255 }
22602256
22612257 if (module_obj_path) |p| {
......@@ -2264,12 +2260,12 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
22642260
22652261 if (comp.tsan_lib) |lib| {
22662262 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));
22682264 }
22692265
22702266 if (comp.fuzzer_lib) |lib| {
22712267 assert(comp.config.any_fuzz);
2272 try argv.append(lib.full_object_path);
2268 try argv.append(try lib.full_object_path.toString(arena));
22732269 }
22742270
22752271 // libc
......@@ -2278,7 +2274,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
22782274 !comp.config.link_libc)
22792275 {
22802276 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));
22822278 }
22832279 }
22842280
......@@ -2311,7 +2307,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
23112307 // libraries and not static libraries (the check for that needs to be earlier),
23122308 // but they could be full paths to .so files, in which case we
23132309 // want to avoid prepending "-l".
2314 argv.appendAssumeCapacity(lib_info.path.?);
2310 argv.appendAssumeCapacity(try lib_info.path.?.toString(arena));
23152311 }
23162312
23172313 if (!as_needed) {
......@@ -2321,13 +2317,13 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
23212317
23222318 // libc++ dep
23232319 if (comp.config.link_libcpp) {
2324 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
2325 try argv.append(comp.libcxx_static_lib.?.full_object_path);
2320 try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena));
2321 try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena));
23262322 }
23272323
23282324 // libunwind dep
23292325 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));
23312327 }
23322328
23332329 // libc dep
......@@ -2349,9 +2345,9 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
23492345 });
23502346 try argv.append(lib_path);
23512347 }
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"));
23532349 } 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) {
23552351 .static => "libc.a",
23562352 .dynamic => "libc.so",
23572353 }));
......@@ -2365,12 +2361,12 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
23652361 // to be after the shared libraries, so they are picked up from the shared
23662362 // libraries, not libcompiler_rt.
23672363 if (compiler_rt_path) |p| {
2368 try argv.append(p);
2364 try argv.append(try p.toString(arena));
23692365 }
23702366
23712367 // crt postlude
2372 if (csu.crtend) |v| try argv.append(v);
2373 if (csu.crtn) |v| try argv.append(v);
2368 if (csu.crtend) |p| try argv.append(try p.toString(arena));
2369 if (csu.crtn) |p| try argv.append(try p.toString(arena));
23742370
23752371 if (self.base.allow_shlib_undefined) {
23762372 try argv.append("--allow-shlib-undefined");
......@@ -3183,8 +3179,9 @@ fn sortInitFini(self: *Elf) !void {
31833179 const object = atom_ptr.file(self).?.object;
31843180 const priority = blk: {
31853181 if (is_ctor_dtor) {
3186 if (mem.indexOf(u8, object.path, "crtbegin") != null) break :blk std.math.minInt(i32);
3187 if (mem.indexOf(u8, object.path, "crtend") != null) break :blk std.math.maxInt(i32);
3182 const basename = object.path.basename();
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);
31883185 }
31893186 const default: i32 = if (is_ctor_dtor) -1 else std.math.maxInt(i32);
31903187 const name = atom_ptr.name(self);
......@@ -4472,210 +4469,6 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
44724469 return actual_size +| (actual_size / ideal_factor);
44734470}
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
46794472/// If a target compiles other output modes as dynamic libraries,
46804473/// this function returns true for those too.
46814474pub fn isEffectivelyDynLib(self: Elf) bool {
......@@ -5089,13 +4882,13 @@ fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void {
50894882
50904883pub fn addParseError(
50914884 self: *Elf,
5092 path: []const u8,
4885 path: Path,
50934886 comptime format: []const u8,
50944887 args: anytype,
50954888) error{OutOfMemory}!void {
50964889 var err = try self.base.addErrorWithNotes(1);
50974890 try err.addMsg(format, args);
5098 try err.addNote("while parsing {s}", .{path});
4891 try err.addNote("while parsing {}", .{path});
50994892}
51004893
51014894pub fn addFileError(
......@@ -5121,7 +4914,7 @@ pub fn failFile(
51214914
51224915pub fn failParse(
51234916 self: *Elf,
5124 path: []const u8,
4917 path: Path,
51254918 comptime format: []const u8,
51264919 args: anytype,
51274920) error{ OutOfMemory, LinkFailure } {
......@@ -5274,7 +5067,7 @@ fn fmtDumpState(
52745067 _ = options;
52755068
52765069 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 });
52785071 try writer.print("{}{}", .{
52795072 zig_object.fmtAtoms(self),
52805073 zig_object.fmtSymtab(self),
......@@ -5299,7 +5092,7 @@ fn fmtDumpState(
52995092 for (self.shared_objects.items) |index| {
53005093 const shared_object = self.file(index).?.shared_object;
53015094 try writer.print("shared_object({d}) : ", .{index});
5302 try writer.print("{s}", .{shared_object.path});
5095 try writer.print("{}", .{shared_object.path});
53035096 try writer.print(" : needed({})", .{shared_object.needed});
53045097 if (!shared_object.alive) try writer.writeAll(" : [*]");
53055098 try writer.writeByte('\n');
......@@ -5482,7 +5275,7 @@ pub const null_shdr = elf.Elf64_Shdr{
54825275
54835276pub const SystemLib = struct {
54845277 needed: bool = false,
5485 path: []const u8,
5278 path: Path,
54865279};
54875280
54885281pub const Ref = struct {
src/link/Elf/Archive.zig+13-7
......@@ -1,8 +1,8 @@
11objects: std.ArrayListUnmanaged(Object) = .empty,
22strtab: std.ArrayListUnmanaged(u8) = .empty,
33
4pub fn isArchive(path: []const u8) !bool {
5 const file = try std.fs.cwd().openFile(path, .{});
4pub fn isArchive(path: Path) !bool {
5 const file = try path.root_dir.handle.openFile(path.sub_path, .{});
66 defer file.close();
77 const reader = file.reader();
88 const magic = reader.readBytesNoEof(elf.ARMAG.len) catch return false;
......@@ -15,7 +15,7 @@ pub fn deinit(self: *Archive, allocator: Allocator) void {
1515 self.strtab.deinit(allocator);
1616}
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 {
1919 const comp = elf_file.base.comp;
2020 const gpa = comp.gpa;
2121 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
5959 else
6060 unreachable;
6161
62 const object = Object{
62 const object: Object = .{
6363 .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 },
6568 .offset = pos,
6669 .size = obj_size,
6770 },
68 .path = try gpa.dupe(u8, name),
71 .path = Path.initCwd(try gpa.dupe(u8, name)),
6972 .file_handle = handle_index,
7073 .index = undefined,
7174 .alive = false,
7275 };
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
7681 try self.objects.append(gpa, object);
7782 }
......@@ -292,6 +297,7 @@ const elf = std.elf;
292297const fs = std.fs;
293298const log = std.log.scoped(.link);
294299const mem = std.mem;
300const Path = std.Build.Cache.Path;
295301
296302const Allocator = mem.Allocator;
297303const Archive = @This();
src/link/Elf/LdScript.zig+16-10
......@@ -1,6 +1,11 @@
1path: []const u8,
1path: Path,
22cpu_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
510pub fn deinit(scr: *LdScript, allocator: Allocator) void {
611 scr.args.deinit(allocator);
......@@ -47,7 +52,7 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
4752
4853 var it = TokenIterator{ .tokens = tokens.items };
4954 var parser = Parser{ .source = data, .it = &it };
50 var args = std.ArrayList(Elf.SystemLib).init(gpa);
55 var args = std.ArrayList(Arg).init(gpa);
5156 scr.doParse(.{
5257 .parser = &parser,
5358 .args = &args,
......@@ -70,7 +75,7 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
7075
7176fn doParse(scr: *LdScript, ctx: struct {
7277 parser: *Parser,
73 args: *std.ArrayList(Elf.SystemLib),
78 args: *std.ArrayList(Arg),
7479}) !void {
7580 while (true) {
7681 ctx.parser.skipAny(&.{ .comment, .new_line });
......@@ -142,7 +147,7 @@ const Parser = struct {
142147 return error.UnknownCpuArch;
143148 }
144149
145 fn group(p: *Parser, args: *std.ArrayList(Elf.SystemLib)) !void {
150 fn group(p: *Parser, args: *std.ArrayList(Arg)) !void {
146151 if (!p.skip(&.{.lparen})) return error.UnexpectedToken;
147152
148153 while (true) {
......@@ -162,7 +167,7 @@ const Parser = struct {
162167 _ = try p.require(.rparen);
163168 }
164169
165 fn asNeeded(p: *Parser, args: *std.ArrayList(Elf.SystemLib)) !void {
170 fn asNeeded(p: *Parser, args: *std.ArrayList(Arg)) !void {
166171 if (!p.skip(&.{.lparen})) return error.UnexpectedToken;
167172
168173 while (p.maybe(.literal)) |tok_id| {
......@@ -239,7 +244,7 @@ const Token = struct {
239244
240245 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 {
243248 return source[tok.start..tok.end];
244249 }
245250};
......@@ -399,11 +404,11 @@ const TokenIterator = struct {
399404 return it.tokens[it.pos];
400405 }
401406
402 inline fn reset(it: *TokenIterator) void {
407 fn reset(it: *TokenIterator) void {
403408 it.pos = 0;
404409 }
405410
406 inline fn seekTo(it: *TokenIterator, pos: Token.Index) void {
411 fn seekTo(it: *TokenIterator, pos: Token.Index) void {
407412 it.pos = pos;
408413 }
409414
......@@ -416,7 +421,7 @@ const TokenIterator = struct {
416421 }
417422 }
418423
419 inline fn get(it: *TokenIterator, pos: Token.Index) Token {
424 fn get(it: *TokenIterator, pos: Token.Index) Token {
420425 assert(pos < it.tokens.len);
421426 return it.tokens[pos];
422427 }
......@@ -426,6 +431,7 @@ const LdScript = @This();
426431
427432const std = @import("std");
428433const assert = std.debug.assert;
434const Path = std.Build.Cache.Path;
429435
430436const Allocator = std.mem.Allocator;
431437const Elf = @import("../Elf.zig");
src/link/Elf/Object.zig+14-13
......@@ -1,5 +1,7 @@
11archive: ?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,
35file_handle: File.HandleIndex,
46index: File.Index,
57
......@@ -36,8 +38,8 @@ output_symtab_ctx: Elf.SymtabCtx = .{},
3638output_ar_state: Archive.ArState = .{},
3739
3840pub fn deinit(self: *Object, allocator: Allocator) void {
39 if (self.archive) |*ar| allocator.free(ar.path);
40 allocator.free(self.path);
41 if (self.archive) |*ar| allocator.free(ar.path.sub_path);
42 allocator.free(self.path.sub_path);
4143 self.shdrs.deinit(allocator);
4244 self.symtab.deinit(allocator);
4345 self.strtab.deinit(allocator);
......@@ -474,8 +476,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {
474476 if (sym.type(elf_file) != elf.STT_FUNC)
475477 // TODO convert into an error
476478 log.debug("{s}: {s}: CIE referencing external data reference", .{
477 self.fmtPath(),
478 sym.name(elf_file),
479 self.fmtPath(), sym.name(elf_file),
479480 });
480481 sym.flags.needs_plt = true;
481482 }
......@@ -996,7 +997,7 @@ pub fn updateArSize(self: *Object, elf_file: *Elf) !void {
996997pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void {
997998 const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;
998999 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);
10001001 const hdr = Archive.setArHdr(.{
10011002 .name = if (name.len <= Archive.max_member_name_len)
10021003 .{ .name = name }
......@@ -1489,15 +1490,14 @@ fn formatPath(
14891490 _ = unused_fmt_string;
14901491 _ = options;
14911492 if (object.archive) |ar| {
1492 try writer.writeAll(ar.path);
1493 try writer.writeByte('(');
1494 try writer.writeAll(object.path);
1495 try writer.writeByte(')');
1496 } else try writer.writeAll(object.path);
1493 try writer.print("{}({})", .{ ar.path, object.path });
1494 } else {
1495 try writer.print("{}", .{object.path});
1496 }
14971497}
14981498
14991499const InArchive = struct {
1500 path: []const u8,
1500 path: Path,
15011501 offset: u64,
15021502 size: u32,
15031503};
......@@ -1512,8 +1512,9 @@ const fs = std.fs;
15121512const log = std.log.scoped(.link);
15131513const math = std.math;
15141514const mem = std.mem;
1515
1515const Path = std.Build.Cache.Path;
15161516const Allocator = mem.Allocator;
1517
15171518const Archive = @import("Archive.zig");
15181519const Atom = @import("Atom.zig");
15191520const AtomList = @import("AtomList.zig");
src/link/Elf/SharedObject.zig+8-7
......@@ -1,4 +1,4 @@
1path: []const u8,
1path: Path,
22index: File.Index,
33
44header: ?elf.Elf64_Ehdr = null,
......@@ -22,8 +22,8 @@ alive: bool,
2222
2323output_symtab_ctx: Elf.SymtabCtx = .{},
2424
25pub fn isSharedObject(path: []const u8) !bool {
26 const file = try std.fs.cwd().openFile(path, .{});
25pub fn isSharedObject(path: Path) !bool {
26 const file = try path.root_dir.handle.openFile(path.sub_path, .{});
2727 defer file.close();
2828 const reader = file.reader();
2929 const header = reader.readStruct(elf.Elf64_Ehdr) catch return false;
......@@ -34,7 +34,7 @@ pub fn isSharedObject(path: []const u8) !bool {
3434}
3535
3636pub fn deinit(self: *SharedObject, allocator: Allocator) void {
37 allocator.free(self.path);
37 allocator.free(self.path.sub_path);
3838 self.shdrs.deinit(allocator);
3939 self.symtab.deinit(allocator);
4040 self.strtab.deinit(allocator);
......@@ -319,7 +319,7 @@ pub fn asFile(self: *SharedObject) File {
319319
320320fn verdefNum(self: *SharedObject) u32 {
321321 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),
323323 else => {},
324324 };
325325 return 0;
......@@ -327,10 +327,10 @@ fn verdefNum(self: *SharedObject) u32 {
327327
328328pub fn soname(self: *SharedObject) []const u8 {
329329 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)),
331331 else => {},
332332 };
333 return std.fs.path.basename(self.path);
333 return std.fs.path.basename(self.path.sub_path);
334334}
335335
336336pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {
......@@ -508,6 +508,7 @@ const assert = std.debug.assert;
508508const elf = std.elf;
509509const log = std.log.scoped(.elf);
510510const mem = std.mem;
511const Path = std.Build.Cache.Path;
511512
512513const Allocator = mem.Allocator;
513514const Elf = @import("../Elf.zig");
src/link/Elf/ZigObject.zig+4-4
......@@ -5,7 +5,7 @@
55
66data: std.ArrayListUnmanaged(u8) = .empty,
77/// Externally owned memory.
8path: []const u8,
8basename: []const u8,
99index: File.Index,
1010
1111symtab: std.MultiArrayList(ElfSym) = .{},
......@@ -88,7 +88,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
8888 try self.strtab.buffer.append(gpa, 0);
8989
9090 {
91 const name_off = try self.strtab.insert(gpa, self.path);
91 const name_off = try self.strtab.insert(gpa, self.basename);
9292 const symbol_index = try self.newLocalSymbol(gpa, name_off);
9393 const sym = self.symbol(symbol_index);
9494 const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
......@@ -774,7 +774,7 @@ pub fn updateArSize(self: *ZigObject) void {
774774}
775775
776776pub fn writeAr(self: ZigObject, writer: anytype) !void {
777 const name = self.path;
777 const name = self.basename;
778778 const hdr = Archive.setArHdr(.{
779779 .name = if (name.len <= Archive.max_member_name_len)
780780 .{ .name = name }
......@@ -2384,9 +2384,9 @@ const relocation = @import("relocation.zig");
23842384const target_util = @import("../../target.zig");
23852385const trace = @import("../../tracy.zig").trace;
23862386const std = @import("std");
2387const Allocator = std.mem.Allocator;
23872388
23882389const Air = @import("../../Air.zig");
2389const Allocator = std.mem.Allocator;
23902390const Archive = @import("Archive.zig");
23912391const Atom = @import("Atom.zig");
23922392const Dwarf = @import("../Dwarf.zig");
src/link/Elf/file.zig+20-18
......@@ -23,10 +23,10 @@ pub const File = union(enum) {
2323 _ = unused_fmt_string;
2424 _ = options;
2525 switch (file) {
26 .zig_object => |x| try writer.print("{s}", .{x.path}),
26 .zig_object => |zo| try writer.writeAll(zo.basename),
2727 .linker_defined => try writer.writeAll("(linker defined)"),
2828 .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)}),
3030 }
3131 }
3232
......@@ -240,30 +240,31 @@ pub const File = union(enum) {
240240 return switch (file) {
241241 .zig_object => |x| x.updateArSymtab(ar_symtab, elf_file),
242242 .object => |x| x.updateArSymtab(ar_symtab, elf_file),
243 inline else => unreachable,
243 else => unreachable,
244244 };
245245 }
246246
247247 pub fn updateArStrtab(file: File, allocator: Allocator, ar_strtab: *Archive.ArStrtab) !void {
248 const path = switch (file) {
249 .zig_object => |x| x.path,
250 .object => |x| x.path,
251 inline else => unreachable,
252 };
253 const state = switch (file) {
254 .zig_object => |x| &x.output_ar_state,
255 .object => |x| &x.output_ar_state,
256 inline else => unreachable,
257 };
258 if (path.len <= Archive.max_member_name_len) return;
259 state.name_off = try ar_strtab.insert(allocator, path);
248 switch (file) {
249 .zig_object => |zo| {
250 const basename = zo.basename;
251 if (basename.len <= Archive.max_member_name_len) return;
252 zo.output_ar_state.name_off = try ar_strtab.insert(allocator, basename);
253 },
254 .object => |o| {
255 const basename = std.fs.path.basename(o.path.sub_path);
256 if (basename.len <= Archive.max_member_name_len) return;
257 o.output_ar_state.name_off = try ar_strtab.insert(allocator, basename);
258 },
259 else => unreachable,
260 }
260261 }
261262
262263 pub fn updateArSize(file: File, elf_file: *Elf) !void {
263264 return switch (file) {
264265 .zig_object => |x| x.updateArSize(),
265266 .object => |x| x.updateArSize(elf_file),
266 inline else => unreachable,
267 else => unreachable,
267268 };
268269 }
269270
......@@ -271,7 +272,7 @@ pub const File = union(enum) {
271272 return switch (file) {
272273 .zig_object => |x| x.writeAr(writer),
273274 .object => |x| x.writeAr(elf_file, writer),
274 inline else => unreachable,
275 else => unreachable,
275276 };
276277 }
277278
......@@ -292,8 +293,9 @@ pub const File = union(enum) {
292293const std = @import("std");
293294const elf = std.elf;
294295const log = std.log.scoped(.link);
295
296const Path = std.Build.Cache.Path;
296297const Allocator = std.mem.Allocator;
298
297299const Archive = @import("Archive.zig");
298300const Atom = @import("Atom.zig");
299301const Cie = @import("eh_frame.zig").Cie;
src/link/Elf/relocatable.zig+15-11
......@@ -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 {
22 const gpa = comp.gpa;
33
44 for (comp.objects) |obj| {
5 switch (Compilation.classifyFileExt(obj.path)) {
5 switch (Compilation.classifyFileExt(obj.path.sub_path)) {
66 .object => try parseObjectStaticLibReportingFailure(elf_file, obj.path),
77 .static_library => try parseArchiveStaticLibReportingFailure(elf_file, obj.path),
88 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
140140 if (elf_file.base.hasErrors()) return error.FlushFailure;
141141}
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 {
144144 for (comp.objects) |obj| {
145145 if (obj.isObject()) {
146146 try elf_file.parseObjectReportingFailure(obj.path);
......@@ -198,7 +198,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const
198198 if (elf_file.base.hasErrors()) return error.FlushFailure;
199199}
200200
201fn parseObjectStaticLibReportingFailure(elf_file: *Elf, path: []const u8) error{OutOfMemory}!void {
201fn parseObjectStaticLibReportingFailure(elf_file: *Elf, path: Path) error{OutOfMemory}!void {
202202 parseObjectStaticLib(elf_file, path) catch |err| switch (err) {
203203 error.LinkFailure => return,
204204 error.OutOfMemory => return error.OutOfMemory,
......@@ -206,7 +206,7 @@ fn parseObjectStaticLibReportingFailure(elf_file: *Elf, path: []const u8) error{
206206 };
207207}
208208
209fn parseArchiveStaticLibReportingFailure(elf_file: *Elf, path: []const u8) error{OutOfMemory}!void {
209fn parseArchiveStaticLibReportingFailure(elf_file: *Elf, path: Path) error{OutOfMemory}!void {
210210 parseArchiveStaticLib(elf_file, path) catch |err| switch (err) {
211211 error.LinkFailure => return,
212212 error.OutOfMemory => return error.OutOfMemory,
......@@ -214,14 +214,17 @@ fn parseArchiveStaticLibReportingFailure(elf_file: *Elf, path: []const u8) error
214214 };
215215}
216216
217fn parseObjectStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
217fn parseObjectStaticLib(elf_file: *Elf, path: Path) Elf.ParseError!void {
218218 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, .{});
220220 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));
223223 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 },
225228 .file_handle = fh,
226229 .index = index,
227230 } });
......@@ -231,9 +234,9 @@ fn parseObjectStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
231234 try object.parseAr(elf_file);
232235}
233236
234fn parseArchiveStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
237fn parseArchiveStaticLib(elf_file: *Elf, path: Path) Elf.ParseError!void {
235238 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, .{});
237240 const fh = try elf_file.addFileHandle(handle);
238241
239242 var archive = Archive{};
......@@ -531,6 +534,7 @@ const log = std.log.scoped(.link);
531534const math = std.math;
532535const mem = std.mem;
533536const state_log = std.log.scoped(.link_state);
537const Path = std.Build.Cache.Path;
534538const std = @import("std");
535539
536540const Archive = @import("Archive.zig");
src/link/MachO.zig+57-47
......@@ -144,14 +144,14 @@ hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{},
144144pub const Framework = struct {
145145 needed: bool = false,
146146 weak: bool = false,
147 path: []const u8,
147 path: Path,
148148};
149149
150150pub fn hashAddFrameworks(man: *Cache.Manifest, hm: []const Framework) !void {
151151 for (hm) |value| {
152152 man.hash.add(value.needed);
153153 man.hash.add(value.weak);
154 _ = try man.addFile(value.path, null);
154 _ = try man.addFilePath(value.path, null);
155155 }
156156}
157157
......@@ -239,9 +239,9 @@ pub fn createEmpty(
239239 const index: File.Index = @intCast(try self.files.addOne(gpa));
240240 self.files.set(index, .{ .zig_object = .{
241241 .index = index,
242 .path = try std.fmt.allocPrint(arena, "{s}.o", .{fs.path.stem(
243 zcu.main_mod.root_src_path,
244 )}),
242 .basename = try std.fmt.allocPrint(arena, "{s}.o", .{
243 fs.path.stem(zcu.main_mod.root_src_path),
244 }),
245245 } });
246246 self.zig_object = index;
247247 const zo = self.getZigObject().?;
......@@ -356,13 +356,12 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
356356 defer sub_prog_node.end();
357357
358358 const directory = self.base.emit.root_dir;
359 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
360 const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {
361 if (fs.path.dirname(full_out_path)) |dirname| {
362 break :blk try fs.path.join(arena, &.{ dirname, path });
363 } else {
364 break :blk path;
365 }
359 const module_obj_path: ?Path = if (self.base.zcu_object_sub_path) |path| .{
360 .root_dir = directory,
361 .sub_path = if (fs.path.dirname(self.base.emit.sub_path)) |dirname|
362 try fs.path.join(arena, &.{ dirname, path })
363 else
364 path,
366365 } else null;
367366
368367 // --verbose-link
......@@ -455,7 +454,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
455454 }
456455
457456 // Finally, link against compiler_rt.
458 const compiler_rt_path: ?[]const u8 = blk: {
457 const compiler_rt_path: ?Path = blk: {
459458 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
460459 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;
461460 break :blk null;
......@@ -567,7 +566,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
567566 // The most important here is to have the correct vm and filesize of the __LINKEDIT segment
568567 // where the code signature goes into.
569568 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);
571570 if (self.entitlements) |path| try codesig.addEntitlements(gpa, path);
572571 try self.writeCodeSignaturePadding(&codesig);
573572 break :blk codesig;
......@@ -625,11 +624,11 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
625624
626625 if (self.base.isRelocatable()) {
627626 for (comp.objects) |obj| {
628 try argv.append(obj.path);
627 try argv.append(try obj.path.toString(arena));
629628 }
630629
631630 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));
633632 }
634633
635634 if (module_obj_path) |p| {
......@@ -711,11 +710,11 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
711710 if (obj.must_link) {
712711 try argv.append("-force_load");
713712 }
714 try argv.append(obj.path);
713 try argv.append(try obj.path.toString(arena));
715714 }
716715
717716 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));
719718 }
720719
721720 if (module_obj_path) |p| {
......@@ -723,13 +722,12 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
723722 }
724723
725724 if (comp.config.any_sanitize_thread) {
726 const path = comp.tsan_lib.?.full_object_path;
727 try argv.append(path);
728 try argv.appendSlice(&.{ "-rpath", std.fs.path.dirname(path) orelse "." });
725 const path = try comp.tsan_lib.?.full_object_path.toString(arena);
726 try argv.appendSlice(&.{ path, "-rpath", std.fs.path.dirname(path) orelse "." });
729727 }
730728
731729 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));
733731 }
734732
735733 for (self.lib_dirs) |lib_dir| {
......@@ -754,7 +752,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
754752 }
755753
756754 for (self.frameworks) |framework| {
757 const name = fs.path.stem(framework.path);
755 const name = framework.path.stem();
758756 const arg = if (framework.needed)
759757 try std.fmt.allocPrint(arena, "-needed_framework {s}", .{name})
760758 else if (framework.weak)
......@@ -765,14 +763,16 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
765763 }
766764
767765 if (comp.config.link_libcpp) {
768 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
769 try argv.append(comp.libcxx_static_lib.?.full_object_path);
766 try argv.appendSlice(&.{
767 try comp.libcxxabi_static_lib.?.full_object_path.toString(arena),
768 try comp.libcxx_static_lib.?.full_object_path.toString(arena),
769 });
770770 }
771771
772772 try argv.append("-lSystem");
773773
774 if (comp.compiler_rt_lib) |lib| try argv.append(lib.full_object_path);
775 if (comp.compiler_rt_obj) |obj| try argv.append(obj.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(try obj.full_object_path.toString(arena));
776776 }
777777
778778 Compilation.dump_argv(argv.items);
......@@ -807,20 +807,20 @@ pub fn resolveLibSystem(
807807 return error.MissingLibSystem;
808808 }
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));
811811 try out_libs.append(.{
812812 .needed = true,
813813 .path = libsystem_path,
814814 });
815815}
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 {
818818 const tracy = trace(@src());
819819 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, .{});
824824 const fh = try self.addFileHandle(file);
825825 var buffer: [Archive.SARMAG]u8 = undefined;
826826
......@@ -844,7 +844,7 @@ pub fn classifyInputFile(self: *MachO, path: []const u8, lib: SystemLib, must_li
844844 _ = try self.addTbd(lib, true, fh);
845845}
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 {
848848 const fat_h = fat.readFatHeader(file) catch return null;
849849 if (fat_h.magic != macho.FAT_MAGIC and fat_h.magic != macho.FAT_MAGIC_64) return null;
850850 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
873873 return buffer[0..Archive.SARMAG];
874874}
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 {
877877 const tracy = trace(@src());
878878 defer tracy.end();
879879
......@@ -886,7 +886,10 @@ fn addObject(self: *MachO, path: []const u8, handle: File.HandleIndex, offset: u
886886 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
887887 self.files.set(index, .{ .object = .{
888888 .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 },
890893 .file_handle = handle,
891894 .mtime = mtime,
892895 .index = index,
......@@ -937,7 +940,7 @@ fn addArchive(self: *MachO, lib: SystemLib, must_link: bool, handle: File.Handle
937940
938941 const gpa = self.base.comp.gpa;
939942
940 var archive = Archive{};
943 var archive: Archive = .{};
941944 defer archive.deinit(gpa);
942945 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
963966 .offset = offset,
964967 .file_handle = handle,
965968 .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 },
967973 .index = index,
968974 .needed = lib.needed,
969975 .weak = lib.weak,
......@@ -986,7 +992,10 @@ fn addTbd(self: *MachO, lib: SystemLib, explicit: bool, handle: File.HandleIndex
986992 .offset = 0,
987993 .file_handle = handle,
988994 .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 },
990999 .index = index,
9911000 .needed = lib.needed,
9921001 .weak = lib.weak,
......@@ -1175,11 +1184,11 @@ fn parseDependentDylibs(self: *MachO) !void {
11751184 continue;
11761185 }
11771186 };
1178 const lib = SystemLib{
1179 .path = full_path,
1187 const lib: SystemLib = .{
1188 .path = Path.initCwd(full_path),
11801189 .weak = is_weak,
11811190 };
1182 const file = try std.fs.cwd().openFile(lib.path, .{});
1191 const file = try lib.path.root_dir.handle.openFile(lib.path.sub_path, .{});
11831192 const fh = try self.addFileHandle(file);
11841193 const fat_arch = try self.parseFatFile(file, lib.path);
11851194 const offset = if (fat_arch) |fa| fa.offset else 0;
......@@ -2865,7 +2874,8 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
28652874 ncmds += 1;
28662875 }
28672876 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);
28692879 const rpath = std.fs.path.dirname(path) orelse ".";
28702880 try load_commands.writeRpathLC(rpath, writer);
28712881 ncmds += 1;
......@@ -3758,13 +3768,13 @@ pub fn eatPrefix(path: []const u8, prefix: []const u8) ?[]const u8 {
37583768
37593769pub fn reportParseError(
37603770 self: *MachO,
3761 path: []const u8,
3771 path: Path,
37623772 comptime format: []const u8,
37633773 args: anytype,
37643774) error{OutOfMemory}!void {
37653775 var err = try self.base.addErrorWithNotes(1);
37663776 try err.addMsg(format, args);
3767 try err.addNote("while parsing {s}", .{path});
3777 try err.addNote("while parsing {}", .{path});
37683778}
37693779
37703780pub fn reportParseError2(
......@@ -3913,7 +3923,7 @@ fn fmtDumpState(
39133923 _ = options;
39143924 _ = unused_fmt_string;
39153925 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 });
39173927 try writer.print("{}{}\n", .{
39183928 zo.fmtAtoms(self),
39193929 zo.fmtSymtab(self),
......@@ -3938,9 +3948,9 @@ fn fmtDumpState(
39383948 }
39393949 for (self.dylibs.items) |index| {
39403950 const dylib = self.getFile(index).?.dylib;
3941 try writer.print("dylib({d}) : {s} : needed({}) : weak({})", .{
3951 try writer.print("dylib({d}) : {} : needed({}) : weak({})", .{
39423952 index,
3943 dylib.path,
3953 @as(Path, dylib.path),
39443954 dylib.needed,
39453955 dylib.weak,
39463956 });
......@@ -4442,7 +4452,7 @@ pub const default_pagezero_size: u64 = 0x100000000;
44424452pub const default_headerpad_size: u32 = 0x1000;
44434453
44444454const SystemLib = struct {
4445 path: []const u8,
4455 path: Path,
44464456 needed: bool = false,
44474457 weak: bool = false,
44484458 hidden: bool = false,
src/link/MachO/Archive.zig+10-6
......@@ -4,7 +4,7 @@ pub fn deinit(self: *Archive, allocator: Allocator) void {
44 self.objects.deinit(allocator);
55}
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 {
88 const gpa = macho_file.base.comp.gpa;
99
1010 var arena = std.heap.ArenaAllocator.init(gpa);
......@@ -55,20 +55,23 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: []const u8, handle_index
5555 mem.eql(u8, name, SYMDEF_SORTED) or
5656 mem.eql(u8, name, SYMDEF64_SORTED)) continue;
5757
58 const object = Object{
58 const object: Object = .{
5959 .offset = pos,
6060 .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 },
6265 .size = hdr_size,
6366 },
64 .path = try gpa.dupe(u8, name),
67 .path = Path.initCwd(try gpa.dupe(u8, name)),
6568 .file_handle = handle_index,
6669 .index = undefined,
6770 .alive = false,
6871 .mtime = hdr.date() catch 0,
6972 };
7073
71 log.debug("extracting object '{s}' from archive '{s}'", .{ object.path, path });
74 log.debug("extracting object '{}' from archive '{}'", .{ object.path, path });
7275
7376 try self.objects.append(gpa, object);
7477 }
......@@ -301,8 +304,9 @@ const log = std.log.scoped(.link);
301304const macho = std.macho;
302305const mem = std.mem;
303306const std = @import("std");
304
305307const Allocator = mem.Allocator;
308const Path = std.Build.Cache.Path;
309
306310const Archive = @This();
307311const File = @import("file.zig").File;
308312const MachO = @import("../MachO.zig");
src/link/MachO/Dylib.zig+6-5
......@@ -1,6 +1,6 @@
11/// Non-zero for fat dylibs
22offset: u64,
3path: []const u8,
3path: Path,
44index: File.Index,
55file_handle: File.HandleIndex,
66tag: enum { dylib, tbd },
......@@ -28,7 +28,7 @@ referenced: bool = false,
2828output_symtab_ctx: MachO.SymtabCtx = .{},
2929
3030pub fn deinit(self: *Dylib, allocator: Allocator) void {
31 allocator.free(self.path);
31 allocator.free(self.path.sub_path);
3232 self.exports.deinit(allocator);
3333 self.strtab.deinit(allocator);
3434 if (self.id) |*id| id.deinit(allocator);
......@@ -61,7 +61,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {
6161 const file = macho_file.getFileHandle(self.file_handle);
6262 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
6666 var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;
6767 {
......@@ -267,7 +267,7 @@ fn parseTbd(self: *Dylib, macho_file: *MachO) !void {
267267
268268 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
272272 const file = macho_file.getFileHandle(self.file_handle);
273273 var lib_stub = LibStub.loadFromFile(gpa, file) catch |err| {
......@@ -959,8 +959,9 @@ const mem = std.mem;
959959const tapi = @import("../tapi.zig");
960960const trace = @import("../../tracy.zig").trace;
961961const std = @import("std");
962
963962const Allocator = mem.Allocator;
963const Path = std.Build.Cache.Path;
964
964965const Dylib = @This();
965966const File = @import("file.zig").File;
966967const LibStub = tapi.LibStub;
src/link/MachO/Object.zig+45-18
......@@ -1,6 +1,8 @@
11/// Non-zero for fat object files or archives
22offset: 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,
46file_handle: File.HandleIndex,
57mtime: u64,
68index: File.Index,
......@@ -39,8 +41,8 @@ output_symtab_ctx: MachO.SymtabCtx = .{},
3941output_ar_state: Archive.ArState = .{},
4042
4143pub fn deinit(self: *Object, allocator: Allocator) void {
42 if (self.in_archive) |*ar| allocator.free(ar.path);
43 allocator.free(self.path);
44 if (self.in_archive) |*ar| allocator.free(ar.path.sub_path);
45 allocator.free(self.path.sub_path);
4446 for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| {
4547 relocs.deinit(allocator);
4648 sub.deinit(allocator);
......@@ -1723,7 +1725,8 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void {
17231725pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void {
17241726 // Header
17251727 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);
17271730 // Data
17281731 const file = macho_file.getFileHandle(self.file_handle);
17291732 // TODO try using copyRangeAll
......@@ -1774,6 +1777,11 @@ pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void {
17741777 self.calcStabsSize(macho_file);
17751778}
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
17771785pub fn calcStabsSize(self: *Object, macho_file: *MachO) void {
17781786 if (self.compile_unit) |cu| {
17791787 const comp_dir = cu.getCompDir(self.*);
......@@ -1784,9 +1792,9 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) void {
17841792 self.output_symtab_ctx.strsize += @as(u32, @intCast(tu_name.len + 1)); // tu_name
17851793
17861794 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);
17881796 } 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);
17901798 }
17911799
17921800 for (self.symbols.items, 0..) |sym, i| {
......@@ -2118,19 +2126,36 @@ pub fn writeStabs(self: Object, stroff: u32, macho_file: *MachO, ctx: anytype) v
21182126 };
21192127 index += 1;
21202128 if (self.in_archive) |ar| {
2121 @memcpy(ctx.strtab.items[n_strx..][0..ar.path.len], ar.path);
2122 n_strx += @intCast(ar.path.len);
2129 if (ar.path.root_dir.path) |p| {
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);
21232139 ctx.strtab.items[n_strx] = '(';
21242140 n_strx += 1;
2125 @memcpy(ctx.strtab.items[n_strx..][0..self.path.len], self.path);
2126 n_strx += @intCast(self.path.len);
2141 const basename = self.path.basename();
2142 @memcpy(ctx.strtab.items[n_strx..][0..basename.len], basename);
2143 n_strx += @intCast(basename.len);
21272144 ctx.strtab.items[n_strx] = ')';
21282145 n_strx += 1;
21292146 ctx.strtab.items[n_strx] = 0;
21302147 n_strx += 1;
21312148 } else {
2132 @memcpy(ctx.strtab.items[n_strx..][0..self.path.len], self.path);
2133 n_strx += @intCast(self.path.len);
2149 if (self.path.root_dir.path) |p| {
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);
21342159 ctx.strtab.items[n_strx] = 0;
21352160 n_strx += 1;
21362161 }
......@@ -2666,11 +2691,12 @@ fn formatPath(
26662691 _ = unused_fmt_string;
26672692 _ = options;
26682693 if (object.in_archive) |ar| {
2669 try writer.writeAll(ar.path);
2670 try writer.writeByte('(');
2671 try writer.writeAll(object.path);
2672 try writer.writeByte(')');
2673 } else try writer.writeAll(object.path);
2694 try writer.print("{}({s})", .{
2695 @as(Path, ar.path), object.path.basename(),
2696 });
2697 } else {
2698 try writer.print("{}", .{@as(Path, object.path)});
2699 }
26742700}
26752701
26762702const Section = struct {
......@@ -2777,7 +2803,7 @@ const CompileUnit = struct {
27772803};
27782804
27792805const InArchive = struct {
2780 path: []const u8,
2806 path: Path,
27812807 size: u32,
27822808};
27832809
......@@ -3170,6 +3196,7 @@ const math = std.math;
31703196const mem = std.mem;
31713197const trace = @import("../../tracy.zig").trace;
31723198const std = @import("std");
3199const Path = std.Build.Cache.Path;
31733200
31743201const Allocator = mem.Allocator;
31753202const Archive = @import("Archive.zig");
src/link/MachO/ZigObject.zig+2-2
......@@ -1,6 +1,6 @@
11data: std.ArrayListUnmanaged(u8) = .empty,
22/// Externally owned memory.
3path: []const u8,
3basename: []const u8,
44index: File.Index,
55
66symtab: std.MultiArrayList(Nlist) = .{},
......@@ -317,7 +317,7 @@ pub fn updateArSize(self: *ZigObject) void {
317317pub fn writeAr(self: ZigObject, ar_format: Archive.Format, writer: anytype) !void {
318318 // Header
319319 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);
321321 // Data
322322 try writer.writeAll(self.data.items);
323323}
src/link/MachO/file.zig+6-5
......@@ -23,10 +23,10 @@ pub const File = union(enum) {
2323 _ = unused_fmt_string;
2424 _ = options;
2525 switch (file) {
26 .zig_object => |x| try writer.writeAll(x.path),
26 .zig_object => |zo| try writer.writeAll(zo.basename),
2727 .internal => try writer.writeAll("internal"),
2828 .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)}),
3030 }
3131 }
3232
......@@ -373,13 +373,14 @@ pub const File = union(enum) {
373373 pub const HandleIndex = Index;
374374};
375375
376const std = @import("std");
376377const assert = std.debug.assert;
377378const log = std.log.scoped(.link);
378379const macho = std.macho;
379const std = @import("std");
380const trace = @import("../../tracy.zig").trace;
381
382380const Allocator = std.mem.Allocator;
381const Path = std.Build.Cache.Path;
382
383const trace = @import("../../tracy.zig").trace;
383384const Archive = @import("Archive.zig");
384385const Atom = @import("Atom.zig");
385386const 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
7272 }
7373
7474 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);
7677 const rpath = std.fs.path.dirname(path) orelse ".";
7778 sizeofcmds += calcInstallNameLen(
7879 @sizeOf(macho.rpath_command),
src/link/MachO/relocatable.zig+23-17
......@@ -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 {
22 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.
45 var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);
56 defer positionals.deinit();
67 try positionals.ensureUnusedCapacity(comp.objects.len);
......@@ -19,7 +20,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]c
1920 // TODO: in the future, when we implement `dsymutil` alternative directly in the Zig
2021 // compiler, investigate if we can get rid of this `if` prong here.
2122 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, .{});
2324 const stat = try in_file.stat();
2425 const amt = try in_file.copyRangeAll(0, macho_file.base.file.?, 0, stat.size);
2526 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
7273 try writeHeader(macho_file, ncmds, sizeofcmds);
7374}
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 {
7677 const gpa = comp.gpa;
7778
7879 var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);
......@@ -173,21 +174,25 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
173174
174175 for (files.items) |index| {
175176 const file = macho_file.getFile(index).?;
176 const state = switch (file) {
177 .zig_object => |x| &x.output_ar_state,
178 .object => |x| &x.output_ar_state,
177 switch (file) {
178 .zig_object => |zo| {
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 },
179194 else => unreachable,
180 };
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;
195 }
191196 }
192197
193198 break :blk pos;
......@@ -777,6 +782,7 @@ const mem = std.mem;
777782const state_log = std.log.scoped(.link_state);
778783const std = @import("std");
779784const trace = @import("../../tracy.zig").trace;
785const Path = std.Build.Cache.Path;
780786
781787const Archive = @import("Archive.zig");
782788const 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 {
1515 if (gop.found_existing) return gop.key_ptr.*;
1616
1717 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
2020 self.buffer.appendSliceAssumeCapacity(string);
2121 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
25072507 } else null;
25082508
25092509 // 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.
25102511 var positionals = std.ArrayList([]const u8).init(arena);
25112512 try positionals.ensureUnusedCapacity(comp.objects.len);
25122513
......@@ -2527,23 +2528,23 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
25272528 (output_mode == .Lib and link_mode == .dynamic);
25282529 if (is_exe_or_dyn_lib) {
25292530 for (comp.wasi_emulated_libs) |crt_file| {
2530 try positionals.append(try comp.get_libc_crt_file(
2531 try positionals.append(try comp.crtFileAsString(
25312532 arena,
25322533 wasi_libc.emulatedLibCRFileLibName(crt_file),
25332534 ));
25342535 }
25352536
25362537 if (link_libc) {
2537 try positionals.append(try comp.get_libc_crt_file(
2538 try positionals.append(try comp.crtFileAsString(
25382539 arena,
25392540 wasi_libc.execModelCrtFileFullName(wasi_exec_model),
25402541 ));
2541 try positionals.append(try comp.get_libc_crt_file(arena, "libc.a"));
2542 try positionals.append(try comp.crtFileAsString(arena, "libc.a"));
25422543 }
25432544
25442545 if (link_libcpp) {
2545 try positionals.append(comp.libcxx_static_lib.?.full_object_path);
2546 try positionals.append(comp.libcxxabi_static_lib.?.full_object_path);
2546 try positionals.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena));
2547 try positionals.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena));
25472548 }
25482549 }
25492550 }
......@@ -2553,15 +2554,15 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
25532554 }
25542555
25552556 for (comp.objects) |object| {
2556 try positionals.append(object.path);
2557 try positionals.append(try object.path.toString(arena));
25572558 }
25582559
25592560 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));
25612562 }
25622563
2563 if (comp.compiler_rt_lib) |lib| try positionals.append(lib.full_object_path);
2564 if (comp.compiler_rt_obj) |obj| try positionals.append(obj.full_object_path);
2564 if (comp.compiler_rt_lib) |lib| try positionals.append(try lib.full_object_path.toString(arena));
2565 if (comp.compiler_rt_obj) |obj| try positionals.append(try obj.full_object_path.toString(arena));
25652566
25662567 try wasm.parseInputFiles(positionals.items);
25672568
......@@ -3365,7 +3366,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
33653366 defer sub_prog_node.end();
33663367
33673368 const is_obj = comp.config.output_mode == .Obj;
3368 const compiler_rt_path: ?[]const u8 = blk: {
3369 const compiler_rt_path: ?Path = blk: {
33693370 if (comp.compiler_rt_lib) |lib| break :blk lib.full_object_path;
33703371 if (comp.compiler_rt_obj) |obj| break :blk obj.full_object_path;
33713372 break :blk null;
......@@ -3387,14 +3388,14 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
33873388 comptime assert(Compilation.link_hash_implementation_version == 14);
33883389
33893390 for (comp.objects) |obj| {
3390 _ = try man.addFile(obj.path, null);
3391 _ = try man.addFilePath(obj.path, null);
33913392 man.hash.add(obj.must_link);
33923393 }
33933394 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);
33953396 }
33963397 try man.addOptionalFile(module_obj_path);
3397 try man.addOptionalFile(compiler_rt_path);
3398 try man.addOptionalFilePath(compiler_rt_path);
33983399 man.hash.addOptionalBytes(wasm.entry_name);
33993400 man.hash.add(wasm.base.stack_size);
34003401 man.hash.add(wasm.base.build_id);
......@@ -3450,17 +3451,19 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
34503451 break :blk comp.c_object_table.keys()[0].status.success.object_path;
34513452
34523453 if (module_obj_path) |p|
3453 break :blk p;
3454 break :blk Path.initCwd(p);
34543455
34553456 // TODO I think this is unreachable. Audit this situation when solving the above TODO
34563457 // regarding eliding redundant object -> object transformations.
34573458 return error.NoObjectsToLink;
34583459 };
3459 // This can happen when using --enable-cache and using the stage1 backend. In this case
3460 // we can skip the file copy.
3461 if (!mem.eql(u8, the_object_path, full_out_path)) {
3462 try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});
3463 }
3460 try std.fs.Dir.copyFile(
3461 the_object_path.root_dir.handle,
3462 the_object_path.sub_path,
3463 directory.handle,
3464 wasm.base.emit.sub_path,
3465 .{},
3466 );
34643467 } else {
34653468 // Create an LLD command line and invoke it.
34663469 var argv = std.ArrayList([]const u8).init(gpa);
......@@ -3581,23 +3584,23 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
35813584 (comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic);
35823585 if (is_exe_or_dyn_lib) {
35833586 for (comp.wasi_emulated_libs) |crt_file| {
3584 try argv.append(try comp.get_libc_crt_file(
3587 try argv.append(try comp.crtFileAsString(
35853588 arena,
35863589 wasi_libc.emulatedLibCRFileLibName(crt_file),
35873590 ));
35883591 }
35893592
35903593 if (comp.config.link_libc) {
3591 try argv.append(try comp.get_libc_crt_file(
3594 try argv.append(try comp.crtFileAsString(
35923595 arena,
35933596 wasi_libc.execModelCrtFileFullName(comp.config.wasi_exec_model),
35943597 ));
3595 try argv.append(try comp.get_libc_crt_file(arena, "libc.a"));
3598 try argv.append(try comp.crtFileAsString(arena, "libc.a"));
35963599 }
35973600
35983601 if (comp.config.link_libcpp) {
3599 try argv.append(comp.libcxx_static_lib.?.full_object_path);
3600 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
3602 try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena));
3603 try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena));
36013604 }
36023605 }
36033606 }
......@@ -3612,7 +3615,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
36123615 try argv.append("-no-whole-archive");
36133616 whole_archive = false;
36143617 }
3615 try argv.append(obj.path);
3618 try argv.append(try obj.path.toString(arena));
36163619 }
36173620 if (whole_archive) {
36183621 try argv.append("-no-whole-archive");
......@@ -3620,7 +3623,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
36203623 }
36213624
36223625 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));
36243627 }
36253628 if (module_obj_path) |p| {
36263629 try argv.append(p);
......@@ -3630,11 +3633,11 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
36303633 !comp.skip_linker_dependencies and
36313634 !comp.config.link_libc)
36323635 {
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));
36343637 }
36353638
36363639 if (compiler_rt_path) |p| {
3637 try argv.append(p);
3640 try argv.append(try p.toString(arena));
36383641 }
36393642
36403643 if (comp.verbose_link) {
src/main.zig+24-23
......@@ -13,6 +13,12 @@ const warn = std.log.warn;
1313const ThreadPool = std.Thread.Pool;
1414const cleanExit = std.process.cleanExit;
1515const 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
1723const tracy = @import("tracy.zig");
1824const Compilation = @import("Compilation.zig");
......@@ -20,16 +26,11 @@ const link = @import("link.zig");
2026const Package = @import("Package.zig");
2127const build_options = @import("build_options");
2228const introspect = @import("introspect.zig");
23const EnvVar = std.zig.EnvVar;
24const LibCInstallation = std.zig.LibCInstallation;
2529const wasi_libc = @import("wasi_libc.zig");
26const Cache = std.Build.Cache;
2730const target_util = @import("target.zig");
2831const crash_report = @import("crash_report.zig");
2932const Zcu = @import("Zcu.zig");
30const AstGen = std.zig.AstGen;
3133const mingw = @import("mingw.zig");
32const Server = std.zig.Server;
3334const dev = @import("dev.zig");
3435
3536pub const std_options = .{
......@@ -1724,14 +1725,14 @@ fn buildOutputType(
17241725 }
17251726 } else switch (file_ext orelse Compilation.classifyFileExt(arg)) {
17261727 .shared_library => {
1727 try create_module.link_objects.append(arena, .{ .path = arg });
1728 try create_module.link_objects.append(arena, .{ .path = Path.initCwd(arg) });
17281729 create_module.opts.any_dyn_libs = true;
17291730 },
17301731 .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) });
17321733 },
17331734 .res => {
1734 try create_module.link_objects.append(arena, .{ .path = arg });
1735 try create_module.link_objects.append(arena, .{ .path = Path.initCwd(arg) });
17351736 contains_res_file = true;
17361737 },
17371738 .manifest => {
......@@ -1845,20 +1846,20 @@ fn buildOutputType(
18451846 },
18461847 .shared_library => {
18471848 try create_module.link_objects.append(arena, .{
1848 .path = it.only_arg,
1849 .path = Path.initCwd(it.only_arg),
18491850 .must_link = must_link,
18501851 });
18511852 create_module.opts.any_dyn_libs = true;
18521853 },
18531854 .unknown, .object, .static_library => {
18541855 try create_module.link_objects.append(arena, .{
1855 .path = it.only_arg,
1856 .path = Path.initCwd(it.only_arg),
18561857 .must_link = must_link,
18571858 });
18581859 },
18591860 .res => {
18601861 try create_module.link_objects.append(arena, .{
1861 .path = it.only_arg,
1862 .path = Path.initCwd(it.only_arg),
18621863 .must_link = must_link,
18631864 });
18641865 contains_res_file = true;
......@@ -1894,7 +1895,7 @@ fn buildOutputType(
18941895 // binary: no extra rpaths and DSO filename exactly
18951896 // as provided. Hello, Go.
18961897 try create_module.link_objects.append(arena, .{
1897 .path = it.only_arg,
1898 .path = Path.initCwd(it.only_arg),
18981899 .must_link = must_link,
18991900 .loption = true,
19001901 });
......@@ -2532,7 +2533,7 @@ fn buildOutputType(
25322533 install_name = linker_args_it.nextOrFatal();
25332534 } else if (mem.eql(u8, arg, "-force_load")) {
25342535 try create_module.link_objects.append(arena, .{
2535 .path = linker_args_it.nextOrFatal(),
2536 .path = Path.initCwd(linker_args_it.nextOrFatal()),
25362537 .must_link = true,
25372538 });
25382539 } else if (mem.eql(u8, arg, "-hash-style") or
......@@ -2707,7 +2708,7 @@ fn buildOutputType(
27072708 break :b create_module.c_source_files.items[0].src_path;
27082709
27092710 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
27122713 if (emit_bin == .yes)
27132714 break :b emit_bin.yes;
......@@ -2963,7 +2964,7 @@ fn buildOutputType(
29632964 framework_dir_path,
29642965 framework_name,
29652966 )) {
2966 const path = try arena.dupe(u8, test_path.items);
2967 const path = Path.initCwd(try arena.dupe(u8, test_path.items));
29672968 try resolved_frameworks.append(.{
29682969 .needed = info.needed,
29692970 .weak = info.weak,
......@@ -3635,7 +3636,7 @@ const CreateModule = struct {
36353636 name: []const u8,
36363637 lib: Compilation.SystemLib,
36373638 }),
3638 wasi_emulated_libs: std.ArrayListUnmanaged(wasi_libc.CRTFile),
3639 wasi_emulated_libs: std.ArrayListUnmanaged(wasi_libc.CrtFile),
36393640
36403641 c_source_files: std.ArrayListUnmanaged(Compilation.CSourceFile),
36413642 rc_source_files: std.ArrayListUnmanaged(Compilation.RcSourceFile),
......@@ -3808,7 +3809,7 @@ fn createModule(
38083809 }
38093810
38103811 if (target.os.tag == .wasi) {
3811 if (wasi_libc.getEmulatedLibCRTFile(lib_name)) |crt_file| {
3812 if (wasi_libc.getEmulatedLibCrtFile(lib_name)) |crt_file| {
38123813 try create_module.wasi_emulated_libs.append(arena, crt_file);
38133814 continue;
38143815 }
......@@ -3929,7 +3930,7 @@ fn createModule(
39293930 target,
39303931 info.preferred_mode,
39313932 )) {
3932 const path = try arena.dupe(u8, test_path.items);
3933 const path = Path.initCwd(try arena.dupe(u8, test_path.items));
39333934 switch (info.preferred_mode) {
39343935 .static => try create_module.link_objects.append(arena, .{ .path = path }),
39353936 .dynamic => try create_module.resolved_system_libs.append(arena, .{
......@@ -3963,7 +3964,7 @@ fn createModule(
39633964 target,
39643965 info.fallbackMode(),
39653966 )) {
3966 const path = try arena.dupe(u8, test_path.items);
3967 const path = Path.initCwd(try arena.dupe(u8, test_path.items));
39673968 switch (info.fallbackMode()) {
39683969 .static => try create_module.link_objects.append(arena, .{ .path = path }),
39693970 .dynamic => try create_module.resolved_system_libs.append(arena, .{
......@@ -3997,7 +3998,7 @@ fn createModule(
39973998 target,
39983999 info.preferred_mode,
39994000 )) {
4000 const path = try arena.dupe(u8, test_path.items);
4001 const path = Path.initCwd(try arena.dupe(u8, test_path.items));
40014002 switch (info.preferred_mode) {
40024003 .static => try create_module.link_objects.append(arena, .{ .path = path }),
40034004 .dynamic => try create_module.resolved_system_libs.append(arena, .{
......@@ -4021,7 +4022,7 @@ fn createModule(
40214022 target,
40224023 info.fallbackMode(),
40234024 )) {
4024 const path = try arena.dupe(u8, test_path.items);
4025 const path = Path.initCwd(try arena.dupe(u8, test_path.items));
40254026 switch (info.fallbackMode()) {
40264027 .static => try create_module.link_objects.append(arena, .{ .path = path }),
40274028 .dynamic => try create_module.resolved_system_libs.append(arena, .{
......@@ -6163,7 +6164,7 @@ fn cmdAstCheck(
61636164 }
61646165
61656166 file.mod = try Package.Module.createLimited(arena, .{
6166 .root = Cache.Path.cwd(),
6167 .root = Path.cwd(),
61676168 .root_src_path = file.sub_file_path,
61686169 .fully_qualified_name = "root",
61696170 });
......@@ -6523,7 +6524,7 @@ fn cmdChangelist(
65236524 };
65246525
65256526 file.mod = try Package.Module.createLimited(arena, .{
6526 .root = Cache.Path.cwd(),
6527 .root = Path.cwd(),
65276528 .root_src_path = file.sub_file_path,
65286529 .fully_qualified_name = "root",
65296530 });
src/mingw.zig+23-19
......@@ -11,13 +11,13 @@ const build_options = @import("build_options");
1111const Cache = std.Build.Cache;
1212const dev = @import("dev.zig");
1313
14pub const CRTFile = enum {
14pub const CrtFile = enum {
1515 crt2_o,
1616 dllcrt2_o,
1717 mingw32_lib,
1818};
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 {
2121 if (!build_options.have_llvm) {
2222 return error.ZigCompilerNotBuiltWithLLVMExtensions;
2323 }
......@@ -160,7 +160,9 @@ fn add_cc_args(
160160pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
161161 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);
164166 defer arena_allocator.deinit();
165167 const arena = arena_allocator.allocator();
166168
......@@ -178,7 +180,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
178180
179181 // Use the global cache directory.
180182 var cache: Cache = .{
181 .gpa = comp.gpa,
183 .gpa = gpa,
182184 .manifest_dir = try comp.global_cache_directory.handle.makeOpenPath("h", .{}),
183185 };
184186 cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });
......@@ -195,17 +197,18 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
195197
196198 _ = try man.addFile(def_file_path, null);
197199
198 const final_lib_basename = try std.fmt.allocPrint(comp.gpa, "{s}.lib", .{lib_name});
199 errdefer comp.gpa.free(final_lib_basename);
200 const final_lib_basename = try std.fmt.allocPrint(gpa, "{s}.lib", .{lib_name});
201 errdefer gpa.free(final_lib_basename);
200202
201203 if (try man.hit()) {
202204 const digest = man.final();
203205
204 try comp.crt_files.ensureUnusedCapacity(comp.gpa, 1);
206 try comp.crt_files.ensureUnusedCapacity(gpa, 1);
205207 comp.crt_files.putAssumeCapacityNoClobber(final_lib_basename, .{
206 .full_object_path = try comp.global_cache_directory.join(comp.gpa, &[_][]const u8{
207 "o", &digest, final_lib_basename,
208 }),
208 .full_object_path = .{
209 .root_dir = comp.global_cache_directory,
210 .sub_path = try std.fs.path.join(gpa, &.{ "o", &digest, final_lib_basename }),
211 },
209212 .lock = man.toOwnedLock(),
210213 });
211214 return;
......@@ -230,7 +233,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
230233 };
231234
232235 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());
234237 defer aro_comp.deinit();
235238
236239 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 {
244247 nosuspend stderr.print("output path: {s}\n", .{def_final_path}) catch break :print;
245248 }
246249
247 try aro_comp.include_dirs.append(comp.gpa, include_dir);
250 try aro_comp.include_dirs.append(gpa, include_dir);
248251
249252 const builtin_macros = try aro_comp.generateBuiltinMacros(.include_system_defines);
250253 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 {
271274 try pp.prettyPrintTokens(def_final_file.writer(), .result_only);
272275 }
273276
274 const lib_final_path = try comp.global_cache_directory.join(comp.gpa, &[_][]const u8{
275 "o", &digest, final_lib_basename,
276 });
277 errdefer comp.gpa.free(lib_final_path);
277 const lib_final_path = try std.fs.path.join(gpa, &.{ "o", &digest, final_lib_basename });
278 errdefer gpa.free(lib_final_path);
278279
279280 if (!build_options.have_llvm) return error.ZigCompilerNotBuiltWithLLVMExtensions;
280281 const llvm_bindings = @import("codegen/llvm/bindings.zig");
281282 const llvm = @import("codegen/llvm.zig");
282283 const arch_tag = llvm.targetArch(target.cpu.arch);
283284 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});
285286 if (llvm_bindings.WriteImportLibrary(def_final_path_z.ptr, arch_tag, lib_final_path_z.ptr, true)) {
286287 // TODO surface a proper error here
287288 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 {
292293 log.warn("failed to write cache manifest for DLL import {s}.lib: {s}", .{ lib_name, @errorName(err) });
293294 };
294295
295 try comp.crt_files.putNoClobber(comp.gpa, final_lib_basename, .{
296 .full_object_path = lib_final_path,
296 try comp.crt_files.putNoClobber(gpa, final_lib_basename, .{
297 .full_object_path = .{
298 .root_dir = comp.global_cache_directory,
299 .sub_path = lib_final_path,
300 },
297301 .lock = man.toOwnedLock(),
298302 });
299303}
src/musl.zig+2-2
......@@ -9,7 +9,7 @@ const archName = std.zig.target.muslArchName;
99const Compilation = @import("Compilation.zig");
1010const build_options = @import("build_options");
1111
12pub const CRTFile = enum {
12pub const CrtFile = enum {
1313 crti_o,
1414 crtn_o,
1515 crt1_o,
......@@ -19,7 +19,7 @@ pub const CRTFile = enum {
1919 libc_so,
2020};
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 {
2323 if (!build_options.have_llvm) {
2424 return error.ZigCompilerNotBuiltWithLLVMExtensions;
2525 }
src/wasi_libc.zig+7-7
......@@ -6,7 +6,7 @@ const Allocator = std.mem.Allocator;
66const Compilation = @import("Compilation.zig");
77const build_options = @import("build_options");
88
9pub const CRTFile = enum {
9pub const CrtFile = enum {
1010 crt1_reactor_o,
1111 crt1_command_o,
1212 libc_a,
......@@ -16,7 +16,7 @@ pub const CRTFile = enum {
1616 libwasi_emulated_signal_a,
1717};
1818
19pub fn getEmulatedLibCRTFile(lib_name: []const u8) ?CRTFile {
19pub fn getEmulatedLibCrtFile(lib_name: []const u8) ?CrtFile {
2020 if (mem.eql(u8, lib_name, "wasi-emulated-process-clocks")) {
2121 return .libwasi_emulated_process_clocks_a;
2222 }
......@@ -32,7 +32,7 @@ pub fn getEmulatedLibCRTFile(lib_name: []const u8) ?CRTFile {
3232 return null;
3333}
3434
35pub fn emulatedLibCRFileLibName(crt_file: CRTFile) []const u8 {
35pub fn emulatedLibCRFileLibName(crt_file: CrtFile) []const u8 {
3636 return switch (crt_file) {
3737 .libwasi_emulated_process_clocks_a => "libwasi-emulated-process-clocks.a",
3838 .libwasi_emulated_getpid_a => "libwasi-emulated-getpid.a",
......@@ -42,10 +42,10 @@ pub fn emulatedLibCRFileLibName(crt_file: CRTFile) []const u8 {
4242 };
4343}
4444
45pub fn execModelCrtFile(wasi_exec_model: std.builtin.WasiExecModel) CRTFile {
45pub fn execModelCrtFile(wasi_exec_model: std.builtin.WasiExecModel) CrtFile {
4646 return switch (wasi_exec_model) {
47 .reactor => CRTFile.crt1_reactor_o,
48 .command => CRTFile.crt1_command_o,
47 .reactor => CrtFile.crt1_reactor_o,
48 .command => CrtFile.crt1_command_o,
4949 };
5050}
5151
......@@ -57,7 +57,7 @@ pub fn execModelCrtFileFullName(wasi_exec_model: std.builtin.WasiExecModel) []co
5757 };
5858}
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 {
6161 if (!build_options.have_llvm) {
6262 return error.ZigCompilerNotBuiltWithLLVMExtensions;
6363 }