authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-18 22:29:50-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-23 16:27:38-07:00
logc2898c436f0c858d10367b7631091f5a52cce76f
treebf2ca1d0dd9b02b530cb70545111091c916727b5
parent5ca54036ca0bc292ead681c03c8ac57e27a127db

branch fixes


10 files changed, 282 insertions(+), 425 deletions(-)

lib/std/zig/target.zig+2-2
...@@ -25,7 +25,7 @@ pub const available_libcs = [_]ArchOsAbi{...@@ -25,7 +25,7 @@ pub const available_libcs = [_]ArchOsAbi{
25 .{ .arch = .thumbeb, .os = .linux, .abi = .musleabihf },25 .{ .arch = .thumbeb, .os = .linux, .abi = .musleabihf },
26 .{ .arch = .aarch64, .os = .linux, .abi = .gnu, .glibc_min = .{ .major = 2, .minor = 17, .patch = 0 } },26 .{ .arch = .aarch64, .os = .linux, .abi = .gnu, .glibc_min = .{ .major = 2, .minor = 17, .patch = 0 } },
27 .{ .arch = .aarch64, .os = .linux, .abi = .musl },27 .{ .arch = .aarch64, .os = .linux, .abi = .musl },
28 .{ .arch = .aarch64, .os = .macos, .abi = .none, .os_ver = .{ .major = 11, .minor = 0, .patch = 0 } },28 .{ .arch = .aarch64, .os = .macos, .abi = .none, .os_ver = .{ .major = 13, .minor = 0, .patch = 0 } },
29 .{ .arch = .aarch64, .os = .windows, .abi = .gnu },29 .{ .arch = .aarch64, .os = .windows, .abi = .gnu },
30 .{ .arch = .aarch64_be, .os = .linux, .abi = .gnu, .glibc_min = .{ .major = 2, .minor = 17, .patch = 0 } },30 .{ .arch = .aarch64_be, .os = .linux, .abi = .gnu, .glibc_min = .{ .major = 2, .minor = 17, .patch = 0 } },
31 .{ .arch = .aarch64_be, .os = .linux, .abi = .musl },31 .{ .arch = .aarch64_be, .os = .linux, .abi = .musl },
...@@ -74,7 +74,7 @@ pub const available_libcs = [_]ArchOsAbi{...@@ -74,7 +74,7 @@ pub const available_libcs = [_]ArchOsAbi{
74 .{ .arch = .x86_64, .os = .linux, .abi = .gnu },74 .{ .arch = .x86_64, .os = .linux, .abi = .gnu },
75 .{ .arch = .x86_64, .os = .linux, .abi = .gnux32 },75 .{ .arch = .x86_64, .os = .linux, .abi = .gnux32 },
76 .{ .arch = .x86_64, .os = .linux, .abi = .musl },76 .{ .arch = .x86_64, .os = .linux, .abi = .musl },
77 .{ .arch = .x86_64, .os = .macos, .abi = .none, .os_ver = .{ .major = 10, .minor = 7, .patch = 0 } },77 .{ .arch = .x86_64, .os = .macos, .abi = .none, .os_ver = .{ .major = 13, .minor = 0, .patch = 0 } },
78 .{ .arch = .x86_64, .os = .windows, .abi = .gnu },78 .{ .arch = .x86_64, .os = .windows, .abi = .gnu },
79};79};
8080
src/Compilation.zig+148-152
...@@ -49,6 +49,8 @@ pub const Config = @import("Compilation/Config.zig");...@@ -49,6 +49,8 @@ pub const Config = @import("Compilation/Config.zig");
49gpa: Allocator,49gpa: Allocator,
50/// Arena-allocated memory, mostly used during initialization. However, it can50/// Arena-allocated memory, mostly used during initialization. However, it can
51/// be used for other things requiring the same lifetime as the `Compilation`.51/// be used for other things requiring the same lifetime as the `Compilation`.
52/// Not thread-safe - lock `mutex` if potentially accessing from multiple
53/// threads at once.
52arena: Allocator,54arena: Allocator,
53/// Not every Compilation compiles .zig code! For example you could do `zig build-exe foo.o`.55/// Not every Compilation compiles .zig code! For example you could do `zig build-exe foo.o`.
54zcu: ?*Zcu,56zcu: ?*Zcu,
...@@ -1760,172 +1762,166 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1760,172 +1762,166 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1760 .incremental => comp.bin_file != null,1762 .incremental => comp.bin_file != null,
1761 };1763 };
17621764
1763 if (have_bin_emit and !comp.skip_linker_dependencies and target.ofmt != .c) {1765 if (have_bin_emit and target.ofmt != .c) {
1764 if (target.isDarwin()) {1766 if (!comp.skip_linker_dependencies) {
1765 switch (target.abi) {1767 // If we need to build libc for the target, add work items for it.
1766 .none,1768 // We go through the work queue so that building can be done in parallel.
1767 .simulator,1769 // If linking against host libc installation, instead queue up jobs
1768 .macabi,1770 // for loading those files in the linker.
1769 => {},1771 if (comp.config.link_libc and is_exe_or_dyn_lib) {
1770 else => return error.LibCUnavailable,1772 if (comp.libc_installation) |lci| {
1771 }1773 const basenames = LibCInstallation.CrtBasenames.get(.{
1772 }1774 .target = target,
1773 // If we need to build glibc for the target, add work items for it.1775 .link_libc = comp.config.link_libc,
1774 // We go through the work queue so that building can be done in parallel.1776 .output_mode = comp.config.output_mode,
1775 // If linking against host libc installation, instead queue up jobs1777 .link_mode = comp.config.link_mode,
1776 // for loading those files in the linker.1778 .pie = comp.config.pie,
1777 if (comp.config.link_libc and is_exe_or_dyn_lib and target.ofmt != .c) {1779 });
1778 if (comp.libc_installation) |lci| {1780 const paths = try lci.resolveCrtPaths(arena, basenames, target);
1779 const basenames = LibCInstallation.CrtBasenames.get(.{
1780 .target = target,
1781 .link_libc = comp.config.link_libc,
1782 .output_mode = comp.config.output_mode,
1783 .link_mode = comp.config.link_mode,
1784 .pie = comp.config.pie,
1785 });
1786 const paths = try lci.resolveCrtPaths(arena, basenames, target);
17871781
1788 const fields = @typeInfo(@TypeOf(paths)).@"struct".fields;1782 const fields = @typeInfo(@TypeOf(paths)).@"struct".fields;
1789 try comp.link_task_queue.shared.ensureUnusedCapacity(gpa, fields.len);1783 try comp.link_task_queue.shared.ensureUnusedCapacity(gpa, fields.len);
1790 inline for (fields) |field| {1784 inline for (fields) |field| {
1791 if (@field(paths, field.name)) |path| {1785 if (@field(paths, field.name)) |path| {
1792 comp.link_task_queue.shared.appendAssumeCapacity(.{ .load_object = path });1786 comp.link_task_queue.shared.appendAssumeCapacity(.{ .load_object = path });
1787 }
1793 }1788 }
1794 }
17951789
1796 const flags = target_util.libcFullLinkFlags(target);1790 const flags = target_util.libcFullLinkFlags(target);
1797 try comp.link_task_queue.shared.ensureUnusedCapacity(gpa, flags.len);1791 try comp.link_task_queue.shared.ensureUnusedCapacity(gpa, flags.len);
1798 for (flags) |flag| {1792 for (flags) |flag| {
1799 assert(mem.startsWith(u8, flag, "-l"));1793 assert(mem.startsWith(u8, flag, "-l"));
1800 const lib_name = flag["-l".len..];1794 const lib_name = flag["-l".len..];
1801 const suffix = switch (comp.config.link_mode) {1795 const suffix = switch (comp.config.link_mode) {
1802 .static => target.staticLibSuffix(),1796 .static => target.staticLibSuffix(),
1803 .dynamic => target.dynamicLibSuffix(),1797 .dynamic => target.dynamicLibSuffix(),
1804 };1798 };
1805 const sep = std.fs.path.sep_str;1799 const sep = std.fs.path.sep_str;
1806 const lib_path = try std.fmt.allocPrint(arena, "{s}" ++ sep ++ "lib{s}{s}", .{1800 const lib_path = try std.fmt.allocPrint(arena, "{s}" ++ sep ++ "lib{s}{s}", .{
1807 lci.crt_dir.?, lib_name, suffix,1801 lci.crt_dir.?, lib_name, suffix,
1808 });1802 });
1809 const resolved_path = Path.initCwd(lib_path);1803 const resolved_path = Path.initCwd(lib_path);
1810 comp.link_task_queue.shared.appendAssumeCapacity(switch (comp.config.link_mode) {1804 comp.link_task_queue.shared.appendAssumeCapacity(switch (comp.config.link_mode) {
1811 .static => .{ .load_archive = resolved_path },1805 .static => .{ .load_archive = resolved_path },
1812 .dynamic => .{ .load_dso = resolved_path },1806 .dynamic => .{ .load_dso = resolved_path },
1807 });
1808 }
1809 } else if (target.isMusl() and !target.isWasm()) {
1810 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
1811
1812 if (musl.needsCrtiCrtn(target)) {
1813 try comp.queueJobs(&[_]Job{
1814 .{ .musl_crt_file = .crti_o },
1815 .{ .musl_crt_file = .crtn_o },
1816 });
1817 }
1818 try comp.queueJobs(&[_]Job{
1819 .{ .musl_crt_file = .crt1_o },
1820 .{ .musl_crt_file = .scrt1_o },
1821 .{ .musl_crt_file = .rcrt1_o },
1822 switch (comp.config.link_mode) {
1823 .static => .{ .musl_crt_file = .libc_a },
1824 .dynamic => .{ .musl_crt_file = .libc_so },
1825 },
1813 });1826 });
1814 }1827 } else if (target.isGnuLibC()) {
1815 } else if (target.isMusl() and !target.isWasm()) {1828 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
1816 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;1829
18171830 if (glibc.needsCrtiCrtn(target)) {
1818 if (musl.needsCrtiCrtn(target)) {1831 try comp.queueJobs(&[_]Job{
1832 .{ .glibc_crt_file = .crti_o },
1833 .{ .glibc_crt_file = .crtn_o },
1834 });
1835 }
1819 try comp.queueJobs(&[_]Job{1836 try comp.queueJobs(&[_]Job{
1820 .{ .musl_crt_file = .crti_o },1837 .{ .glibc_crt_file = .scrt1_o },
1821 .{ .musl_crt_file = .crtn_o },1838 .{ .glibc_crt_file = .libc_nonshared_a },
1839 .{ .glibc_shared_objects = {} },
1822 });1840 });
1823 }1841 } else if (target.isWasm() and target.os.tag == .wasi) {
1824 try comp.queueJobs(&[_]Job{1842 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
1825 .{ .musl_crt_file = .crt1_o },
1826 .{ .musl_crt_file = .scrt1_o },
1827 .{ .musl_crt_file = .rcrt1_o },
1828 switch (comp.config.link_mode) {
1829 .static => .{ .musl_crt_file = .libc_a },
1830 .dynamic => .{ .musl_crt_file = .libc_so },
1831 },
1832 });
1833 } else if (target.isGnuLibC()) {
1834 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
18351843
1836 if (glibc.needsCrtiCrtn(target)) {1844 for (comp.wasi_emulated_libs) |crt_file| {
1845 try comp.queueJob(.{
1846 .wasi_libc_crt_file = crt_file,
1847 });
1848 }
1837 try comp.queueJobs(&[_]Job{1849 try comp.queueJobs(&[_]Job{
1838 .{ .glibc_crt_file = .crti_o },1850 .{ .wasi_libc_crt_file = wasi_libc.execModelCrtFile(comp.config.wasi_exec_model) },
1839 .{ .glibc_crt_file = .crtn_o },1851 .{ .wasi_libc_crt_file = .libc_a },
1840 });1852 });
1841 }1853 } else if (target.isMinGW()) {
1842 try comp.queueJobs(&[_]Job{1854 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
1843 .{ .glibc_crt_file = .scrt1_o },
1844 .{ .glibc_crt_file = .libc_nonshared_a },
1845 .{ .glibc_shared_objects = {} },
1846 });
1847 } else if (target.isWasm() and target.os.tag == .wasi) {
1848 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
18491855
1850 for (comp.wasi_emulated_libs) |crt_file| {1856 const crt_job: Job = .{ .mingw_crt_file = if (is_dyn_lib) .dllcrt2_o else .crt2_o };
1851 try comp.queueJob(.{1857 try comp.queueJobs(&.{
1852 .wasi_libc_crt_file = crt_file,1858 .{ .mingw_crt_file = .mingw32_lib },
1859 crt_job,
1853 });1860 });
1854 }
1855 try comp.queueJobs(&[_]Job{
1856 .{ .wasi_libc_crt_file = wasi_libc.execModelCrtFile(comp.config.wasi_exec_model) },
1857 .{ .wasi_libc_crt_file = .libc_a },
1858 });
1859 } else if (target.isMinGW()) {
1860 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
18611861
1862 const crt_job: Job = .{ .mingw_crt_file = if (is_dyn_lib) .dllcrt2_o else .crt2_o };1862 // When linking mingw-w64 there are some import libs we always need.
1863 try comp.queueJobs(&.{1863 try comp.windows_libs.ensureUnusedCapacity(gpa, mingw.always_link_libs.len);
1864 .{ .mingw_crt_file = .mingw32_lib },1864 for (mingw.always_link_libs) |name| comp.windows_libs.putAssumeCapacity(name, {});
1865 crt_job,1865 } else if (target.isDarwin()) {
1866 });1866 switch (target.abi) {
18671867 .none, .simulator, .macabi => {},
1868 // When linking mingw-w64 there are some import libs we always need.1868 else => return error.LibCUnavailable,
1869 try comp.windows_libs.ensureUnusedCapacity(gpa, mingw.always_link_libs.len);1869 }
1870 for (mingw.always_link_libs) |name| comp.windows_libs.putAssumeCapacity(name, {});1870 } else if (target.os.tag == .freestanding and capable_of_building_zig_libc) {
1871 } else {1871 try comp.queueJob(.{ .zig_libc = {} });
1872 return error.LibCUnavailable;1872 } else {
1873 return error.LibCUnavailable;
1874 }
1873 }1875 }
1874 }
18751876
1876 // Generate Windows import libs.1877 // Generate Windows import libs.
1877 if (target.os.tag == .windows) {1878 if (target.os.tag == .windows) {
1878 const count = comp.windows_libs.count();1879 const count = comp.windows_libs.count();
1879 for (0..count) |i| {1880 for (0..count) |i| {
1880 try comp.queueJob(.{ .windows_import_lib = i });1881 try comp.queueJob(.{ .windows_import_lib = i });
1882 }
1883 }
1884 if (comp.wantBuildLibUnwindFromSource()) {
1885 try comp.queueJob(.{ .libunwind = {} });
1886 }
1887 if (build_options.have_llvm and is_exe_or_dyn_lib and comp.config.link_libcpp) {
1888 try comp.queueJob(.libcxx);
1889 try comp.queueJob(.libcxxabi);
1890 }
1891 if (build_options.have_llvm and comp.config.any_sanitize_thread) {
1892 try comp.queueJob(.libtsan);
1881 }1893 }
1882 }
1883 if (comp.wantBuildLibUnwindFromSource()) {
1884 try comp.queueJob(.{ .libunwind = {} });
1885 }
1886 if (build_options.have_llvm and is_exe_or_dyn_lib and comp.config.link_libcpp) {
1887 try comp.queueJob(.libcxx);
1888 try comp.queueJob(.libcxxabi);
1889 }
1890 if (build_options.have_llvm and comp.config.any_sanitize_thread) {
1891 try comp.queueJob(.libtsan);
1892 }
1893
1894 if (target.isMinGW() and comp.config.any_non_single_threaded) {
1895 // LLD might drop some symbols as unused during LTO and GCing, therefore,
1896 // we force mark them for resolution here.
18971894
1898 const tls_index_sym = switch (target.cpu.arch) {1895 if (target.isMinGW() and comp.config.any_non_single_threaded) {
1899 .x86 => "__tls_index",1896 // LLD might drop some symbols as unused during LTO and GCing, therefore,
1900 else => "_tls_index",1897 // we force mark them for resolution here.
1901 };
19021898
1903 try comp.force_undefined_symbols.put(comp.gpa, tls_index_sym, {});1899 const tls_index_sym = switch (target.cpu.arch) {
1904 }1900 .x86 => "__tls_index",
1901 else => "_tls_index",
1902 };
19051903
1906 if (comp.include_compiler_rt and capable_of_building_compiler_rt) {1904 try comp.force_undefined_symbols.put(comp.gpa, tls_index_sym, {});
1907 if (is_exe_or_dyn_lib) {
1908 log.debug("queuing a job to build compiler_rt_lib", .{});
1909 comp.job_queued_compiler_rt_lib = true;
1910 } else if (output_mode != .Obj) {
1911 log.debug("queuing a job to build compiler_rt_obj", .{});
1912 // In this case we are making a static library, so we ask
1913 // for a compiler-rt object to put in it.
1914 comp.job_queued_compiler_rt_obj = true;
1915 }1905 }
1916 }
19171906
1918 if (comp.config.any_fuzz and capable_of_building_compiler_rt) {1907 if (comp.include_compiler_rt and capable_of_building_compiler_rt) {
1919 if (is_exe_or_dyn_lib) {1908 if (is_exe_or_dyn_lib) {
1920 log.debug("queuing a job to build libfuzzer", .{});1909 log.debug("queuing a job to build compiler_rt_lib", .{});
1921 comp.job_queued_fuzzer_lib = true;1910 comp.job_queued_compiler_rt_lib = true;
1911 } else if (output_mode != .Obj) {
1912 log.debug("queuing a job to build compiler_rt_obj", .{});
1913 // In this case we are making a static library, so we ask
1914 // for a compiler-rt object to put in it.
1915 comp.job_queued_compiler_rt_obj = true;
1916 }
1922 }1917 }
1923 }
19241918
1925 if (!comp.skip_linker_dependencies and is_exe_or_dyn_lib and1919 if (comp.config.any_fuzz and capable_of_building_compiler_rt) {
1926 !comp.config.link_libc and capable_of_building_zig_libc)1920 if (is_exe_or_dyn_lib) {
1927 {1921 log.debug("queuing a job to build libfuzzer", .{});
1928 try comp.queueJob(.{ .zig_libc = {} });1922 comp.job_queued_fuzzer_lib = true;
1923 }
1924 }
1929 }1925 }
19301926
1931 try comp.link_task_queue.shared.append(gpa, .load_explicitly_provided);1927 try comp.link_task_queue.shared.append(gpa, .load_explicitly_provided);
...@@ -3521,7 +3517,7 @@ fn performAllTheWorkInner(...@@ -3521,7 +3517,7 @@ fn performAllTheWorkInner(
3521 defer work_queue_wait_group.wait();3517 defer work_queue_wait_group.wait();
35223518
3523 if (comp.bin_file) |lf| {3519 if (comp.bin_file) |lf| {
3524 if (try comp.link_task_queue.enqueue(comp.gpa, &.{.load_explicitly_provided})) {3520 if (comp.link_task_queue.start()) {
3525 comp.thread_pool.spawnWg(work_queue_wait_group, link.File.flushTaskQueue, .{ lf, main_progress_node });3521 comp.thread_pool.spawnWg(work_queue_wait_group, link.File.flushTaskQueue, .{ lf, main_progress_node });
3526 }3522 }
3527 }3523 }
...@@ -4980,7 +4976,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr...@@ -4980,7 +4976,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
4980 },4976 },
4981 };4977 };
49824978
4983 comp.enqueueLinkTasks(&.{.{ .load_object = c_object.status.success.object_path }});4979 comp.queueLinkTasks(&.{.{ .load_object = c_object.status.success.object_path }});
4984}4980}
49854981
4986fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32_resource_prog_node: std.Progress.Node) !void {4982fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32_resource_prog_node: std.Progress.Node) !void {
...@@ -6114,7 +6110,7 @@ fn wantBuildLibUnwindFromSource(comp: *Compilation) bool {...@@ -6114,7 +6110,7 @@ fn wantBuildLibUnwindFromSource(comp: *Compilation) bool {
6114 return is_exe_or_dyn_lib and comp.config.link_libunwind and ofmt != .c;6110 return is_exe_or_dyn_lib and comp.config.link_libunwind and ofmt != .c;
6115}6111}
61166112
6117fn setAllocFailure(comp: *Compilation) void {6113pub fn setAllocFailure(comp: *Compilation) void {
6118 @branchHint(.cold);6114 @branchHint(.cold);
6119 log.debug("memory allocation failure", .{});6115 log.debug("memory allocation failure", .{});
6120 comp.alloc_failure_occurred = true;6116 comp.alloc_failure_occurred = true;
...@@ -6355,7 +6351,7 @@ fn buildOutputFromZig(...@@ -6355,7 +6351,7 @@ fn buildOutputFromZig(
6355 assert(out.* == null);6351 assert(out.* == null);
6356 out.* = crt_file;6352 out.* = crt_file;
63576353
6358 comp.enqueueLinkTaskMode(crt_file.full_object_path, output_mode);6354 comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
6359}6355}
63606356
6361pub fn build_crt_file(6357pub fn build_crt_file(
...@@ -6463,7 +6459,7 @@ pub fn build_crt_file(...@@ -6463,7 +6459,7 @@ pub fn build_crt_file(
6463 try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node);6459 try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node);
64646460
6465 const crt_file = try sub_compilation.toCrtFile();6461 const crt_file = try sub_compilation.toCrtFile();
6466 comp.enqueueLinkTaskMode(crt_file.full_object_path, output_mode);6462 comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
64676463
6468 {6464 {
6469 comp.mutex.lock();6465 comp.mutex.lock();
...@@ -6473,8 +6469,8 @@ pub fn build_crt_file(...@@ -6473,8 +6469,8 @@ pub fn build_crt_file(
6473 }6469 }
6474}6470}
64756471
6476pub fn enqueueLinkTaskMode(comp: *Compilation, path: Path, output_mode: std.builtin.OutputMode) void {6472pub fn queueLinkTaskMode(comp: *Compilation, path: Path, output_mode: std.builtin.OutputMode) void {
6477 comp.enqueueLinkTasks(switch (output_mode) {6473 comp.queueLinkTasks(switch (output_mode) {
6478 .Exe => unreachable,6474 .Exe => unreachable,
6479 .Obj => &.{.{ .load_object = path }},6475 .Obj => &.{.{ .load_object = path }},
6480 .Lib => &.{.{ .load_archive = path }},6476 .Lib => &.{.{ .load_archive = path }},
...@@ -6483,7 +6479,7 @@ pub fn enqueueLinkTaskMode(comp: *Compilation, path: Path, output_mode: std.buil...@@ -6483,7 +6479,7 @@ pub fn enqueueLinkTaskMode(comp: *Compilation, path: Path, output_mode: std.buil
64836479
6484/// Only valid to call during `update`. Automatically handles queuing up a6480/// Only valid to call during `update`. Automatically handles queuing up a
6485/// linker worker task if there is not already one.6481/// linker worker task if there is not already one.
6486fn enqueueLinkTasks(comp: *Compilation, tasks: []const link.File.Task) void {6482pub fn queueLinkTasks(comp: *Compilation, tasks: []const link.File.Task) void {
6487 const use_lld = build_options.have_llvm and comp.config.use_lld;6483 const use_lld = build_options.have_llvm and comp.config.use_lld;
6488 if (use_lld) return;6484 if (use_lld) return;
6489 const target = comp.root_mod.resolved_target.result;6485 const target = comp.root_mod.resolved_target.result;
src/ThreadSafeQueue.zig+8
...@@ -59,5 +59,13 @@ pub fn ThreadSafeQueue(comptime T: type) type {...@@ -59,5 +59,13 @@ pub fn ThreadSafeQueue(comptime T: type) type {
59 self.state = .run;59 self.state = .run;
60 return was_waiting;60 return was_waiting;
61 }61 }
62
63 /// Safe only to call exactly once when initially starting the worker.
64 pub fn start(self: *Self) bool {
65 assert(self.state == .wait);
66 if (self.shared.items.len == 0) return false;
67 self.state = .run;
68 return true;
69 }
62 };70 };
63}71}
src/glibc.zig+54-17
...@@ -6,12 +6,14 @@ const fs = std.fs;...@@ -6,12 +6,14 @@ const fs = std.fs;
6const path = fs.path;6const path = fs.path;
7const assert = std.debug.assert;7const assert = std.debug.assert;
8const Version = std.SemanticVersion;8const Version = std.SemanticVersion;
9const Path = std.Build.Cache.Path;
910
10const Compilation = @import("Compilation.zig");11const Compilation = @import("Compilation.zig");
11const build_options = @import("build_options");12const build_options = @import("build_options");
12const trace = @import("tracy.zig").trace;13const trace = @import("tracy.zig").trace;
13const Cache = std.Build.Cache;14const Cache = std.Build.Cache;
14const Module = @import("Package/Module.zig");15const Module = @import("Package/Module.zig");
16const link = @import("link.zig");
1517
16pub const Lib = struct {18pub const Lib = struct {
17 name: []const u8,19 name: []const u8,
...@@ -717,11 +719,11 @@ fn lib_path(comp: *Compilation, arena: Allocator, sub_path: []const u8) ![]const...@@ -717,11 +719,11 @@ fn lib_path(comp: *Compilation, arena: Allocator, sub_path: []const u8) ![]const
717719
718pub const BuiltSharedObjects = struct {720pub const BuiltSharedObjects = struct {
719 lock: Cache.Lock,721 lock: Cache.Lock,
720 dir_path: []u8,722 dir_path: Path,
721723
722 pub fn deinit(self: *BuiltSharedObjects, gpa: Allocator) void {724 pub fn deinit(self: *BuiltSharedObjects, gpa: Allocator) void {
723 self.lock.release();725 self.lock.release();
724 gpa.free(self.dir_path);726 gpa.free(self.dir_path.sub_path);
725 self.* = undefined;727 self.* = undefined;
726 }728 }
727};729};
...@@ -742,7 +744,9 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi...@@ -742,7 +744,9 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi
742 return error.ZigCompilerNotBuiltWithLLVMExtensions;744 return error.ZigCompilerNotBuiltWithLLVMExtensions;
743 }745 }
744746
745 var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);747 const gpa = comp.gpa;
748
749 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
746 defer arena_allocator.deinit();750 defer arena_allocator.deinit();
747 const arena = arena_allocator.allocator();751 const arena = arena_allocator.allocator();
748752
...@@ -751,7 +755,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi...@@ -751,7 +755,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi
751755
752 // Use the global cache directory.756 // Use the global cache directory.
753 var cache: Cache = .{757 var cache: Cache = .{
754 .gpa = comp.gpa,758 .gpa = gpa,
755 .manifest_dir = try comp.global_cache_directory.handle.makeOpenPath("h", .{}),759 .manifest_dir = try comp.global_cache_directory.handle.makeOpenPath("h", .{}),
756 };760 };
757 cache.addPrefix(.{ .path = null, .handle = fs.cwd() });761 cache.addPrefix(.{ .path = null, .handle = fs.cwd() });
...@@ -772,12 +776,13 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi...@@ -772,12 +776,13 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi
772 if (try man.hit()) {776 if (try man.hit()) {
773 const digest = man.final();777 const digest = man.final();
774778
775 assert(comp.glibc_so_files == null);779 return queueSharedObjects(comp, .{
776 comp.glibc_so_files = BuiltSharedObjects{
777 .lock = man.toOwnedLock(),780 .lock = man.toOwnedLock(),
778 .dir_path = try comp.global_cache_directory.join(comp.gpa, &.{ "o", &digest }),781 .dir_path = .{
779 };782 .root_dir = comp.global_cache_directory,
780 return;783 .sub_path = try gpa.dupe(u8, "o" ++ fs.path.sep_str ++ digest),
784 },
785 });
781 }786 }
782787
783 const digest = man.final();788 const digest = man.final();
...@@ -790,8 +795,8 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi...@@ -790,8 +795,8 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi
790 defer o_directory.handle.close();795 defer o_directory.handle.close();
791796
792 const abilists_contents = man.files.keys()[abilists_index].contents.?;797 const abilists_contents = man.files.keys()[abilists_index].contents.?;
793 const metadata = try loadMetaData(comp.gpa, abilists_contents);798 const metadata = try loadMetaData(gpa, abilists_contents);
794 defer metadata.destroy(comp.gpa);799 defer metadata.destroy(gpa);
795800
796 const target_targ_index = for (metadata.all_targets, 0..) |targ, i| {801 const target_targ_index = for (metadata.all_targets, 0..) |targ, i| {
797 if (targ.arch == target.cpu.arch and802 if (targ.arch == target.cpu.arch and
...@@ -835,7 +840,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi...@@ -835,7 +840,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi
835 map_contents.deinit(); // The most recent allocation of an arena can be freed :)840 map_contents.deinit(); // The most recent allocation of an arena can be freed :)
836 }841 }
837842
838 var stubs_asm = std.ArrayList(u8).init(comp.gpa);843 var stubs_asm = std.ArrayList(u8).init(gpa);
839 defer stubs_asm.deinit();844 defer stubs_asm.deinit();
840845
841 for (libs, 0..) |lib, lib_i| {846 for (libs, 0..) |lib, lib_i| {
...@@ -1195,7 +1200,6 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi...@@ -1195,7 +1200,6 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi
1195 var lib_name_buf: [32]u8 = undefined; // Larger than each of the names "c", "pthread", etc.1200 var lib_name_buf: [32]u8 = undefined; // Larger than each of the names "c", "pthread", etc.
1196 const asm_file_basename = std.fmt.bufPrint(&lib_name_buf, "{s}.s", .{lib.name}) catch unreachable;1201 const asm_file_basename = std.fmt.bufPrint(&lib_name_buf, "{s}.s", .{lib.name}) catch unreachable;
1197 try o_directory.handle.writeFile(.{ .sub_path = asm_file_basename, .data = stubs_asm.items });1202 try o_directory.handle.writeFile(.{ .sub_path = asm_file_basename, .data = stubs_asm.items });
1198
1199 try buildSharedLib(comp, arena, comp.global_cache_directory, o_directory, asm_file_basename, lib, prog_node);1203 try buildSharedLib(comp, arena, comp.global_cache_directory, o_directory, asm_file_basename, lib, prog_node);
1200 }1204 }
12011205
...@@ -1203,11 +1207,44 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi...@@ -1203,11 +1207,44 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi
1203 log.warn("failed to write cache manifest for glibc stubs: {s}", .{@errorName(err)});1207 log.warn("failed to write cache manifest for glibc stubs: {s}", .{@errorName(err)});
1204 };1208 };
12051209
1206 assert(comp.glibc_so_files == null);1210 return queueSharedObjects(comp, .{
1207 comp.glibc_so_files = .{
1208 .lock = man.toOwnedLock(),1211 .lock = man.toOwnedLock(),
1209 .dir_path = try comp.global_cache_directory.join(comp.gpa, &.{ "o", &digest }),1212 .dir_path = .{
1210 };1213 .root_dir = comp.global_cache_directory,
1214 .sub_path = try gpa.dupe(u8, "o" ++ fs.path.sep_str ++ digest),
1215 },
1216 });
1217}
1218
1219fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {
1220 const target_version = comp.getTarget().os.version_range.linux.glibc;
1221
1222 assert(comp.glibc_so_files == null);
1223 comp.glibc_so_files = so_files;
1224
1225 var task_buffer: [libs.len]link.File.Task = undefined;
1226 var task_buffer_i: usize = 0;
1227
1228 {
1229 comp.mutex.lock(); // protect comp.arena
1230 defer comp.mutex.unlock();
1231
1232 for (libs) |lib| {
1233 if (lib.removed_in) |rem_in| {
1234 if (target_version.order(rem_in) != .lt) continue;
1235 }
1236 const so_path: Path = .{
1237 .root_dir = so_files.dir_path.root_dir,
1238 .sub_path = std.fmt.allocPrint(comp.arena, "{s}{c}lib{s}.so.{d}", .{
1239 so_files.dir_path.sub_path, fs.path.sep, lib.name, lib.sover,
1240 }) catch return comp.setAllocFailure(),
1241 };
1242 task_buffer[task_buffer_i] = .{ .load_dso = so_path };
1243 task_buffer_i += 1;
1244 }
1245 }
1246
1247 comp.queueLinkTasks(task_buffer[0..task_buffer_i]);
1211}1248}
12121249
1213fn buildSharedLib(1250fn buildSharedLib(
src/libcxx.zig+2-2
...@@ -357,7 +357,7 @@ pub fn buildLibCXX(comp: *Compilation, prog_node: std.Progress.Node) BuildError!...@@ -357,7 +357,7 @@ pub fn buildLibCXX(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
357 assert(comp.libcxx_static_lib == null);357 assert(comp.libcxx_static_lib == null);
358 const crt_file = try sub_compilation.toCrtFile();358 const crt_file = try sub_compilation.toCrtFile();
359 comp.libcxx_static_lib = crt_file;359 comp.libcxx_static_lib = crt_file;
360 comp.enqueueLinkTaskMode(crt_file.full_object_path, output_mode);360 comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
361}361}
362362
363pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void {363pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void {
...@@ -588,7 +588,7 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -588,7 +588,7 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
588 assert(comp.libcxxabi_static_lib == null);588 assert(comp.libcxxabi_static_lib == null);
589 const crt_file = try sub_compilation.toCrtFile();589 const crt_file = try sub_compilation.toCrtFile();
590 comp.libcxxabi_static_lib = crt_file;590 comp.libcxxabi_static_lib = crt_file;
591 comp.enqueueLinkTaskMode(crt_file.full_object_path, output_mode);591 comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
592}592}
593593
594pub fn hardeningModeFlag(optimize_mode: std.builtin.OptimizeMode) []const u8 {594pub fn hardeningModeFlag(optimize_mode: std.builtin.OptimizeMode) []const u8 {
src/libtsan.zig+1-1
...@@ -343,7 +343,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo...@@ -343,7 +343,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
343 };343 };
344344
345 const crt_file = try sub_compilation.toCrtFile();345 const crt_file = try sub_compilation.toCrtFile();
346 comp.enqueueLinkTaskMode(crt_file.full_object_path, output_mode);346 comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
347 assert(comp.tsan_lib == null);347 assert(comp.tsan_lib == null);
348 comp.tsan_lib = crt_file;348 comp.tsan_lib = crt_file;
349}349}
src/libunwind.zig+1-1
...@@ -200,7 +200,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -200,7 +200,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
200 };200 };
201201
202 const crt_file = try sub_compilation.toCrtFile();202 const crt_file = try sub_compilation.toCrtFile();
203 comp.enqueueLinkTaskMode(crt_file.full_object_path, output_mode);203 comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
204 assert(comp.libunwind_static_lib == null);204 assert(comp.libunwind_static_lib == null);
205 comp.libunwind_static_lib = crt_file;205 comp.libunwind_static_lib = crt_file;
206}206}
src/link.zig+5-27
...@@ -1349,12 +1349,14 @@ pub const File = struct {...@@ -1349,12 +1349,14 @@ pub const File = struct {
1349 /// Does all the tasks in the queue. Runs in exactly one separate thread1349 /// Does all the tasks in the queue. Runs in exactly one separate thread
1350 /// from the rest of compilation. All tasks performed here are1350 /// from the rest of compilation. All tasks performed here are
1351 /// single-threaded with respect to one another.1351 /// single-threaded with respect to one another.
1352 pub fn flushTaskQueue(base: *File, prog_node: std.Progress.Node) void {1352 pub fn flushTaskQueue(base: *File, parent_prog_node: std.Progress.Node) void {
1353 const comp = base.comp;1353 const comp = base.comp;
1354 base.task_queue_safety.lock();1354 base.task_queue_safety.lock();
1355 defer base.task_queue_safety.unlock();1355 defer base.task_queue_safety.unlock();
1356 const prog_node = parent_prog_node.start("Parse Linker Inputs", 0);
1357 defer prog_node.end();
1356 while (comp.link_task_queue.check()) |tasks| {1358 while (comp.link_task_queue.check()) |tasks| {
1357 for (tasks) |task| doTask(base, prog_node, task);1359 for (tasks) |task| doTask(base, task);
1358 }1360 }
1359 }1361 }
13601362
...@@ -1374,16 +1376,11 @@ pub const File = struct {...@@ -1374,16 +1376,11 @@ pub const File = struct {
1374 load_input: Input,1376 load_input: Input,
1375 };1377 };
13761378
1377 fn doTask(base: *File, parent_prog_node: std.Progress.Node, task: Task) void {1379 fn doTask(base: *File, task: Task) void {
1378 const comp = base.comp;1380 const comp = base.comp;
1379 switch (task) {1381 switch (task) {
1380 .load_explicitly_provided => {1382 .load_explicitly_provided => {
1381 const prog_node = parent_prog_node.start("Linker Parse Input", comp.link_inputs.len);
1382 defer prog_node.end();
1383
1384 for (comp.link_inputs) |input| {1383 for (comp.link_inputs) |input| {
1385 const sub_node = prog_node.start(input.taskName(), 0);
1386 defer sub_node.end();
1387 base.loadInput(input) catch |err| switch (err) {1384 base.loadInput(input) catch |err| switch (err) {
1388 error.LinkFailure => return, // error reported via link_diags1385 error.LinkFailure => return, // error reported via link_diags
1389 else => |e| {1386 else => |e| {
...@@ -1397,33 +1394,18 @@ pub const File = struct {...@@ -1397,33 +1394,18 @@ pub const File = struct {
1397 }1394 }
1398 },1395 },
1399 .load_object => |path| {1396 .load_object => |path| {
1400 const prog_node = parent_prog_node.start("Linker Parse Object", 0);
1401 defer prog_node.end();
1402 const sub_node = prog_node.start(path.basename(), 0);
1403 defer sub_node.end();
1404
1405 base.openLoadObject(path) catch |err| switch (err) {1397 base.openLoadObject(path) catch |err| switch (err) {
1406 error.LinkFailure => return, // error reported via link_diags1398 error.LinkFailure => return, // error reported via link_diags
1407 else => |e| comp.link_diags.addParseError(path, "failed to parse object: {s}", .{@errorName(e)}),1399 else => |e| comp.link_diags.addParseError(path, "failed to parse object: {s}", .{@errorName(e)}),
1408 };1400 };
1409 },1401 },
1410 .load_archive => |path| {1402 .load_archive => |path| {
1411 const prog_node = parent_prog_node.start("Linker Parse Archive", 0);
1412 defer prog_node.end();
1413 const sub_node = prog_node.start(path.basename(), 0);
1414 defer sub_node.end();
1415
1416 base.openLoadArchive(path) catch |err| switch (err) {1403 base.openLoadArchive(path) catch |err| switch (err) {
1417 error.LinkFailure => return, // error reported via link_diags1404 error.LinkFailure => return, // error reported via link_diags
1418 else => |e| comp.link_diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(e)}),1405 else => |e| comp.link_diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(e)}),
1419 };1406 };
1420 },1407 },
1421 .load_dso => |path| {1408 .load_dso => |path| {
1422 const prog_node = parent_prog_node.start("Linker Parse Shared Library", 0);
1423 defer prog_node.end();
1424 const sub_node = prog_node.start(path.basename(), 0);
1425 defer sub_node.end();
1426
1427 base.openLoadDso(path, .{1409 base.openLoadDso(path, .{
1428 .preferred_mode = .dynamic,1410 .preferred_mode = .dynamic,
1429 .search_strategy = .paths_first,1411 .search_strategy = .paths_first,
...@@ -1433,10 +1415,6 @@ pub const File = struct {...@@ -1433,10 +1415,6 @@ pub const File = struct {
1433 };1415 };
1434 },1416 },
1435 .load_input => |input| {1417 .load_input => |input| {
1436 const prog_node = parent_prog_node.start("Linker Parse Input", 0);
1437 defer prog_node.end();
1438 const sub_node = prog_node.start(input.taskName(), 0);
1439 defer sub_node.end();
1440 base.loadInput(input) catch |err| switch (err) {1418 base.loadInput(input) catch |err| switch (err) {
1441 error.LinkFailure => return, // error reported via link_diags1419 error.LinkFailure => return, // error reported via link_diags
1442 else => |e| {1420 else => |e| {
src/link/Elf.zig+60-222
...@@ -114,6 +114,10 @@ comment_merge_section_index: ?Merge.Section.Index = null,...@@ -114,6 +114,10 @@ comment_merge_section_index: ?Merge.Section.Index = null,
114114
115first_eflags: ?elf.Word = null,115first_eflags: ?elf.Word = null,
116116
117/// `--verbose-link` output.
118/// Initialized on creation, appended to as inputs are added, printed during `flush`.
119dump_argv_list: std.ArrayListUnmanaged([]const u8),
120
117const SectionIndexes = struct {121const SectionIndexes = struct {
118 copy_rel: ?u32 = null,122 copy_rel: ?u32 = null,
119 dynamic: ?u32 = null,123 dynamic: ?u32 = null,
...@@ -338,6 +342,7 @@ pub fn createEmpty(...@@ -338,6 +342,7 @@ pub fn createEmpty(
338 .enable_new_dtags = options.enable_new_dtags,342 .enable_new_dtags = options.enable_new_dtags,
339 .print_icf_sections = options.print_icf_sections,343 .print_icf_sections = options.print_icf_sections,
340 .print_map = options.print_map,344 .print_map = options.print_map,
345 .dump_argv_list = .empty,
341 };346 };
342 if (use_llvm and comp.config.have_zcu) {347 if (use_llvm and comp.config.have_zcu) {
343 self.llvm_object = try LlvmObject.create(arena, comp);348 self.llvm_object = try LlvmObject.create(arena, comp);
...@@ -350,7 +355,7 @@ pub fn createEmpty(...@@ -350,7 +355,7 @@ pub fn createEmpty(
350 }355 }
351356
352 // --verbose-link357 // --verbose-link
353 if (comp.verbose_link) try self.dumpArgv(comp);358 if (comp.verbose_link) try dumpArgvInit(self, arena);
354359
355 const is_obj = output_mode == .Obj;360 const is_obj = output_mode == .Obj;
356 const is_obj_or_ar = is_obj or (output_mode == .Lib and link_mode == .static);361 const is_obj_or_ar = is_obj or (output_mode == .Lib and link_mode == .static);
...@@ -501,6 +506,7 @@ pub fn deinit(self: *Elf) void {...@@ -501,6 +506,7 @@ pub fn deinit(self: *Elf) void {
501 self.rela_dyn.deinit(gpa);506 self.rela_dyn.deinit(gpa);
502 self.rela_plt.deinit(gpa);507 self.rela_plt.deinit(gpa);
503 self.comdat_group_sections.deinit(gpa);508 self.comdat_group_sections.deinit(gpa);
509 self.dump_argv_list.deinit(gpa);
504}510}
505511
506pub fn getNavVAddr(self: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, reloc_info: link.File.RelocInfo) !u64 {512pub fn getNavVAddr(self: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, reloc_info: link.File.RelocInfo) !u64 {
...@@ -753,12 +759,23 @@ pub fn allocateChunk(self: *Elf, args: struct {...@@ -753,12 +759,23 @@ pub fn allocateChunk(self: *Elf, args: struct {
753}759}
754760
755pub fn loadInput(self: *Elf, input: link.Input) !void {761pub fn loadInput(self: *Elf, input: link.Input) !void {
756 const gpa = self.base.comp.gpa;762 const comp = self.base.comp;
757 const diags = &self.base.comp.link_diags;763 const gpa = comp.gpa;
764 const diags = &comp.link_diags;
758 const target = self.getTarget();765 const target = self.getTarget();
759 const debug_fmt_strip = self.base.comp.config.debug_format == .strip;766 const debug_fmt_strip = comp.config.debug_format == .strip;
760 const default_sym_version = self.default_sym_version;767 const default_sym_version = self.default_sym_version;
761768
769 if (comp.verbose_link) {
770 const argv = &self.dump_argv_list;
771 switch (input) {
772 .res => unreachable,
773 .dso_exact => |dso_exact| try argv.appendSlice(gpa, &.{ "-l", dso_exact.name }),
774 .object, .archive => |obj| try argv.append(gpa, try obj.path.toString(comp.arena)),
775 .dso => |dso| try argv.append(gpa, try dso.path.toString(comp.arena)),
776 }
777 }
778
762 switch (input) {779 switch (input) {
763 .res => unreachable,780 .res => unreachable,
764 .dso_exact => @panic("TODO"),781 .dso_exact => @panic("TODO"),
...@@ -790,6 +807,8 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -790,6 +807,8 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
790 if (use_lld) return;807 if (use_lld) return;
791 }808 }
792809
810 if (comp.verbose_link) Compilation.dump_argv(self.dump_argv_list.items);
811
793 const sub_prog_node = prog_node.start("ELF Flush", 0);812 const sub_prog_node = prog_node.start("ELF Flush", 0);
794 defer sub_prog_node.end();813 defer sub_prog_node.end();
795814
...@@ -965,291 +984,110 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -965,291 +984,110 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
965 if (diags.hasErrors()) return error.FlushFailure;984 if (diags.hasErrors()) return error.FlushFailure;
966}985}
967986
968/// --verbose-link output987fn dumpArgvInit(self: *Elf, arena: Allocator) !void {
969fn dumpArgv(self: *Elf, comp: *Compilation) !void {988 const comp = self.base.comp;
970 const gpa = self.base.comp.gpa;989 const gpa = comp.gpa;
971 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
972 defer arena_allocator.deinit();
973 const arena = arena_allocator.allocator();
974
975 const target = self.getTarget();990 const target = self.getTarget();
976 const link_mode = self.base.comp.config.link_mode;991 const full_out_path = try self.base.emit.root_dir.join(arena, &[_][]const u8{self.base.emit.sub_path});
977 const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
978 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
979 const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {
980 if (fs.path.dirname(full_out_path)) |dirname| {
981 break :blk try fs.path.join(arena, &.{ dirname, path });
982 } else {
983 break :blk path;
984 }
985 } else null;
986992
987 const crt_basenames = std.zig.LibCInstallation.CrtBasenames.get(.{993 const argv = &self.dump_argv_list;
988 .target = target,
989 .link_libc = comp.config.link_libc,
990 .output_mode = comp.config.output_mode,
991 .link_mode = link_mode,
992 .pie = comp.config.pie,
993 });
994 const crt_paths: std.zig.LibCInstallation.CrtPaths = if (comp.libc_installation) |lci|
995 try lci.resolveCrtPaths(arena, crt_basenames, target)
996 else
997 .{};
998 const compiler_rt_path: ?[]const u8 = blk: {
999 if (comp.compiler_rt_lib) |x| break :blk try x.full_object_path.toString(arena);
1000 if (comp.compiler_rt_obj) |x| break :blk try x.full_object_path.toString(arena);
1001 break :blk null;
1002 };
1003994
1004 var argv = std.ArrayList([]const u8).init(arena);995 try argv.append(gpa, "zig");
1005
1006 try argv.append("zig");
1007996
1008 if (self.base.isStaticLib()) {997 if (self.base.isStaticLib()) {
1009 try argv.append("ar");998 try argv.append(gpa, "ar");
1010 } else {999 } else {
1011 try argv.append("ld");1000 try argv.append(gpa, "ld");
1012 }1001 }
10131002
1014 if (self.base.isObject()) {1003 if (self.base.isObject()) {
1015 try argv.append("-r");1004 try argv.append(gpa, "-r");
1016 }1005 }
10171006
1018 try argv.append("-o");1007 try argv.append(gpa, "-o");
1019 try argv.append(full_out_path);1008 try argv.append(gpa, full_out_path);
1020
1021 if (self.base.isRelocatable()) {
1022 for (self.base.comp.link_inputs) |link_input| switch (link_input) {
1023 .res => unreachable,
1024 .dso => |dso| try argv.append(try dso.path.toString(arena)),
1025 .object, .archive => |obj| try argv.append(try obj.path.toString(arena)),
1026 .dso_exact => |dso_exact| {
1027 assert(dso_exact.name[0] == ':');
1028 try argv.appendSlice(&.{ "-l", dso_exact.name });
1029 },
1030 };
1031
1032 for (comp.c_object_table.keys()) |key| {
1033 try argv.append(try key.status.success.object_path.toString(arena));
1034 }
10351009
1036 if (module_obj_path) |p| {1010 if (!self.base.isRelocatable()) {
1037 try argv.append(p);
1038 }
1039 } else {
1040 if (!self.base.isStatic()) {1011 if (!self.base.isStatic()) {
1041 if (target.dynamic_linker.get()) |path| {1012 if (target.dynamic_linker.get()) |path| {
1042 try argv.append("-dynamic-linker");1013 try argv.appendSlice(gpa, &.{ "-dynamic-linker", try arena.dupe(u8, path) });
1043 try argv.append(path);
1044 }1014 }
1045 }1015 }
10461016
1047 if (self.base.isDynLib()) {1017 if (self.base.isDynLib()) {
1048 if (self.soname) |name| {1018 if (self.soname) |name| {
1049 try argv.append("-soname");1019 try argv.append(gpa, "-soname");
1050 try argv.append(name);1020 try argv.append(gpa, name);
1051 }1021 }
1052 }1022 }
10531023
1054 if (self.entry_name) |name| {1024 if (self.entry_name) |name| {
1055 try argv.appendSlice(&.{ "--entry", name });1025 try argv.appendSlice(gpa, &.{ "--entry", name });
1056 }1026 }
10571027
1058 for (self.rpath_table.keys()) |rpath| {1028 for (self.rpath_table.keys()) |rpath| {
1059 try argv.appendSlice(&.{ "-rpath", rpath });1029 try argv.appendSlice(gpa, &.{ "-rpath", rpath });
1060 }1030 }
10611031
1062 try argv.appendSlice(&.{1032 try argv.appendSlice(gpa, &.{
1063 "-z",1033 "-z",
1064 try std.fmt.allocPrint(arena, "stack-size={d}", .{self.base.stack_size}),1034 try std.fmt.allocPrint(arena, "stack-size={d}", .{self.base.stack_size}),
1065 });1035 });
10661036
1067 try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{self.image_base}));1037 try argv.append(gpa, try std.fmt.allocPrint(arena, "--image-base={d}", .{self.image_base}));
10681038
1069 if (self.base.gc_sections) {1039 if (self.base.gc_sections) {
1070 try argv.append("--gc-sections");1040 try argv.append(gpa, "--gc-sections");
1071 }1041 }
10721042
1073 if (self.base.print_gc_sections) {1043 if (self.base.print_gc_sections) {
1074 try argv.append("--print-gc-sections");1044 try argv.append(gpa, "--print-gc-sections");
1075 }1045 }
10761046
1077 if (comp.link_eh_frame_hdr) {1047 if (comp.link_eh_frame_hdr) {
1078 try argv.append("--eh-frame-hdr");1048 try argv.append(gpa, "--eh-frame-hdr");
1079 }1049 }
10801050
1081 if (comp.config.rdynamic) {1051 if (comp.config.rdynamic) {
1082 try argv.append("--export-dynamic");1052 try argv.append(gpa, "--export-dynamic");
1083 }1053 }
10841054
1085 if (self.z_notext) {1055 if (self.z_notext) {
1086 try argv.append("-z");1056 try argv.append(gpa, "-z");
1087 try argv.append("notext");1057 try argv.append(gpa, "notext");
1088 }1058 }
10891059
1090 if (self.z_nocopyreloc) {1060 if (self.z_nocopyreloc) {
1091 try argv.append("-z");1061 try argv.append(gpa, "-z");
1092 try argv.append("nocopyreloc");1062 try argv.append(gpa, "nocopyreloc");
1093 }1063 }
10941064
1095 if (self.z_now) {1065 if (self.z_now) {
1096 try argv.append("-z");1066 try argv.append(gpa, "-z");
1097 try argv.append("now");1067 try argv.append(gpa, "now");
1098 }1068 }
10991069
1100 if (self.base.isStatic()) {1070 if (self.base.isStatic()) {
1101 try argv.append("-static");1071 try argv.append(gpa, "-static");
1102 } else if (self.isEffectivelyDynLib()) {1072 } else if (self.isEffectivelyDynLib()) {
1103 try argv.append("-shared");1073 try argv.append(gpa, "-shared");
1104 }1074 }
11051075
1106 if (comp.config.pie and self.base.isExe()) {1076 if (comp.config.pie and self.base.isExe()) {
1107 try argv.append("-pie");1077 try argv.append(gpa, "-pie");
1108 }1078 }
11091079
1110 if (comp.config.debug_format == .strip) {1080 if (comp.config.debug_format == .strip) {
1111 try argv.append("-s");1081 try argv.append(gpa, "-s");
1112 }1082 }
11131083
1114 if (crt_paths.crt0) |path| try argv.append(try path.toString(arena));
1115 if (crt_paths.crti) |path| try argv.append(try path.toString(arena));
1116 if (crt_paths.crtbegin) |path| try argv.append(try path.toString(arena));
1117
1118 if (comp.config.link_libc) {1084 if (comp.config.link_libc) {
1119 if (self.base.comp.libc_installation) |libc_installation| {1085 if (self.base.comp.libc_installation) |lci| {
1120 try argv.append("-L");1086 try argv.append(gpa, "-L");
1121 try argv.append(libc_installation.crt_dir.?);1087 try argv.append(gpa, lci.crt_dir.?);
1122 }1088 }
1123 }1089 }
1124
1125 var whole_archive = false;
1126
1127 for (self.base.comp.link_inputs) |link_input| switch (link_input) {
1128 .res => unreachable,
1129 .dso => continue,
1130 .object, .archive => |obj| {
1131 if (obj.must_link and !whole_archive) {
1132 try argv.append("-whole-archive");
1133 whole_archive = true;
1134 } else if (!obj.must_link and whole_archive) {
1135 try argv.append("-no-whole-archive");
1136 whole_archive = false;
1137 }
1138 try argv.append(try obj.path.toString(arena));
1139 },
1140 .dso_exact => |dso_exact| {
1141 assert(dso_exact.name[0] == ':');
1142 try argv.appendSlice(&.{ "-l", dso_exact.name });
1143 },
1144 };
1145
1146 if (whole_archive) {
1147 try argv.append("-no-whole-archive");
1148 whole_archive = false;
1149 }
1150
1151 for (comp.c_object_table.keys()) |key| {
1152 try argv.append(try key.status.success.object_path.toString(arena));
1153 }
1154
1155 if (module_obj_path) |p| {
1156 try argv.append(p);
1157 }
1158
1159 if (comp.config.any_sanitize_thread) {
1160 try argv.append(try comp.tsan_lib.?.full_object_path.toString(arena));
1161 }
1162
1163 if (comp.config.any_fuzz) {
1164 try argv.append(try comp.fuzzer_lib.?.full_object_path.toString(arena));
1165 }
1166
1167 // libc
1168 if (!comp.skip_linker_dependencies and !comp.config.link_libc) {
1169 if (comp.libc_static_lib) |lib| {
1170 try argv.append(try lib.full_object_path.toString(arena));
1171 }
1172 }
1173
1174 // Shared libraries.
1175 // Worst-case, we need an --as-needed argument for every lib, as well
1176 // as one before and one after.
1177 argv.appendAssumeCapacity("--as-needed");
1178 var as_needed = true;
1179
1180 for (self.base.comp.link_inputs) |link_input| switch (link_input) {
1181 .object, .archive, .dso_exact => continue,
1182 .dso => |dso| {
1183 const lib_as_needed = !dso.needed;
1184 switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) {
1185 0b00, 0b11 => {},
1186 0b01 => {
1187 try argv.append("--no-as-needed");
1188 as_needed = false;
1189 },
1190 0b10 => {
1191 try argv.append("--as-needed");
1192 as_needed = true;
1193 },
1194 }
1195 argv.appendAssumeCapacity(try dso.path.toString(arena));
1196 },
1197 .res => unreachable,
1198 };
1199
1200 if (!as_needed) {
1201 argv.appendAssumeCapacity("--as-needed");
1202 as_needed = true;
1203 }
1204
1205 // libc++ dep
1206 if (comp.config.link_libcpp) {
1207 try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena));
1208 try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena));
1209 }
1210
1211 // libunwind dep
1212 if (comp.config.link_libunwind) {
1213 try argv.append(try comp.libunwind_static_lib.?.full_object_path.toString(arena));
1214 }
1215
1216 // libc dep
1217 if (comp.config.link_libc) {
1218 if (self.base.comp.libc_installation != null) {
1219 const needs_grouping = link_mode == .static;
1220 if (needs_grouping) try argv.append("--start-group");
1221 try argv.appendSlice(target_util.libcFullLinkFlags(target));
1222 if (needs_grouping) try argv.append("--end-group");
1223 } else if (target.isGnuLibC()) {
1224 for (glibc.libs) |lib| {
1225 if (lib.removed_in) |rem_in| {
1226 if (target.os.version_range.linux.glibc.order(rem_in) != .lt) continue;
1227 }
1228
1229 const lib_path = try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{
1230 comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
1231 });
1232 try argv.append(lib_path);
1233 }
1234 try argv.append(try comp.crtFileAsString(arena, "libc_nonshared.a"));
1235 } else if (target.isMusl()) {
1236 try argv.append(try comp.crtFileAsString(arena, switch (link_mode) {
1237 .static => "libc.a",
1238 .dynamic => "libc.so",
1239 }));
1240 }
1241 }
1242
1243 // compiler-rt
1244 if (compiler_rt_path) |p| {
1245 try argv.append(p);
1246 }
1247
1248 if (crt_paths.crtend) |path| try argv.append(try path.toString(arena));
1249 if (crt_paths.crtn) |path| try argv.append(try path.toString(arena));
1250 }1090 }
1251
1252 Compilation.dump_argv(argv.items);
1253}1091}
12541092
1255pub const ParseError = error{1093pub const ParseError = error{
...@@ -2177,7 +2015,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -2177,7 +2015,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
2177 if (target.os.version_range.linux.glibc.order(rem_in) != .lt) continue;2015 if (target.os.version_range.linux.glibc.order(rem_in) != .lt) continue;
2178 }2016 }
21792017
2180 const lib_path = try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{2018 const lib_path = try std.fmt.allocPrint(arena, "{}{c}lib{s}.so.{d}", .{
2181 comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,2019 comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
2182 });2020 });
2183 try argv.append(lib_path);2021 try argv.append(lib_path);
src/musl.zig+1-1
...@@ -281,7 +281,7 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro...@@ -281,7 +281,7 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
281 errdefer comp.gpa.free(basename);281 errdefer comp.gpa.free(basename);
282282
283 const crt_file = try sub_compilation.toCrtFile();283 const crt_file = try sub_compilation.toCrtFile();
284 comp.enqueueLinkTaskMode(crt_file.full_object_path, output_mode);284 comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
285 {285 {
286 comp.mutex.lock();286 comp.mutex.lock();
287 defer comp.mutex.unlock();287 defer comp.mutex.unlock();