Skip to content

Commit 7f064ee

Browse files
committed
link: make zig cc pass -l/-L like Clang/GCC for ELF
1 parent 14ec9e4 commit 7f064ee

File tree

2 files changed

+36
-16
lines changed

2 files changed

+36
-16
lines changed

src/link.zig

Lines changed: 19 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 {
@@ -2145,7 +2147,7 @@ fn resolveLibInput(
21452147
else => |e| fatal("unable to search for tbd library '{}': {s}", .{ test_path, @errorName(e) }),
21462148
};
21472149
errdefer file.close();
2148-
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);
2150+
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query, name_query.name, lib_directory);
21492151
}
21502152

21512153
{
@@ -2159,10 +2161,10 @@ fn resolveLibInput(
21592161
}),
21602162
};
21612163
try checked_paths.writer(gpa).print("\n {}", .{test_path});
2162-
switch (try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, .{
2164+
switch (try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, lib_directory, target, .{
21632165
.path = test_path,
21642166
.query = name_query.query,
2165-
}, link_mode, color)) {
2167+
}, link_mode, color, name_query.name)) {
21662168
.no_match => {},
21672169
.ok => return .ok,
21682170
}
@@ -2183,7 +2185,7 @@ fn resolveLibInput(
21832185
}),
21842186
};
21852187
errdefer file.close();
2186-
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);
2188+
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query, name_query.name, lib_directory);
21872189
}
21882190

21892191
// In the case of MinGW, the main check will be .lib but we also need to
@@ -2199,7 +2201,7 @@ fn resolveLibInput(
21992201
else => |e| fatal("unable to search for static library '{}': {s}", .{ test_path, @errorName(e) }),
22002202
};
22012203
errdefer file.close();
2202-
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);
2204+
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query, name_query.name, lib_directory);
22032205
}
22042206

22052207
return .no_match;
@@ -2211,6 +2213,8 @@ fn finishResolveLibInput(
22112213
file: std.fs.File,
22122214
link_mode: std.builtin.LinkMode,
22132215
query: UnresolvedInput.Query,
2216+
name: ?[]const u8,
2217+
lib_directory: Directory,
22142218
) ResolveLibInputResult {
22152219
switch (link_mode) {
22162220
.static => resolved_inputs.appendAssumeCapacity(.{ .archive = .{
@@ -2225,6 +2229,8 @@ fn finishResolveLibInput(
22252229
.needed = query.needed,
22262230
.weak = query.weak,
22272231
.reexport = query.reexport,
2232+
.name = name,
2233+
.lib_directory = lib_directory,
22282234
} }),
22292235
}
22302236
return .ok;
@@ -2244,8 +2250,8 @@ fn resolvePathInput(
22442250
color: std.zig.Color,
22452251
) Allocator.Error!?ResolveLibInputResult {
22462252
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),
2253+
.static_library => return try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, Directory.cwd(), target, pq, .static, color, null),
2254+
.shared_library => return try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, Directory.cwd(), target, pq, .dynamic, color, null),
22492255
.object => {
22502256
var file = pq.path.root_dir.handle.openFile(pq.path.sub_path, .{}) catch |err|
22512257
fatal("failed to open object {}: {s}", .{ pq.path, @errorName(err) });
@@ -2281,10 +2287,12 @@ fn resolvePathInputLib(
22812287
resolved_inputs: *std.ArrayListUnmanaged(Input),
22822288
/// Allocated via `gpa`.
22832289
ld_script_bytes: *std.ArrayListUnmanaged(u8),
2290+
lib_directory: Directory,
22842291
target: std.Target,
22852292
pq: UnresolvedInput.PathQuery,
22862293
link_mode: std.builtin.LinkMode,
22872294
color: std.zig.Color,
2295+
name: ?[]const u8,
22882296
) Allocator.Error!ResolveLibInputResult {
22892297
try resolved_inputs.ensureUnusedCapacity(gpa, 1);
22902298

@@ -2309,7 +2317,7 @@ fn resolvePathInputLib(
23092317
if (n != ld_script_bytes.items.len) break :elf_file;
23102318
if (!mem.eql(u8, ld_script_bytes.items[0..4], "\x7fELF")) break :elf_file;
23112319
// Appears to be an ELF file.
2312-
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query);
2320+
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query, name, lib_directory);
23132321
}
23142322
const stat = file.stat() catch |err|
23152323
fatal("failed to stat {}: {s}", .{ test_path, @errorName(err) });
@@ -2375,7 +2383,7 @@ fn resolvePathInputLib(
23752383
}),
23762384
};
23772385
errdefer file.close();
2378-
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query);
2386+
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query, name, lib_directory);
23792387
}
23802388

23812389
pub fn openObject(path: Path, must_link: bool, hidden: bool) !Input.Object {
@@ -2398,6 +2406,8 @@ pub fn openDso(path: Path, needed: bool, weak: bool, reexport: bool) !Input.Dso
23982406
.needed = needed,
23992407
.weak = weak,
24002408
.reexport = reexport,
2409+
.name = null,
2410+
.lib_directory = Directory.cwd(),
24012411
};
24022412
}
24032413

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)