mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-03 14:08:56 +00:00
ges, gst-python: Fix libpython dlopen on macOS
First encountered at https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1171#note_2290789 Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6159>
This commit is contained in:
parent
2cc9a181f9
commit
64fdded13a
5 changed files with 66 additions and 20 deletions
|
@ -43,7 +43,34 @@
|
||||||
#ifdef HAS_PYTHON
|
#ifdef HAS_PYTHON
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
#include "ges-resources.h"
|
#include "ges-resources.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to call dlopen() directly on macOS to workaround a macOS runtime
|
||||||
|
* linker bug. When there are nested dlopen() calls and the second dlopen() is
|
||||||
|
* called from another library (such as gmodule), @loader_path is resolved as
|
||||||
|
* @executable_path and RPATHs are read from the executable (gst-plugin-scanner)
|
||||||
|
* instead of the library itself (libgstges.dylib). This doesn't happen if the
|
||||||
|
* second dlopen() call is directly in the source code of the library.
|
||||||
|
* Previously seen at:
|
||||||
|
* https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1171#note_2290789
|
||||||
|
*/
|
||||||
|
#ifdef G_OS_WIN32
|
||||||
|
#include <gmodule.h>
|
||||||
|
#define ges_module_open(fname) g_module_open(fname,0)
|
||||||
|
#define ges_module_error g_module_error
|
||||||
|
#define ges_module_symbol(module,name,symbol) g_module_symbol(module,name,symbol)
|
||||||
|
#else
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#define ges_module_open(fname) dlopen(fname,RTLD_NOW | RTLD_GLOBAL)
|
||||||
|
#define ges_module_error dlerror
|
||||||
|
static inline gboolean
|
||||||
|
ges_module_symbol (gpointer handle, const char *name, gpointer * symbol)
|
||||||
|
{
|
||||||
|
*symbol = dlsym (handle, name);
|
||||||
|
return *symbol != NULL;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif /* HAS_PYTHON */
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_STATIC (ges_formatter_debug);
|
GST_DEBUG_CATEGORY_STATIC (ges_formatter_debug);
|
||||||
#undef GST_CAT_DEFAULT
|
#undef GST_CAT_DEFAULT
|
||||||
|
@ -558,25 +585,22 @@ load_python_formatters (void)
|
||||||
G_RESOURCE_LOOKUP_FLAGS_NONE, &err);
|
G_RESOURCE_LOOKUP_FLAGS_NONE, &err);
|
||||||
PyObject *code = NULL, *res = NULL;
|
PyObject *code = NULL, *res = NULL;
|
||||||
gboolean we_initialized = FALSE;
|
gboolean we_initialized = FALSE;
|
||||||
GModule *libpython;
|
|
||||||
gpointer has_python = NULL;
|
gpointer has_python = NULL;
|
||||||
|
|
||||||
GST_LOG ("Checking to see if libpython is already loaded");
|
GST_LOG ("Checking to see if libpython is already loaded");
|
||||||
if (g_module_symbol (g_module_open (NULL, G_MODULE_BIND_LOCAL),
|
if (ges_module_symbol (ges_module_open (NULL),
|
||||||
"_Py_NoneStruct", &has_python) && has_python) {
|
"_Py_NoneStruct", &has_python) && has_python) {
|
||||||
GST_LOG ("libpython is already loaded");
|
GST_LOG ("libpython is already loaded");
|
||||||
} else {
|
} else {
|
||||||
GST_LOG ("loading libpython by name: %s", PY_LIB_FNAME);
|
GST_LOG ("loading libpython by name: %s", PY_LIB_FNAME);
|
||||||
libpython = g_module_open (PY_LIB_FNAME, 0);
|
if (!ges_module_open (PY_LIB_FNAME)) {
|
||||||
if (!libpython) {
|
GST_ERROR ("Couldn't load libpython. Reason: %s", ges_module_error ());
|
||||||
GST_ERROR ("Couldn't g_module_open libpython. Reason: %s",
|
|
||||||
g_module_error ());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Py_IsInitialized ()) {
|
if (!Py_IsInitialized ()) {
|
||||||
GST_LOG ("python wasn't initialized");
|
GST_LOG ("python wasn't already initialized");
|
||||||
/* set the correct plugin for registering stuff */
|
/* set the correct plugin for registering stuff */
|
||||||
Py_Initialize ();
|
Py_Initialize ();
|
||||||
we_initialized = TRUE;
|
we_initialized = TRUE;
|
||||||
|
|
|
@ -114,6 +114,7 @@ gstvalidate_dep = dependency('gstreamer-validate-1.0', version : gst_req, requir
|
||||||
|
|
||||||
gio_dep = dependency('gio-2.0', version: glib_req)
|
gio_dep = dependency('gio-2.0', version: glib_req)
|
||||||
gmodule_dep = dependency('gmodule-no-export-2.0')
|
gmodule_dep = dependency('gmodule-no-export-2.0')
|
||||||
|
libdl = cc.find_library('dl', required: false)
|
||||||
libxml_dep = dependency('libxml-2.0', required: get_option('xptv'))
|
libxml_dep = dependency('libxml-2.0', required: get_option('xptv'))
|
||||||
cdata.set('DISABLE_XPTV', not libxml_dep.found())
|
cdata.set('DISABLE_XPTV', not libxml_dep.found())
|
||||||
|
|
||||||
|
@ -202,7 +203,7 @@ elif build_gir and python.found()
|
||||||
foreach loc: pylib_locs
|
foreach loc: pylib_locs
|
||||||
foreach fname: pylib_fnames
|
foreach fname: pylib_fnames
|
||||||
if fsmod.exists(loc / fname)
|
if fsmod.exists(loc / fname)
|
||||||
libges_deps = libges_deps + [python_dep, gmodule_dep]
|
libges_deps = libges_deps + [python_dep, gmodule_dep, libdl]
|
||||||
has_python = true
|
has_python = true
|
||||||
cdata.set('HAS_PYTHON', true)
|
cdata.set('HAS_PYTHON', true)
|
||||||
cdata.set_quoted('PY_LIB_FNAME', fname)
|
cdata.set_quoted('PY_LIB_FNAME', fname)
|
||||||
|
|
|
@ -22,6 +22,7 @@ gst_dep = dependency('gstreamer-1.0', version : gst_req,
|
||||||
gstbase_dep = dependency('gstreamer-base-1.0', version : gst_req,
|
gstbase_dep = dependency('gstreamer-base-1.0', version : gst_req,
|
||||||
fallback : ['gstreamer', 'gst_base_dep'])
|
fallback : ['gstreamer', 'gst_base_dep'])
|
||||||
gmodule_dep = dependency('gmodule-no-export-2.0')
|
gmodule_dep = dependency('gmodule-no-export-2.0')
|
||||||
|
libdl = cc.find_library('dl', required: false)
|
||||||
pygobject_dep = dependency('pygobject-3.0', fallback: ['pygobject', 'pygobject_dep'], version : '>= 3.8')
|
pygobject_dep = dependency('pygobject-3.0', fallback: ['pygobject', 'pygobject_dep'], version : '>= 3.8')
|
||||||
|
|
||||||
pymod = import('python')
|
pymod = import('python')
|
||||||
|
|
|
@ -25,8 +25,33 @@
|
||||||
/* include this first, before NO_IMPORT_PYGOBJECT is defined */
|
/* include this first, before NO_IMPORT_PYGOBJECT is defined */
|
||||||
#include <pygobject.h>
|
#include <pygobject.h>
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <gmodule.h>
|
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
|
/*
|
||||||
|
* We need to call dlopen() directly on macOS to workaround a macOS runtime
|
||||||
|
* linker bug. When there are nested dlopen() calls and the second dlopen() is
|
||||||
|
* called from another library (such as gmodule), @loader_path is resolved as
|
||||||
|
* @executable_path and RPATHs are read from the executable (gst-plugin-scanner)
|
||||||
|
* instead of the library itself (libgstges.dylib). This doesn't happen if the
|
||||||
|
* second dlopen() call is directly in the source code of the library.
|
||||||
|
* Previously seen at:
|
||||||
|
* https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1171#note_2290789
|
||||||
|
*/
|
||||||
|
#ifdef G_OS_WIN32
|
||||||
|
#include <gmodule.h>
|
||||||
|
#define gstpy_module_open(fname) g_module_open(fname,0)
|
||||||
|
#define gstpy_module_error g_module_error
|
||||||
|
#define gstpy_module_symbol(module,name,symbol) g_module_symbol(module,name,symbol)
|
||||||
|
#else
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#define gstpy_module_open(fname) dlopen(fname,RTLD_NOW | RTLD_GLOBAL)
|
||||||
|
#define gstpy_module_error dlerror
|
||||||
|
static inline gboolean
|
||||||
|
gstpy_module_symbol (gpointer handle, const char *name, gpointer * symbol)
|
||||||
|
{
|
||||||
|
*symbol = dlsym (handle, name);
|
||||||
|
return *symbol != NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void *_PyGstElement_Type;
|
void *_PyGstElement_Type;
|
||||||
|
|
||||||
|
@ -214,7 +239,6 @@ plugin_init (GstPlugin * plugin)
|
||||||
PyGILState_STATE state = 0;
|
PyGILState_STATE state = 0;
|
||||||
PyObject *gi, *require_version, *args, *gst, *dict, *pyplugin;
|
PyObject *gi, *require_version, *args, *gst, *dict, *pyplugin;
|
||||||
gboolean we_initialized = FALSE;
|
gboolean we_initialized = FALSE;
|
||||||
GModule *libpython;
|
|
||||||
gpointer has_python = NULL;
|
gpointer has_python = NULL;
|
||||||
const gchar *override_path;
|
const gchar *override_path;
|
||||||
|
|
||||||
|
@ -229,23 +253,19 @@ plugin_init (GstPlugin * plugin)
|
||||||
GST_PLUGIN_DEPENDENCY_FLAG_NONE);
|
GST_PLUGIN_DEPENDENCY_FLAG_NONE);
|
||||||
|
|
||||||
GST_LOG ("Checking to see if libpython is already loaded");
|
GST_LOG ("Checking to see if libpython is already loaded");
|
||||||
if (g_module_symbol (g_module_open (NULL, G_MODULE_BIND_LOCAL),
|
if (gstpy_module_symbol (gstpy_module_open (NULL),
|
||||||
"_Py_NoneStruct", &has_python) && has_python) {
|
"_Py_NoneStruct", &has_python) && has_python) {
|
||||||
GST_LOG ("libpython is already loaded");
|
GST_LOG ("libpython is already loaded");
|
||||||
} else {
|
} else {
|
||||||
const gchar *libpython_path =
|
GST_LOG ("loading libpython by name: %s", PY_LIB_FNAME);
|
||||||
PY_LIB_LOC "/libpython" PYTHON_VERSION PY_ABI_FLAGS "." PY_LIB_SUFFIX;
|
if (!gstpy_module_open (PY_LIB_FNAME)) {
|
||||||
GST_LOG ("loading libpython from '%s'", libpython_path);
|
GST_ERROR ("Couldn't load libpython. Reason: %s", gstpy_module_error ());
|
||||||
libpython = g_module_open (libpython_path, 0);
|
|
||||||
if (!libpython) {
|
|
||||||
g_critical ("Couldn't g_module_open libpython. Reason: %s",
|
|
||||||
g_module_error ());
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Py_IsInitialized ()) {
|
if (!Py_IsInitialized ()) {
|
||||||
GST_LOG ("python wasn't initialized");
|
GST_LOG ("python wasn't already initialized");
|
||||||
/* set the correct plugin for registering stuff */
|
/* set the correct plugin for registering stuff */
|
||||||
Py_Initialize ();
|
Py_Initialize ();
|
||||||
we_initialized = TRUE;
|
we_initialized = TRUE;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
gstpython = library('gstpython',
|
gstpython = library('gstpython',
|
||||||
['gstpythonplugin.c'],
|
['gstpythonplugin.c'],
|
||||||
include_directories : [configinc],
|
include_directories : [configinc],
|
||||||
dependencies : [gst_dep, pygobject_dep, gstbase_dep, python_dep, gmodule_dep] ,
|
dependencies : [gst_dep, pygobject_dep, gstbase_dep, python_dep, gmodule_dep, libdl],
|
||||||
install : true,
|
install : true,
|
||||||
install_dir : '@0@/gstreamer-1.0'.format(get_option('libdir')),
|
install_dir : '@0@/gstreamer-1.0'.format(get_option('libdir')),
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue