Hi, back from vacation and catching up here.
Really cool ![]()
For my linux desktop app library hobby project, when using wayland I load libwayland-client.so.0 (and others like libwayland-cursor.so.0) thanks to the dynamic loader and use zig-wayland as bindings. I assume these helper libraries are present anyway when a wayland display is active. I really should add a wayland-vulkan-triangle example in the dynamic loader repo to illustrate this.
Again, I personally will load libpulse.so.0 using the dynamic loader when it is present on the user’s system.
The philosophy of my app framework diverges a bit from what Andrew is doing / proposing here: he skips using a client dynamic library if possible for a given functionality (by implementing it in zig), whereas I prefer using the system provided one through handcrafted bindings. The static dlopen approach with optional runtime probing is my go to now, and it serves me very well. Having dlopen implemented in zig is so nice, and the fact that it is at all possible to load dynamic libraries from a static executable is such a breath of fresh air to me. I tried this many times before, and now that it works (with thread local storage, with good stack traces thanks to the customizable SelfInfo, etc.) it makes me think it will finally be possible to easily solve any problems related to the diversity of linux distributions. To me, the fact that by default a zig program on linux is not linked to libc without giving up any feature is a blessing, and it is this very fact that makes zig special for this use case. If I understand correctly, rust standard library just needs libc, and with go, calling foreign functions will also require it one way or another (I might be wrong here). And I suspect TLS will be a problem anyway in other languages. There is this line in the dynamic loader:
std.os.linux.tls.area_desc = new_tls_area_desc;
This is what makes it possible to correctly “colocate” TLS between C and zig. Maybe the fact that TLS handling on linux is in std lib and that std.os.linux.tls.area_desc is a public declaration is accidental, but I think that in other languages chances are that it will be much more closed than that.
Absolutely. This is my core motivation. I can accept that a system library is distributed as a dynamic library by an OS, and that this dynamic library is also linked to an OS tailored libc with the right version, etc., but I disagree that an end user should have to compile a program on their OS (or be basically forced to use a system distributed version of this program) to make it work. The logical conclusion is that you, as a developer, should avoid linking your program to a system provided resource, even if it is libc. Instead, you should be able to load it into your process address space and call its functions transparently.
I think having dlopen from non-libc static executables makes it a non issue: libvulkan (or opengl, egl, etc.) is provided by the end user’s hardware drivers, the program will just load it at runtime (and thus will theoretically not depend on any specifics of it at compile time) and make use of it :).
As a side note, if this vision gains some traction, I’d be willing to implement the same functionality for aarch64. As I don’t personally own a machine with such a CPU, I suspect the first step will be learning how to properly run an aarch64 system on an x86_64 one using qemu or something.
Also, if I may, I would like to bring attention to this topic and this issue, as I very often depend on “cross module” stack traces quality ![]()