Subject: Re: zig: fail to link SDL2

From: Ekaitz Zarraga <[email-masked]>
Date: Wed, 01 Nov 2023 20:52:35 +0000

------- Original Message -------
On Monday, October 23rd, 2023 at 09:34, Nguyễn Gia Phong <[email-masked]> wrote:

> I am trying to package Mepo, an OpenStreetMap frontend written in Zig.
> The currently packaged Zig fails to find transitive dependencies of SDL2:
> https://paste.sr.ht/~cnx/db21e1ef9a6828f3ec898db43b790d71b5ef213a
> 
> Here's a minimal reproducible Zig project:
> 
> // main.zig
> const c = @cImport(@cInclude("SDL2/SDL.h"));
> pub fn main() !void {
> if (c.SDL_Init(c.SDL_INIT_VIDEO) != 0)
> return error.SDLInitializationFailed;
> c.SDL_Quit();
> }
> 
> // build.zig
> pub fn build(b: *@import("std").build.Builder) void {
> const exe = b.addExecutable("sdl2-smoke-test", "main.zig");
> exe.linkSystemLibrary("SDL2");
> exe.setTarget(b.standardTargetOptions(.{}));
> exe.setBuildMode(b.standardReleaseOptions());
> exe.install();
> }
> 
> For convenience, here goes a manifest for use with guix build -f:
> 
> (use-modules (guix build-system zig)
> (guix gexp)
> (guix licenses)
> (guix packages)
> (gnu packages pkg-config)
> (gnu packages sdl))
> (package
> (name "sdl2-smoke-test")
> (version "0.0.0")
> (source (local-file "." "sdl2-smoke-test" #:recursive? #t))
> (build-system zig-build-system)
> (arguments (list #:tests? #f
> #:zig-release-type "safe"))
> (native-inputs (list pkg-config))
> (inputs (list sdl2))
> (synopsis "Zig build system SDL2 linkage failure reproducer")
> (description
> (string-append "This is a reproducer of zig-build-system"
> " failing to link SDL2's transitive dependencies,"
> " as seen when trying to package mepo."))
> (home-page "https://larkspur.one/notice/Ab24w1IMGVoZ72J9xg")
> (license zlib))

Hi,

I have good and bad news for you.

I tried to replicate the problem, and I certainly did. I also managed to mitigate the problem adding `exe.linkSystemLibrary()` lines to the build.zig with the transitive dependencies.
And later I wondered how did this all work in GCC, just in case.

(NOTE: take in account you also need to link with libc! for that you can add it as a linkSystemLibrary("c"))

The problem is not Zig specific, look:

I tried a random example from a repo in Github using SDL2 and SDL2-Image: 
https://github.com/aminosbh/sdl2-image-sample/blob/master/src/main.c

Made a shell for it:

guix shell sdl2 sdl2-image gcc-toolchain glibc:static

And tried to build:

$ gcc a.c -static -lSDL2 -lSDL2_image -lm -lc 2>&1 | head
ld: /gnu/store/0mhh6ycg8dq6n43qwpvpvr2smbxlixpi-profile/lib/libSDL2.a(SDL_dynapi.o):(.text+0x27d8): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
ld: /gnu/store/0mhh6ycg8dq6n43qwpvpvr2smbxlixpi-profile/lib/libSDL2.a(SDL_waylandvideo.o):(.text+0x48f): undefined reference to `wl_proxy_get_version'
ld: /gnu/store/0mhh6ycg8dq6n43qwpvpvr2smbxlixpi-profile/lib/libSDL2.a(SDL_waylandvideo.o):(.text+0xd3e): undefined reference to `wl_proxy_get_version'
ld: /gnu/store/0mhh6ycg8dq6n43qwpvpvr2smbxlixpi-profile/lib/libSDL2.a(SDL_waylandvideo.o):(.text+0xd5a): undefined reference to `wl_proxy_marshal_flags'
ld: /gnu/store/0mhh6ycg8dq6n43qwpvpvr2smbxlixpi-profile/lib/libSDL2.a(SDL_waylandvideo.o):(.text+0xd73): undefined reference to `wl_proxy_add_listener'
ld: /gnu/store/0mhh6ycg8dq6n43qwpvpvr2smbxlixpi-profile/lib/libSDL2.a(SDL_waylandvideo.o):(.text+0xeb9): undefined reference to `wl_proxy_get_version'
ld: /gnu/store/0mhh6ycg8dq6n43qwpvpvr2smbxlixpi-profile/lib/libSDL2.a(SDL_waylandvideo.o):(.text+0xfa8): undefined reference to `wl_proxy_marshal_flags'
ld: /gnu/store/0mhh6ycg8dq6n43qwpvpvr2smbxlixpi-profile/lib/libSDL2.a(SDL_waylandvideo.o):(.text+0x1002): undefined reference to `wl_proxy_marshal_flags'
ld: /gnu/store/0mhh6ycg8dq6n43qwpvpvr2smbxlixpi-profile/lib/libSDL2.a(SDL_waylandvideo.o):(.text+0x1071): undefined reference to `wl_proxy_add_listener'
ld: /gnu/store/0mhh6ycg8dq6n43qwpvpvr2smbxlixpi-profile/lib/libSDL2.a(SDL_waylandvideo.o):(.text+0x107e): undefined reference to `wl_proxy_set_tag'

The list of errors are basically the same you have.
Zig builds statically if I'm not mistaken so it's triggering the same problem GCC would for that case.

We need to research this further...

I also checked Mepo, how do they manage to build directly?

I don't have the Zig knowledge to know how does all this work, but I know it's not just the build-system's fault because it happens in GCC too, and also with a normal shell with `zig` available, and running the command by hand. The build-system just replicates that behavior.

We need to dig on this further. Are you, Nguyễn, a Zig programmer? Maybe you can help me figure out this?

Thanks for the report, the patience and the help!

All the best,
Ekaitz