Confusing linker error when library specified by extern declaration is not found
Zig Version
0.12.0
Steps to Reproduce and Observed Behavior
I tried to use a function that's not accessible through the omp.h header ( or any other accessible header file for that matter ) that is declared here __kmpc_push_proc_bind(). I have rewritten in zig the function declaration, like when doing binary patching, and I get an error when using the self-hosted linker.
// repro.zig
pub fn main() void {
var id = ident_t{ .psource = "" };
__kmpc_push_proc_bind(&id, 0, 1); // This is just a random function that I picked, i behaves the same with other functions
}
// This isn't important, it's just to match as much as possible the function declaration of the original function
pub const ident_t = extern struct {
reserved_1: c_int = 0,
flags: c_int = 0,
reserved_2: c_int = 0,
reserved_3: c_int = 0x1a,
psource: [*:0]const u8,
};
extern "C" fn __kmpc_push_proc_bind(loc: *ident_t, global_tid: c_int, proc_binds: c_int) void;
Command : zig build-exe repro.zig -fno-llvm -fno-lld -lc -lomp
Result:
error: unexpected error: parsing library failed with error FileNotFound
note: while parsing
Command : zig build-exe repro.zig -fllvm -fno-lld -lc -lomp
Result:
error: unexpected error: parsing library failed with error FileNotFound
note: while parsing
When using the llvm backend normally it compiles
Command : zig build-exe repro.zig -lc -lomp
Result: no error
This doesn't happen if I try to call a function using @cImport("omp.h");, like for example
const c = @cImport({
@cInclude("omp.h");
});
pub fn main() void {
c.omp_get_max_num_thread();
}
I haven't tested with other libraries if I can replicate the same result and this was tested with llvm version of openmp, not the gnu one.
Expected Behavior
They both compile.
I'm pretty sure the library name (after extern) is case sensitive, and the usual system c library uses lowercase, i.e. extern "c".
There's also the option of instead specifying the library name (f.e. extern "kernel32"),
so it seems pretty likely that Zig tries to look for a library named "C" instead of realizing you're talking about a system c library function.
That would also explain the FileNotFound error, because there's (probably) no library named "C" in any of the default or provided library search paths.
Don't know if it actually is case sensitive, but even if it were, the llvm backend wouldn't crash.
Regardless i tested with extern "c" all of the examples above and I get the same results.
@Vexu I think you may have misunderstood, it's a bug not a weird error message. This function declaration exists, you can call it and it works like any other function when using the LLVM backend.
It's just that when you use the self-hosted backend it doesn't compile giving this error message. But the expected behaviour should be that the program compiles and runs normally.
I was testing with a release build of Zig, when using a debug build it panics if the library is not specified on the command line. I am able to build it with the self-hosted backend when using extern "omp".
Stack trace
thread 274647 panic: attempt to use null value
/home/vexu/Documents/zig/zig/src/link/Elf.zig:1174:93: 0xa52b93a in flushModule (zig)
system_libs.appendAssumeCapacity(.{ .needed = lib_info.needed, .path = lib_info.path.? });
^
/home/vexu/Documents/zig/zig/src/link/Elf.zig:1072:25: 0xa1ee444 in flush (zig)
try self.flushModule(arena, prog_node);
^
/home/vexu/Documents/zig/zig/src/link.zig:566:77: 0x9f5a46d in flush (zig)
return @as(*tag.Type(), @fieldParentPtr("base", base)).flush(arena, prog_node);
^
/home/vexu/Documents/zig/zig/src/Compilation.zig:2262:17: 0x9f59b0f in flush (zig)
lf.flush(arena, prog_node) catch |err| switch (err) {
^
/home/vexu/Documents/zig/zig/src/Compilation.zig:2253:22: 0x9f5d63e in update (zig)
try flush(comp, arena, main_progress_node);
^
/home/vexu/Documents/zig/zig/src/main.zig:4483:24: 0x9f8da9f in updateModule (zig)
try comp.update(main_progress_node);
^
/home/vexu/Documents/zig/zig/src/main.zig:3405:17: 0x9ff63d2 in buildOutputType (zig)
updateModule(comp, color) catch |err| switch (err) {
^
I tried it too with the 0.12.0 version but I'm getting different results. Using extern "omp" and building with zig build-exe repro.zig -fno-llvm -fno-lld -lc -lomp works.
I also tried to omit the library in the command line and it doesn't crash, but it gives the FileNotFound error, which I guess has to be expected since I told him not to look for libomp. Weirdly enough if I omit only -lc it compiles and if I omit both -lc and -lomp it gives me a nice error message
repro.zig:16:8: error: dependency on dynamic library 'omp' requires enabling Position Independent Code. Fixed by '-lomp' or '-fPIC'.
extern "omp" fn __kmpc_push_proc_bind(loc: *ident_t, global_tid: c_int, proc_binds: c_int) void;
^~~~~
referenced by:
main: repro.zig:4:5
callMain: /nix/store/ymq0w17q7vy4xf2phd74pqhsyfdmam3s-zig-0.12.0/lib/zig/std/start.zig:501:17
remaining reference traces hidden; use '-freference-trace' to see all reference traces