libsdl-org / SDL

Simple Directmedia Layer
https://libsdl.org
zlib License
9.71k stars 1.8k forks source link

pkgconfig Requires.private changes between SDL2 and SDL3 #11112

Closed davexunit closed 1 week ago

davexunit commented 1 week ago

I'm working with commit 596fcfa6c4fd20e5a952c0a1b0147f2fa9f69198 from main in anticipation of SDL3's official release (for both packaging in the Guix Linux distro and writing language wrappers) and having trouble with the sdl3.pc pkgconfig file being generated.

Relevant context: I'm compiling with GCC 11.4.0 with the following CMake flags so that SDL links against specific libraries rather than trying to dlopen at runtime:

-DSDL_ALSA_SHARED=OFF
-DSDL_PULSEAUDIO_SHARED=OFF
-DSDL_PIPEWIRE_SHARED=OFF
-DSDL_X11_SHARED=OFF
-DSDL_WAYLAND_SHARED=OFF
-DSDL_KMSDRM_SHARED=OFF

Here's the contents of my sdl3.pc:

prefix=${pcfiledir}/../..
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include

Name: sdl3
Description: Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer.
URL: https://www.libsdl.org/
Version: 3.1.3
Requires.private: alsa libpipewire-0.3 >= 0.3.44 libpulse >= 0.9.15 x11 xext xcursor xrandr libdrm gbm wayland-client >= 1.18 wayland-egl wayland-cursor egl xkbcommon >= 0.5.0
Conflicts:
Libs: -L${libdir} -Wl,-rpath,${libdir} -Wl,--enable-new-dtags -lSDL3 
Libs.private: -pthread -lm
Cflags: -I${includedir} 

Should the Requires.private line have all these things in it if my libSDL3.so is linked against all the relevant libraries? For contrast, the sdl2.pc file on my system (from upstream Guix's sdl2 package, built with the equivalent -D flags) is:

# sdl pkg-config source file

prefix=/gnu/store/gfgz7ylz1jja9qcm1fjqyjrx1lz88i3h-sdl2-2.30.1
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include

Name: sdl2
Description: Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer.
Version: 2.30.1
Requires.private: 
Conflicts:
Libs: -L${libdir} -Wl,-rpath,${libdir} -Wl,--enable-new-dtags -lSDL2 
Libs.private:  -lm  -lasound -lm -ldl -lpthread -L/gnu/store/747pc21xckzr5hvpnc1k86hfs5q8a18y-pulseaudio-16.1/lib -lpulse -pthread  -lX11 -lXext -lXcursor -lXrandr -L/gnu/store/z9d9l2hvkzknxnavnqz6wiz2pwl451jk-libdrm-2.4.120/lib -ldrm -L/gnu/store/p1886myn15762wbmzrdp6lyx85vjqwvh-mesa-24.0.4/lib -lgbm -L/gnu/store/zb3831v93l0l2sdbaz5fb5i29ix86fr7-libxkbcommon-1.6.0/lib -L/gnu/store/wz3q862kc7czls6iws2qr5vz3lrarbjw-wayland-1.22.0/lib -lwayland-egl -lwayland-client -lwayland-cursor -lxkbcommon -lpthread
Cflags: -I${includedir} -I${includedir}/SDL2   -D_REENTRANT

Note the empty Requires.private line.

This difference becomes significant when I try to bootstrap an autotools project with this in configure.ac:

PKG_CHECK_MODULES([SDL3], [sdl3])

When building in an environment with sdl3.pc but not the .pc files of dependencies on PKG_CONFIG_PATH, I get an error:

checking for sdl3... no
configure: error: Package requirements (sdl3) were not met:

Package 'alsa', required by 'sdl3', not found

The equivalent check for SDL2 works fine because it doesn't need all the dependent .pc files. This is the property I'd like to have for SDL3, as well. Is there an additional CMake flag I should be using or something? I took a look at the build system files but if it's there I missed it.

(p.s: Having a great time with SDL3 so far. The GPU API is a very welcomed addition!)

slouken commented 1 week ago

That sounds like it's doing the right thing here. If you're linking directly to those libraries, then your built library has those dependencies, and if they're not installed, SDL won't run.

davexunit commented 1 week ago

Hi @slouken, the libraries are installed, it's just that Guix (and also Nix) do not conform to the FHS and use the runpath mechanism to hardcode the path to the libraries. Thus there's no need to search for them with pkgconfig. It would be very cumbersome to have to drag those .pc files along in this context, and something that is not needed for other C libraries packaged in Guix. I'm not a CMake nor a pkgconfig expert, but I do know that SDL2 does the right thing without any intervention here. Perhaps it's not an issue with Requirements.private but Libs.private. I will poke around a bit more.

slouken commented 1 week ago

It sounds like you want to include a patch in your distro packaging to prevent including dependencies in sdl3.pc. It doesn't sound like that's a change we generally want to make upstream.

madebr commented 1 week ago

Requires.private, Cflags.private and Libs.private are only used when you want to link to a static SDL3 library. By adding --static to the call to pkg-config/pkgconf.

Reading pkgconf's implementation of the autoconf macros, --static is only added when using PKG_CHECK_MODULES_STATIC instead of PKG_CHECK_MODULES.

davexunit commented 1 week ago

FWIW pkgconfig is being invoked like this: pkg-config --short-errors --print-errors --cflags --libs sdl3. I'll continue debugging under the assumption that there's something on my end that's wrong.

smcv commented 1 week ago

Requires.private, Cflags.private and Libs.private are only used when you want to link to a static SDL3 library.

That's not 100% true. Requires.private and Cflags.private are also used for pkg-config --cflags during dynamic linking, because pkg-config/pkgconf can't tell the difference between these two scenarios:

So it pessimistically assumes the stronger dependency (the first one). This is actually unnecessarily strict for SDL, but pkg-config/pkgconf doesn't have enough information to know that for sure.

.private libraries are not included in pkg-config --libs, to avoid "overlinking". For example, when you build a SDL game, the game doesn't need to be linked to -lX11 unless it explicitly calls libX11 functions itself. libX11 gets loaded into its process space indirectly, via SDL's DT_NEEDED ELF header, or the equivalent in non-ELF environments.

The only two solutions I'm aware of for this are:

  1. Do nothing, and require distros to deal with it.
    • In distros that use an ordinary GNU-style ${prefix}, this is just a matter of adding dependencies, for example in Debian I made libsdl3-dev depend on libx11-dev and many others.
    • In Guix/NixOS, this would additionally require adding all the dependencies to the PKG_CONFIG_PATH. Your distro presumably already has a mechanism to do this, somehow, otherwise you wouldn't be able to package (for example) GTK.
  2. Or, instead of the implementation-detail dependencies being a pkg-config filename like alsa or x11 in Requires.private, move them to being a library name like -lasound or -lX11 in Libs.private.
davexunit commented 1 week ago

Thanks for helping me get my head on straight to debug this properly. The differences between the generated .pc files between SDL2 and SDL3 threw me for a loop, but your replies helped me get a better understanding of what I was looking at. You're all right that sdl3.pc is fine just the way it is. The pattern we need to use in Guix to handle situations where a library depends on the .pc files of their dependencies is to mark those dependencies as propagated so PKG_CONFIG_PATH can be set correctly. Thanks again! Closing.