plugin: API: GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_RELATIVE_TO_EXE
authorMathieu Duponchelle <mathieu@centricular.com>
Mon, 25 Sep 2017 18:35:59 +0000 (20:35 +0200)
committerMathieu Duponchelle <mathieu@centricular.com>
Tue, 26 Sep 2017 11:12:00 +0000 (13:12 +0200)
When a plugin declares a dependency using this flag, all the
relative paths are considered to be relative to the path of
the main executable.

We try to determine the path of the executable portably,
with implementations provided for Linux, Windows and Mac.

If retrieval of the path fails, we will not detect changes.

In order for the main executable path to be the same when
scanning a plugin in a child process, a new variable is
exposed in gst_private.h, _gst_executable_path

https://bugzilla.gnome.org/show_bug.cgi?id=788152

gst/gst.c
gst/gst_private.h
gst/gstplugin.c
gst/gstplugin.h
gst/gstpluginloader.c
libs/gst/helpers/gst-plugin-scanner.c
win32/common/libgstreamer.def

index e0225b4..26948da 100644 (file)
--- a/gst/gst.c
+++ b/gst/gst.c
 #define WIN32_LEAN_AND_MEAN     /* prevents from including too many things */
 #include <windows.h>            /* GetStdHandle, windows console */
 #endif
+#if defined (__APPLE__)
+#include <errno.h>
+#include <libproc.h>            /* proc_pidpath, PROC_PIDPATHINFO_MAXSIZE */
+#endif
 
 #include "gst-i18n-lib.h"
 #include <locale.h>             /* for LC_ALL */
@@ -133,6 +137,8 @@ extern gboolean _priv_gst_disable_registry;
 extern gboolean _priv_gst_disable_registry_update;
 #endif
 
+gchar *_gst_executable_path = NULL;
+
 #ifndef GST_DISABLE_GST_DEBUG
 const gchar *priv_gst_dump_dot_dir;
 #endif
@@ -311,6 +317,56 @@ gst_init_get_option_group (void)
 #endif
 }
 
+#if defined(__linux__)
+static void
+find_executable_path (void)
+{
+  GError *error = NULL;
+  gchar *path;
+
+  if (_gst_executable_path)
+    return;
+
+  path = g_file_read_link ("/proc/self/exe", &error);
+
+  if (path) {
+    _gst_executable_path = g_path_get_dirname (path);
+    g_free (path);
+  }
+}
+#elif defined(G_OS_WIN32)
+static void
+find_executable_path (void)
+{
+  char buffer[MAX_PATH];
+
+  if (!GetModuleFilename (NULL, buffer, MAX_PATH))
+    return;
+
+  _gst_executable_path = g_strdup (buffer);
+}
+#elif defined(__APPLE__)
+static void
+find_executable_path (void)
+{
+  int ret;
+  pid_t pid;
+  char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
+
+  pid = getpid ();
+  ret = proc_pidpath (pid, pathbuf, sizeof (pathbuf));
+  if (ret > 0)
+    _gst_executable_path = g_strdup (pathbuf)
+    }
+#else
+static void
+find_executable_path (void)
+{
+  GST_FIXME ("Couldn't look up executable path, add support for this platform");
+}
+#endif
+
+
 /**
  * gst_init_check:
  * @argc: (inout) (allow-none): pointer to application's argc
@@ -343,6 +399,9 @@ gst_init_check (int *argc, char **argv[], GError ** err)
     g_mutex_unlock (&init_lock);
     return TRUE;
   }
+
+  find_executable_path ();
+
 #ifndef GST_DISABLE_OPTION_PARSING
   ctx = g_option_context_new ("- GStreamer initialization");
   g_option_context_set_ignore_unknown_options (ctx, TRUE);
@@ -1019,6 +1078,11 @@ gst_deinit (void)
   _priv_gst_plugin_paths = NULL;
 #endif
 
+  if (_gst_executable_path) {
+    g_free (_gst_executable_path);
+    _gst_executable_path = NULL;
+  }
+
   clock = gst_system_clock_obtain ();
   gst_object_unref (clock);
   gst_object_unref (clock);
index e88bb60..b2905a0 100644 (file)
@@ -229,6 +229,10 @@ GstCapsFeatures * __gst_caps_get_features_unchecked (const GstCaps * caps, guint
 GST_EXPORT gboolean _gst_disable_registry_cache;
 #endif
 
+/* Secret variable to let the plugin scanner use the same base path
+ * as the main application in order to determine dependencies */
+GST_EXPORT gchar *_gst_executable_path;
+
 /* provide inline gst_g_value_get_foo_unchecked(), used in gststructure.c */
 #define DEFINE_INLINE_G_VALUE_GET_UNCHECKED(ret_type,name_type,v_field) \
 static inline ret_type                                                  \
