authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-18 00:23:35-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-23 16:27:38-07:00
log5ca54036ca0bc292ead681c03c8ac57e27a127db
tree17b151d68b2cb40c49d82af85286074be929db7d
parent2dcfa723767d284cef5eb180be7c080583ddbe25

move linker input file parsing to the compilation pipeline


12 files changed, 509 insertions(+), 432 deletions(-)

CMakeLists.txt+1
...@@ -522,6 +522,7 @@ set(ZIG_STAGE2_SOURCES...@@ -522,6 +522,7 @@ set(ZIG_STAGE2_SOURCES
522 src/Sema.zig522 src/Sema.zig
523 src/Sema/bitcast.zig523 src/Sema/bitcast.zig
524 src/Sema/comptime_ptr_access.zig524 src/Sema/comptime_ptr_access.zig
525 src/ThreadSafeQueue.zig
525 src/Type.zig526 src/Type.zig
526 src/Value.zig527 src/Value.zig
527 src/Zcu.zig528 src/Zcu.zig
src/Compilation.zig+174-124
...@@ -10,6 +10,7 @@ const Target = std.Target;...@@ -10,6 +10,7 @@ const Target = std.Target;
10const ThreadPool = std.Thread.Pool;10const ThreadPool = std.Thread.Pool;
11const WaitGroup = std.Thread.WaitGroup;11const WaitGroup = std.Thread.WaitGroup;
12const ErrorBundle = std.zig.ErrorBundle;12const ErrorBundle = std.zig.ErrorBundle;
13const Path = Cache.Path;
1314
14const Value = @import("Value.zig");15const Value = @import("Value.zig");
15const Type = @import("Type.zig");16const Type = @import("Type.zig");
...@@ -39,9 +40,9 @@ const Air = @import("Air.zig");...@@ -39,9 +40,9 @@ const Air = @import("Air.zig");
39const Builtin = @import("Builtin.zig");40const Builtin = @import("Builtin.zig");
40const LlvmObject = @import("codegen/llvm.zig").Object;41const LlvmObject = @import("codegen/llvm.zig").Object;
41const dev = @import("dev.zig");42const dev = @import("dev.zig");
42pub const Directory = Cache.Directory;43const ThreadSafeQueue = @import("ThreadSafeQueue.zig").ThreadSafeQueue;
43const Path = Cache.Path;
4444
45pub const Directory = Cache.Directory;
45pub const Config = @import("Compilation/Config.zig");46pub const Config = @import("Compilation/Config.zig");
4647
47/// General-purpose allocator. Used for both temporary and long-term storage.48/// General-purpose allocator. Used for both temporary and long-term storage.
...@@ -108,6 +109,7 @@ win32_resource_table: if (dev.env.supports(.win32_resource)) std.AutoArrayHashMa...@@ -108,6 +109,7 @@ win32_resource_table: if (dev.env.supports(.win32_resource)) std.AutoArrayHashMa
108} = .{},109} = .{},
109110
110link_diags: link.Diags,111link_diags: link.Diags,
112link_task_queue: ThreadSafeQueue(link.File.Task) = .empty,
111113
112work_queues: [114work_queues: [
113 len: {115 len: {
...@@ -263,6 +265,9 @@ emit_asm: ?EmitLoc,...@@ -263,6 +265,9 @@ emit_asm: ?EmitLoc,
263emit_llvm_ir: ?EmitLoc,265emit_llvm_ir: ?EmitLoc,
264emit_llvm_bc: ?EmitLoc,266emit_llvm_bc: ?EmitLoc,
265267
268work_queue_wait_group: WaitGroup = .{},
269work_queue_progress_node: std.Progress.Node = .none,
270
266llvm_opt_bisect_limit: c_int,271llvm_opt_bisect_limit: c_int,
267272
268file_system_inputs: ?*std.ArrayListUnmanaged(u8),273file_system_inputs: ?*std.ArrayListUnmanaged(u8),
...@@ -358,9 +363,6 @@ const Job = union(enum) {...@@ -358,9 +363,6 @@ const Job = union(enum) {
358 /// After analysis, a `codegen_func` job will be queued.363 /// After analysis, a `codegen_func` job will be queued.
359 /// These must be separate jobs to ensure any needed type resolution occurs *before* codegen.364 /// These must be separate jobs to ensure any needed type resolution occurs *before* codegen.
360 analyze_func: InternPool.Index,365 analyze_func: InternPool.Index,
361 /// The source file containing the Decl has been updated, and so the
362 /// Decl may need its line number information updated in the debug info.
363 update_line_number: void, // TODO
364 /// The main source file for the module needs to be analyzed.366 /// The main source file for the module needs to be analyzed.
365 analyze_mod: *Package.Module,367 analyze_mod: *Package.Module,
366 /// Fully resolve the given `struct` or `union` type.368 /// Fully resolve the given `struct` or `union` type.
...@@ -374,6 +376,7 @@ const Job = union(enum) {...@@ -374,6 +376,7 @@ const Job = union(enum) {
374 musl_crt_file: musl.CrtFile,376 musl_crt_file: musl.CrtFile,
375 /// one of the mingw-w64 static objects377 /// one of the mingw-w64 static objects
376 mingw_crt_file: mingw.CrtFile,378 mingw_crt_file: mingw.CrtFile,
379
377 /// libunwind.a, usually needed when linking libc380 /// libunwind.a, usually needed when linking libc
378 libunwind: void,381 libunwind: void,
379 libcxx: void,382 libcxx: void,
...@@ -1769,68 +1772,107 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1769,68 +1772,107 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1769 }1772 }
1770 // If we need to build glibc for the target, add work items for it.1773 // If we need to build glibc for the target, add work items for it.
1771 // We go through the work queue so that building can be done in parallel.1774 // We go through the work queue so that building can be done in parallel.
1772 if (comp.wantBuildGLibCFromSource()) {1775 // If linking against host libc installation, instead queue up jobs
1773 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;1776 // for loading those files in the linker.
1777 if (comp.config.link_libc and is_exe_or_dyn_lib and target.ofmt != .c) {
1778 if (comp.libc_installation) |lci| {
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);
1787
1788 const fields = @typeInfo(@TypeOf(paths)).@"struct".fields;
1789 try comp.link_task_queue.shared.ensureUnusedCapacity(gpa, fields.len);
1790 inline for (fields) |field| {
1791 if (@field(paths, field.name)) |path| {
1792 comp.link_task_queue.shared.appendAssumeCapacity(.{ .load_object = path });
1793 }
1794 }
1795
1796 const flags = target_util.libcFullLinkFlags(target);
1797 try comp.link_task_queue.shared.ensureUnusedCapacity(gpa, flags.len);
1798 for (flags) |flag| {
1799 assert(mem.startsWith(u8, flag, "-l"));
1800 const lib_name = flag["-l".len..];
1801 const suffix = switch (comp.config.link_mode) {
1802 .static => target.staticLibSuffix(),
1803 .dynamic => target.dynamicLibSuffix(),
1804 };
1805 const sep = std.fs.path.sep_str;
1806 const lib_path = try std.fmt.allocPrint(arena, "{s}" ++ sep ++ "lib{s}{s}", .{
1807 lci.crt_dir.?, lib_name, suffix,
1808 });
1809 const resolved_path = Path.initCwd(lib_path);
1810 comp.link_task_queue.shared.appendAssumeCapacity(switch (comp.config.link_mode) {
1811 .static => .{ .load_archive = resolved_path },
1812 .dynamic => .{ .load_dso = resolved_path },
1813 });
1814 }
1815 } else if (target.isMusl() and !target.isWasm()) {
1816 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
17741817
1775 if (glibc.needsCrtiCrtn(target)) {1818 if (musl.needsCrtiCrtn(target)) {
1819 try comp.queueJobs(&[_]Job{
1820 .{ .musl_crt_file = .crti_o },
1821 .{ .musl_crt_file = .crtn_o },
1822 });
1823 }
1776 try comp.queueJobs(&[_]Job{1824 try comp.queueJobs(&[_]Job{
1777 .{ .glibc_crt_file = .crti_o },1825 .{ .musl_crt_file = .crt1_o },
1778 .{ .glibc_crt_file = .crtn_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 },
1779 });1832 });
1780 }1833 } else if (target.isGnuLibC()) {
1781 try comp.queueJobs(&[_]Job{1834 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
1782 .{ .glibc_crt_file = .scrt1_o },
1783 .{ .glibc_crt_file = .libc_nonshared_a },
1784 .{ .glibc_shared_objects = {} },
1785 });
1786 }
1787 if (comp.wantBuildMuslFromSource()) {
1788 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
17891835
1790 if (musl.needsCrtiCrtn(target)) {1836 if (glibc.needsCrtiCrtn(target)) {
1837 try comp.queueJobs(&[_]Job{
1838 .{ .glibc_crt_file = .crti_o },
1839 .{ .glibc_crt_file = .crtn_o },
1840 });
1841 }
1791 try comp.queueJobs(&[_]Job{1842 try comp.queueJobs(&[_]Job{
1792 .{ .musl_crt_file = .crti_o },1843 .{ .glibc_crt_file = .scrt1_o },
1793 .{ .musl_crt_file = .crtn_o },1844 .{ .glibc_crt_file = .libc_nonshared_a },
1845 .{ .glibc_shared_objects = {} },
1794 });1846 });
1795 }1847 } else if (target.isWasm() and target.os.tag == .wasi) {
1796 try comp.queueJobs(&[_]Job{1848 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
1797 .{ .musl_crt_file = .crt1_o },
1798 .{ .musl_crt_file = .scrt1_o },
1799 .{ .musl_crt_file = .rcrt1_o },
1800 switch (comp.config.link_mode) {
1801 .static => .{ .musl_crt_file = .libc_a },
1802 .dynamic => .{ .musl_crt_file = .libc_so },
1803 },
1804 });
1805 }
18061849
1807 if (comp.wantBuildWasiLibcFromSource()) {1850 for (comp.wasi_emulated_libs) |crt_file| {
1808 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;1851 try comp.queueJob(.{
1852 .wasi_libc_crt_file = crt_file,
1853 });
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;
18091861
1810 for (comp.wasi_emulated_libs) |crt_file| {1862 const crt_job: Job = .{ .mingw_crt_file = if (is_dyn_lib) .dllcrt2_o else .crt2_o };
1811 try comp.queueJob(.{1863 try comp.queueJobs(&.{
1812 .wasi_libc_crt_file = crt_file,1864 .{ .mingw_crt_file = .mingw32_lib },
1865 crt_job,
1813 });1866 });
1867
1868 // When linking mingw-w64 there are some import libs we always need.
1869 try comp.windows_libs.ensureUnusedCapacity(gpa, mingw.always_link_libs.len);
1870 for (mingw.always_link_libs) |name| comp.windows_libs.putAssumeCapacity(name, {});
1871 } else {
1872 return error.LibCUnavailable;
1814 }1873 }
1815 try comp.queueJobs(&[_]Job{
1816 .{ .wasi_libc_crt_file = wasi_libc.execModelCrtFile(comp.config.wasi_exec_model) },
1817 .{ .wasi_libc_crt_file = .libc_a },
1818 });
1819 }1874 }
18201875
1821 if (comp.wantBuildMinGWFromSource()) {
1822 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
1823
1824 const crt_job: Job = .{ .mingw_crt_file = if (is_dyn_lib) .dllcrt2_o else .crt2_o };
1825 try comp.queueJobs(&.{
1826 .{ .mingw_crt_file = .mingw32_lib },
1827 crt_job,
1828 });
1829
1830 // When linking mingw-w64 there are some import libs we always need.
1831 try comp.windows_libs.ensureUnusedCapacity(gpa, mingw.always_link_libs.len);
1832 for (mingw.always_link_libs) |name| comp.windows_libs.putAssumeCapacity(name, {});
1833 }
1834 // Generate Windows import libs.1876 // Generate Windows import libs.
1835 if (target.os.tag == .windows) {1877 if (target.os.tag == .windows) {
1836 const count = comp.windows_libs.count();1878 const count = comp.windows_libs.count();
...@@ -1885,12 +1927,16 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1885,12 +1927,16 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1885 {1927 {
1886 try comp.queueJob(.{ .zig_libc = {} });1928 try comp.queueJob(.{ .zig_libc = {} });
1887 }1929 }
1930
1931 try comp.link_task_queue.shared.append(gpa, .load_explicitly_provided);
1888 }1932 }
18891933
1890 return comp;1934 return comp;
1891}1935}
18921936
1893pub fn destroy(comp: *Compilation) void {1937pub fn destroy(comp: *Compilation) void {
1938 const gpa = comp.gpa;
1939
1894 if (comp.bin_file) |lf| lf.destroy();1940 if (comp.bin_file) |lf| lf.destroy();
1895 if (comp.zcu) |zcu| zcu.deinit();1941 if (comp.zcu) |zcu| zcu.deinit();
1896 comp.cache_use.deinit();1942 comp.cache_use.deinit();
...@@ -1901,7 +1947,6 @@ pub fn destroy(comp: *Compilation) void {...@@ -1901,7 +1947,6 @@ pub fn destroy(comp: *Compilation) void {
1901 comp.astgen_work_queue.deinit();1947 comp.astgen_work_queue.deinit();
1902 comp.embed_file_work_queue.deinit();1948 comp.embed_file_work_queue.deinit();
19031949
1904 const gpa = comp.gpa;
1905 comp.windows_libs.deinit(gpa);1950 comp.windows_libs.deinit(gpa);
19061951
1907 {1952 {
...@@ -3446,6 +3491,9 @@ pub fn performAllTheWork(...@@ -3446,6 +3491,9 @@ pub fn performAllTheWork(
3446 comp: *Compilation,3491 comp: *Compilation,
3447 main_progress_node: std.Progress.Node,3492 main_progress_node: std.Progress.Node,
3448) JobError!void {3493) JobError!void {
3494 comp.work_queue_progress_node = main_progress_node;
3495 defer comp.work_queue_progress_node = .none;
3496
3449 defer if (comp.zcu) |zcu| {3497 defer if (comp.zcu) |zcu| {
3450 zcu.sema_prog_node.end();3498 zcu.sema_prog_node.end();
3451 zcu.sema_prog_node = std.Progress.Node.none;3499 zcu.sema_prog_node = std.Progress.Node.none;
...@@ -3467,12 +3515,20 @@ fn performAllTheWorkInner(...@@ -3467,12 +3515,20 @@ fn performAllTheWorkInner(
3467 // (at least for now) single-threaded main work queue. However, C object compilation3515 // (at least for now) single-threaded main work queue. However, C object compilation
3468 // only needs to be finished by the end of this function.3516 // only needs to be finished by the end of this function.
34693517
3470 var work_queue_wait_group: WaitGroup = .{};3518 const work_queue_wait_group = &comp.work_queue_wait_group;
3519
3520 work_queue_wait_group.reset();
3471 defer work_queue_wait_group.wait();3521 defer work_queue_wait_group.wait();
34723522
3523 if (comp.bin_file) |lf| {
3524 if (try comp.link_task_queue.enqueue(comp.gpa, &.{.load_explicitly_provided})) {
3525 comp.thread_pool.spawnWg(work_queue_wait_group, link.File.flushTaskQueue, .{ lf, main_progress_node });
3526 }
3527 }
3528
3473 if (comp.docs_emit != null) {3529 if (comp.docs_emit != null) {
3474 dev.check(.docs_emit);3530 dev.check(.docs_emit);
3475 comp.thread_pool.spawnWg(&work_queue_wait_group, workerDocsCopy, .{comp});3531 comp.thread_pool.spawnWg(work_queue_wait_group, workerDocsCopy, .{comp});
3476 work_queue_wait_group.spawnManager(workerDocsWasm, .{ comp, main_progress_node });3532 work_queue_wait_group.spawnManager(workerDocsWasm, .{ comp, main_progress_node });
3477 }3533 }
34783534
...@@ -3538,21 +3594,32 @@ fn performAllTheWorkInner(...@@ -3538,21 +3594,32 @@ fn performAllTheWorkInner(
3538 }3594 }
35393595
3540 while (comp.c_object_work_queue.readItem()) |c_object| {3596 while (comp.c_object_work_queue.readItem()) |c_object| {
3541 comp.thread_pool.spawnWg(&work_queue_wait_group, workerUpdateCObject, .{3597 comp.thread_pool.spawnWg(work_queue_wait_group, workerUpdateCObject, .{
3542 comp, c_object, main_progress_node,3598 comp, c_object, main_progress_node,
3543 });3599 });
3544 }3600 }
35453601
3546 while (comp.win32_resource_work_queue.readItem()) |win32_resource| {3602 while (comp.win32_resource_work_queue.readItem()) |win32_resource| {
3547 comp.thread_pool.spawnWg(&work_queue_wait_group, workerUpdateWin32Resource, .{3603 comp.thread_pool.spawnWg(work_queue_wait_group, workerUpdateWin32Resource, .{
3548 comp, win32_resource, main_progress_node,3604 comp, win32_resource, main_progress_node,
3549 });3605 });
3550 }3606 }
3551 }3607 }
35523608
3553 if (comp.job_queued_compiler_rt_lib) work_queue_wait_group.spawnManager(buildRt, .{ comp, "compiler_rt.zig", .compiler_rt, .Lib, &comp.compiler_rt_lib, main_progress_node });3609 if (comp.job_queued_compiler_rt_lib) {
3554 if (comp.job_queued_compiler_rt_obj) work_queue_wait_group.spawnManager(buildRt, .{ comp, "compiler_rt.zig", .compiler_rt, .Obj, &comp.compiler_rt_obj, main_progress_node });3610 comp.job_queued_compiler_rt_lib = false;
3555 if (comp.job_queued_fuzzer_lib) work_queue_wait_group.spawnManager(buildRt, .{ comp, "fuzzer.zig", .libfuzzer, .Lib, &comp.fuzzer_lib, main_progress_node });3611 work_queue_wait_group.spawnManager(buildRt, .{ comp, "compiler_rt.zig", .compiler_rt, .Lib, &comp.compiler_rt_lib, main_progress_node });
3612 }
3613
3614 if (comp.job_queued_compiler_rt_obj) {
3615 comp.job_queued_compiler_rt_obj = false;
3616 work_queue_wait_group.spawnManager(buildRt, .{ comp, "compiler_rt.zig", .compiler_rt, .Obj, &comp.compiler_rt_obj, main_progress_node });
3617 }
3618
3619 if (comp.job_queued_fuzzer_lib) {
3620 comp.job_queued_fuzzer_lib = false;
3621 work_queue_wait_group.spawnManager(buildRt, .{ comp, "fuzzer.zig", .libfuzzer, .Lib, &comp.fuzzer_lib, main_progress_node });
3622 }
35563623
3557 if (comp.zcu) |zcu| {3624 if (comp.zcu) |zcu| {
3558 const pt: Zcu.PerThread = .{ .zcu = zcu, .tid = .main };3625 const pt: Zcu.PerThread = .{ .zcu = zcu, .tid = .main };
...@@ -3570,7 +3637,7 @@ fn performAllTheWorkInner(...@@ -3570,7 +3637,7 @@ fn performAllTheWorkInner(
35703637
3571 if (!InternPool.single_threaded) {3638 if (!InternPool.single_threaded) {
3572 comp.codegen_work.done = false; // may be `true` from a prior update3639 comp.codegen_work.done = false; // may be `true` from a prior update
3573 comp.thread_pool.spawnWgId(&work_queue_wait_group, codegenThread, .{comp});3640 comp.thread_pool.spawnWgId(work_queue_wait_group, codegenThread, .{comp});
3574 }3641 }
3575 defer if (!InternPool.single_threaded) {3642 defer if (!InternPool.single_threaded) {
3576 {3643 {
...@@ -3679,31 +3746,6 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre...@@ -3679,31 +3746,6 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
3679 error.AnalysisFail => return,3746 error.AnalysisFail => return,
3680 };3747 };
3681 },3748 },
3682 .update_line_number => |decl_index| {
3683 const named_frame = tracy.namedFrame("update_line_number");
3684 defer named_frame.end();
3685
3686 if (true) @panic("TODO: update_line_number");
3687
3688 const gpa = comp.gpa;
3689 const pt: Zcu.PerThread = .{ .zcu = comp.zcu.?, .tid = @enumFromInt(tid) };
3690 const decl = pt.zcu.declPtr(decl_index);
3691 const lf = comp.bin_file.?;
3692 lf.updateDeclLineNumber(pt, decl_index) catch |err| {
3693 try pt.zcu.failed_analysis.ensureUnusedCapacity(gpa, 1);
3694 pt.zcu.failed_analysis.putAssumeCapacityNoClobber(
3695 InternPool.AnalUnit.wrap(.{ .decl = decl_index }),
3696 try Zcu.ErrorMsg.create(
3697 gpa,
3698 decl.navSrcLoc(pt.zcu),
3699 "unable to update line number: {s}",
3700 .{@errorName(err)},
3701 ),
3702 );
3703 decl.analysis = .codegen_failure;
3704 try pt.zcu.retryable_failures.append(gpa, InternPool.AnalUnit.wrap(.{ .decl = decl_index }));
3705 };
3706 },
3707 .analyze_mod => |mod| {3749 .analyze_mod => |mod| {
3708 const named_frame = tracy.namedFrame("analyze_mod");3750 const named_frame = tracy.namedFrame("analyze_mod");
3709 defer named_frame.end();3751 defer named_frame.end();
...@@ -4920,7 +4962,9 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr...@@ -4920,7 +4962,9 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
4920 // the contents were the same, we hit the cache but the manifest is dirty and we need to update4962 // the contents were the same, we hit the cache but the manifest is dirty and we need to update
4921 // it to prevent doing a full file content comparison the next time around.4963 // it to prevent doing a full file content comparison the next time around.
4922 man.writeManifest() catch |err| {4964 man.writeManifest() catch |err| {
4923 log.warn("failed to write cache manifest when compiling '{s}': {s}", .{ c_object.src.src_path, @errorName(err) });4965 log.warn("failed to write cache manifest when compiling '{s}': {s}", .{
4966 c_object.src.src_path, @errorName(err),
4967 });
4924 };4968 };
4925 }4969 }
49264970
...@@ -4935,6 +4979,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr...@@ -4935,6 +4979,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
4935 .lock = man.toOwnedLock(),4979 .lock = man.toOwnedLock(),
4936 },4980 },
4937 };4981 };
4982
4983 comp.enqueueLinkTasks(&.{.{ .load_object = c_object.status.success.object_path }});
4938}4984}
49394985
4940fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32_resource_prog_node: std.Progress.Node) !void {4986fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32_resource_prog_node: std.Progress.Node) !void {
...@@ -6058,35 +6104,6 @@ fn crtFilePath(crt_files: *std.StringHashMapUnmanaged(CrtFile), basename: []cons...@@ -6058,35 +6104,6 @@ fn crtFilePath(crt_files: *std.StringHashMapUnmanaged(CrtFile), basename: []cons
6058 return crt_file.full_object_path;6104 return crt_file.full_object_path;
6059}6105}
60606106
6061fn wantBuildLibCFromSource(comp: Compilation) bool {
6062 const is_exe_or_dyn_lib = switch (comp.config.output_mode) {
6063 .Obj => false,
6064 .Lib => comp.config.link_mode == .dynamic,
6065 .Exe => true,
6066 };
6067 const ofmt = comp.root_mod.resolved_target.result.ofmt;
6068 return comp.config.link_libc and is_exe_or_dyn_lib and
6069 comp.libc_installation == null and ofmt != .c;
6070}
6071
6072fn wantBuildGLibCFromSource(comp: Compilation) bool {
6073 return comp.wantBuildLibCFromSource() and comp.getTarget().isGnuLibC();
6074}
6075
6076fn wantBuildMuslFromSource(comp: Compilation) bool {
6077 return comp.wantBuildLibCFromSource() and comp.getTarget().isMusl() and
6078 !comp.getTarget().isWasm();
6079}
6080
6081fn wantBuildWasiLibcFromSource(comp: Compilation) bool {
6082 return comp.wantBuildLibCFromSource() and comp.getTarget().isWasm() and
6083 comp.getTarget().os.tag == .wasi;
6084}
6085
6086fn wantBuildMinGWFromSource(comp: Compilation) bool {
6087 return comp.wantBuildLibCFromSource() and comp.getTarget().isMinGW();
6088}
6089
6090fn wantBuildLibUnwindFromSource(comp: *Compilation) bool {6107fn wantBuildLibUnwindFromSource(comp: *Compilation) bool {
6091 const is_exe_or_dyn_lib = switch (comp.config.output_mode) {6108 const is_exe_or_dyn_lib = switch (comp.config.output_mode) {
6092 .Obj => false,6109 .Obj => false,
...@@ -6334,9 +6351,11 @@ fn buildOutputFromZig(...@@ -6334,9 +6351,11 @@ fn buildOutputFromZig(
63346351
6335 try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node);6352 try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node);
63366353
6337 // Under incremental compilation, `out` may already be populated from a prior update.6354 const crt_file = try sub_compilation.toCrtFile();
6338 assert(out.* == null or comp.incremental);6355 assert(out.* == null);
6339 out.* = try sub_compilation.toCrtFile();6356 out.* = crt_file;
6357
6358 comp.enqueueLinkTaskMode(crt_file.full_object_path, output_mode);
6340}6359}
63416360
6342pub fn build_crt_file(6361pub fn build_crt_file(
...@@ -6443,8 +6462,39 @@ pub fn build_crt_file(...@@ -6443,8 +6462,39 @@ pub fn build_crt_file(
64436462
6444 try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node);6463 try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node);
64456464
6446 try comp.crt_files.ensureUnusedCapacity(gpa, 1);6465 const crt_file = try sub_compilation.toCrtFile();
6447 comp.crt_files.putAssumeCapacityNoClobber(basename, try sub_compilation.toCrtFile());6466 comp.enqueueLinkTaskMode(crt_file.full_object_path, output_mode);
6467
6468 {
6469 comp.mutex.lock();
6470 defer comp.mutex.unlock();
6471 try comp.crt_files.ensureUnusedCapacity(gpa, 1);
6472 comp.crt_files.putAssumeCapacityNoClobber(basename, crt_file);
6473 }
6474}
6475
6476pub fn enqueueLinkTaskMode(comp: *Compilation, path: Path, output_mode: std.builtin.OutputMode) void {
6477 comp.enqueueLinkTasks(switch (output_mode) {
6478 .Exe => unreachable,
6479 .Obj => &.{.{ .load_object = path }},
6480 .Lib => &.{.{ .load_archive = path }},
6481 });
6482}
6483
6484/// Only valid to call during `update`. Automatically handles queuing up a
6485/// linker worker task if there is not already one.
6486fn enqueueLinkTasks(comp: *Compilation, tasks: []const link.File.Task) void {
6487 const use_lld = build_options.have_llvm and comp.config.use_lld;
6488 if (use_lld) return;
6489 const target = comp.root_mod.resolved_target.result;
6490 if (target.ofmt != .elf) return;
6491 if (comp.link_task_queue.enqueue(comp.gpa, tasks) catch |err| switch (err) {
6492 error.OutOfMemory => return comp.setAllocFailure(),
6493 }) {
6494 comp.thread_pool.spawnWg(&comp.work_queue_wait_group, link.File.flushTaskQueue, .{
6495 comp.bin_file.?, comp.work_queue_progress_node,
6496 });
6497 }
6448}6498}
64496499
6450pub fn toCrtFile(comp: *Compilation) Allocator.Error!CrtFile {6500pub fn toCrtFile(comp: *Compilation) Allocator.Error!CrtFile {
src/ThreadSafeQueue.zig created+63
...@@ -0,0 +1,63 @@
1const std = @import("std");
2const assert = std.debug.assert;
3const Allocator = std.mem.Allocator;
4
5pub fn ThreadSafeQueue(comptime T: type) type {
6 return struct {
7 worker_owned: std.ArrayListUnmanaged(T),
8 /// Protected by `mutex`.
9 shared: std.ArrayListUnmanaged(T),
10 mutex: std.Thread.Mutex,
11 state: State,
12
13 const Self = @This();
14
15 pub const State = enum { wait, run };
16
17 pub const empty: Self = .{
18 .worker_owned = .empty,
19 .shared = .empty,
20 .mutex = .{},
21 .state = .wait,
22 };
23
24 pub fn deinit(self: *Self, gpa: Allocator) void {
25 self.worker_owned.deinit(gpa);
26 self.shared.deinit(gpa);
27 self.* = undefined;
28 }
29
30 /// Must be called from the worker thread.
31 pub fn check(self: *Self) ?[]T {
32 assert(self.worker_owned.items.len == 0);
33 {
34 self.mutex.lock();
35 defer self.mutex.unlock();
36 assert(self.state == .run);
37 if (self.shared.items.len == 0) {
38 self.state = .wait;
39 return null;
40 }
41 std.mem.swap(std.ArrayListUnmanaged(T), &self.worker_owned, &self.shared);
42 }
43 const result = self.worker_owned.items;
44 self.worker_owned.clearRetainingCapacity();
45 return result;
46 }
47
48 /// Adds items to the queue, returning true if and only if the worker
49 /// thread is waiting. Thread-safe.
50 /// Not safe to call from the worker thread.
51 pub fn enqueue(self: *Self, gpa: Allocator, items: []const T) error{OutOfMemory}!bool {
52 self.mutex.lock();
53 defer self.mutex.unlock();
54 try self.shared.appendSlice(gpa, items);
55 const was_waiting = switch (self.state) {
56 .run => false,
57 .wait => true,
58 };
59 self.state = .run;
60 return was_waiting;
61 }
62 };
63}
src/glibc.zig+1-3
...@@ -1204,14 +1204,12 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi...@@ -1204,14 +1204,12 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi
1204 };1204 };
12051205
1206 assert(comp.glibc_so_files == null);1206 assert(comp.glibc_so_files == null);
1207 comp.glibc_so_files = BuiltSharedObjects{1207 comp.glibc_so_files = .{
1208 .lock = man.toOwnedLock(),1208 .lock = man.toOwnedLock(),
1209 .dir_path = try comp.global_cache_directory.join(comp.gpa, &.{ "o", &digest }),1209 .dir_path = try comp.global_cache_directory.join(comp.gpa, &.{ "o", &digest }),
1210 };1210 };
1211}1211}
12121212
1213// zig fmt: on
1214
1215fn buildSharedLib(1213fn buildSharedLib(
1216 comp: *Compilation,1214 comp: *Compilation,
1217 arena: Allocator,1215 arena: Allocator,
src/libcxx.zig+6-2
...@@ -355,7 +355,9 @@ pub fn buildLibCXX(comp: *Compilation, prog_node: std.Progress.Node) BuildError!...@@ -355,7 +355,9 @@ pub fn buildLibCXX(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
355 };355 };
356356
357 assert(comp.libcxx_static_lib == null);357 assert(comp.libcxx_static_lib == null);
358 comp.libcxx_static_lib = try sub_compilation.toCrtFile();358 const crt_file = try sub_compilation.toCrtFile();
359 comp.libcxx_static_lib = crt_file;
360 comp.enqueueLinkTaskMode(crt_file.full_object_path, output_mode);
359}361}
360362
361pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void {363pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void {
...@@ -584,7 +586,9 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -584,7 +586,9 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
584 };586 };
585587
586 assert(comp.libcxxabi_static_lib == null);588 assert(comp.libcxxabi_static_lib == null);
587 comp.libcxxabi_static_lib = try sub_compilation.toCrtFile();589 const crt_file = try sub_compilation.toCrtFile();
590 comp.libcxxabi_static_lib = crt_file;
591 comp.enqueueLinkTaskMode(crt_file.full_object_path, output_mode);
588}592}
589593
590pub fn hardeningModeFlag(optimize_mode: std.builtin.OptimizeMode) []const u8 {594pub fn hardeningModeFlag(optimize_mode: std.builtin.OptimizeMode) []const u8 {
src/libtsan.zig+3-1
...@@ -342,8 +342,10 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo...@@ -342,8 +342,10 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
342 },342 },
343 };343 };
344344
345 const crt_file = try sub_compilation.toCrtFile();
346 comp.enqueueLinkTaskMode(crt_file.full_object_path, output_mode);
345 assert(comp.tsan_lib == null);347 assert(comp.tsan_lib == null);
346 comp.tsan_lib = try sub_compilation.toCrtFile();348 comp.tsan_lib = crt_file;
347}349}
348350
349const tsan_sources = [_][]const u8{351const tsan_sources = [_][]const u8{
src/libunwind.zig+3-1
...@@ -199,8 +199,10 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -199,8 +199,10 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
199 },199 },
200 };200 };
201201
202 const crt_file = try sub_compilation.toCrtFile();
203 comp.enqueueLinkTaskMode(crt_file.full_object_path, output_mode);
202 assert(comp.libunwind_static_lib == null);204 assert(comp.libunwind_static_lib == null);
203 comp.libunwind_static_lib = try sub_compilation.toCrtFile();205 comp.libunwind_static_lib = crt_file;
204}206}
205207
206const unwind_src_list = [_][]const u8{208const unwind_src_list = [_][]const u8{
src/link.zig+197
...@@ -24,6 +24,7 @@ const LlvmObject = @import("codegen/llvm.zig").Object;...@@ -24,6 +24,7 @@ const LlvmObject = @import("codegen/llvm.zig").Object;
24const lldMain = @import("main.zig").lldMain;24const lldMain = @import("main.zig").lldMain;
25const Package = @import("Package.zig");25const Package = @import("Package.zig");
26const dev = @import("dev.zig");26const dev = @import("dev.zig");
27const ThreadSafeQueue = @import("ThreadSafeQueue.zig").ThreadSafeQueue;
2728
28pub const LdScript = @import("link/LdScript.zig");29pub const LdScript = @import("link/LdScript.zig");
2930
...@@ -368,6 +369,9 @@ pub const File = struct {...@@ -368,6 +369,9 @@ pub const File = struct {
368 lock: ?Cache.Lock = null,369 lock: ?Cache.Lock = null,
369 child_pid: ?std.process.Child.Id = null,370 child_pid: ?std.process.Child.Id = null,
370371
372 /// Ensure only 1 simultaneous call to `flushTaskQueue`.
373 task_queue_safety: std.debug.SafetyLock = .{},
374
371 pub const OpenOptions = struct {375 pub const OpenOptions = struct {
372 symbol_count_hint: u64 = 32,376 symbol_count_hint: u64 = 32,
373 program_code_size_hint: u64 = 256 * 1024,377 program_code_size_hint: u64 = 256 * 1024,
...@@ -995,6 +999,86 @@ pub const File = struct {...@@ -995,6 +999,86 @@ pub const File = struct {
995 }999 }
996 }1000 }
9971001
1002 /// Opens a path as an object file and parses it into the linker.
1003 fn openLoadObject(base: *File, path: Path) anyerror!void {
1004 const diags = &base.comp.link_diags;
1005 const input = try openObjectInput(diags, path);
1006 errdefer input.object.file.close();
1007 try loadInput(base, input);
1008 }
1009
1010 /// Opens a path as a static library and parses it into the linker.
1011 fn openLoadArchive(base: *File, path: Path) anyerror!void {
1012 const diags = &base.comp.link_diags;
1013 const input = try openArchiveInput(diags, path, false, false);
1014 errdefer input.archive.file.close();
1015 try loadInput(base, input);
1016 }
1017
1018 /// Opens a path as a shared library and parses it into the linker.
1019 /// Handles GNU ld scripts.
1020 fn openLoadDso(base: *File, path: Path, query: UnresolvedInput.Query) anyerror!void {
1021 const dso = try openDso(path, query.needed, query.weak, query.reexport);
1022 errdefer dso.file.close();
1023 loadInput(base, .{ .dso = dso }) catch |err| switch (err) {
1024 error.BadMagic, error.UnexpectedEndOfFile => {
1025 if (base.tag != .elf) return err;
1026 try loadGnuLdScript(base, path, query, dso.file);
1027 dso.file.close();
1028 return;
1029 },
1030 else => return err,
1031 };
1032 }
1033
1034 fn loadGnuLdScript(base: *File, path: Path, parent_query: UnresolvedInput.Query, file: fs.File) anyerror!void {
1035 const diags = &base.comp.link_diags;
1036 const gpa = base.comp.gpa;
1037 const stat = try file.stat();
1038 const size = std.math.cast(u32, stat.size) orelse return error.FileTooBig;
1039 const buf = try gpa.alloc(u8, size);
1040 defer gpa.free(buf);
1041 const n = try file.preadAll(buf, 0);
1042 if (buf.len != n) return error.UnexpectedEndOfFile;
1043 var ld_script = try LdScript.parse(gpa, diags, path, buf);
1044 defer ld_script.deinit(gpa);
1045 for (ld_script.args) |arg| {
1046 const query: UnresolvedInput.Query = .{
1047 .needed = arg.needed or parent_query.needed,
1048 .weak = parent_query.weak,
1049 .reexport = parent_query.reexport,
1050 .preferred_mode = parent_query.preferred_mode,
1051 .search_strategy = parent_query.search_strategy,
1052 .allow_so_scripts = parent_query.allow_so_scripts,
1053 };
1054 if (mem.startsWith(u8, arg.path, "-l")) {
1055 @panic("TODO");
1056 } else {
1057 if (fs.path.isAbsolute(arg.path)) {
1058 const new_path = Path.initCwd(try gpa.dupe(u8, arg.path));
1059 switch (Compilation.classifyFileExt(arg.path)) {
1060 .shared_library => try openLoadDso(base, new_path, query),
1061 .object => try openLoadObject(base, new_path),
1062 .static_library => try openLoadArchive(base, new_path),
1063 else => diags.addParseError(path, "GNU ld script references file with unrecognized extension: {s}", .{arg.path}),
1064 }
1065 } else {
1066 @panic("TODO");
1067 }
1068 }
1069 }
1070 }
1071
1072 pub fn loadInput(base: *File, input: Input) anyerror!void {
1073 switch (base.tag) {
1074 inline .elf => |tag| {
1075 dev.check(tag.devFeature());
1076 return @as(*tag.Type(), @fieldParentPtr("base", base)).loadInput(input);
1077 },
1078 else => {},
1079 }
1080 }
1081
998 pub fn linkAsArchive(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) FlushError!void {1082 pub fn linkAsArchive(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) FlushError!void {
999 dev.check(.lld_linker);1083 dev.check(.lld_linker);
10001084
...@@ -1261,6 +1345,111 @@ pub const File = struct {...@@ -1261,6 +1345,111 @@ pub const File = struct {
1261 pub const Wasm = @import("link/Wasm.zig");1345 pub const Wasm = @import("link/Wasm.zig");
1262 pub const NvPtx = @import("link/NvPtx.zig");1346 pub const NvPtx = @import("link/NvPtx.zig");
1263 pub const Dwarf = @import("link/Dwarf.zig");1347 pub const Dwarf = @import("link/Dwarf.zig");
1348
1349 /// Does all the tasks in the queue. Runs in exactly one separate thread
1350 /// from the rest of compilation. All tasks performed here are
1351 /// single-threaded with respect to one another.
1352 pub fn flushTaskQueue(base: *File, prog_node: std.Progress.Node) void {
1353 const comp = base.comp;
1354 base.task_queue_safety.lock();
1355 defer base.task_queue_safety.unlock();
1356 while (comp.link_task_queue.check()) |tasks| {
1357 for (tasks) |task| doTask(base, prog_node, task);
1358 }
1359 }
1360
1361 pub const Task = union(enum) {
1362 /// Loads the objects, shared objects, and archives that are already
1363 /// known from the command line.
1364 load_explicitly_provided,
1365 /// Tells the linker to load an object file by path.
1366 load_object: Path,
1367 /// Tells the linker to load a static library by path.
1368 load_archive: Path,
1369 /// Tells the linker to load a shared library, possibly one that is a
1370 /// GNU ld script.
1371 load_dso: Path,
1372 /// Tells the linker to load an input which could be an object file,
1373 /// archive, or shared library.
1374 load_input: Input,
1375 };
1376
1377 fn doTask(base: *File, parent_prog_node: std.Progress.Node, task: Task) void {
1378 const comp = base.comp;
1379 switch (task) {
1380 .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| {
1385 const sub_node = prog_node.start(input.taskName(), 0);
1386 defer sub_node.end();
1387 base.loadInput(input) catch |err| switch (err) {
1388 error.LinkFailure => return, // error reported via link_diags
1389 else => |e| {
1390 if (input.path()) |path| {
1391 comp.link_diags.addParseError(path, "failed to parse linker input: {s}", .{@errorName(e)});
1392 } else {
1393 comp.link_diags.addError("failed to {s}: {s}", .{ input.taskName(), @errorName(e) });
1394 }
1395 },
1396 };
1397 }
1398 },
1399 .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) {
1406 error.LinkFailure => return, // error reported via link_diags
1407 else => |e| comp.link_diags.addParseError(path, "failed to parse object: {s}", .{@errorName(e)}),
1408 };
1409 },
1410 .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) {
1417 error.LinkFailure => return, // error reported via link_diags
1418 else => |e| comp.link_diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(e)}),
1419 };
1420 },
1421 .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, .{
1428 .preferred_mode = .dynamic,
1429 .search_strategy = .paths_first,
1430 }) catch |err| switch (err) {
1431 error.LinkFailure => return, // error reported via link_diags
1432 else => |e| comp.link_diags.addParseError(path, "failed to parse shared library: {s}", .{@errorName(e)}),
1433 };
1434 },
1435 .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) {
1441 error.LinkFailure => return, // error reported via link_diags
1442 else => |e| {
1443 if (input.path()) |path| {
1444 comp.link_diags.addParseError(path, "failed to parse linker input: {s}", .{@errorName(e)});
1445 } else {
1446 comp.link_diags.addError("failed to {s}: {s}", .{ input.taskName(), @errorName(e) });
1447 }
1448 },
1449 };
1450 },
1451 }
1452 }
1264};1453};
12651454
1266pub fn spawnLld(1455pub fn spawnLld(
...@@ -1480,6 +1669,14 @@ pub const Input = union(enum) {...@@ -1480,6 +1669,14 @@ pub const Input = union(enum) {
1480 .dso_exact => null,1669 .dso_exact => null,
1481 };1670 };
1482 }1671 }
1672
1673 pub fn taskName(input: Input) []const u8 {
1674 return switch (input) {
1675 .object, .archive => |obj| obj.path.basename(),
1676 inline .res, .dso => |x| x.path.basename(),
1677 .dso_exact => "dso_exact",
1678 };
1679 }
1483};1680};
14841681
1485pub fn hashInputs(man: *Cache.Manifest, link_inputs: []const Input) !void {1682pub fn hashInputs(man: *Cache.Manifest, link_inputs: []const Input) !void {
src/link/Elf.zig+37-206
...@@ -35,8 +35,7 @@ ptr_width: PtrWidth,...@@ -35,8 +35,7 @@ ptr_width: PtrWidth,
35llvm_object: ?LlvmObject.Ptr = null,35llvm_object: ?LlvmObject.Ptr = null,
3636
37/// A list of all input files.37/// A list of all input files.
38/// Index of each input file also encodes the priority or precedence of one input file38/// First index is a special "null file". Order is otherwise not observed.
39/// over another.
40files: std.MultiArrayList(File.Entry) = .{},39files: std.MultiArrayList(File.Entry) = .{},
41/// Long-lived list of all file descriptors.40/// Long-lived list of all file descriptors.
42/// We store them globally rather than per actual File so that we can re-use41/// We store them globally rather than per actual File so that we can re-use
...@@ -350,6 +349,9 @@ pub fn createEmpty(...@@ -350,6 +349,9 @@ pub fn createEmpty(
350 return self;349 return self;
351 }350 }
352351
352 // --verbose-link
353 if (comp.verbose_link) try self.dumpArgv(comp);
354
353 const is_obj = output_mode == .Obj;355 const is_obj = output_mode == .Obj;
354 const is_obj_or_ar = is_obj or (output_mode == .Lib and link_mode == .static);356 const is_obj_or_ar = is_obj or (output_mode == .Lib and link_mode == .static);
355357
...@@ -750,6 +752,22 @@ pub fn allocateChunk(self: *Elf, args: struct {...@@ -750,6 +752,22 @@ pub fn allocateChunk(self: *Elf, args: struct {
750 return res;752 return res;
751}753}
752754
755pub fn loadInput(self: *Elf, input: link.Input) !void {
756 const gpa = self.base.comp.gpa;
757 const diags = &self.base.comp.link_diags;
758 const target = self.getTarget();
759 const debug_fmt_strip = self.base.comp.config.debug_format == .strip;
760 const default_sym_version = self.default_sym_version;
761
762 switch (input) {
763 .res => unreachable,
764 .dso_exact => @panic("TODO"),
765 .object => |obj| try parseObject(self, obj),
766 .archive => |obj| try parseArchive(gpa, diags, &self.file_handles, &self.files, &self.first_eflags, target, debug_fmt_strip, default_sym_version, &self.objects, obj),
767 .dso => |dso| try parseDso(gpa, diags, dso, &self.shared_objects, &self.files, target),
768 }
769}
770
753pub fn flush(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {771pub fn flush(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
754 const use_lld = build_options.have_llvm and self.base.comp.config.use_lld;772 const use_lld = build_options.have_llvm and self.base.comp.config.use_lld;
755 if (use_lld) {773 if (use_lld) {
...@@ -775,8 +793,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -775,8 +793,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
775 const sub_prog_node = prog_node.start("ELF Flush", 0);793 const sub_prog_node = prog_node.start("ELF Flush", 0);
776 defer sub_prog_node.end();794 defer sub_prog_node.end();
777795
778 const target = self.getTarget();
779 const link_mode = comp.config.link_mode;
780 const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.796 const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
781 const module_obj_path: ?Path = if (self.base.zcu_object_sub_path) |path| .{797 const module_obj_path: ?Path = if (self.base.zcu_object_sub_path) |path| .{
782 .root_dir = directory,798 .root_dir = directory,
...@@ -786,9 +802,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -786,9 +802,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
786 path,802 path,
787 } else null;803 } else null;
788804
789 // --verbose-link
790 if (comp.verbose_link) try self.dumpArgv(comp);
791
792 if (self.zigObjectPtr()) |zig_object| try zig_object.flush(self, tid);805 if (self.zigObjectPtr()) |zig_object| try zig_object.flush(self, tid);
793806
794 switch (comp.config.output_mode) {807 switch (comp.config.output_mode) {
...@@ -800,124 +813,8 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -800,124 +813,8 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
800 .Exe => {},813 .Exe => {},
801 }814 }
802815
803 const csu = try comp.getCrtPaths(arena);
804
805 // csu prelude
806 if (csu.crt0) |path| openParseObjectReportingFailure(self, path);
807 if (csu.crti) |path| openParseObjectReportingFailure(self, path);
808 if (csu.crtbegin) |path| openParseObjectReportingFailure(self, path);
809
810 // objects and archives
811 for (comp.link_inputs) |link_input| switch (link_input) {
812 .object, .archive => parseInputReportingFailure(self, link_input),
813 .dso_exact => @panic("TODO"),
814 .dso => continue, // handled below
815 .res => unreachable,
816 };
817
818 // This is a set of object files emitted by clang in a single `build-exe` invocation.
819 // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up
820 // in this set.
821 for (comp.c_object_table.keys()) |key| {
822 openParseObjectReportingFailure(self, key.status.success.object_path);
823 }
824
825 if (module_obj_path) |path| openParseObjectReportingFailure(self, path);816 if (module_obj_path) |path| openParseObjectReportingFailure(self, path);
826817
827 if (comp.config.any_sanitize_thread)
828 openParseArchiveReportingFailure(self, comp.tsan_lib.?.full_object_path);
829
830 if (comp.config.any_fuzz)
831 openParseArchiveReportingFailure(self, comp.fuzzer_lib.?.full_object_path);
832
833 // libc
834 if (!comp.skip_linker_dependencies and !comp.config.link_libc) {
835 if (comp.libc_static_lib) |lib|
836 openParseArchiveReportingFailure(self, lib.full_object_path);
837 }
838
839 // dynamic libraries
840 for (comp.link_inputs) |link_input| switch (link_input) {
841 .object, .archive, .dso_exact => continue, // handled above
842 .dso => parseInputReportingFailure(self, link_input),
843 .res => unreachable,
844 };
845
846 // libc++ dep
847 if (comp.config.link_libcpp) {
848 openParseArchiveReportingFailure(self, comp.libcxxabi_static_lib.?.full_object_path);
849 openParseArchiveReportingFailure(self, comp.libcxx_static_lib.?.full_object_path);
850 }
851
852 // libunwind dep
853 if (comp.config.link_libunwind) {
854 openParseArchiveReportingFailure(self, comp.libunwind_static_lib.?.full_object_path);
855 }
856
857 // libc dep
858 diags.flags.missing_libc = false;
859 if (comp.config.link_libc) {
860 if (comp.libc_installation) |lc| {
861 const flags = target_util.libcFullLinkFlags(target);
862
863 for (flags) |flag| {
864 assert(mem.startsWith(u8, flag, "-l"));
865 const lib_name = flag["-l".len..];
866 const suffix = switch (comp.config.link_mode) {
867 .static => target.staticLibSuffix(),
868 .dynamic => target.dynamicLibSuffix(),
869 };
870 const lib_path = try std.fmt.allocPrint(arena, "{s}/lib{s}{s}", .{
871 lc.crt_dir.?, lib_name, suffix,
872 });
873 const resolved_path = Path.initCwd(lib_path);
874 switch (comp.config.link_mode) {
875 .static => openParseArchiveReportingFailure(self, resolved_path),
876 .dynamic => openParseDsoReportingFailure(self, resolved_path),
877 }
878 }
879 } else if (target.isGnuLibC()) {
880 for (glibc.libs) |lib| {
881 if (lib.removed_in) |rem_in| {
882 if (target.os.version_range.linux.glibc.order(rem_in) != .lt) continue;
883 }
884
885 const lib_path = Path.initCwd(try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{
886 comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
887 }));
888 openParseDsoReportingFailure(self, lib_path);
889 }
890 const crt_file_path = try comp.get_libc_crt_file(arena, "libc_nonshared.a");
891 openParseArchiveReportingFailure(self, crt_file_path);
892 } else if (target.isMusl()) {
893 const path = try comp.get_libc_crt_file(arena, switch (link_mode) {
894 .static => "libc.a",
895 .dynamic => "libc.so",
896 });
897 switch (link_mode) {
898 .static => openParseArchiveReportingFailure(self, path),
899 .dynamic => openParseDsoReportingFailure(self, path),
900 }
901 } else {
902 diags.flags.missing_libc = true;
903 }
904 }
905
906 // Finally, as the last input objects we add compiler_rt and CSU postlude (if any).
907
908 // compiler-rt. Since compiler_rt exports symbols like `memset`, it needs
909 // to be after the shared libraries, so they are picked up from the shared
910 // libraries, not libcompiler_rt.
911 if (comp.compiler_rt_lib) |crt_file| {
912 openParseArchiveReportingFailure(self, crt_file.full_object_path);
913 } else if (comp.compiler_rt_obj) |crt_file| {
914 openParseObjectReportingFailure(self, crt_file.full_object_path);
915 }
916
917 // csu postlude
918 if (csu.crtend) |path| openParseObjectReportingFailure(self, path);
919 if (csu.crtn) |path| openParseObjectReportingFailure(self, path);
920
921 if (diags.hasErrors()) return error.FlushFailure;818 if (diags.hasErrors()) return error.FlushFailure;
922819
923 // If we haven't already, create a linker-generated input file comprising of820 // If we haven't already, create a linker-generated input file comprising of
...@@ -1087,7 +984,17 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1087,7 +984,17 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1087 }984 }
1088 } else null;985 } else null;
1089986
1090 const csu = try comp.getCrtPaths(arena);987 const crt_basenames = std.zig.LibCInstallation.CrtBasenames.get(.{
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 .{};
1091 const compiler_rt_path: ?[]const u8 = blk: {998 const compiler_rt_path: ?[]const u8 = blk: {
1092 if (comp.compiler_rt_lib) |x| break :blk try x.full_object_path.toString(arena);999 if (comp.compiler_rt_lib) |x| break :blk try x.full_object_path.toString(arena);
1093 if (comp.compiler_rt_obj) |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);
...@@ -1204,10 +1111,9 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1204,10 +1111,9 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1204 try argv.append("-s");1111 try argv.append("-s");
1205 }1112 }
12061113
1207 // csu prelude1114 if (crt_paths.crt0) |path| try argv.append(try path.toString(arena));
1208 if (csu.crt0) |path| try argv.append(try path.toString(arena));1115 if (crt_paths.crti) |path| try argv.append(try path.toString(arena));
1209 if (csu.crti) |path| try argv.append(try path.toString(arena));1116 if (crt_paths.crtbegin) |path| try argv.append(try path.toString(arena));
1210 if (csu.crtbegin) |path| try argv.append(try path.toString(arena));
12111117
1212 if (comp.config.link_libc) {1118 if (comp.config.link_libc) {
1213 if (self.base.comp.libc_installation) |libc_installation| {1119 if (self.base.comp.libc_installation) |libc_installation| {
...@@ -1339,9 +1245,8 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1339,9 +1245,8 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1339 try argv.append(p);1245 try argv.append(p);
1340 }1246 }
13411247
1342 // crt postlude1248 if (crt_paths.crtend) |path| try argv.append(try path.toString(arena));
1343 if (csu.crtend) |path| try argv.append(try path.toString(arena));1249 if (crt_paths.crtn) |path| try argv.append(try path.toString(arena));
1344 if (csu.crtn) |path| try argv.append(try path.toString(arena));
1345 }1250 }
13461251
1347 Compilation.dump_argv(argv.items);1252 Compilation.dump_argv(argv.items);
...@@ -1361,20 +1266,6 @@ pub const ParseError = error{...@@ -1361,20 +1266,6 @@ pub const ParseError = error{
1361 UnknownFileType,1266 UnknownFileType,
1362} || fs.Dir.AccessError || fs.File.SeekError || fs.File.OpenError || fs.File.ReadError;1267} || fs.Dir.AccessError || fs.File.SeekError || fs.File.OpenError || fs.File.ReadError;
13631268
1364pub fn parseInputReportingFailure(self: *Elf, input: link.Input) void {
1365 const gpa = self.base.comp.gpa;
1366 const diags = &self.base.comp.link_diags;
1367 const target = self.getTarget();
1368
1369 switch (input) {
1370 .res => unreachable,
1371 .dso_exact => unreachable,
1372 .object => |obj| parseObjectReportingFailure(self, obj),
1373 .archive => |obj| parseArchiveReportingFailure(self, obj),
1374 .dso => |dso| parseDsoReportingFailure(gpa, diags, dso, &self.shared_objects, &self.files, target),
1375 }
1376}
1377
1378pub fn openParseObjectReportingFailure(self: *Elf, path: Path) void {1269pub fn openParseObjectReportingFailure(self: *Elf, path: Path) void {
1379 const diags = &self.base.comp.link_diags;1270 const diags = &self.base.comp.link_diags;
1380 const obj = link.openObject(path, false, false) catch |err| {1271 const obj = link.openObject(path, false, false) catch |err| {
...@@ -1385,7 +1276,7 @@ pub fn openParseObjectReportingFailure(self: *Elf, path: Path) void {...@@ -1385,7 +1276,7 @@ pub fn openParseObjectReportingFailure(self: *Elf, path: Path) void {
1385 self.parseObjectReportingFailure(obj);1276 self.parseObjectReportingFailure(obj);
1386}1277}
13871278
1388pub fn parseObjectReportingFailure(self: *Elf, obj: link.Input.Object) void {1279fn parseObjectReportingFailure(self: *Elf, obj: link.Input.Object) void {
1389 const diags = &self.base.comp.link_diags;1280 const diags = &self.base.comp.link_diags;
1390 self.parseObject(obj) catch |err| switch (err) {1281 self.parseObject(obj) catch |err| switch (err) {
1391 error.LinkFailure => return, // already reported1282 error.LinkFailure => return, // already reported
...@@ -1423,33 +1314,6 @@ fn parseObject(self: *Elf, obj: link.Input.Object) ParseError!void {...@@ -1423,33 +1314,6 @@ fn parseObject(self: *Elf, obj: link.Input.Object) ParseError!void {
1423 try object.parse(gpa, diags, obj.path, handle, first_eflags, target, debug_fmt_strip, default_sym_version);1314 try object.parse(gpa, diags, obj.path, handle, first_eflags, target, debug_fmt_strip, default_sym_version);
1424}1315}
14251316
1426pub fn openParseArchiveReportingFailure(self: *Elf, path: Path) void {
1427 const diags = &self.base.comp.link_diags;
1428 const obj = link.openObject(path, false, false) catch |err| {
1429 switch (diags.failParse(path, "failed to open archive {}: {s}", .{ path, @errorName(err) })) {
1430 error.LinkFailure => return,
1431 }
1432 };
1433 parseArchiveReportingFailure(self, obj);
1434}
1435
1436pub fn parseArchiveReportingFailure(self: *Elf, obj: link.Input.Object) void {
1437 const gpa = self.base.comp.gpa;
1438 const diags = &self.base.comp.link_diags;
1439 const first_eflags = &self.first_eflags;
1440 const target = self.base.comp.root_mod.resolved_target.result;
1441 const debug_fmt_strip = self.base.comp.config.debug_format == .strip;
1442 const default_sym_version = self.default_sym_version;
1443 const file_handles = &self.file_handles;
1444 const files = &self.files;
1445 const objects = &self.objects;
1446
1447 parseArchive(gpa, diags, file_handles, files, first_eflags, target, debug_fmt_strip, default_sym_version, objects, obj) catch |err| switch (err) {
1448 error.LinkFailure => return, // already reported
1449 else => |e| diags.addParseError(obj.path, "failed to parse archive: {s}", .{@errorName(e)}),
1450 };
1451}
1452
1453fn parseArchive(1317fn parseArchive(
1454 gpa: Allocator,1318 gpa: Allocator,
1455 diags: *Diags,1319 diags: *Diags,
...@@ -1480,38 +1344,6 @@ fn parseArchive(...@@ -1480,38 +1344,6 @@ fn parseArchive(
1480 }1344 }
1481}1345}
14821346
1483fn openParseDsoReportingFailure(self: *Elf, path: Path) void {
1484 const diags = &self.base.comp.link_diags;
1485 const target = self.getTarget();
1486 const dso = link.openDso(path, false, false, false) catch |err| {
1487 switch (diags.failParse(path, "failed to open shared object {}: {s}", .{ path, @errorName(err) })) {
1488 error.LinkFailure => return,
1489 }
1490 };
1491 const gpa = self.base.comp.gpa;
1492 parseDsoReportingFailure(gpa, diags, dso, &self.shared_objects, &self.files, target);
1493}
1494
1495fn parseDsoReportingFailure(
1496 gpa: Allocator,
1497 diags: *Diags,
1498 dso: link.Input.Dso,
1499 shared_objects: *std.StringArrayHashMapUnmanaged(File.Index),
1500 files: *std.MultiArrayList(File.Entry),
1501 target: std.Target,
1502) void {
1503 parseDso(gpa, diags, dso, shared_objects, files, target) catch |err| switch (err) {
1504 error.LinkFailure => return, // already reported
1505 error.BadMagic, error.UnexpectedEndOfFile => {
1506 var notes = diags.addErrorWithNotes(2) catch return diags.setAllocFailure();
1507 notes.addMsg("failed to parse shared object: {s}", .{@errorName(err)}) catch return diags.setAllocFailure();
1508 notes.addNote("while parsing {}", .{dso.path}) catch return diags.setAllocFailure();
1509 notes.addNote("{s}", .{@as([]const u8, "the file may be a GNU ld script, in which case it is not an ELF file but a text file referencing other libraries to link. In this case, avoid depending on the library, convince your system administrators to refrain from using this kind of file, or pass -fallow-so-scripts to force the compiler to check every shared library in case it is an ld script.")}) catch return diags.setAllocFailure();
1510 },
1511 else => |e| diags.addParseError(dso.path, "failed to parse shared object: {s}", .{@errorName(e)}),
1512 };
1513}
1514
1515fn parseDso(1347fn parseDso(
1516 gpa: Allocator,1348 gpa: Allocator,
1517 diags: *Diags,1349 diags: *Diags,
...@@ -1524,7 +1356,6 @@ fn parseDso(...@@ -1524,7 +1356,6 @@ fn parseDso(
1524 defer tracy.end();1356 defer tracy.end();
15251357
1526 const handle = dso.file;1358 const handle = dso.file;
1527 defer handle.close();
15281359
1529 const stat = Stat.fromFs(try handle.stat());1360 const stat = Stat.fromFs(try handle.stat());
1530 var header = try SharedObject.parseHeader(gpa, diags, dso.path, handle, stat, target);1361 var header = try SharedObject.parseHeader(gpa, diags, dso.path, handle, stat, target);
src/link/Elf/relocatable.zig-56
...@@ -2,26 +2,10 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path...@@ -2,26 +2,10 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path
2 const gpa = comp.gpa;2 const gpa = comp.gpa;
3 const diags = &comp.link_diags;3 const diags = &comp.link_diags;
44
5 for (comp.link_inputs) |link_input| switch (link_input) {
6 .object => |obj| parseObjectStaticLibReportingFailure(elf_file, obj.path),
7 .archive => |obj| parseArchiveStaticLibReportingFailure(elf_file, obj.path),
8 .dso_exact => unreachable,
9 .res => unreachable,
10 .dso => unreachable,
11 };
12
13 for (comp.c_object_table.keys()) |key| {
14 parseObjectStaticLibReportingFailure(elf_file, key.status.success.object_path);
15 }
16
17 if (module_obj_path) |path| {5 if (module_obj_path) |path| {
18 parseObjectStaticLibReportingFailure(elf_file, path);6 parseObjectStaticLibReportingFailure(elf_file, path);
19 }7 }
208
21 if (comp.include_compiler_rt) {
22 parseObjectStaticLibReportingFailure(elf_file, comp.compiler_rt_obj.?.full_object_path);
23 }
24
25 if (diags.hasErrors()) return error.FlushFailure;9 if (diags.hasErrors()) return error.FlushFailure;
2610
27 // First, we flush relocatable object file generated with our backends.11 // First, we flush relocatable object file generated with our backends.
...@@ -153,17 +137,6 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path...@@ -153,17 +137,6 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path
153pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) link.File.FlushError!void {137pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) link.File.FlushError!void {
154 const diags = &comp.link_diags;138 const diags = &comp.link_diags;
155139
156 for (comp.link_inputs) |link_input| {
157 elf_file.parseInputReportingFailure(link_input);
158 }
159
160 // This is a set of object files emitted by clang in a single `build-exe` invocation.
161 // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up
162 // in this set.
163 for (comp.c_object_table.keys()) |key| {
164 elf_file.openParseObjectReportingFailure(key.status.success.object_path);
165 }
166
167 if (module_obj_path) |path| elf_file.openParseObjectReportingFailure(path);140 if (module_obj_path) |path| elf_file.openParseObjectReportingFailure(path);
168141
169 if (diags.hasErrors()) return error.FlushFailure;142 if (diags.hasErrors()) return error.FlushFailure;
...@@ -223,14 +196,6 @@ fn parseObjectStaticLibReportingFailure(elf_file: *Elf, path: Path) void {...@@ -223,14 +196,6 @@ fn parseObjectStaticLibReportingFailure(elf_file: *Elf, path: Path) void {
223 };196 };
224}197}
225198
226fn parseArchiveStaticLibReportingFailure(elf_file: *Elf, path: Path) void {
227 const diags = &elf_file.base.comp.link_diags;
228 parseArchiveStaticLib(elf_file, path) catch |err| switch (err) {
229 error.LinkFailure => return,
230 else => |e| diags.addParseError(path, "parsing static library failed: {s}", .{@errorName(e)}),
231 };
232}
233
234fn parseObjectStaticLib(elf_file: *Elf, path: Path) Elf.ParseError!void {199fn parseObjectStaticLib(elf_file: *Elf, path: Path) Elf.ParseError!void {
235 const gpa = elf_file.base.comp.gpa;200 const gpa = elf_file.base.comp.gpa;
236 const file_handles = &elf_file.file_handles;201 const file_handles = &elf_file.file_handles;
...@@ -253,27 +218,6 @@ fn parseObjectStaticLib(elf_file: *Elf, path: Path) Elf.ParseError!void {...@@ -253,27 +218,6 @@ fn parseObjectStaticLib(elf_file: *Elf, path: Path) Elf.ParseError!void {
253 try object.parseAr(path, elf_file);218 try object.parseAr(path, elf_file);
254}219}
255220
256fn parseArchiveStaticLib(elf_file: *Elf, path: Path) Elf.ParseError!void {
257 const gpa = elf_file.base.comp.gpa;
258 const diags = &elf_file.base.comp.link_diags;
259 const file_handles = &elf_file.file_handles;
260
261 const handle = try path.root_dir.handle.openFile(path.sub_path, .{});
262 const fh = try Elf.addFileHandle(gpa, file_handles, handle);
263
264 var archive = try Archive.parse(gpa, diags, file_handles, path, fh);
265 defer archive.deinit(gpa);
266
267 for (archive.objects) |extracted| {
268 const index: File.Index = @intCast(try elf_file.files.addOne(gpa));
269 elf_file.files.set(index, .{ .object = extracted });
270 const object = &elf_file.files.items(.data)[index].object;
271 object.index = index;
272 try object.parseAr(path, elf_file);
273 try elf_file.objects.append(gpa, index);
274 }
275}
276
277fn claimUnresolved(elf_file: *Elf) void {221fn claimUnresolved(elf_file: *Elf) void {
278 if (elf_file.zigObjectPtr()) |zig_object| {222 if (elf_file.zigObjectPtr()) |zig_object| {
279 zig_object.claimUnresolvedRelocatable(elf_file);223 zig_object.claimUnresolvedRelocatable(elf_file);
src/musl.zig+12-6
...@@ -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, in_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 }
...@@ -28,7 +28,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre...@@ -28,7 +28,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
28 defer arena_allocator.deinit();28 defer arena_allocator.deinit();
29 const arena = arena_allocator.allocator();29 const arena = arena_allocator.allocator();
3030
31 switch (crt_file) {31 switch (in_crt_file) {
32 .crti_o => {32 .crti_o => {
33 var args = std.ArrayList([]const u8).init(arena);33 var args = std.ArrayList([]const u8).init(arena);
34 try addCcArgs(comp, arena, &args, false);34 try addCcArgs(comp, arena, &args, false);
...@@ -195,8 +195,9 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre...@@ -195,8 +195,9 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
195 .libc_so => {195 .libc_so => {
196 const optimize_mode = comp.compilerRtOptMode();196 const optimize_mode = comp.compilerRtOptMode();
197 const strip = comp.compilerRtStrip();197 const strip = comp.compilerRtStrip();
198 const output_mode: std.builtin.OutputMode = .Lib;
198 const config = try Compilation.Config.resolve(.{199 const config = try Compilation.Config.resolve(.{
199 .output_mode = .Lib,200 .output_mode = output_mode,
200 .link_mode = .dynamic,201 .link_mode = .dynamic,
201 .resolved_target = comp.root_mod.resolved_target,202 .resolved_target = comp.root_mod.resolved_target,
202 .is_test = false,203 .is_test = false,
...@@ -276,12 +277,17 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre...@@ -276,12 +277,17 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
276277
277 try comp.updateSubCompilation(sub_compilation, .@"musl libc.so", prog_node);278 try comp.updateSubCompilation(sub_compilation, .@"musl libc.so", prog_node);
278279
279 try comp.crt_files.ensureUnusedCapacity(comp.gpa, 1);
280
281 const basename = try comp.gpa.dupe(u8, "libc.so");280 const basename = try comp.gpa.dupe(u8, "libc.so");
282 errdefer comp.gpa.free(basename);281 errdefer comp.gpa.free(basename);
283282
284 comp.crt_files.putAssumeCapacityNoClobber(basename, try sub_compilation.toCrtFile());283 const crt_file = try sub_compilation.toCrtFile();
284 comp.enqueueLinkTaskMode(crt_file.full_object_path, output_mode);
285 {
286 comp.mutex.lock();
287 defer comp.mutex.unlock();
288 try comp.crt_files.ensureUnusedCapacity(comp.gpa, 1);
289 comp.crt_files.putAssumeCapacityNoClobber(basename, crt_file);
290 }
285 },291 },
286 }292 }
287}293}
src/target.zig+12-33
...@@ -1,4 +1,6 @@...@@ -1,4 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const assert = std.debug.assert;
3
2const Type = @import("Type.zig");4const Type = @import("Type.zig");
3const AddressSpace = std.builtin.AddressSpace;5const AddressSpace = std.builtin.AddressSpace;
4const Alignment = @import("InternPool.zig").Alignment;6const Alignment = @import("InternPool.zig").Alignment;
...@@ -284,40 +286,17 @@ pub fn hasRedZone(target: std.Target) bool {...@@ -284,40 +286,17 @@ pub fn hasRedZone(target: std.Target) bool {
284pub fn libcFullLinkFlags(target: std.Target) []const []const u8 {286pub fn libcFullLinkFlags(target: std.Target) []const []const u8 {
285 // The linking order of these is significant and should match the order other287 // The linking order of these is significant and should match the order other
286 // c compilers such as gcc or clang use.288 // c compilers such as gcc or clang use.
287 return switch (target.os.tag) {289 const result: []const []const u8 = switch (target.os.tag) {
288 .netbsd, .openbsd => &[_][]const u8{290 .netbsd, .openbsd => &.{ "-lm", "-lpthread", "-lc", "-lutil" },
289 "-lm",291 // Solaris releases after 10 merged the threading libraries into libc.
290 "-lpthread",292 .solaris, .illumos => &.{ "-lm", "-lsocket", "-lnsl", "-lc" },
291 "-lc",293 .haiku => &.{ "-lm", "-lroot", "-lpthread", "-lc", "-lnetwork" },
292 "-lutil",294 else => if (target.isAndroid() or target.abi.isOpenHarmony())
293 },295 &.{ "-lm", "-lc", "-ldl" }
294 .solaris, .illumos => &[_][]const u8{296 else
295 "-lm",297 &.{ "-lm", "-lpthread", "-lc", "-ldl", "-lrt", "-lutil" },
296 "-lsocket",
297 "-lnsl",
298 // Solaris releases after 10 merged the threading libraries into libc.
299 "-lc",
300 },
301 .haiku => &[_][]const u8{
302 "-lm",
303 "-lroot",
304 "-lpthread",
305 "-lc",
306 "-lnetwork",
307 },
308 else => if (target.isAndroid() or target.abi.isOpenHarmony()) &[_][]const u8{
309 "-lm",
310 "-lc",
311 "-ldl",
312 } else &[_][]const u8{
313 "-lm",
314 "-lpthread",
315 "-lc",
316 "-ldl",
317 "-lrt",
318 "-lutil",
319 },
320 };298 };
299 return result;
321}300}
322301
323pub fn clangMightShellOutForAssembly(target: std.Target) bool {302pub fn clangMightShellOutForAssembly(target: std.Target) bool {