Skip to content

Latest commit

 

History

History
42 lines (33 loc) · 3.41 KB

linking.md

File metadata and controls

42 lines (33 loc) · 3.41 KB

GTK4 Layer Shell Linking Weirdness

TL;DR

The dynamic linker needs to load libgtk4-layer-shell.so before libwayland-client.so.

My code doesn't work, help!

C/C++ (and other compiled languages)

In your build system, make sure gtk4-layer-shell is explicitly linked to and first in the list. For example in meson it should appear first in the list of dependencies to your executable. To debug where a problem might be follow these steps:

  1. Inspect the compiler commands (for example by running ninja -C build -v) and make sure gtk4-layer-shell is being linked before libwayland-client (ideally before GTK as well, though that doesn't seem to be necessary)
  2. Run ldd on your binary and make sure gtk4-layer-shell appears before libwayland
  3. Run your binary with LD_DEBUG=libs and make sure gtk4-layer-shell is loaded before libwayland. It may be helpful to redirect stderr to stdout and grep for "find library", so a full command might look like LD_DEBUG=libs build/my-bin 2>&1 | grep 'find library='

Python

GI Repository likes to load all dependencies before loading a library, so you need to make sure this is at the top of your main script:

# For GTK4 Layer Shell to get linked before libwayland-client we must explicitly load it before importing with gi
from ctypes import CDLL
CDLL('libgtk4-layer-shell.so')

If that still isn't working you can debug with LD_DEBUG as described above.

LD_PRELOAD

You should be able to get most things working using the LD_PRELOAD environment variable. Run the program with it set to the path of gtk4-layer-shell:

LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libgtk4-layer-shell.so my-app

Underlying cause

At time of writing GTK4 has no official support for non-XDG Wayland shells (which is fair enough, since GTK3 only had partial broken support). To get around this we shim some libwayland calls. We define some symbols normally defined by libwayland, so that GTK calls into us when it thinks it's calling into libwayland. We dlopen the real libwayland and pass most calls directly on to it, while modifying calls that pertain to XDG Shell and Layer Shell. This allows us to provide GTK the XDG Shell interface it expects and speak Layer Shell to libwayland-client (and beyond that the Wayland compositor).

The main downside is that if libwayland gets loaded before us, it's calls take precedence and the shim doesn't work. We attempt to detect this and display a warning.

Triggering the error

Triggering the link error intentionally (for example for testing that the library detects it) can be difficult. You need at least the following:

  1. Build separate from the gtk4-layer-shell project. If your app is built within the project (even if it's a different executable) meson links our library first.
  2. Link libwayland-client before gtk4-layer-shell
  3. Make at least one call to libwayland in your app (otherwise your linking of libwayland-client is ignored)

Alternatively you can test by editing the CDLL call out of the example Python script and calling ninja -C build && GI_TYPELIB_PATH=$PWD/build/src LD_LIBRARY_PATH=$PWD/build/src python examples/simple-example.py.

Wayland Debug

Old versions of my wayland-debug tool set used LD_PRELOAD to load a patched libwayland, which breaks this library. wayland-debug has been updated to use LD_LIBRARY_PATH instead which seems to work fine. If you have any problems please let me know.