Undefined reference to pthread_mutex_trylock when using libc
$ cat atest.zig
const std = @import("std");
pub fn main() void {
var mtx = std.Thread.Mutex {};
_ = mtx.tryAcquire();
}
$ zig build-exe --libc <(zig libc) -lc -lpthread ./atest.zig
ld.lld: error: undefined symbol: pthread_mutex_trylock
>>> referenced by Mutex.zig:198 (/usr/lib/zig/std/Thread/Mutex.zig:198)
>>> ./zig-cache/o/7b8d8fca250dcd6cd96d73f316c15033/atest.o:(std.Thread.Mutex.PthreadMutex.tryAcquire)
error: LLDReportedFailure
$ nm /usr/lib64/libc.so.6 | grep pthread_mutex_trylock
$ nm /usr/lib64/libpthread.so.0 | grep pthread_mutex_trylock
000000000000bf51 t .annobin___GI___pthread_mutex_trylock.end
000000000000b900 t .annobin___GI___pthread_mutex_trylock.start
000000000000b900 t .annobin_pthread_mutex_trylock.c
0000000000007ab5 t .annobin_pthread_mutex_trylock.c.exit
0000000000007ab5 t .annobin_pthread_mutex_trylock.c.hot
0000000000007ab5 t .annobin_pthread_mutex_trylock.c.startup
0000000000007ab5 t .annobin_pthread_mutex_trylock.c.unlikely
000000000000bf51 t .annobin_pthread_mutex_trylock.c_end
0000000000007ab5 t .annobin_pthread_mutex_trylock.c_end.exit
0000000000007ab5 t .annobin_pthread_mutex_trylock.c_end.hot
0000000000007ab5 t .annobin_pthread_mutex_trylock.c_end.startup
0000000000007ab5 t .annobin_pthread_mutex_trylock.c_end.unlikely
000000000000b900 t __GI___pthread_mutex_trylock
000000000000b900 T __pthread_mutex_trylock
000000000000b900 W pthread_mutex_trylock
There's a small but significant difference between musl and glibc, the former ships a single libc.so while the latter ships much more than a single .so object. is_libc_lib_name detects -lc -lpthread and discards them, the code in src/link/Elf.zig already knows what to link, the compiler understands you want the libc to be linked.
linkWithLLD in src/link/Elf.zig is, on the other hand, unaware of any other libc component beside lc and lm!
The linker error you see is caused by this problem as -lpthread is never relayed to the linker :\
Keep in mind that this problem shows up only when --libc is specified.
You can compile your code as: zig build-exe -target native-linux-gnu -lc -lpthread /tmp/foo.zig or, if your system uses glibc, with zig build-exe -lc -lpthread /tmp/foo.zig
Keep in mind that this problem shows up only when
--libcis specified. You can compile your code as:zig build-exe -target native-linux-gnu -lc -lpthread /tmp/foo.zigor, if your system uses glibc, withzig build-exe -lc -lpthread /tmp/foo.zig
If I don't specify --libc, zig tries to access its glibc fork, which is a thing I want to avoid. In particular, I don't want to have to make sure that zig's glibc fork is ABI-compatible with the one on my system.
If I don't specify --libc, zig tries to access its glibc fork, which is a thing I want to avoid.
There's no glibc fork.
We only build fake .so files containing the correctly-versioned symbol names, that is to appease the linker and bake the correct library requirements into the resulting ELF file.
If I don't specify --libc, zig tries to access its glibc fork, which is a thing I want to avoid.
There's no glibc fork.
OK, not a fork, but a bundled modified copy.
We only build fake
.sofiles containing the correctly-versioned symbol names, that is to appease the linker and bake the correct library requirements into the resulting ELF file.
How do I use the system libc instead?
By the way, I managed to link the binary by providing a symlink to libpthread.so under a different name and linking that.
OK, not a fork, but a bundled modified copy.
There's no bundled modified copy, the handful of .c files are only needed to provide some symbols that are not exported by libc.so.
How do I use the system libc instead?
zig build-exe -lc -lpthread /tmp/foo.zig
OK, not a fork, but a bundled modified copy.
There's no bundled modified copy, the handful of
.cfiles are only needed to provide some symbols that are not exported bylibc.so.
OK, let's call it a bundled copy of a particular release of glibc with some files deleted.
How do I use the system libc instead?
zig build-exe -lc -lpthread /tmp/foo.zig
That uses crti.S from zig's bundled copy of glibc. I'd like to use the system crti.o.
That uses crti.S from zig's bundled copy of glibc. I'd like to use the system crti.o.
Then it's: zig build-exe --libc <(zig libc) -lc -lpthread ./atest.zig
That uses crti.S from zig's bundled copy of glibc. I'd like to use the system crti.o.
Then it's:
zig build-exe --libc <(zig libc) -lc -lpthread ./atest.zig
which fails because -lpthread is ignored.
Here's an idea: if --libc is given, we don't remove the -l arguments, and we don't add -lc -lm. I will test it and I will submit a pull request if it works.
I think https://github.com/ziglang/zig/pull/7870 is a better idea.