Skip to content

Commit 1860048

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 9691da7 commit 1860048

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
@@ -3794,14 +3794,20 @@ fn createModule(
37943794
const path = try arena.dupe(u8, test_path.items);
37953795
switch (info.preferred_mode) {
37963796
.static => try create_module.link_objects.append(arena, .{ .path = path }),
3797-
.dynamic => try create_module.resolved_system_libs.append(arena, .{
3798-
.name = lib_name,
3799-
.lib = .{
3800-
.needed = info.needed,
3801-
.weak = info.weak,
3797+
.dynamic => if (info.needed)
3798+
try create_module.resolved_system_libs.append(arena, .{
3799+
.name = lib_name,
3800+
.lib = .{
3801+
.needed = info.needed,
3802+
.weak = info.weak,
3803+
.path = path,
3804+
},
3805+
})
3806+
else
3807+
try create_module.link_objects.append(arena, .{
38023808
.path = path,
3803-
},
3804-
}),
3809+
.loption = true,
3810+
}),
38053811
}
38063812
continue :syslib;
38073813
}
@@ -3828,14 +3834,20 @@ fn createModule(
38283834
const path = try arena.dupe(u8, test_path.items);
38293835
switch (info.fallbackMode()) {
38303836
.static => try create_module.link_objects.append(arena, .{ .path = path }),
3831-
.dynamic => try create_module.resolved_system_libs.append(arena, .{
3832-
.name = lib_name,
3833-
.lib = .{
3834-
.needed = info.needed,
3835-
.weak = info.weak,
3837+
.dynamic => if (info.needed)
3838+
try create_module.resolved_system_libs.append(arena, .{
3839+
.name = lib_name,
3840+
.lib = .{
3841+
.needed = info.needed,
3842+
.weak = info.weak,
3843+
.path = path,
3844+
},
3845+
})
3846+
else
3847+
try create_module.link_objects.append(arena, .{
38363848
.path = path,
3837-
},
3838-
}),
3849+
.loption = true,
3850+
}),
38393851
}
38403852
continue :syslib;
38413853
}
@@ -3862,14 +3874,20 @@ fn createModule(
38623874
const path = try arena.dupe(u8, test_path.items);
38633875
switch (info.preferred_mode) {
38643876
.static => try create_module.link_objects.append(arena, .{ .path = path }),
3865-
.dynamic => try create_module.resolved_system_libs.append(arena, .{
3866-
.name = lib_name,
3867-
.lib = .{
3868-
.needed = info.needed,
3869-
.weak = info.weak,
3877+
.dynamic => if (info.needed)
3878+
try create_module.resolved_system_libs.append(arena, .{
3879+
.name = lib_name,
3880+
.lib = .{
3881+
.needed = info.needed,
3882+
.weak = info.weak,
3883+
.path = path,
3884+
},
3885+
})
3886+
else
3887+
try create_module.link_objects.append(arena, .{
38703888
.path = path,
3871-
},
3872-
}),
3889+
.loption = true,
3890+
}),
38733891
}
38743892
continue :syslib;
38753893
}
@@ -3886,14 +3904,20 @@ fn createModule(
38863904
const path = try arena.dupe(u8, test_path.items);
38873905
switch (info.fallbackMode()) {
38883906
.static => try create_module.link_objects.append(arena, .{ .path = path }),
3889-
.dynamic => try create_module.resolved_system_libs.append(arena, .{
3890-
.name = lib_name,
3891-
.lib = .{
3892-
.needed = info.needed,
3893-
.weak = info.weak,
3907+
.dynamic => if (info.needed)
3908+
try create_module.resolved_system_libs.append(arena, .{
3909+
.name = lib_name,
3910+
.lib = .{
3911+
.needed = info.needed,
3912+
.weak = info.weak,
3913+
.path = path,
3914+
},
3915+
})
3916+
else
3917+
try create_module.link_objects.append(arena, .{
38943918
.path = path,
3895-
},
3896-
}),
3919+
.loption = true,
3920+
}),
38973921
}
38983922
continue :syslib;
38993923
}

test/tests.zig

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

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

0 commit comments

Comments
 (0)