`zig cc` fails to compile trivial shared library with target specified
Zig Version
0.11.0-dev.4320+6f0a613b6
Steps to Reproduce and Observed Behavior
Create a C source file shlib.c:
#include <math.h>
float our_sin(float x) {
return sinf(x);
}
Then:
$ zig cc -target x86_64-linux -shared -o shlib.so shlib.c
$ ldd shlib.so
linux-vdso.so.1 (0x00007ffc2938a000)
libc.so => not found
This library is not correctly linked to libc.so.6 as it should be and cannot be loaded or used at all.
Expected Behavior
e.g. with gcc:
$ gcc -shared -o shlib.so shlib.c
$ ldd shlib.so
linux-vdso.so.1 (0x00007fff5e5f8000)
libc.so.6 => /lib64/libc.so.6 (0x00007f6e6ee00000)
/lib64/ld-linux-x86-64.so.2 (0x00007f6e6f0f4000)
and the shared library can be used.
In Zig 0.10.0, the same command works as expected.
Something similar happens to me too.
#include <stdio.h>
void helloMessage() {
printf("Hello world\n");
}
zig cc -target x86_64-linux -shared -o index.so index.c
ldd index.so
./index.so: error while loading shared libraries: /lib/x86_64-linux-gnu/libc.so: invalid ELF header
(I'm reproducing this bug with 0.12.0-dev.1491+c2629e49a.)
I believe -target x86_64-linux is equivalent to -target x86_64-linux-musl in Zig, so the Musl C library is being statically linked into the generated library. The resulting shared library binary is not acceptable to the dynamic linker. And, as pointed out on the Musl mailing list a Musl-statically-linked shared library is really unlikely to be useful (its not clear if initialization of global things like thread-local storage, or process state like args/envp would happen correctly).
$ zig cc -target x86_64-linux-musl -shared -o shlib-musl.so shlib.c
$ zig cc -target x86_64-linux -shared -o shlib.so shlib.c
$ cmp -b shlib.so shlib-musl.so
$
$ ldd shlib-musl.so
./shlib-musl.so: error while loading shared libraries: /lib/x86_64-linux-gnu/libc.so: invalid ELF header
Switching to the glibc library with -target x86_64-linux-gnu generates a viable shared library:
$ zig cc -target x86_64-linux-gnu -shared -o shlib-gnu.so shlib.c
$ ldd shlib-gnu.so
linux-vdso.so.1 (0x00007fff9891b000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fd44c40a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd44c229000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd44c50d000)
So, when Zig is building a shared library, it should probably disallow the -musl target and/or default to -gnu.
So, when Zig is building a shared library, it should probably disallow the
-musltarget and/or default to-gnu.
No, musl has a dynamic linker too, and the file you produced is in fact dynamically linked:
❯ zig cc -target x86_64-linux -shared shlib.c
❯ file a.out
a.out: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, with debug_info, not stripped
❯ ldd a.out
./a.out: error while loading shared libraries: /lib/x86_64-linux-gnu/libc.so: invalid ELF header
❯ musl-ldd a.out
musl-ldd (0x71c16ca53000)
libc.so => musl-ldd (0x71c16ca53000)
Note that you must use musl-ldd for musl-based libraries; the glibc dynamic linker won't know what to do with these.
In other words: This is all working as designed. Use x86_64-linux-gnu if that's what you actually mean.
Closing per the comment above, but feel free to comment if I missed something and I'll reopen.