Skip to content

Commit 5f810f0

Browse files
committed
fix: make zig cc pass -l/-L like Clang/GCC for ELF
This commit makes the way `zig cc` passes `-l/-L` flags for ELF linking consistent with Clang and GCC. Closes #19699
1 parent 956f53b commit 5f810f0

File tree

3 files changed

+118
-32
lines changed

3 files changed

+118
-32
lines changed

src/link/Elf.zig

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1585,10 +1585,17 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
15851585
}
15861586

15871587
if (obj.loption) {
1588-
assert(obj.path[0] == ':');
15891588
try argv.append("-l");
1589+
if (obj.path[0] == ':') {
1590+
try argv.append(obj.path);
1591+
} else {
1592+
const stem = fs.path.stem(obj.path);
1593+
assert(mem.startsWith(u8, stem, "lib"));
1594+
try argv.append(stem[3..]);
1595+
}
1596+
} else {
1597+
try argv.append(obj.path);
15901598
}
1591-
try argv.append(obj.path);
15921599
}
15931600
if (whole_archive) {
15941601
try argv.append("-no-whole-archive");
@@ -2594,10 +2601,17 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) !voi
25942601
}
25952602

25962603
if (obj.loption) {
2597-
assert(obj.path[0] == ':');
25982604
try argv.append("-l");
2605+
if (obj.path[0] == ':') {
2606+
try argv.append(obj.path);
2607+
} else {
2608+
const stem = fs.path.stem(obj.path);
2609+
assert(mem.startsWith(u8, stem, "lib"));
2610+
try argv.append(stem[3..]);
2611+
}
2612+
} else {
2613+
try argv.append(obj.path);
25992614
}
2600-
try argv.append(obj.path);
26012615
}
26022616
if (whole_archive) {
26032617
try argv.append("-no-whole-archive");

src/main.zig

Lines changed: 52 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3788,14 +3788,20 @@ fn createModule(
37883788
const path = try arena.dupe(u8, test_path.items);
37893789
switch (info.preferred_mode) {
37903790
.static => try create_module.link_objects.append(arena, .{ .path = path }),
3791-
.dynamic => try create_module.resolved_system_libs.append(arena, .{
3792-
.name = lib_name,
3793-
.lib = .{
3794-
.needed = info.needed,
3795-
.weak = info.weak,
3791+
.dynamic => if (info.needed)
3792+
try create_module.resolved_system_libs.append(arena, .{
3793+
.name = lib_name,
3794+
.lib = .{
3795+
.needed = info.needed,
3796+
.weak = info.weak,
3797+
.path = path,
3798+
},
3799+
})
3800+
else
3801+
try create_module.link_objects.append(arena, .{
37963802
.path = path,
3797-
},
3798-
}),
3803+
.loption = true,
3804+
}),
37993805
}
38003806
continue :syslib;
38013807
}
@@ -3822,14 +3828,20 @@ fn createModule(
38223828
const path = try arena.dupe(u8, test_path.items);
38233829
switch (info.fallbackMode()) {
38243830
.static => try create_module.link_objects.append(arena, .{ .path = path }),
3825-
.dynamic => try create_module.resolved_system_libs.append(arena, .{
3826-
.name = lib_name,
3827-
.lib = .{
3828-
.needed = info.needed,
3829-
.weak = info.weak,
3831+
.dynamic => if (info.needed)
3832+
try create_module.resolved_system_libs.append(arena, .{
3833+
.name = lib_name,
3834+
.lib = .{
3835+
.needed = info.needed,
3836+
.weak = info.weak,
3837+
.path = path,
3838+
},
3839+
})
3840+
else
3841+
try create_module.link_objects.append(arena, .{
38303842
.path = path,
3831-
},
3832-
}),
3843+
.loption = true,
3844+
}),
38333845
}
38343846
continue :syslib;
38353847
}
@@ -3856,14 +3868,20 @@ fn createModule(
38563868
const path = try arena.dupe(u8, test_path.items);
38573869
switch (info.preferred_mode) {
38583870
.static => try create_module.link_objects.append(arena, .{ .path = path }),
3859-
.dynamic => try create_module.resolved_system_libs.append(arena, .{
3860-
.name = lib_name,
3861-
.lib = .{
3862-
.needed = info.needed,
3863-
.weak = info.weak,
3871+
.dynamic => if (info.needed)
3872+
try create_module.resolved_system_libs.append(arena, .{
3873+
.name = lib_name,
3874+
.lib = .{
3875+
.needed = info.needed,
3876+
.weak = info.weak,
3877+
.path = path,
3878+
},
3879+
})
3880+
else
3881+
try create_module.link_objects.append(arena, .{
38643882
.path = path,
3865-
},
3866-
}),
3883+
.loption = true,
3884+
}),
38673885
}
38683886
continue :syslib;
38693887
}
@@ -3880,14 +3898,20 @@ fn createModule(
38803898
const path = try arena.dupe(u8, test_path.items);
38813899
switch (info.fallbackMode()) {
38823900
.static => try create_module.link_objects.append(arena, .{ .path = path }),
3883-
.dynamic => try create_module.resolved_system_libs.append(arena, .{
3884-
.name = lib_name,
3885-
.lib = .{
3886-
.needed = info.needed,
3887-
.weak = info.weak,
3901+
.dynamic => if (info.needed)
3902+
try create_module.resolved_system_libs.append(arena, .{
3903+
.name = lib_name,
3904+
.lib = .{
3905+
.needed = info.needed,
3906+
.weak = info.weak,
3907+
.path = path,
3908+
},
3909+
})
3910+
else
3911+
try create_module.link_objects.append(arena, .{
38883912
.path = path,
3889-
},
3890-
}),
3913+
.loption = true,
3914+
}),
38913915
}
38923916
continue :syslib;
38933917
}

test/tests.zig

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,54 @@ pub fn addCliTests(b: *std.Build) *Step {
769769
step.dependOn(&cleanup.step);
770770
}
771771

772+
{
773+
// Test `zig cc` `-l`/`-L` linker flag forwarding for ELF.
774+
const tmp_path = b.makeTempPath();
775+
var dir = std.fs.cwd().openDir(tmp_path, .{}) catch @panic("unhandled");
776+
defer dir.close();
777+
dir.writeFile("main.c",
778+
\\#include "foo/foo.h"
779+
\\int main() { f(); }
780+
) catch @panic("unhandled");
781+
dir.makeDir("foo") catch @panic("unhandled");
782+
var subdir = dir.openDir("foo", .{}) catch @panic("unhandled");
783+
defer subdir.close();
784+
subdir.writeFile("foo.h", "void f();") catch @panic("unhandled");
785+
subdir.writeFile("foo.c", "void f() {}") catch @panic("unhandled");
786+
787+
const cc_shared = b.addSystemCommand(&.{
788+
b.graph.zig_exe, "cc",
789+
"-shared", "foo/foo.c",
790+
"-target", "x86_64-linux-gnu",
791+
"-o", "foo/libfoo.so",
792+
});
793+
cc_shared.setCwd(.{ .cwd_relative = tmp_path });
794+
cc_shared.setName("build the shared library");
795+
796+
const cc_link = b.addSystemCommand(&.{
797+
b.graph.zig_exe, "cc",
798+
"main.c", "-Lfoo",
799+
"-lfoo", "-target",
800+
"x86_64-linux-gnu", "-o",
801+
"main",
802+
});
803+
const main_path = std.fs.path.join(b.allocator, &.{ tmp_path, "main" }) catch @panic("OOM");
804+
cc_link.setCwd(.{ .cwd_relative = tmp_path });
805+
cc_link.setName("link the shared library");
806+
cc_link.step.dependOn(&cc_shared.step);
807+
808+
const check = Step.CheckObject.create(step.owner, .{ .cwd_relative = main_path }, .elf);
809+
check.checkInDynamicSection();
810+
check.checkExact("NEEDED libfoo.so");
811+
check.checkNotPresent("NEEDED foo/libfoo.so");
812+
check.step.dependOn(&cc_link.step);
813+
814+
const cleanup = b.addRemoveDirTree(tmp_path);
815+
cleanup.step.dependOn(&check.step);
816+
817+
step.dependOn(&cleanup.step);
818+
}
819+
772820
// Test Godbolt API
773821
if (builtin.os.tag == .linux and builtin.cpu.arch == .x86_64) {
774822
const tmp_path = b.makeTempPath();

0 commit comments

Comments
 (0)