diff --git a/src/Compilation.zig b/src/Compilation.zig index a4d464068e..066dfc3220 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1780,32 +1780,14 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil const paths = try lci.resolveCrtPaths(arena, basenames, target); const fields = @typeInfo(@TypeOf(paths)).@"struct".fields; - try comp.link_task_queue.shared.ensureUnusedCapacity(gpa, fields.len); + try comp.link_task_queue.shared.ensureUnusedCapacity(gpa, fields.len + 1); inline for (fields) |field| { if (@field(paths, field.name)) |path| { comp.link_task_queue.shared.appendAssumeCapacity(.{ .load_object = path }); } } - - const flags = target_util.libcFullLinkFlags(target); - try comp.link_task_queue.shared.ensureUnusedCapacity(gpa, flags.len); - for (flags) |flag| { - assert(mem.startsWith(u8, flag, "-l")); - const lib_name = flag["-l".len..]; - const suffix = switch (comp.config.link_mode) { - .static => target.staticLibSuffix(), - .dynamic => target.dynamicLibSuffix(), - }; - const sep = std.fs.path.sep_str; - const lib_path = try std.fmt.allocPrint(arena, "{s}" ++ sep ++ "lib{s}{s}", .{ - lci.crt_dir.?, lib_name, suffix, - }); - const resolved_path = Path.initCwd(lib_path); - comp.link_task_queue.shared.appendAssumeCapacity(switch (comp.config.link_mode) { - .static => .{ .load_archive = resolved_path }, - .dynamic => .{ .load_dso = resolved_path }, - }); - } + // Loads the libraries provided by `target_util.libcFullLinkFlags(target)`. + comp.link_task_queue.shared.appendAssumeCapacity(.load_host_libc); } else if (target.isMusl() and !target.isWasm()) { if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable; diff --git a/src/link.zig b/src/link.zig index b6a8cdebaf..a935458f56 100644 --- a/src/link.zig +++ b/src/link.zig @@ -25,6 +25,7 @@ const lldMain = @import("main.zig").lldMain; const Package = @import("Package.zig"); const dev = @import("dev.zig"); const ThreadSafeQueue = @import("ThreadSafeQueue.zig").ThreadSafeQueue; +const target_util = @import("target.zig"); pub const LdScript = @import("link/LdScript.zig"); @@ -1364,6 +1365,10 @@ pub const File = struct { /// Loads the objects, shared objects, and archives that are already /// known from the command line. load_explicitly_provided, + /// Loads the shared objects and archives by resolving + /// `target_util.libcFullLinkFlags()` against the host libc + /// installation. + load_host_libc, /// Tells the linker to load an object file by path. load_object: Path, /// Tells the linker to load a static library by path. @@ -1393,6 +1398,45 @@ pub const File = struct { }; } }, + .load_host_libc => { + const target = comp.root_mod.resolved_target.result; + const flags = target_util.libcFullLinkFlags(target); + const crt_dir = comp.libc_installation.?.crt_dir.?; + const sep = std.fs.path.sep_str; + const diags = &comp.link_diags; + for (flags) |flag| { + assert(mem.startsWith(u8, flag, "-l")); + const lib_name = flag["-l".len..]; + switch (comp.config.link_mode) { + .dynamic => d: { + const path = Path.initCwd( + std.fmt.allocPrint(comp.arena, "{s}" ++ sep ++ "{s}{s}{s}", .{ + crt_dir, target.libPrefix(), lib_name, target.dynamicLibSuffix(), + }) catch return diags.setAllocFailure(), + ); + base.openLoadDso(path, .{ + .preferred_mode = .dynamic, + .search_strategy = .paths_first, + }) catch |err| switch (err) { + error.FileNotFound => break :d, // also try static + error.LinkFailure => return, // error reported via diags + else => |e| diags.addParseError(path, "failed to parse shared library: {s}", .{@errorName(e)}), + }; + continue; + }, + .static => {}, + } + const path = Path.initCwd( + std.fmt.allocPrint(comp.arena, "{s}" ++ sep ++ "{s}{s}{s}", .{ + crt_dir, target.libPrefix(), lib_name, target.staticLibSuffix(), + }) catch return diags.setAllocFailure(), + ); + base.openLoadArchive(path) catch |err| switch (err) { + error.LinkFailure => return, // error reported via diags + else => |e| diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(e)}), + }; + } + }, .load_object => |path| { base.openLoadObject(path) catch |err| switch (err) { error.LinkFailure => return, // error reported via link_diags @@ -1873,7 +1917,7 @@ pub fn resolveInputs( } } -const AccessLibPathResult = enum { ok, no_match }; +const ResolveLibInputResult = enum { ok, no_match }; const fatal = std.process.fatal; fn resolveLibInput( @@ -1892,7 +1936,7 @@ fn resolveLibInput( target: std.Target, link_mode: std.builtin.LinkMode, color: std.zig.Color, -) Allocator.Error!AccessLibPathResult { +) Allocator.Error!ResolveLibInputResult { try resolved_inputs.ensureUnusedCapacity(gpa, 1); const lib_name = name_query.name; @@ -1909,7 +1953,7 @@ fn resolveLibInput( else => |e| fatal("unable to search for tbd library '{}': {s}", .{ test_path, @errorName(e) }), }; errdefer file.close(); - return finishAccessLibPath(resolved_inputs, test_path, file, link_mode, name_query.query); + return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query); } { @@ -1947,7 +1991,7 @@ fn resolveLibInput( }), }; errdefer file.close(); - return finishAccessLibPath(resolved_inputs, test_path, file, link_mode, name_query.query); + return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query); } // In the case of MinGW, the main check will be .lib but we also need to @@ -1963,19 +2007,19 @@ fn resolveLibInput( else => |e| fatal("unable to search for static library '{}': {s}", .{ test_path, @errorName(e) }), }; errdefer file.close(); - return finishAccessLibPath(resolved_inputs, test_path, file, link_mode, name_query.query); + return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query); } return .no_match; } -fn finishAccessLibPath( +fn finishResolveLibInput( resolved_inputs: *std.ArrayListUnmanaged(Input), path: Path, file: std.fs.File, link_mode: std.builtin.LinkMode, query: UnresolvedInput.Query, -) AccessLibPathResult { +) ResolveLibInputResult { switch (link_mode) { .static => resolved_inputs.appendAssumeCapacity(.{ .archive = .{ .path = path, @@ -2052,7 +2096,7 @@ fn resolvePathInputLib( pq: UnresolvedInput.PathQuery, link_mode: std.builtin.LinkMode, color: std.zig.Color, -) Allocator.Error!AccessLibPathResult { +) Allocator.Error!ResolveLibInputResult { try resolved_inputs.ensureUnusedCapacity(gpa, 1); const test_path: Path = pq.path; @@ -2074,7 +2118,7 @@ fn resolvePathInputLib( if (n != ld_script_bytes.items.len) break :elf_file; if (!mem.eql(u8, ld_script_bytes.items[0..4], "\x7fELF")) break :elf_file; // Appears to be an ELF file. - return finishAccessLibPath(resolved_inputs, test_path, file, link_mode, pq.query); + return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query); } const stat = file.stat() catch |err| fatal("failed to stat {}: {s}", .{ test_path, @errorName(err) }); @@ -2140,7 +2184,7 @@ fn resolvePathInputLib( }), }; errdefer file.close(); - return finishAccessLibPath(resolved_inputs, test_path, file, link_mode, pq.query); + return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query); } pub fn openObject(path: Path, must_link: bool, hidden: bool) !Input.Object { diff --git a/src/target.zig b/src/target.zig index 8e0b90cd82..ec34a23f0d 100644 --- a/src/target.zig +++ b/src/target.zig @@ -291,10 +291,11 @@ pub fn libcFullLinkFlags(target: std.Target) []const []const u8 { // Solaris releases after 10 merged the threading libraries into libc. .solaris, .illumos => &.{ "-lm", "-lsocket", "-lnsl", "-lc" }, .haiku => &.{ "-lm", "-lroot", "-lpthread", "-lc", "-lnetwork" }, - else => if (target.isAndroid() or target.abi.isOpenHarmony()) - &.{ "-lm", "-lc", "-ldl" } - else - &.{ "-lm", "-lpthread", "-lc", "-ldl", "-lrt", "-lutil" }, + .linux => switch (target.abi) { + .android, .androideabi, .ohos, .ohoseabi => &.{ "-lm", "-lc", "-ldl" }, + else => &.{ "-lm", "-lpthread", "-lc", "-ldl", "-lrt", "-lutil" }, + }, + else => &.{}, }; return result; }