authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-10 22:30:04-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-10-10 22:30:04-07:00
log1340565e22e154db41e90a8d4f0b552176711ba0
tree0fcb0dde8105082065f46d1f477c97903f69b7e5
parent92ae5818d26925af7816fabcaec85236133b9e46
parent2857a3bcb61ad8f119f46acf3a76fd70195f9bd5
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #21654 from ziglang/embrace-path-abstraction

link: fix false positive crtbegin/crtend detection

32 files changed, 987 insertions(+), 701 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+22-2
......@@ -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,
......@@ -137,7 +149,7 @@ pub fn format(
137149 const stringEscape = std.zig.stringEscape;
138150 const f = switch (fmt_string[0]) {
139151 'q' => "",
140 '\'' => '\'',
152 '\'' => "\'",
141153 else => @compileError("unsupported format string: " ++ fmt_string),
142154 };
143155 if (self.root_dir.path) |p| {
......@@ -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/Build/Step/CheckObject.zig+32-12
......@@ -557,15 +557,15 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
557557 const check_object: *CheckObject = @fieldParentPtr("step", step);
558558 try step.singleUnchangingWatchInput(check_object.source);
559559
560 const src_path = check_object.source.getPath2(b, step);
561 const contents = fs.cwd().readFileAllocOptions(
560 const src_path = check_object.source.getPath3(b, step);
561 const contents = src_path.root_dir.handle.readFileAllocOptions(
562562 gpa,
563 src_path,
563 src_path.sub_path,
564564 check_object.max_bytes,
565565 null,
566566 @alignOf(u64),
567567 null,
568 ) catch |err| return step.fail("unable to read '{s}': {s}", .{ src_path, @errorName(err) });
568 ) catch |err| return step.fail("unable to read '{'}': {s}", .{ src_path, @errorName(err) });
569569
570570 var vars = std.StringHashMap(u64).init(gpa);
571571 for (check_object.checks.items) |chk| {
......@@ -640,8 +640,13 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
640640 \\{s}
641641 \\========= but parsed file does not contain it: =======
642642 \\{s}
643 \\======================================================
644 , .{ fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output) });
643 \\========= file path: =================================
644 \\{}
645 , .{
646 fmtMessageString(chk.kind, act.phrase.resolve(b, step)),
647 fmtMessageString(chk.kind, output),
648 src_path,
649 });
645650 }
646651 },
647652
......@@ -655,8 +660,13 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
655660 \\*{s}*
656661 \\========= but parsed file does not contain it: =======
657662 \\{s}
658 \\======================================================
659 , .{ fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output) });
663 \\========= file path: =================================
664 \\{}
665 , .{
666 fmtMessageString(chk.kind, act.phrase.resolve(b, step)),
667 fmtMessageString(chk.kind, output),
668 src_path,
669 });
660670 }
661671 },
662672
......@@ -669,8 +679,13 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
669679 \\{s}
670680 \\========= but parsed file does contain it: ========
671681 \\{s}
672 \\===================================================
673 , .{ fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output) });
682 \\========= file path: ==============================
683 \\{}
684 , .{
685 fmtMessageString(chk.kind, act.phrase.resolve(b, step)),
686 fmtMessageString(chk.kind, output),
687 src_path,
688 });
674689 }
675690 },
676691
......@@ -684,8 +699,13 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
684699 \\{s}
685700 \\========= but parsed file does not contain it: =======
686701 \\{s}
687 \\======================================================
688 , .{ act.phrase.resolve(b, step), fmtMessageString(chk.kind, output) });
702 \\========= file path: ==============================
703 \\{}
704 , .{
705 act.phrase.resolve(b, step),
706 fmtMessageString(chk.kind, output),
707 src_path,
708 });
689709 }
690710 },
691711
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+102-63
......@@ -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.
......@@ -2302,7 +2302,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
23022302 try pt.processExports();
23032303 }
23042304
2305 if (try comp.totalErrorCount() != 0) {
2305 if (anyErrors(comp)) {
23062306 // Skip flushing and keep source files loaded for error reporting.
23072307 comp.link_error_flags = .{};
23082308 return;
......@@ -2392,6 +2392,10 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
23922392 .sub_path = o_sub_path,
23932393 }, .main, main_progress_node);
23942394
2395 // Calling `flush` may have produced errors, in which case the
2396 // cache manifest must not be written.
2397 if (anyErrors(comp)) return;
2398
23952399 // Failure here only means an unnecessary cache miss.
23962400 man.writeManifest() catch |err| {
23972401 log.warn("failed to write cache manifest: {s}", .{@errorName(err)});
......@@ -2578,7 +2582,7 @@ fn addNonIncrementalStuffToCacheManifest(
25782582 }
25792583
25802584 for (comp.objects) |obj| {
2581 _ = try man.addFile(obj.path, null);
2585 _ = try man.addFilePath(obj.path, null);
25822586 man.hash.add(obj.must_link);
25832587 man.hash.add(obj.loption);
25842588 }
......@@ -2703,9 +2707,8 @@ fn emitOthers(comp: *Compilation) void {
27032707 return;
27042708 }
27052709 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];
2710 const ext = std.fs.path.extension(obj_path.sub_path);
2711 const dirname = obj_path.sub_path[0 .. obj_path.sub_path.len - ext.len];
27092712 // This obj path always ends with the object file extension, but if we change the
27102713 // extension to .ll, .bc, or .s, then it will be the path to those things.
27112714 const outs = [_]struct {
......@@ -2720,13 +2723,13 @@ fn emitOthers(comp: *Compilation) void {
27202723 if (out.emit) |loc| {
27212724 if (loc.directory) |directory| {
27222725 const src_path = std.fmt.allocPrint(comp.gpa, "{s}{s}", .{
2723 basename, out.ext,
2726 dirname, out.ext,
27242727 }) catch |err| {
2725 log.err("unable to copy {s}{s}: {s}", .{ basename, out.ext, @errorName(err) });
2728 log.err("unable to copy {s}{s}: {s}", .{ dirname, out.ext, @errorName(err) });
27262729 continue;
27272730 };
27282731 defer comp.gpa.free(src_path);
2729 cwd.copyFile(src_path, directory.handle, loc.basename, .{}) catch |err| {
2732 obj_path.root_dir.handle.copyFile(src_path, directory.handle, loc.basename, .{}) catch |err| {
27302733 log.err("unable to copy {s}: {s}", .{ src_path, @errorName(err) });
27312734 };
27322735 }
......@@ -3292,6 +3295,10 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
32923295 return bundle.toOwnedBundle(compile_log_text);
32933296}
32943297
3298fn anyErrors(comp: *Compilation) bool {
3299 return (totalErrorCount(comp) catch return true) != 0;
3300}
3301
32953302fn totalErrorCount(comp: *Compilation) !u32 {
32963303 var errors = try comp.getAllErrorsAlloc();
32973304 defer errors.deinit(comp.gpa);
......@@ -3774,7 +3781,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
37743781 const named_frame = tracy.namedFrame("glibc_crt_file");
37753782 defer named_frame.end();
37763783
3777 glibc.buildCRTFile(comp, crt_file, prog_node) catch |err| {
3784 glibc.buildCrtFile(comp, crt_file, prog_node) catch |err| {
37783785 // TODO Surface more error details.
37793786 comp.lockAndSetMiscFailure(.glibc_crt_file, "unable to build glibc CRT file: {s}", .{
37803787 @errorName(err),
......@@ -3798,7 +3805,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
37983805 const named_frame = tracy.namedFrame("musl_crt_file");
37993806 defer named_frame.end();
38003807
3801 musl.buildCRTFile(comp, crt_file, prog_node) catch |err| {
3808 musl.buildCrtFile(comp, crt_file, prog_node) catch |err| {
38023809 // TODO Surface more error details.
38033810 comp.lockAndSetMiscFailure(
38043811 .musl_crt_file,
......@@ -3811,7 +3818,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
38113818 const named_frame = tracy.namedFrame("mingw_crt_file");
38123819 defer named_frame.end();
38133820
3814 mingw.buildCRTFile(comp, crt_file, prog_node) catch |err| {
3821 mingw.buildCrtFile(comp, crt_file, prog_node) catch |err| {
38153822 // TODO Surface more error details.
38163823 comp.lockAndSetMiscFailure(
38173824 .mingw_crt_file,
......@@ -3894,7 +3901,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
38943901 const named_frame = tracy.namedFrame("wasi_libc_crt_file");
38953902 defer named_frame.end();
38963903
3897 wasi_libc.buildCRTFile(comp, crt_file, prog_node) catch |err| {
3904 wasi_libc.buildCrtFile(comp, crt_file, prog_node) catch |err| {
38983905 // TODO Surface more error details.
38993906 comp.lockAndSetMiscFailure(
39003907 .wasi_libc_crt_file,
......@@ -4602,7 +4609,7 @@ fn buildRt(
46024609 root_source_name: []const u8,
46034610 misc_task: MiscTask,
46044611 output_mode: std.builtin.OutputMode,
4605 out: *?CRTFile,
4612 out: *?CrtFile,
46064613 prog_node: std.Progress.Node,
46074614) void {
46084615 comp.buildOutputFromZig(
......@@ -4703,7 +4710,9 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
47034710
47044711 log.debug("updating C object: {s}", .{c_object.src.src_path});
47054712
4706 if (c_object.clearStatus(comp.gpa)) {
4713 const gpa = comp.gpa;
4714
4715 if (c_object.clearStatus(gpa)) {
47074716 // There was previous failure.
47084717 comp.mutex.lock();
47094718 defer comp.mutex.unlock();
......@@ -4722,7 +4731,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
47224731
47234732 try cache_helpers.hashCSource(&man, c_object.src);
47244733
4725 var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
4734 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
47264735 defer arena_allocator.deinit();
47274736 const arena = arena_allocator.allocator();
47284737
......@@ -4744,7 +4753,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
47444753 const target = comp.getTarget();
47454754 const o_ext = target.ofmt.fileExt(target.cpu.arch);
47464755 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);
4756 var argv = std.ArrayList([]const u8).init(gpa);
47484757 defer argv.deinit();
47494758
47504759 // In case we are doing passthrough mode, we need to detect -S and -emit-llvm.
......@@ -4908,7 +4917,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
49084917
49094918 switch (term) {
49104919 .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| {
4920 const bundle = CObject.Diag.Bundle.parse(gpa, diag_file_path) catch |err| {
49124921 log.err("{}: failed to parse clang diagnostics: {s}", .{ err, stderr });
49134922 return comp.failCObj(c_object, "clang exited with code {d}", .{code});
49144923 };
......@@ -4982,9 +4991,10 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
49824991
49834992 c_object.status = .{
49844993 .success = .{
4985 .object_path = try comp.local_cache_directory.join(comp.gpa, &[_][]const u8{
4986 "o", &digest, o_basename,
4987 }),
4994 .object_path = .{
4995 .root_dir = comp.local_cache_directory,
4996 .sub_path = try std.fs.path.join(gpa, &.{ "o", &digest, o_basename }),
4997 },
49884998 .lock = man.toOwnedLock(),
49894999 },
49905000 };
......@@ -6092,18 +6102,23 @@ test "classifyFileExt" {
60926102 try std.testing.expectEqual(FileExt.zig, classifyFileExt("foo.zig"));
60936103}
60946104
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;
6105pub fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const u8) !Path {
6106 return (try crtFilePath(comp, basename)) orelse {
6107 const lci = comp.libc_installation orelse return error.LibCInstallationNotAvailable;
6108 const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCrtDir;
6109 const full_path = try std.fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename });
6110 return Path.initCwd(full_path);
6111 };
6112}
6113
6114pub fn crtFileAsString(comp: *Compilation, arena: Allocator, basename: []const u8) ![]const u8 {
6115 const path = try get_libc_crt_file(comp, arena, basename);
6116 return path.toString(arena);
6117}
6118
6119pub fn crtFilePath(comp: *Compilation, basename: []const u8) Allocator.Error!?Path {
6120 const crt_file = comp.crt_files.get(basename) orelse return null;
6121 return crt_file.full_object_path;
61076122}
61086123
61096124fn wantBuildLibCFromSource(comp: Compilation) bool {
......@@ -6314,7 +6329,7 @@ fn buildOutputFromZig(
63146329 comp: *Compilation,
63156330 src_basename: []const u8,
63166331 output_mode: std.builtin.OutputMode,
6317 out: *?CRTFile,
6332 out: *?CrtFile,
63186333 misc_task_tag: MiscTask,
63196334 prog_node: std.Progress.Node,
63206335) !void {
......@@ -6542,15 +6557,39 @@ pub fn build_crt_file(
65426557 comp.crt_files.putAssumeCapacityNoClobber(basename, try sub_compilation.toCrtFile());
65436558}
65446559
6545pub fn toCrtFile(comp: *Compilation) Allocator.Error!CRTFile {
6560pub fn toCrtFile(comp: *Compilation) Allocator.Error!CrtFile {
65466561 return .{
6547 .full_object_path = try comp.local_cache_directory.join(comp.gpa, &.{
6548 comp.cache_use.whole.bin_sub_path.?,
6549 }),
6562 .full_object_path = .{
6563 .root_dir = comp.local_cache_directory,
6564 .sub_path = try comp.gpa.dupe(u8, comp.cache_use.whole.bin_sub_path.?),
6565 },
65506566 .lock = comp.cache_use.whole.moveLock(),
65516567 };
65526568}
65536569
6570pub fn getCrtPaths(
6571 comp: *Compilation,
6572 arena: Allocator,
6573) error{ OutOfMemory, LibCInstallationMissingCrtDir }!LibCInstallation.CrtPaths {
6574 const target = comp.root_mod.resolved_target.result;
6575 const basenames = LibCInstallation.CrtBasenames.get(.{
6576 .target = target,
6577 .link_libc = comp.config.link_libc,
6578 .output_mode = comp.config.output_mode,
6579 .link_mode = comp.config.link_mode,
6580 .pie = comp.config.pie,
6581 });
6582 if (comp.libc_installation) |lci| return lci.resolveCrtPaths(arena, basenames, target);
6583
6584 return .{
6585 .crt0 = if (basenames.crt0) |basename| try comp.crtFilePath(basename) else null,
6586 .crti = if (basenames.crti) |basename| try comp.crtFilePath(basename) else null,
6587 .crtbegin = if (basenames.crtbegin) |basename| try comp.crtFilePath(basename) else null,
6588 .crtend = if (basenames.crtend) |basename| try comp.crtFilePath(basename) else null,
6589 .crtn = if (basenames.crtn) |basename| try comp.crtFilePath(basename) else null,
6590 };
6591}
6592
65546593pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void {
65556594 // Avoid deadlocking on building import libs such as kernel32.lib
65566595 // 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 }
test/link/elf.zig+7-7
......@@ -952,25 +952,25 @@ fn testEmitStaticLib(b: *Build, opts: Options) *Step {
952952
953953 const check = lib.checkObject();
954954 check.checkInArchiveSymtab();
955 check.checkExactPath("in object", obj1.getEmittedBin());
955 check.checkExact("in object obj1.o");
956956 check.checkExact("foo");
957957 check.checkInArchiveSymtab();
958 check.checkExactPath("in object", obj1.getEmittedBin());
958 check.checkExact("in object obj1.o");
959959 check.checkExact("bar");
960960 check.checkInArchiveSymtab();
961 check.checkExactPath("in object", obj1.getEmittedBin());
961 check.checkExact("in object obj1.o");
962962 check.checkExact("fooBar");
963963 check.checkInArchiveSymtab();
964 check.checkExactPath("in object", obj2.getEmittedBin());
964 check.checkExact("in object obj2.o");
965965 check.checkExact("tentative");
966966 check.checkInArchiveSymtab();
967 check.checkExactPath("in object", obj3.getEmittedBin());
967 check.checkExact("in object a_very_long_file_name_so_that_it_ends_up_in_strtab.o");
968968 check.checkExact("weakFoo");
969969 check.checkInArchiveSymtab();
970 check.checkExactPath("in object", obj3.getEmittedBin());
970 check.checkExact("in object a_very_long_file_name_so_that_it_ends_up_in_strtab.o");
971971 check.checkExact("strongBar");
972972 check.checkInArchiveSymtab();
973 check.checkExactPath("in object", obj3.getEmittedBin());
973 check.checkExact("in object a_very_long_file_name_so_that_it_ends_up_in_strtab.o");
974974 check.checkExact("strongBarAlias");
975975 test_step.dependOn(&check.step);
976976
test/link/link.zig+1-1
......@@ -74,8 +74,8 @@ fn addCompileStep(
7474 .target = base.target,
7575 .optimize = base.optimize,
7676 .root_source_file = rsf: {
77 const name = b.fmt("{s}.zig", .{overlay.name});
7877 const bytes = overlay.zig_source_bytes orelse break :rsf null;
78 const name = b.fmt("{s}.zig", .{overlay.name});
7979 break :rsf b.addWriteFiles().add(name, bytes);
8080 },
8181 .pic = overlay.pic,