| author | |
| committer | |
| log | 5ca54036ca0bc292ead681c03c8ac57e27a127db |
| tree | 17b151d68b2cb40c49d82af85286074be929db7d |
| parent | 2dcfa723767d284cef5eb180be7c080583ddbe25 |
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.zig | 522 | src/Sema.zig |
| 523 | src/Sema/bitcast.zig | 523 | src/Sema/bitcast.zig |
| 524 | src/Sema/comptime_ptr_access.zig | 524 | src/Sema/comptime_ptr_access.zig |
| 525 | src/ThreadSafeQueue.zig | ||
| 525 | src/Type.zig | 526 | src/Type.zig |
| 526 | src/Value.zig | 527 | src/Value.zig |
| 527 | src/Zcu.zig | 528 | src/Zcu.zig |
src/Compilation.zig+174-124| ... | @@ -10,6 +10,7 @@ const Target = std.Target; | ... | @@ -10,6 +10,7 @@ const Target = std.Target; |
| 10 | const ThreadPool = std.Thread.Pool; | 10 | const ThreadPool = std.Thread.Pool; |
| 11 | const WaitGroup = std.Thread.WaitGroup; | 11 | const WaitGroup = std.Thread.WaitGroup; |
| 12 | const ErrorBundle = std.zig.ErrorBundle; | 12 | const ErrorBundle = std.zig.ErrorBundle; |
| 13 | const Path = Cache.Path; | ||
| 13 | 14 | ||
| 14 | const Value = @import("Value.zig"); | 15 | const Value = @import("Value.zig"); |
| 15 | const Type = @import("Type.zig"); | 16 | const Type = @import("Type.zig"); |
| ... | @@ -39,9 +40,9 @@ const Air = @import("Air.zig"); | ... | @@ -39,9 +40,9 @@ const Air = @import("Air.zig"); |
| 39 | const Builtin = @import("Builtin.zig"); | 40 | const Builtin = @import("Builtin.zig"); |
| 40 | const LlvmObject = @import("codegen/llvm.zig").Object; | 41 | const LlvmObject = @import("codegen/llvm.zig").Object; |
| 41 | const dev = @import("dev.zig"); | 42 | const dev = @import("dev.zig"); |
| 42 | pub const Directory = Cache.Directory; | 43 | const ThreadSafeQueue = @import("ThreadSafeQueue.zig").ThreadSafeQueue; |
| 43 | const Path = Cache.Path; | ||
| 44 | 44 | ||
| 45 | pub const Directory = Cache.Directory; | ||
| 45 | pub const Config = @import("Compilation/Config.zig"); | 46 | pub const Config = @import("Compilation/Config.zig"); |
| 46 | 47 | ||
| 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 | } = .{}, |
| 109 | 110 | ||
| 110 | link_diags: link.Diags, | 111 | link_diags: link.Diags, |
| 112 | link_task_queue: ThreadSafeQueue(link.File.Task) = .empty, | ||
| 111 | 113 | ||
| 112 | work_queues: [ | 114 | work_queues: [ |
| 113 | len: { | 115 | len: { |
| ... | @@ -263,6 +265,9 @@ emit_asm: ?EmitLoc, | ... | @@ -263,6 +265,9 @@ emit_asm: ?EmitLoc, |
| 263 | emit_llvm_ir: ?EmitLoc, | 265 | emit_llvm_ir: ?EmitLoc, |
| 264 | emit_llvm_bc: ?EmitLoc, | 266 | emit_llvm_bc: ?EmitLoc, |
| 265 | 267 | ||
| 268 | work_queue_wait_group: WaitGroup = .{}, | ||
| 269 | work_queue_progress_node: std.Progress.Node = .none, | ||
| 270 | |||
| 266 | llvm_opt_bisect_limit: c_int, | 271 | llvm_opt_bisect_limit: c_int, |
| 267 | 272 | ||
| 268 | file_system_inputs: ?*std.ArrayListUnmanaged(u8), | 273 | file_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 objects | 377 | /// 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 libc | 380 | /// 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; | ||
| 1774 | 1817 | ||
| 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; | ||
| 1789 | 1835 | ||
| 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 | } | ||
| 1806 | 1849 | ||
| 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; | ||
| 1809 | 1861 | ||
| 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 | } |
| 1820 | 1875 | ||
| 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 | } |
| 1889 | 1933 | ||
| 1890 | return comp; | 1934 | return comp; |
| 1891 | } | 1935 | } |
| 1892 | 1936 | ||
| 1893 | pub fn destroy(comp: *Compilation) void { | 1937 | pub 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(); |
| 1903 | 1949 | ||
| 1904 | const gpa = comp.gpa; | ||
| 1905 | comp.windows_libs.deinit(gpa); | 1950 | comp.windows_libs.deinit(gpa); |
| 1906 | 1951 | ||
| 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 compilation | 3515 | // (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. |
| 3469 | 3517 | ||
| 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(); |
| 3472 | 3522 | ||
| 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 | } |
| 3478 | 3534 | ||
| ... | @@ -3538,21 +3594,32 @@ fn performAllTheWorkInner( | ... | @@ -3538,21 +3594,32 @@ fn performAllTheWorkInner( |
| 3538 | } | 3594 | } |
| 3539 | 3595 | ||
| 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 | } |
| 3545 | 3601 | ||
| 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 | } |
| 3552 | 3608 | ||
| 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 | } | ||
| 3556 | 3623 | ||
| 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( |
| 3570 | 3637 | ||
| 3571 | if (!InternPool.single_threaded) { | 3638 | if (!InternPool.single_threaded) { |
| 3572 | comp.codegen_work.done = false; // may be `true` from a prior update | 3639 | 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 update | 4962 | // 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 | } |
| 4926 | 4970 | ||
| ... | @@ -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 | } |
| 4939 | 4985 | ||
| 4940 | fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32_resource_prog_node: std.Progress.Node) !void { | 4986 | fn 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 | } |
| 6060 | 6106 | ||
| 6061 | fn 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 | |||
| 6072 | fn wantBuildGLibCFromSource(comp: Compilation) bool { | ||
| 6073 | return comp.wantBuildLibCFromSource() and comp.getTarget().isGnuLibC(); | ||
| 6074 | } | ||
| 6075 | |||
| 6076 | fn wantBuildMuslFromSource(comp: Compilation) bool { | ||
| 6077 | return comp.wantBuildLibCFromSource() and comp.getTarget().isMusl() and | ||
| 6078 | !comp.getTarget().isWasm(); | ||
| 6079 | } | ||
| 6080 | |||
| 6081 | fn wantBuildWasiLibcFromSource(comp: Compilation) bool { | ||
| 6082 | return comp.wantBuildLibCFromSource() and comp.getTarget().isWasm() and | ||
| 6083 | comp.getTarget().os.tag == .wasi; | ||
| 6084 | } | ||
| 6085 | |||
| 6086 | fn wantBuildMinGWFromSource(comp: Compilation) bool { | ||
| 6087 | return comp.wantBuildLibCFromSource() and comp.getTarget().isMinGW(); | ||
| 6088 | } | ||
| 6089 | |||
| 6090 | fn wantBuildLibUnwindFromSource(comp: *Compilation) bool { | 6107 | fn 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( |
| 6334 | 6351 | ||
| 6335 | try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node); | 6352 | try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node); |
| 6336 | 6353 | ||
| 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 | } |
| 6341 | 6360 | ||
| 6342 | pub fn build_crt_file( | 6361 | pub fn build_crt_file( |
| ... | @@ -6443,8 +6462,39 @@ pub fn build_crt_file( | ... | @@ -6443,8 +6462,39 @@ pub fn build_crt_file( |
| 6443 | 6462 | ||
| 6444 | try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node); | 6463 | try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node); |
| 6445 | 6464 | ||
| 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 | |||
| 6476 | pub 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. | ||
| 6486 | fn 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 | } |
| 6449 | 6499 | ||
| 6450 | pub fn toCrtFile(comp: *Compilation) Allocator.Error!CrtFile { | 6500 | pub fn toCrtFile(comp: *Compilation) Allocator.Error!CrtFile { |
src/ThreadSafeQueue.zig created+63| ... | @@ -0,0 +1,63 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | const Allocator = std.mem.Allocator; | ||
| 4 | |||
| 5 | pub 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 | }; |
| 1205 | 1205 | ||
| 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 | } |
| 1212 | 1212 | ||
| 1213 | // zig fmt: on | ||
| 1214 | |||
| 1215 | fn buildSharedLib( | 1213 | fn 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 | }; |
| 356 | 356 | ||
| 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 | } |
| 360 | 362 | ||
| 361 | pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void { | 363 | pub 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 | }; |
| 585 | 587 | ||
| 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 | } |
| 589 | 593 | ||
| 590 | pub fn hardeningModeFlag(optimize_mode: std.builtin.OptimizeMode) []const u8 { | 594 | pub 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 | }; |
| 344 | 344 | ||
| 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 | } |
| 348 | 350 | ||
| 349 | const tsan_sources = [_][]const u8{ | 351 | const 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 | }; |
| 201 | 201 | ||
| 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 | } |
| 205 | 207 | ||
| 206 | const unwind_src_list = [_][]const u8{ | 208 | const 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; |
| 24 | const lldMain = @import("main.zig").lldMain; | 24 | const lldMain = @import("main.zig").lldMain; |
| 25 | const Package = @import("Package.zig"); | 25 | const Package = @import("Package.zig"); |
| 26 | const dev = @import("dev.zig"); | 26 | const dev = @import("dev.zig"); |
| 27 | const ThreadSafeQueue = @import("ThreadSafeQueue.zig").ThreadSafeQueue; | ||
| 27 | 28 | ||
| 28 | pub const LdScript = @import("link/LdScript.zig"); | 29 | pub const LdScript = @import("link/LdScript.zig"); |
| 29 | 30 | ||
| ... | @@ -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, |
| 370 | 371 | ||
| 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 | } |
| 997 | 1001 | ||
| 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); |
| 1000 | 1084 | ||
| ... | @@ -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 | }; |
| 1265 | 1454 | ||
| 1266 | pub fn spawnLld( | 1455 | pub 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 | }; |
| 1484 | 1681 | ||
| 1485 | pub fn hashInputs(man: *Cache.Manifest, link_inputs: []const Input) !void { | 1682 | pub 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, |
| 35 | llvm_object: ?LlvmObject.Ptr = null, | 35 | llvm_object: ?LlvmObject.Ptr = null, |
| 36 | 36 | ||
| 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 file | 38 | /// First index is a special "null file". Order is otherwise not observed. |
| 39 | /// over another. | ||
| 40 | files: std.MultiArrayList(File.Entry) = .{}, | 39 | files: 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-use | 41 | /// 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 | } |
| 352 | 351 | ||
| 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); |
| 355 | 357 | ||
| ... | @@ -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 | } |
| 752 | 754 | ||
| 755 | pub 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 | |||
| 753 | pub fn flush(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { | 771 | pub 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(); |
| 777 | 795 | ||
| 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; |
| 788 | 804 | ||
| 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); |
| 793 | 806 | ||
| 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 | } |
| 802 | 815 | ||
| 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); |
| 826 | 817 | ||
| 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; |
| 922 | 819 | ||
| 923 | // If we haven't already, create a linker-generated input file comprising of | 820 | // 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; |
| 1089 | 986 | ||
| 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 | } |
| 1206 | 1113 | ||
| 1207 | // csu prelude | 1114 | 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)); | ||
| 1211 | 1117 | ||
| 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 | } |
| 1341 | 1247 | ||
| 1342 | // crt postlude | 1248 | 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 | } |
| 1346 | 1251 | ||
| 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; |
| 1363 | 1268 | ||
| 1364 | pub 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 | |||
| 1378 | pub fn openParseObjectReportingFailure(self: *Elf, path: Path) void { | 1269 | pub 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 | } |
| 1387 | 1278 | ||
| 1388 | pub fn parseObjectReportingFailure(self: *Elf, obj: link.Input.Object) void { | 1279 | fn 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 reported | 1282 | 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 | } |
| 1425 | 1316 | ||
| 1426 | pub 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 | |||
| 1436 | pub 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 | |||
| 1453 | fn parseArchive( | 1317 | fn 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 | } |
| 1482 | 1346 | ||
| 1483 | fn 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 | |||
| 1495 | fn 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 | |||
| 1515 | fn parseDso( | 1347 | fn 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(); |
| 1525 | 1357 | ||
| 1526 | const handle = dso.file; | 1358 | const handle = dso.file; |
| 1527 | defer handle.close(); | ||
| 1528 | 1359 | ||
| 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; |
| 4 | 4 | ||
| 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 | } |
| 20 | 8 | ||
| 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; |
| 26 | 10 | ||
| 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 |
| 153 | pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) link.File.FlushError!void { | 137 | pub 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; |
| 155 | 139 | ||
| 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); |
| 168 | 141 | ||
| 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 | } |
| 225 | 198 | ||
| 226 | fn 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 | |||
| 234 | fn parseObjectStaticLib(elf_file: *Elf, path: Path) Elf.ParseError!void { | 199 | fn 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 | } |
| 255 | 220 | ||
| 256 | fn 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 | |||
| 277 | fn claimUnresolved(elf_file: *Elf) void { | 221 | fn 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 | }; |
| 21 | 21 | ||
| 22 | pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progress.Node) !void { | 22 | pub 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(); |
| 30 | 30 | ||
| 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 |
| 276 | 277 | ||
| 277 | try comp.updateSubCompilation(sub_compilation, .@"musl libc.so", prog_node); | 278 | try comp.updateSubCompilation(sub_compilation, .@"musl libc.so", prog_node); |
| 278 | 279 | ||
| 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); |
| 283 | 282 | ||
| 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 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const assert = std.debug.assert; | ||
| 3 | |||
| 2 | const Type = @import("Type.zig"); | 4 | const Type = @import("Type.zig"); |
| 3 | const AddressSpace = std.builtin.AddressSpace; | 5 | const AddressSpace = std.builtin.AddressSpace; |
| 4 | const Alignment = @import("InternPool.zig").Alignment; | 6 | const 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 { |
| 284 | pub fn libcFullLinkFlags(target: std.Target) []const []const u8 { | 286 | pub fn libcFullLinkFlags(target: std.Target) []const []const u8 { |
| 285 | // The linking order of these is significant and should match the order other | 287 | // 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 | } |
| 322 | 301 | ||
| 323 | pub fn clangMightShellOutForAssembly(target: std.Target) bool { | 302 | pub fn clangMightShellOutForAssembly(target: std.Target) bool { |