[tracker/wip/carlosg/two-spoonfuls-of-soup] libtracker-sparql: Allow building against multiple versions of libsoup




commit dc99d92836e55aa68dccc0dea0ebd228bbb048ac
Author: Carlos Garnacho <carlosg gnome org>
Date:   Wed Jul 28 12:53:47 2021 +0200

    libtracker-sparql: Allow building against multiple versions of libsoup
    
    Tracker is an innocent bystander hindering libsoup3 port, since the
    libsoup2/3->tracker->gtk3 dependency chain imposes a libsoup version,
    graphical applications using libsoup cannot port at their own pace.
    
    Make our remote code (connection & endpoint) be a private module
    that is built against both versions of libsoup (if found), then we
    pick one at runtime, with a preference on libsoup3 if libsoup2 .so
    file is not seen in the already loaded libraries.
    
    This patch should be reverted ASAP, once we can consider libsoup2
    deprecated.
    
    Fixes: https://gitlab.gnome.org/GNOME/tracker/-/issues/320

 config.h.meson.in                             |   3 +
 meson.build                                   |  27 ++++--
 meson_options.txt                             |   4 +-
 src/libtracker-sparql/meson.build             |  58 ++++++++++++-
 src/libtracker-sparql/remote/meson.build      |  36 --------
 src/libtracker-sparql/tracker-backend.vala    |   5 --
 src/libtracker-sparql/tracker-remote-module.c | 115 ++++++++++++++++++++++++++
 7 files changed, 194 insertions(+), 54 deletions(-)
---
diff --git a/config.h.meson.in b/config.h.meson.in
index 9d1439e91..4aff15f72 100644
--- a/config.h.meson.in
+++ b/config.h.meson.in
@@ -57,3 +57,6 @@
 
 /* Define to the Tracker minor version */
 #mesondefine TRACKER_MINOR_VERSION
+
+/* Whether RTLD_NOLOAD is defined */
+#mesondefine HAVE_RTLD_NOLOAD
diff --git a/meson.build b/meson.build
index aae611bca..ed8fdd3ff 100644
--- a/meson.build
+++ b/meson.build
@@ -1,6 +1,6 @@
 project('tracker', 'c', 'vala',
         version: '3.2.0.alpha.1',
-        meson_version: '>=0.51',
+        meson_version: '>=0.56',
         default_options: [
           'c_std=c99',
           'warning_level=2'])
@@ -44,6 +44,7 @@ sqlite_required = '3.15.0'
 gio = dependency('gio-2.0', version: '>' + glib_required)
 gio_unix = dependency('gio-unix-2.0', version: '>' + glib_required)
 glib = dependency('glib-2.0', version: '>' + glib_required)
+gmodule = dependency('gmodule-2.0', version: '>' + glib_required)
 gobject = dependency('gobject-2.0', version: '>' + glib_required)
 gobject_introspection = dependency('gobject-introspection-1.0', required: get_option('introspection'))
 icu_i18n = dependency('icu-i18n', version: '> 4.8.1.1', required: false)
@@ -52,14 +53,23 @@ json_glib = dependency('json-glib-1.0', version: '>= 1.4', required: true)
 libxml2 = dependency('libxml-2.0', version: '> 2.6')
 sqlite = dependency('sqlite3', version: '>' + sqlite_required)
 dbus = dependency('dbus-1')
+libsoup2 = dependency('libsoup-2.4', version: '> 2.40', required: false)
+libsoup3 = dependency('libsoup-3.0', version: '>= 2.99.2', required: false)
 
-if get_option('soup2')
-  libsoup = dependency('libsoup-2.4', version: '> 2.40', required: true)
-else
-  libsoup = dependency('libsoup-3.0', version: '>= 2.99.2', required: true)
+libmath = cc.find_library('m', required: false)
+libdl = cc.find_library('dl')
+
+soup_backends = ''
+if libsoup2.found()
+  soup_backends = soup_backends + '2.x '
+endif
+if libsoup3.found()
+  soup_backends = soup_backends + '3.x '
 endif
 
