Skip to content

Commit 31be45e

Browse files
committed
link: make zig cc pass -l/-L like Clang/GCC for ELF
1 parent 99261d9 commit 31be45e

File tree

2 files changed

+38
-16
lines changed

2 files changed

+38
-16
lines changed

src/link.zig

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1818,6 +1818,8 @@ pub const Input = union(enum) {
18181818
needed: bool,
18191819
weak: bool,
18201820
reexport: bool,
1821+
name: ?[]const u8,
1822+
lib_directory: Directory,
18211823
};
18221824

18231825
pub const DsoExact = struct {
@@ -1870,6 +1872,8 @@ pub fn hashInputs(man: *Cache.Manifest, link_inputs: []const Input) !void {
18701872
man.hash.add(dso.needed);
18711873
man.hash.add(dso.weak);
18721874
man.hash.add(dso.reexport);
1875+
man.hash.addOptionalBytes(dso.name);
1876+
man.hash.addOptionalBytes(dso.lib_directory.path);
18731877
},
18741878
.dso_exact => |dso_exact| {
18751879
man.hash.addBytes(dso_exact.name);
@@ -2145,7 +2149,7 @@ fn resolveLibInput(
21452149
else => |e| fatal("unable to search for tbd library '{}': {s}", .{ test_path, @errorName(e) }),
21462150
};
21472151
errdefer file.close();
2148-
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);
2152+
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query, name_query.name, lib_directory);
21492153
}
21502154

21512155
{
@@ -2159,10 +2163,10 @@ fn resolveLibInput(
21592163
}),
21602164
};
21612165
try checked_paths.writer(gpa).print("\n {}", .{test_path});
2162-
switch (try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, .{
2166+
switch (try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, lib_directory, target, .{
21632167
.path = test_path,
21642168
.query = name_query.query,
2165-
}, link_mode, color)) {
2169+
}, link_mode, color, name_query.name)) {
21662170
.no_match => {},
21672171
.ok => return .ok,
21682172
}
@@ -2183,7 +2187,7 @@ fn resolveLibInput(
21832187
}),
21842188
};
21852189
errdefer file.close();
2186-
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);
2190+
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query, name_query.name, lib_directory);
21872191
}
21882192

21892193
// In the case of MinGW, the main check will be .lib but we also need to
@@ -2199,7 +2203,7 @@ fn resolveLibInput(
21992203
else => |e| fatal("unable to search for static library '{}': {s}", .{ test_path, @errorName(e) }),
22002204
};
22012205
errdefer file.close();
2202-
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);
2206+
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query, name_query.name, lib_directory);
22032207
}
22042208

