Skip to content

Commit 0a646aa

Browse files
committed
link: make zig cc pass -l/-L like Clang/GCC for ELF
1 parent e37cf1f commit 0a646aa

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
@@ -1794,6 +1794,8 @@ pub const Input = union(enum) {
17941794
needed: bool,
17951795
weak: bool,
17961796
reexport: bool,
1797+
name: ?[]const u8,
1798+
lib_directory: Directory,
17971799
};
17981800

17991801
pub const DsoExact = struct {
@@ -2121,7 +2123,7 @@ fn resolveLibInput(
21212123
else => |e| fatal("unable to search for tbd library '{}': {s}", .{ test_path, @errorName(e) }),
21222124
};
21232125
errdefer file.close();
2124-
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);
2126+
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query, name_query.name, lib_directory);
21252127
}
21262128

21272129
{
@@ -2135,10 +2137,10 @@ fn resolveLibInput(
21352137
}),
21362138
};
21372139
try checked_paths.writer(gpa).print("\n {}", .{test_path});
2138-
switch (try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, .{
2140+
switch (try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, lib_directory, target, .{
21392141
.path = test_path,
21402142
.query = name_query.query,
2141-
}, link_mode, color)) {
2143+
}, link_mode, color, name_query.name)) {
21422144
.no_match => {},
21432145
.ok => return .ok,
21442146
}
@@ -2159,7 +2161,7 @@ fn resolveLibInput(
21592161
}),
21602162
};
21612163
errdefer file.close();
2162-
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);
2164+
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query, name_query.name, lib_directory);
21632165
}
21642166

21652167
// In the case of MinGW, the main check will be .lib but we also need to
@@ -2175,7 +2177,7 @@ fn resolveLibInput(
21752177
else => |e| fatal("unable to search for static library '{}': {s}", .{ test_path, @errorName(e) }),
21762178
};
21772179
errdefer file.close();
2178-
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);
2180+
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query, name_query.name, lib_directory);
21792181
}
21802182

21812183
return .no_match;
@@ -2187,6 +2189,8 @@ fn finishResolveLibInput(
21872189
file: std.fs.File,
21882190
link_mode: std.builtin.LinkMode,
21892191
query: UnresolvedInput.Query,
2192+
name: ?[]const u8,
2193+
lib_directory: Directory,
21902194
) ResolveLibInputResult {
21912195
switch (link_mode) {
21922196
.static => resolved_inputs.appendAssumeCapacity(.{ .archive = .{
@@ -2201,6 +2205,8 @@ fn finishResolveLibInput(
22012205
.needed = query.needed,
22022206
.weak = query.weak,
22032207
.reexport = query.reexport,
2208+
.name = name,
2209+
.lib_directory = lib_directory,
22042210
} }),
22052211
}
22062212
return .ok;
@@ -2220,8 +2226,8 @@ fn resolvePathInput(
22202226
color: std.zig.Color,
22212227
) Allocator.Error!?ResolveLibInputResult {
22222228
switch (Compilation.classifyFileExt(pq.path.sub_path)) {
2223-
.static_library => return try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, pq, .static, color),
2224-
.shared_library => return try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, pq, .dynamic, color),
2229+
.static_library => return try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, Directory.cwd(), target, pq, .static, color, null),
2230+
.shared_library => return try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, Directory.cwd(), target, pq, .dynamic, color, null),
22252231
.object => {
22262232
var file = pq.path.root_dir.handle.openFile(pq.path.sub_path, .{}) catch |err|
22272233
fatal("failed to open object {}: {s}", .{ pq.path, @errorName(err) });
@@ -2257,10 +2263,12 @@ fn resolvePathInputLib(
22572263
resolved_inputs: *std.ArrayListUnmanaged(Input),
22582264
/// Allocated via `gpa`.
22592265
ld_script_bytes: *std.ArrayListUnmanaged(u8),
2266+
lib_directory: Directory,
22602267
target: std.Target,
22612268
pq: UnresolvedInput.PathQuery,
22622269
link_mode: std.builtin.LinkMode,
22632270
color: std.zig.Color,
2271+
name: ?[]const u8,
22642272
) Allocator.Error!ResolveLibInputResult {
22652273
try resolved_inputs.ensureUnusedCapacity(gpa, 1);
22662274

@@ -2285,7 +2293,7 @@ fn resolvePathInputLib(
22852293
if (n != ld_script_bytes.items.len) break :elf_file;
22862294
if (!mem.eql(u8, ld_script_bytes.items[0..4], "\x7fELF")) break :elf_file;
22872295
// Appears to be an ELF file.
2288-
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query);
2296+
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query, name, lib_directory);
22892297
}
22902298
const stat = file.stat() catch |err|
22912299
fatal("failed to stat {}: {s}", .{ test_path, @errorName(err) });
@@ -2351,7 +2359,7 @@ fn resolvePathInputLib(
23512359
}),
23522360
};
23532361
errdefer file.close();
2354-
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query);
2362+
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query, name, lib_directory);
23552363
}
23562364

23572365
pub fn openObject(path: Path, must_link: bool, hidden: bool) !Input.Object {
@@ -2374,6 +2382,8 @@ pub fn openDso(path: Path, needed: bool, weak: bool, reexport: bool) !Input.Dso
23742382
.needed = needed,
23752383
.weak = weak,
23762384
.reexport = reexport,
2385+
.name = null,
2386+
.lib_directory = Directory.cwd(),
23772387
};
23782388
}
23792389

src/link/Elf.zig

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

19871987
// Shared libraries.
19881988
if (is_exe_or_dyn_lib) {
1989-
// Worst-case, we need an --as-needed argument for every lib, as well
1990-
// as one before and one after.
1991-
try argv.ensureUnusedCapacity(2 * self.base.comp.link_inputs.len + 2);
1989+
// Worst-case, we need:
1990+
// * an --as-needed/--no-as-needed argument for every lib
1991+
// * -L, lib directory, -l/-weak-l, library name for every lib
1992+
// * one --as-needed before and one --as-needed after
1993+
try argv.ensureUnusedCapacity(5 * self.base.comp.link_inputs.len + 2);
1994+
19921995
argv.appendAssumeCapacity("--as-needed");
19931996
var as_needed = true;
19941997

@@ -2010,10 +2013,17 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
20102013
}
20112014

20122015
// By this time, we depend on these libs being dynamically linked
2013-
// libraries and not static libraries (the check for that needs to be earlier),
2014-
// but they could be full paths to .so files, in which case we
2015-
// want to avoid prepending "-l".
2016-
argv.appendAssumeCapacity(try dso.path.toString(arena));
2016+
// libraries and not static libraries (the check for that needs to be earlier).
2017+
if (dso.name) |name| {
2018+
if (dso.lib_directory.path) |path| {
2019+
argv.appendAssumeCapacity("-L");
2020+
argv.appendAssumeCapacity(path);
2021+
}
2022+
argv.appendAssumeCapacity(if (dso.weak) "-weak-l" else "-l");
2023+
argv.appendAssumeCapacity(name);
2024+
} else {
2025+
argv.appendAssumeCapacity(try dso.path.toString(arena));
2026+
}
20172027
},
20182028
};
20192029

0 commit comments

Comments
 (0)