-libmath = cc.find_library('m', required: false)
+if not libsoup2.found() and not libsoup3.found()
+  error('At least one of libsoup2 or libsoup3 is required')
+endif
 
 if get_option('man')
   asciidoc = find_program('asciidoc')
@@ -293,6 +303,10 @@ conf.set('TRACKER_MICRO_VERSION', tracker_micro_version)
 conf.set('TRACKER_INTERFACE_AGE', 0)
 conf.set('TRACKER_BINARY_AGE', 100 * tracker_minor_version + tracker_micro_version)
 
+# Check for RTLD_NOLOAD
+have_rtld_noload = cc.has_header_symbol('dlfcn.h', 'RTLD_NOLOAD')
+conf.set('HAVE_RTLD_NOLOAD', have_rtld_noload)
+
 # Config that goes in some other generated files (.desktop, .service, etc)
 conf.set('abs_top_builddir', meson.current_build_dir())
 conf.set('libexecdir', join_paths(get_option('prefix'), get_option('libexecdir')))
@@ -387,6 +401,7 @@ summary = [
   '    Build with Stemming support:            ' + have_libstemmer.to_string(),
   '    API documentation:                      ' + get_option('docs').to_string(),
   '    CLI documentation (manpages):           ' + get_option('man').to_string(),
+  '    Libsoup backends:                       ' + soup_backends,
 ]
 
 if get_option('bash_completion')
diff --git a/meson_options.txt b/meson_options.txt
index a5cccb891..a7e647d02 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -26,7 +26,5 @@ option('test_utils_dir', type: 'string', value: '',
        description: 'Directory to install trackertestutils Python package (or empty to use the default)')
 option('tests_tap_protocol', type: 'boolean', value: false,
        description: 'Whether to enable TAP protocol on tests')
