Bug: CMake Linux tooling should not link plugins against libwebkit2gtk

I have a plugin configured to use a webview for UI. With the JUCE CMake tools, this looks like:

juce_add_plugin(MyPlugin
        IS_SYNTH TRUE
        NEEDS_MIDI_INPUT TRUE
        NEEDS_WEB_BROWSER TRUE
        NEEDS_CURL TRUE
        # ...etc
)

On Linux, JUCE does the correct thing and launches the actual WebKit X window in a subprocess, with an especially elegant solution of dlopen’ing the original plugin shared library which does dlsym dynamic lookups of webkit symbols. The point of all this is to prevent symbol conflicts with the GUI library the host might be using, especially hosts that use GTK2.

But. It turns out the plugin still directly links against these libraries! This defeats most of the point of doing the above subprocess technique:

$ readelf -d MyPlugin_artefacts/RelWithDebInfo/VST3/MyPlugin.vst3/Contents/x86_64-linux/MyPlugin.so | grep 'NEEDED'
 0x0000000000000001 (NEEDED)             Shared library: [libcurl.so.4]
 0x0000000000000001 (NEEDED)             Shared library: [libwebkit2gtk-4.1.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libharfbuzz.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libpangocairo-1.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libpango-1.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libsoup-3.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libgmodule-2.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libjavascriptcoregtk-4.1.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libglib-2.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libgobject-2.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libgtk-3.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libgdk-3.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libz.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libatk-1.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libcairo.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libcairo-gobject.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libgdk_pixbuf-2.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libgio-2.0.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libblas.so.3]
 0x0000000000000001 (NEEDED)             Shared library: [liblapack.so.3]
 0x0000000000000001 (NEEDED)             Shared library: [libarpack.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libfontconfig.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libfreetype.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libasound.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libatomic.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [ld-linux-x86-64.so.2]

The root cause of this is that the CMake helper is propagating pkgconfig’s specified link libraries, which is normally what is wanted but in this case, again, defeats the point of the dlsym dynamic symbol lookups JUCE goes to so much trouble to do.

The following quick and dirty experiment skips adding the LINK_LIBRARIES for the browser (yes, this can be improved - goal is just to demonstrate the root of the problem):

diff --git a/extras/Build/CMake/JUCEModuleSupport.cmake b/extras/Build/CMake/JUCEModuleSupport.cmake
index cac20db12..82234c802 100644
--- a/extras/Build/CMake/JUCEModuleSupport.cmake
+++ b/extras/Build/CMake/JUCEModuleSupport.cmake
@@ -381,7 +381,10 @@ function(_juce_create_pkgconfig_target name)
         list(GET pair 1 value)
 
         if(${name}_${value})
-            set_target_properties(pkgconfig_${name} PROPERTIES INTERFACE_${key} "${${name}_${value}}")
+            if(NOT (name STREQUAL JUCE_BROWSER_LINUX_DEPS AND key STREQUAL LINK_LIBRARIES))
+                set_target_properties(pkgconfig_${name} PROPERTIES INTERFACE_${key} "${${name}_${value}}")
+            endif()
         endif()
     endforeach()
 endfunction()

which makes the linked libraries look much nicer (and the web UI continues to work):

$ readelf -d MyPlugin_artefacts/RelWithDebInfo/VST3/MyPlugin.vst3/Contents/x86_64-linux/MyPlugin.so | grep 'NEEDED'
 0x0000000000000001 (NEEDED)             Shared library: [libcurl.so.4]
 0x0000000000000001 (NEEDED)             Shared library: [libblas.so.3]
 0x0000000000000001 (NEEDED)             Shared library: [liblapack.so.3]
 0x0000000000000001 (NEEDED)             Shared library: [libarpack.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libfontconfig.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libfreetype.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libasound.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libatomic.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [ld-linux-x86-64.so.2]

I consider this behavior a bug; is the direct linking intended? Is there something I am missing? Or can this be fixed? Thanks!

1 Like

This could be an oversight, thank you for reporting this. We’ll take a closer look.

1 Like

A fix has been released on develop

2 Likes

We received a report from a Linux user with some similar issue.

Since the JUCE 8 update, the plugin crashes because of the dependency on libfontconfig. Is it possible to remove the link to this library too? It wasn’t required with JUCE 7.

Set the preprocessor definition JUCE_USE_FONTCONFIG=0. This will break font fallback behaviour.

1 Like

I wonder if you recommend to disable it. Are there any drawbacks when we use embedded fonts? Probably with Japanese characters?

If you allow your users to enter arbitrary text anywhere, e.g. when naming presets or macro dials, it’s probably a good idea to leave fontconfig enabled so that typeface substitution will work. This way, if your bundled font doesn’t include a character that the user typed (and they might type things like emoji), fontconfig can suggest a good substitute font from the system that’s able to render the character.

I’m quite surprised that your user’s system doesn’t already have fontconfig installed. I was under the impression that this is the main mechanism for resolving fallback fonts on linux, so I’d expect most non-headless systems to include it. I’d be interested to know whether the user is on a mainstream distro.

That’s good to know. There are preset and folder names we show in the UI. I think it’s better to keep it enabled then.

The user has installed NixOS. It looks like it is missing that package. Not sure if it can be installed afterward.