index 6970fdf..18183c3 100644 (file)
@@ -1702,6 +1702,7 @@ static guint
 gst_plugin_ext_dep_get_stat_hash (GstPlugin * plugin, GstPluginDep * dep)
 {
   gboolean paths_are_default_only;
+  gboolean paths_are_relative_to_exe;
   GQueue scan_paths = G_QUEUE_INIT;
   guint scan_hash = 0;
   gchar *path;
@@ -1710,6 +1711,8 @@ gst_plugin_ext_dep_get_stat_hash (GstPlugin * plugin, GstPluginDep * dep)
 
   paths_are_default_only =
       dep->flags & GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_DEFAULT_ONLY;
+  paths_are_relative_to_exe =
+      dep->flags & GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_RELATIVE_TO_EXE;
 
   gst_plugin_ext_dep_extract_env_vars_paths (plugin, dep, &scan_paths);
 
@@ -1718,12 +1721,26 @@ gst_plugin_ext_dep_get_stat_hash (GstPlugin * plugin, GstPluginDep * dep)
 
     for (paths = dep->paths; paths != NULL && *paths != NULL; ++paths) {
       const gchar *path = *paths;
+      gchar *full_path;
+
+      if (paths_are_relative_to_exe && !g_path_is_absolute (path)) {
+        if (!_gst_executable_path) {
+          GST_FIXME_OBJECT (plugin,
+              "Path dependency %s relative to executable path but could not retrieve executable path",
+              path);
+          continue;
+        }
+        full_path = g_build_filename (_gst_executable_path, path, NULL);
+      } else {
+        full_path = g_strdup (path);
+      }
 
-      if (!g_queue_find_custom (&scan_paths, path, (GCompareFunc) strcmp)) {
-        GST_LOG_OBJECT (plugin, "path: '%s'", path);
-        g_queue_push_tail (&scan_paths, g_strdup (path));
+      if (!g_queue_find_custom (&scan_paths, full_path, (GCompareFunc) strcmp)) {
+        GST_LOG_OBJECT (plugin, "path: '%s'", full_path);
+        g_queue_push_tail (&scan_paths, full_path);
       } else {
-        GST_LOG_OBJECT (plugin, "path: '%s' (duplicate, ignoring)", path);
+        GST_LOG_OBJECT (plugin, "path: '%s' (duplicate, ignoring)", full_path);
+        g_free (full_path);
       }
     }
   }
index 7258388..691d5f6 100644 (file)
@@ -98,6 +98,9 @@ typedef enum
  * @GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_PREFIX : interpret
  *         filename argument as filter prefix and check all matching files in
  *         the directory. Since 1.8.
+ * @GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_RELATIVE_TO_EXE : interpret
+ *   non-absolute paths as relative to the main executable directory. Since
+ *   1.14.
  *
  * Flags used in connection with gst_plugin_add_dependency().
  */
@@ -106,7 +109,8 @@ typedef enum {
   GST_PLUGIN_DEPENDENCY_FLAG_RECURSE = (1 << 0),
   GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_DEFAULT_ONLY = (1 << 1),
   GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_SUFFIX = (1 << 2),
-  GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_PREFIX = (1 << 3)
+  GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_PREFIX = (1 << 3),
+  GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_RELATIVE_TO_EXE = (1 << 4)
 } GstPluginDependencyFlags;
 
 /**
index be40cb5..a933a4b 100644 (file)
@@ -408,7 +408,7 @@ gst_plugin_loader_use_usr_bin_arch (void)
 static gboolean
 gst_plugin_loader_try_helper (GstPluginLoader * loader, gchar * location)
 {
-  char *argv[5] = { NULL, };
+  char *argv[6] = { NULL, };
   int c = 0;
 
 #if defined (__APPLE__) && defined (USR_BIN_ARCH_SWITCH)
@@ -419,9 +419,10 @@ gst_plugin_loader_try_helper (GstPluginLoader * loader, gchar * location)
 #endif
   argv[c++] = location;
   argv[c++] = (char *) "-l";
+  argv[c++] = _gst_executable_path;
   argv[c++] = NULL;
 
-  if (c > 3) {
+  if (c > 4) {
     GST_LOG ("Trying to spawn gst-plugin-scanner helper at %s with arch %s",
         location, argv[1]);
   } else {
index b5b3980..cda1ac9 100644 (file)
@@ -38,7 +38,7 @@ main (int argc, char *argv[])
   char **my_argv;
   int my_argc;
 
-  if (argc != 2 || strcmp (argv[1], "-l"))
+  if (argc != 3 || strcmp (argv[1], "-l"))
     return 1;
 
   my_argc = 2;
@@ -50,6 +50,7 @@ main (int argc, char *argv[])
   _gst_disable_registry_cache = TRUE;
 #endif
 
+  _gst_executable_path = g_strdup (argv[2]);
   res = gst_init_check (&my_argc, &my_argv, NULL);
 
   g_free (my_argv);
index d9007e9..a8d14f5 100644 (file)
@@ -50,6 +50,7 @@ EXPORTS
        _gst_debug_nameof_funcptr
        _gst_debug_register_funcptr
        _gst_disable_registry_cache DATA
+       _gst_executable_path DATA
        _gst_double_range_type DATA
        _gst_element_error_printf
        _gst_event_type DATA