-option('soup2', type: 'boolean', value: true,
-       description: 'Whether to build with libsoup2')
 option('introspection', type: 'feature', value: 'enabled',
-       description: 'Whether to enable introspection')
\ No newline at end of file
+       description: 'Whether to enable introspection')
diff --git a/src/libtracker-sparql/meson.build b/src/libtracker-sparql/meson.build
index 6fcc8a667..5cd8e613e 100644
--- a/src/libtracker-sparql/meson.build
+++ b/src/libtracker-sparql/meson.build
@@ -20,7 +20,6 @@ libtracker_sparql_c_sources = files(
     'tracker-cursor.c',
     'tracker-endpoint.c',
     'tracker-endpoint-dbus.c',
-    'tracker-endpoint-http.c',
     'tracker-error.c',
     'tracker-namespace-manager.c',
     'tracker-notifier.c',
@@ -54,7 +53,7 @@ libtracker_sparql_c_public_headers = files(
 libtracker_sparql_intermediate = static_library('tracker-sparql-intermediate',
     enum_types,
     libtracker_sparql_c_sources,
-    dependencies: [tracker_common_dep, json_glib, libxml2, libsoup],
+    dependencies: [tracker_common_dep, json_glib, libxml2],
     gnu_symbol_visibility: 'hidden',
 )
 
@@ -88,13 +87,61 @@ install_data(
 
 subdir('bus')
 subdir('direct')
-subdir('remote')
+
+tracker_remote_dependencies = [json_glib, libxml2]
+
+remote_sources = [
+    'tracker-endpoint-http.c',
+    'remote/tracker-json-cursor.vala',
+    'remote/tracker-xml-cursor.vala',
+    'remote/tracker-remote.vala',
+]
+
+if libsoup2.found()
+    libtracker_remote = shared_module('tracker-remote-soup2', remote_sources,
+        dependencies: tracker_remote_dependencies + [tracker_common_dep, tracker_sparql_intermediate_dep, 
libsoup2],
+        c_args: tracker_c_args + [
+            '-include', 'config.h',
+            '-include', 'libtracker-sparql/tracker-private.h',
+        ],
+        vala_args: [
+            '--debug',
+            '--pkg', 'posix',
+            # FIXME: Meson has code to add --target-glib automatically, but it
+            # doesn't seem to work here.
+            '--target-glib', glib_required,
+            '--define=SOUP2',
+        ],
+        install: true,
+        install_dir: tracker_internal_libs_dir,
+    )
+endif
+
+if libsoup3.found()
+    libtracker_remote = shared_module('tracker-remote-soup3', remote_sources,
+        dependencies: tracker_remote_dependencies + [tracker_common_dep, tracker_sparql_intermediate_dep, 
libsoup3],
+        c_args: tracker_c_args + [
+            '-include', 'config.h',
+            '-include', 'libtracker-sparql/tracker-private.h',
+        ],
+        vala_args: [
+            '--debug',
+            '--pkg', 'posix',
+            # FIXME: Meson has code to add --target-glib automatically, but it
+            # doesn't seem to work here.
+            '--target-glib', glib_required,
+        ],
+        install: true,
+        install_dir: tracker_internal_libs_dir,
+    )
+endif
 
 libtracker_sparql = library('tracker-sparql-' + tracker_api_version,
     '../libtracker-common/libtracker-common.vapi',
     '../libtracker-data/libtracker-data.vapi',
     'direct/tracker-direct.vapi',
     'tracker-backend.vala',
+    'tracker-remote-module.c',
     tracker_gresources,
 
     gnu_symbol_visibility: 'hidden',
@@ -107,11 +154,14 @@ libtracker_sparql = library('tracker-sparql-' + tracker_api_version,
 
     c_args: [
        '-include', 'libtracker-sparql/tracker-private.h',
+        '-DPRIVATE_LIBDIR="@0@"'.format(tracker_internal_libs_dir),
+        '-DBUILD_LIBDIR="@0@"'.format(meson.current_build_dir()),
+        '-DBUILDROOT="@0@"'.format(meson.project_build_root()),
     ],
 
     link_whole: [libtracker_sparql_intermediate],
 
-    dependencies: [tracker_common_dep, tracker_sparql_remote_dep, tracker_sparql_bus_dep, 
tracker_sparql_direct_dep, tracker_sparql_vapi_dep],
+    dependencies: [tracker_common_dep, tracker_sparql_bus_dep, tracker_sparql_direct_dep, 
tracker_sparql_vapi_dep, gmodule, libdl],
 )
 
 tracker_sparql_dep = declare_dependency(
diff --git a/src/libtracker-sparql/tracker-backend.vala b/src/libtracker-sparql/tracker-backend.vala
index ae6313118..af1102d5a 100644
--- a/src/libtracker-sparql/tracker-backend.vala
+++ b/src/libtracker-sparql/tracker-backend.vala
@@ -22,11 +22,6 @@
  * effect of printing the 'help' message if TRACKER_DEBUG=help is set.
  */
 
-public static Tracker.Sparql.Connection tracker_sparql_connection_remote_new (string url_base) {
-       Tracker.get_debug_flags ();
-       return new Tracker.Remote.Connection (url_base);
-}
-
 public static Tracker.Sparql.Connection tracker_sparql_connection_bus_new (string service, string? 
object_path, DBusConnection? conn) throws Tracker.Sparql.Error, IOError, DBusError, GLib.Error {
        Tracker.get_debug_flags ();
 
diff --git a/src/libtracker-sparql/tracker-remote-module.c b/src/libtracker-sparql/tracker-remote-module.c
new file mode 100644
index 000000000..2ca0fd181
--- /dev/null
+++ b/src/libtracker-sparql/tracker-remote-module.c
@@ -0,0 +1,115 @@
+/* Yuck */
+
+#include "config.h"
+
+#include <gio/gio.h>
+#include <tracker-sparql.h>
+#include <dlfcn.h>
+
+#define LIBSOUP_2_SONAME "libsoup-2.4.so.1"
+
+static gboolean initialized = FALSE;
+
+GType (* remote_endpoint_get_type) (void) = NULL;
+
+TrackerEndpoint * (* remote_endpoint_new) (TrackerSparqlConnection  *sparql_connection,
+                                           guint                     port,
+                                           GTlsCertificate          *certificate,
+                                           GCancellable             *cancellable,
+                                           GError                  **error) = NULL;
+TrackerSparqlConnection * (* remote_connection_new) (const gchar *url_base) = NULL;
+
+static void
+tracker_init_remote (void)
+{
+       const char *modules[3] = { 0 };
+       gpointer handle = NULL;
+       gint i = 0;
+
+       if (initialized)
+               return;
+
+       g_assert (g_module_supported ());
+
+#ifdef HAVE_RTLD_NOLOAD
+       if ((handle = dlopen (LIBSOUP_2_SONAME, RTLD_NOW | RTLD_NOLOAD))) {
+               /* Force load of soup2 module */
+               modules[0] = "libtracker-remote-soup2.so";
+       } else
+#endif
+       {
+               modules[0] = "libtracker-remote-soup3.so";
+               modules[1] = "libtracker-remote-soup2.so";
+       }
+
+       g_clear_pointer (&handle, dlclose);
+
+       for (i = 0; modules[i]; i++) {
+               GModule *remote_module;
+               gchar *module_path;
+
+               if (g_strcmp0 (g_get_current_dir (), BUILDROOT) == 0) {
+                       /* Detect in-build runtime of this code, this may happen
+                        * building introspection information or running tests.
+                        * We want the in-tree modules to be loaded then.
+                        */
+                       module_path = g_strdup_printf (BUILD_LIBDIR "/%s", modules[i]);
+               } else {
+                       module_path = g_strdup_printf (PRIVATE_LIBDIR "/%s", modules[i]);
+               }
+
+               remote_module = g_module_open (module_path,
+                                              G_MODULE_BIND_LAZY |
+                                              G_MODULE_BIND_LOCAL);
+               g_free (module_path);
+
+               if (!remote_module)
+                       continue;
+
+               if (!g_module_symbol (remote_module, "tracker_endpoint_http_get_type", (gpointer *) 
&remote_endpoint_get_type) ||
+                   !g_module_symbol (remote_module, "tracker_endpoint_http_new", (gpointer *) 
&remote_endpoint_new) ||
+                   !g_module_symbol (remote_module, "tracker_remote_connection_new", (gpointer *) 
&remote_connection_new)) {
+                       g_clear_pointer (&remote_module, g_module_close);
+                       continue;
+               }
+
+               g_module_make_resident (remote_module);
+               g_module_close (remote_module);
+               initialized = TRUE;
+               return;
+       }
+
+       g_assert_not_reached ();
+}
+
+GType
+tracker_endpoint_http_get_type (void)
+{
+       tracker_init_remote ();
+
+       return remote_endpoint_get_type ();
+}
+
+TrackerEndpointHttp *
+tracker_endpoint_http_new (TrackerSparqlConnection  *sparql_connection,
+                           guint                     port,
+                           GTlsCertificate          *certificate,
+                           GCancellable             *cancellable,
+                           GError                  **error)
+{
+       tracker_init_remote ();
+
+       return (TrackerEndpointHttp *) remote_endpoint_new (sparql_connection,
+                                                           port,
+                                                           certificate,
+                                                           cancellable,
+                                                           error);
+}
+
+TrackerSparqlConnection *
+tracker_sparql_connection_remote_new (const gchar *url_base)
+{
+       tracker_init_remote ();
+
+       return remote_connection_new (url_base);
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]