But after $ zig build --release=fast -Dtarget=aarch64-linux-musl and a user of my library trying to dlopen it, they get this: dlopen failed: cannot locate symbol "cosf" referenced by "./libname.so".
Here’s other undefined symbols in the .so I was able to find out with readelf:
$ readelf --syms --dyn-syms zig-out/aarch64-linux-musl/libname.so | grep -Fw UND
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND cosf
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND sinf
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND posix_memalign
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND malloc_usable_size
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND free
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND memcpy
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND write
8: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __errno_location
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
247: 0000000000000000 0 FUNC GLOBAL DEFAULT UND cosf
248: 0000000000000000 0 FUNC GLOBAL DEFAULT UND sinf
261: 0000000000000000 0 FUNC GLOBAL DEFAULT UND posix_memalign
262: 0000000000000000 0 FUNC GLOBAL DEFAULT UND malloc_usable_size
263: 0000000000000000 0 FUNC GLOBAL DEFAULT UND free
264: 0000000000000000 0 FUNC GLOBAL DEFAULT UND memcpy
265: 0000000000000000 0 FUNC GLOBAL DEFAULT UND write
266: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __errno_location
The question is: how do I link musl properly and make the errors go away? I noticed the Zig toolchain distro contains source code of musl, including the implementation of the cosf function, but how do I instruct zig to use it?
I am guessing that lib.linkSystemLibrary("m"); is causing the problem. There is no libm in musl (the contents are in libc). Your system libm might be the gnu one that is missing from the target system. i.e. use only lib.linkLibC(); without linking to libm.
--release=fast does not work with zig build; zig build -Doptimize=ReleaseFast -Dtarget=aarch64-linux-musl is the correct invocation.
I tried to call it both as @cos(angle) and c.cosf(angle); with no effect on the error.
And speaking of other undefined symbols: posix_memalign and free, my code uses the c allocator in the following way: std.heap.ArenaAllocator.init(std.heap.c_allocator).
I doubt a way of calling libc functions matters here.
$ zig build-lib test.zig -dynamic -OReleaseFast -lc -target aarch64-linux-musl
$ readelf --syms --dyn-syms libtest.so | grep -Fw UND
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND cosf
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND memset
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND write
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __errno_location
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
43: 0000000000000000 0 FUNC GLOBAL DEFAULT UND cosf
44: 0000000000000000 0 FUNC GLOBAL DEFAULT UND memset
45: 0000000000000000 0 FUNC GLOBAL DEFAULT UND write
46: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __errno_location
-dynamic means both “build a shared object” and “link musl dynamically”.
I tried -search_static_only (the outcome of .preferred_link_mode = .static) without any effect.
I am not sure if this is a musl or a zig limitation.
I made a post yesterday, but it had issues and then I got busy so I deleted it. Unfortunately even in the case of musl, linking libc isn’t as simple as just linking a static library. Libc has a global internal state that needs to be initialized by it’s corresponding C runtime. I believe that using a shared object that is simply statically linked with libc.a can run into UB issues with unitialized state depending on what parts of libc the shared object makes use of.
I was able to get some very simple experiments to work by manually linking libc.a into a shared object, but as stated above this is not an intended use case and it’s not supported for a good reason.
Please find or file a bug in the Zig issue tracker. Zig supports dynamically linking musl libc and clearly it is not working correctly as demonstrated in your original post.
Edit, sorry I misread your title as “how do I link musl dynamically?” If you are making a shared library then dynamic linking libc is very likely what you want. If you are trying to make a dynamic library using static musl, I’m not convinced that’s something zig needs to explicitly help you accomplish.
That was perhaps because I did wrong: I tried to use the produced .so in an app on Android, which is bionic-based rather than musl-based, which the dynamic linking of musl assumes, I guess.
Originally, I built it for the aarch64-linux-android triple and did successfully. But then tried to also .linkLibC it, to see if I’d be able to adopt existing C code more easily. Zig responded with this:
error: error: unable to find or provide libc for target 'aarch64-linux.4.19...6.11.5-android.2.28'
info: zig can provide libc for related target aarch64-linux-gnu.2.17
info: zig can provide libc for related target aarch64-linux-musl
Which I interpreted as: “you can link libc for your Android target if only you change your triple a bit”. I didn’t want to mess with installing Android NDKs and, recalling that musl can static link nicely, I followed the Zig suggestion (as I interpreted it) and changed the triple to: aarch64-linux-musl. Unfortunately in reality things turned out to not be that simple.
At the moment you do indeed have to install the Android NDK and inform Zig about it through a libc.txt or similar (see zig libc). It’s possible Zig will have native support for bionic in the future.