ges, gst-python: Rework libpython loading to be relocatable
authorNirbheek Chauhan <nirbheek@centricular.com>
Wed, 21 Feb 2024 04:24:22 +0000 (09:54 +0530)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Wed, 21 Feb 2024 21:47:12 +0000 (21:47 +0000)
If we don't specify a path for loading, the runtime linker will search
for the library instead, which will use the usual mechanisms: RPATHs,
LD_LIBRARY_PATH, PATH (on Windows), etc.

Also try harder to load a non-devel libpython using INSTSONAME, if
available.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6159>

subprojects/gst-editing-services/ges/ges-formatter.c
subprojects/gst-editing-services/meson.build
subprojects/gst-python/meson.build

index c5b39eb2de14a18d1f1f9bf6b2cbe94272e9b625..0db4f946846ed9509a45f8f7af402f92edf11c40 100644 (file)
@@ -566,10 +566,8 @@ load_python_formatters (void)
           "_Py_NoneStruct", &has_python) && has_python) {
     GST_LOG ("libpython is already loaded");
   } else {
-    const gchar *libpython_path =
-        PY_LIB_LOC "/libpython" PYTHON_VERSION PY_ABI_FLAGS "." PY_LIB_SUFFIX;
-    GST_LOG ("loading libpython from '%s'", libpython_path);
-    libpython = g_module_open (libpython_path, 0);
+    GST_LOG ("loading libpython by name: %s", PY_LIB_FNAME);
+    libpython = g_module_open (PY_LIB_FNAME, 0);
     if (!libpython) {
       GST_ERROR ("Couldn't g_module_open libpython. Reason: %s",
           g_module_error ());
index 13af8ec3e819f8062691b8895a23d980bcf41cad..3f91dd45c9315e1c2a0086c88cee732565e289ca 100644 (file)
@@ -144,73 +144,79 @@ gir_init_section = [ '--add-init-section=' + \
     'ges_init();', '--quiet']
 
 pymod = import('python')
-python = pymod.find_installation(required: get_option('python'))
+python_opt = get_option('python')
+python = pymod.find_installation(required: python_opt)
 has_python = false
 static_build = get_option('default_library') == 'static'
 if static_build
-  if get_option('python').enabled()
+  if python_opt.enabled()
     error('Want to build python based modules but it is not supported while static building')
   else
     message('Disabling python support as it is not supported on static builds')
   endif
-elif build_gir
-  if python.found()
-    # Workaround for https://github.com/mesonbuild/meson/issues/5629
-    pythonver = python.language_version()
-    python_dep = dependency('python-@0@-embed'.format(pythonver), version: '>=3',
-                            required: false, include_type: 'system')
-    if not python_dep.found()
-      python_dep = python.dependency(required : get_option('python'),
-                                     include_type: 'system')
-    endif
-  else
-    python_dep = dependency('', required: false)
-  endif
+elif build_gir and python.found()
+  python_dep = python.dependency(required : python_opt, embed: true,
+                                 include_type: 'system')
   if python_dep.found()
     python_abi_flags = python.get_variable('ABIFLAGS', '')
+    message(f'python_abi_flags = @python_abi_flags@')
     pylib_loc = get_option('libpython-dir')
 
     error_msg = ''
     if not cc.compiles('#include <Python.h>', dependencies: [python_dep])
       error_msg = 'Could not compile a simple program against python'
-    elif pylib_loc == ''
-      fsmod = import('fs')
-      pylib_loc = python.get_variable('LIBPL', '')
-      if host_system != 'windows' and host_system != 'darwin'
-        pylib_ldlibrary = python.get_variable('LDLIBRARY', '')
-        if not fsmod.exists(pylib_loc / pylib_ldlibrary)
-          # Workaround for Fedora
-          pylib_loc = python.get_variable('LIBDIR', '')
-          message('pylib_loc = @0@'.format(pylib_loc))
-        endif
-
-        if not fsmod.exists(pylib_loc / pylib_ldlibrary)
-          error_msg = '@0@ doesn\' exist, can\'t use python'.format(join_paths(pylib_loc, pylib_ldlibrary))
-        endif
+      if python_opt.enabled()
+        error(error_msg)
+      else
+        message(error_msg)
+      endif
+    endif
+    fsmod = import('fs')
+    pylib_prefix = 'lib'
+    pylib_suffix = 'so'
+    if host_system == 'windows'
+      if cc.get_argument_syntax() == 'msvc'
+        pylib_prefix = ''
       endif
-      if error_msg == ''
-        pylib_suffix = 'so'
-        if host_system == 'windows'
-          pylib_suffix = 'dll'
-        elif host_system == 'darwin'
-          pylib_suffix = 'dylib'
+      pylib_suffix = 'dll'
+    elif host_system == 'darwin'
+      pylib_suffix = 'dylib'
+    endif
+    pylib_fnames = []
+    # Library name with soversion, non-devel package
+    pylib_fnames += python.get_variable('INSTSONAME', [])
+    # Library name without soversion, devel package, framework, etc.
+    pylib_fnames += python.get_variable('LDLIBRARY', [])
+    # Manually construct name as a fallback
+    pylib_fnames += [
+      pylib_prefix + 'python' + python_dep.version() + python_abi_flags + '.' + pylib_suffix
+    ]
+    if pylib_loc != ''
+      pylib_locs = [pylib_loc]
+    else
+      pylib_locs = [
+        python.get_variable('LIBDIR', ''),
+        python.get_variable('LIBPL', ''),
+      ]
+    endif
+    foreach loc: pylib_locs
+      foreach fname: pylib_fnames
+        if fsmod.exists(loc / fname)
+          libges_deps = libges_deps + [python_dep, gmodule_dep]
+          has_python = true
+          cdata.set('HAS_PYTHON', true)
+          cdata.set_quoted('PY_LIB_FNAME', fname)
+          message(f'PY_LIB_FNAME = @fname@ (@loc@)')
+          break
         endif
-
-        libges_deps = libges_deps + [python_dep, gmodule_dep]
-        has_python = true
-        message('python_abi_flags = @0@'.format(python_abi_flags))
-        message('pylib_loc = @0@'.format(pylib_loc))
-        cdata.set('HAS_PYTHON', true)
-        cdata.set('PY_LIB_LOC', '"@0@"'.format(pylib_loc))
-        cdata.set('PY_ABI_FLAGS', '"@0@"'.format(python_abi_flags))
-        cdata.set('PY_LIB_SUFFIX', '"@0@"'.format(pylib_suffix))
-        cdata.set('PYTHON_VERSION', '"@0@"'.format(python_dep.version()))
+      endforeach
+    endforeach
+    if not has_python
+      error_msg = 'Could not find python library to load'
+      if python_opt.enabled()
+        error(error_msg)
       else
-          if get_option('python').enabled()
-            error(error_msg)
-          else
-            message(error_msg)
-          endif
+        message(error_msg)
       endif
     endif
   endif
index 3eb2d7dfab25737d2840ac9715511ef0cc43642f..432b3475b9d3098e1ef41e9a73c5a5e1f9190be7 100644 (file)
@@ -10,6 +10,8 @@ version_arr = gst_version.split('.')
 gst_version_major = version_arr[0]
 gst_version_minor = version_arr[1]
 api_version = '@0@.0'.format(gst_version_major)
+host_system = host_machine.system()
+cc = meson.get_compiler('c')
 
 add_project_arguments('-DHAVE_CONFIG_H', language: 'c')
 
@@ -33,30 +35,58 @@ if pythonver.version_compare('<3.7')
 endif
 
 
-python_dep = python.dependency(embed:true, required : true)
+python_dep = python.dependency(embed: true, required: true)
 
 python_abi_flags = python.get_variable('ABIFLAGS', '')
+message(f'python_abi_flags = @python_abi_flags@')
 pylib_loc = get_option('libpython-dir')
-if pylib_loc == ''
-  fsmod = import('fs')
-  pylib_loc = python.get_variable('LIBPL', '')
-  if host_machine.system() != 'windows' and host_machine.system() != 'darwin'
-    pylib_ldlibrary = python.get_variable('LDLIBRARY', '')
-    if not fsmod.exists(pylib_loc / pylib_ldlibrary)
-      # Workaround for Fedora
-      pylib_loc = python.get_variable('LIBDIR', '')
-      message('pylib_loc = @0@'.format(pylib_loc))
-    endif
-
-    if not fsmod.exists(pylib_loc / pylib_ldlibrary)
-      error('Python dynamic library path could not be determined')
+fsmod = import('fs')
+pylib_prefix = 'lib'
+pylib_suffix = 'so'
+if host_system == 'windows'
+  if cc.get_argument_syntax() == 'msvc'
+    pylib_prefix = ''
+  endif
+  pylib_suffix = 'dll'
+elif host_system == 'darwin'
+  pylib_suffix = 'dylib'
+endif
+pylib_fnames = []
+# Library name with soversion, non-devel package
+pylib_fnames += python.get_variable('INSTSONAME', [])
+# Library name without soversion, devel package, framework, etc.
+pylib_fnames += python.get_variable('LDLIBRARY', [])
+# Manually construct name as a fallback
+pylib_fnames += [
+  pylib_prefix + 'python' + python_dep.version() + python_abi_flags + '.' + pylib_suffix
+]
+if pylib_loc != ''
+  pylib_locs = [pylib_loc]
+else
+  pylib_locs = [
+    python.get_variable('LIBDIR', ''),
+    python.get_variable('LIBPL', ''),
+  ]
+endif
+pylib_fname = ''
+foreach loc: pylib_locs
+  foreach fname: pylib_fnames
+    if fsmod.exists(loc / fname)
+      pylib_fname = fname
+      message(f'PY_LIB_FNAME = @fname@ (@loc@)')
+      break
     endif
+  endforeach
+endforeach
+if pylib_fname == ''
+  error_msg = 'Could not find python library to load'
+  if python_opt.enabled()
+    error(error_msg)
+  else
+    message(error_msg)
   endif
 endif
 
-message('python_abi_flags = @0@'.format(python_abi_flags))
-message('pylib_loc = @0@'.format(pylib_loc))
-
 pygi_override_dir = get_option('pygi-overrides-dir')
 
 if pygi_override_dir == ''
@@ -71,13 +101,6 @@ message('pygobject overrides directory = @0@'.format(pygi_override_dir))
 # libdir has to be built from pieces.
 libdir = get_option('prefix')+'/'+get_option('libdir')
 
-
-pylib_suffix = 'so'
-if host_machine.system() == 'windows'
-  pylib_suffix = 'dll'
-elif host_machine.system() == 'darwin'
-  pylib_suffix = 'dylib'
-endif
 cdata = configuration_data()
 cdata.set('PACKAGE', '"gst-python"')
 cdata.set('VERSION', '"@0@"'.format(gst_version))
@@ -85,10 +108,7 @@ cdata.set('GST_PACKAGE_NAME', '"GStreamer Python"')
 cdata.set('PACKAGE_NAME', '"GStreamer Python"')
 cdata.set('GST_API_VERSION', '"@0@"'.format(api_version))
 cdata.set('PLUGINDIR', '"@0@/gstreamer-1.0"'.format(libdir))
-cdata.set('PY_LIB_LOC', '"@0@"'.format(pylib_loc))
-cdata.set('PY_ABI_FLAGS', '"@0@"'.format(python_abi_flags))
-cdata.set('PY_LIB_SUFFIX', '"@0@"'.format(pylib_suffix))
-cdata.set('PYTHON_VERSION', '"@0@"'.format(python_dep.version()))
+cdata.set_quoted('PY_LIB_FNAME', pylib_fname)
 configure_file(output : 'config.h', configuration : cdata)
 configinc = include_directories('.')