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