22052209
return .no_match;
@@ -2211,6 +2215,8 @@ fn finishResolveLibInput(
22112215
file: std.fs.File,
22122216
link_mode: std.builtin.LinkMode,
22132217
query: UnresolvedInput.Query,
2218+
name: ?[]const u8,
2219+
lib_directory: Directory,
22142220
) ResolveLibInputResult {
22152221
switch (link_mode) {
22162222
.static => resolved_inputs.appendAssumeCapacity(.{ .archive = .{
@@ -2225,6 +2231,8 @@ fn finishResolveLibInput(
22252231
.needed = query.needed,
22262232
.weak = query.weak,
22272233
.reexport = query.reexport,
2234+
.name = name,
2235+
.lib_directory = lib_directory,
22282236
} }),
22292237
}
22302238
return .ok;
@@ -2244,8 +2252,8 @@ fn resolvePathInput(
22442252
color: std.zig.Color,
22452253
) Allocator.Error!?ResolveLibInputResult {
22462254
switch (Compilation.classifyFileExt(pq.path.sub_path)) {
2247-
.static_library => return try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, pq, .static, color),
2248-
.shared_library => return try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, pq, .dynamic, color),
2255+
.static_library => return try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, Directory.cwd(), target, pq, .static, color, null),
2256+
.shared_library => return try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, Directory.cwd(), target, pq, .dynamic, color, null),
22492257
.object => {
22502258
var file = pq.path.root_dir.handle.openFile(pq.path.sub_path, .{}) catch |err|
22512259
fatal("failed to open object {}: {s}", .{ pq.path, @errorName(err) });
@@ -2281,10 +2289,12 @@ fn resolvePathInputLib(
22812289
resolved_inputs: *std.ArrayListUnmanaged(Input),
22822290
/// Allocated via `gpa`.
22832291
ld_script_bytes: *std.ArrayListUnmanaged(u8),
2292+
lib_directory: Directory,
22842293
target: std.Target,
22852294
pq: UnresolvedInput.PathQuery,
22862295
link_mode: std.builtin.LinkMode,
22872296
color: std.zig.Color,
2297+
name: ?[]const u8,
22882298
) Allocator.Error!ResolveLibInputResult {
22892299
try resolved_inputs.ensureUnusedCapacity(gpa, 1);
22902300

@@ -2309,7 +2319,7 @@ fn resolvePathInputLib(
23092319
if (n != ld_script_bytes.items.len) break :elf_file;
23102320
if (!mem.eql(u8, ld_script_bytes.items[0..4], "\x7fELF")) break :elf_file;
23112321
// Appears to be an ELF file.
2312-
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query);
2322+
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query, name, lib_directory);
23132323
}
23142324
const stat = file.stat() catch |err|
23152325
fatal("failed to stat {}: {s}", .{ test_path, @errorName(err) });
@@ -2375,7 +2385,7 @@ fn resolvePathInputLib(
23752385
}),
23762386
};
23772387
errdefer file.close();
2378-
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query);
2388+
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query, name, lib_directory);
23792389
}
23802390

23812391
pub fn openObject(path: Path, must_link: bool, hidden: bool) !Input.Object {
@@ -2398,6 +2408,8 @@ pub fn openDso(path: Path, needed: bool, weak: bool, reexport: bool) !Input.Dso
23982408
.needed = needed,
23992409
.weak = weak,
24002410
.reexport = reexport,
2411+
.name = null,
2412+
.lib_directory = Directory.cwd(),
24012413
};
24022414
}
24032415

src/link/Elf.zig

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1980,9 +1980,12 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
19801980

19811981
// Shared libraries.
19821982
if (is_exe_or_dyn_lib) {
1983-
// Worst-case, we need an --as-needed argument for every lib, as well
1984-
// as one before and one after.
1985-
try argv.ensureUnusedCapacity(2 * self.base.comp.link_inputs.len + 2);
1983+
// Worst-case, we need:
1984+
// * an --as-needed/--no-as-needed argument for every lib
1985+
// * -L, lib directory, -l/-weak-l, library name for every lib
1986+
// * one --as-needed before and one --as-needed after
1987+
try argv.ensureUnusedCapacity(5 * self.base.comp.link_inputs.len + 2);
1988+
19861989
argv.appendAssumeCapacity("--as-needed");
19871990
var as_needed = true;
19881991

@@ -2004,10 +2007,17 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
20042007
}
20052008

20062009
// By this time, we depend on these libs being dynamically linked
2007-
// libraries and not static libraries (the check for that needs to be earlier),
2008-
// but they could be full paths to .so files, in which case we
2009-
// want to avoid prepending "-l".
2010-
argv.appendAssumeCapacity(try dso.path.toString(arena));
2010+
// libraries and not static libraries (the check for that needs to be earlier).
2011+
if (dso.name) |name| {
2012+
if (dso.lib_directory.path) |path| {
2013+
argv.appendAssumeCapacity("-L");
2014+
argv.appendAssumeCapacity(path);
2015+
}
2016+
argv.appendAssumeCapacity(if (dso.weak) "-weak-l" else "-l");
2017+
argv.appendAssumeCapacity(name);
2018+
} else {
2019+
argv.appendAssumeCapacity(try dso.path.toString(arena));
2020+
}
20112021
},
20122022
};
20132023

0 commit comments

Comments
 (0)