diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 8a3192f93ea3..68c8481a480a 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1585,10 +1585,17 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { } if (obj.loption) { - assert(obj.path[0] == ':'); try argv.append("-l"); + if (obj.path[0] == ':') { + try argv.append(obj.path); + } else { + const stem = fs.path.stem(obj.path); + assert(mem.startsWith(u8, stem, "lib")); + try argv.append(stem[3..]); + } + } else { + try argv.append(obj.path); } - try argv.append(obj.path); } if (whole_archive) { try argv.append("-no-whole-archive"); @@ -2594,10 +2601,17 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) !voi } if (obj.loption) { - assert(obj.path[0] == ':'); try argv.append("-l"); + if (obj.path[0] == ':') { + try argv.append(obj.path); + } else { + const stem = fs.path.stem(obj.path); + assert(mem.startsWith(u8, stem, "lib")); + try argv.append(stem[3..]); + } + } else { + try argv.append(obj.path); } - try argv.append(obj.path); } if (whole_archive) { try argv.append("-no-whole-archive"); diff --git a/src/main.zig b/src/main.zig index 61a97de3f54d..82238ddab3b2 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3794,14 +3794,20 @@ fn createModule( const path = try arena.dupe(u8, test_path.items); switch (info.preferred_mode) { .static => try create_module.link_objects.append(arena, .{ .path = path }), - .dynamic => try create_module.resolved_system_libs.append(arena, .{ - .name = lib_name, - .lib = .{ - .needed = info.needed, - .weak = info.weak, + .dynamic => if (info.needed) + try create_module.resolved_system_libs.append(arena, .{ + .name = lib_name, + .lib = .{ + .needed = info.needed, + .weak = info.weak, + .path = path, + }, + }) + else + try create_module.link_objects.append(arena, .{ .path = path, - }, - }), + .loption = true, + }), } continue :syslib; } @@ -3828,14 +3834,20 @@ fn createModule( const path = try arena.dupe(u8, test_path.items); switch (info.fallbackMode()) { .static => try create_module.link_objects.append(arena, .{ .path = path }), - .dynamic => try create_module.resolved_system_libs.append(arena, .{ - .name = lib_name, - .lib = .{ - .needed = info.needed, - .weak = info.weak, + .dynamic => if (info.needed) + try create_module.resolved_system_libs.append(arena, .{ + .name = lib_name, + .lib = .{ + .needed = info.needed, + .weak = info.weak, + .path = path, + }, + }) + else + try create_module.link_objects.append(arena, .{ .path = path, - }, - }), + .loption = true, + }), } continue :syslib; } @@ -3862,14 +3874,20 @@ fn createModule( const path = try arena.dupe(u8, test_path.items); switch (info.preferred_mode) { .static => try create_module.link_objects.append(arena, .{ .path = path }), - .dynamic => try create_module.resolved_system_libs.append(arena, .{ - .name = lib_name, - .lib = .{ - .needed = info.needed, - .weak = info.weak, + .dynamic => if (info.needed) + try create_module.resolved_system_libs.append(arena, .{ + .name = lib_name, + .lib = .{ + .needed = info.needed, + .weak = info.weak, + .path = path, + }, + }) + else + try create_module.link_objects.append(arena, .{ .path = path, - }, - }), + .loption = true, + }), } continue :syslib; } @@ -3886,14 +3904,20 @@ fn createModule( const path = try arena.dupe(u8, test_path.items); switch (info.fallbackMode()) { .static => try create_module.link_objects.append(arena, .{ .path = path }), - .dynamic => try create_module.resolved_system_libs.append(arena, .{ - .name = lib_name, - .lib = .{ - .needed = info.needed, - .weak = info.weak, + .dynamic => if (info.needed) + try create_module.resolved_system_libs.append(arena, .{ + .name = lib_name, + .lib = .{ + .needed = info.needed, + .weak = info.weak, + .path = path, + }, + }) + else + try create_module.link_objects.append(arena, .{ .path = path, - }, - }), + .loption = true, + }), } continue :syslib; } diff --git a/test/tests.zig b/test/tests.zig index c0ef4a536a35..e0950af58bee 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -779,6 +779,54 @@ pub fn addCliTests(b: *std.Build) *Step { step.dependOn(&cleanup.step); } + { + // Test `zig cc` `-l`/`-L` linker flag forwarding for ELF. + const tmp_path = b.makeTempPath(); + var dir = std.fs.cwd().openDir(tmp_path, .{}) catch @panic("unhandled"); + defer dir.close(); + dir.writeFile("main.c", + \\#include "foo/foo.h" + \\int main() { f(); } + ) catch @panic("unhandled"); + dir.makeDir("foo") catch @panic("unhandled"); + var subdir = dir.openDir("foo", .{}) catch @panic("unhandled"); + defer subdir.close(); + subdir.writeFile("foo.h", "void f();") catch @panic("unhandled"); + subdir.writeFile("foo.c", "void f() {}") catch @panic("unhandled"); + + const cc_shared = b.addSystemCommand(&.{ + b.graph.zig_exe, "cc", + "-shared", "foo/foo.c", + "-target", "x86_64-linux-gnu", + "-o", "foo/libfoo.so", + }); + cc_shared.setCwd(.{ .cwd_relative = tmp_path }); + cc_shared.setName("build the shared library"); + + const cc_link = b.addSystemCommand(&.{ + b.graph.zig_exe, "cc", + "main.c", "-Lfoo", + "-lfoo", "-target", + "x86_64-linux-gnu", "-o", + "main", + }); + const main_path = std.fs.path.join(b.allocator, &.{ tmp_path, "main" }) catch @panic("OOM"); + cc_link.setCwd(.{ .cwd_relative = tmp_path }); + cc_link.setName("link the shared library"); + cc_link.step.dependOn(&cc_shared.step); + + const check = Step.CheckObject.create(step.owner, .{ .cwd_relative = main_path }, .elf); + check.checkInDynamicSection(); + check.checkExact("NEEDED libfoo.so"); + check.checkNotPresent("NEEDED foo/libfoo.so"); + check.step.dependOn(&cc_link.step); + + const cleanup = b.addRemoveDirTree(tmp_path); + cleanup.step.dependOn(&check.step); + + step.dependOn(&cleanup.step); + } + // Test Godbolt API if (builtin.os.tag == .linux and builtin.cpu.arch == .x86_64) { const tmp_path = b.makeTempPath();