Skip to content

Commit

Permalink
fix: make zig cc pass -l/-L like Clang/GCC for ELF
Browse files Browse the repository at this point in the history
This commit makes the way `zig cc` passes `-l/-L` flags for ELF linking
consistent with Clang and GCC.

Closes ziglang#19699
  • Loading branch information
a-khabarov committed Apr 30, 2024
1 parent 956f53b commit 5f810f0
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 32 deletions.
22 changes: 18 additions & 4 deletions src/link/Elf.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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");
Expand Down
80 changes: 52 additions & 28 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3788,14 +3788,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;
}
Expand All @@ -3822,14 +3828,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;
}
Expand All @@ -3856,14 +3868,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;
}
Expand All @@ -3880,14 +3898,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;
}
Expand Down
48 changes: 48 additions & 0 deletions test/tests.zig
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,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();
Expand Down

0 comments on commit 5f810f0

Please sign in to comment.