main: Prepend RPATH or RUNPATH paths to gir search paths
If one wants to run tests the non-installed gnome-shell, that currently fails as gnome-shell the executable attempts to link against ./build/src/libgnome-shell.so, but when GObject introspection tries to find what library to link to for Shell, it goes to the installed libgnome-shell.so, causing two different versions of libgnome-shell.so to be loaded. This, however, can be avoided thanks to meson adding $ORIGIN paths to relevant libraries before installing an executable. What this means in practice is that we can inspect ourself upon startup, discover whether the RPATH/RUNPATH header contains $ORIGIN, and if so, expand it to the directory containing the executable, and prepend the introspection search paths with said directory. This effectively means that the introspection machinery now finds the same library that the linker linked the gnome-shell executable with, making it run successfully. It's not possible to use $GI_TYPELIB_PATH since g_irepository_prepend_library_path() takes precedence. There is no "append" variant of that API. Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1349>
This commit is contained in:
parent
1559f03a82
commit
9bc89b821c
@ -36,3 +36,6 @@
|
||||
|
||||
/* Define if polkit defines autocleanup functions */
|
||||
#mesondefine HAVE_POLKIT_AUTOCLEANUP
|
||||
|
||||
/* Define to 1 if the <elf.h> and <link.h> header file exist. */
|
||||
#mesondefine HAVE_EXE_INTROSPECTION
|
||||
|
@ -148,6 +148,8 @@ cdata.set('HAVE_FDWALK', cc.has_function('fdwalk'))
|
||||
cdata.set('HAVE_MALLINFO', cc.has_function('mallinfo'))
|
||||
cdata.set('HAVE_MALLINFO2', cc.has_function('mallinfo2'))
|
||||
cdata.set('HAVE_SYS_RESOURCE_H', cc.has_header('sys/resource.h'))
|
||||
cdata.set('HAVE_EXE_INTROSPECTION',
|
||||
cc.has_header('elf.h') and cc.has_header('link.h'))
|
||||
cdata.set('HAVE__NL_TIME_FIRST_WEEKDAY',
|
||||
cc.has_header_symbol('langinfo.h', '_NL_TIME_FIRST_WEEKDAY')
|
||||
)
|
||||
|
77
src/main.c
77
src/main.c
@ -18,6 +18,11 @@
|
||||
#include <meta/meta-plugin.h>
|
||||
#include <meta/prefs.h>
|
||||
#include <atk-bridge.h>
|
||||
#include <link.h>
|
||||
|
||||
#ifdef HAVE_EXE_INTROSPECTION
|
||||
#include <elf.h>
|
||||
#endif
|
||||
|
||||
#include "shell-global.h"
|
||||
#include "shell-global-private.h"
|
||||
@ -123,6 +128,74 @@ shell_dbus_init (gboolean replace)
|
||||
g_object_unref (session);
|
||||
}
|
||||
|
||||
#ifdef HAVE_EXE_INTROSPECTION
|
||||
static void
|
||||
maybe_add_rpath_introspection_paths (void)
|
||||
{
|
||||
ElfW (Dyn) *dyn;
|
||||
ElfW (Dyn) *rpath = NULL;
|
||||
ElfW (Dyn) *runpath = NULL;
|
||||
const char *strtab = NULL;
|
||||
g_auto (GStrv) paths = NULL;
|
||||
g_autofree char *exe_dir = NULL;
|
||||
GStrv str;
|
||||
|
||||
for (dyn = _DYNAMIC; dyn->d_tag != DT_NULL; dyn++)
|
||||
{
|
||||
if (dyn->d_tag == DT_RPATH)
|
||||
rpath = dyn;
|
||||
else if (dyn->d_tag == DT_RUNPATH)
|
||||
runpath = dyn;
|
||||
else if (dyn->d_tag == DT_STRTAB)
|
||||
strtab = (const char *) dyn->d_un.d_val;
|
||||
}
|
||||
|
||||
if ((!rpath && !runpath) || !strtab)
|
||||
return;
|
||||
|
||||
if (rpath)
|
||||
paths = g_strsplit (strtab + rpath->d_un.d_val, ":", -1);
|
||||
else
|
||||
paths = g_strsplit (strtab + runpath->d_un.d_val, ":", -1);
|
||||
|
||||
if (!paths)
|
||||
return;
|
||||
|
||||
for (str = paths; *str; str++)
|
||||
{
|
||||
g_autoptr (GError) error = NULL;
|
||||
g_autoptr (GString) rpath_dir = NULL;
|
||||
|
||||
if (!strstr (*str, "$ORIGIN"))
|
||||
continue;
|
||||
|
||||
if (!exe_dir)
|
||||
{
|
||||
g_autofree char *exe_path = NULL;
|
||||
|
||||
exe_path = g_file_read_link ("/proc/self/exe", &error);
|
||||
if (!exe_path)
|
||||
{
|
||||
g_warning ("Failed to find directory of executable: %s",
|
||||
error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
exe_dir = g_path_get_dirname (exe_path);
|
||||
}
|
||||
|
||||
rpath_dir = g_string_new (*str);
|
||||
g_string_replace (rpath_dir, "$ORIGIN", exe_dir, 0);
|
||||
|
||||
g_debug ("Prepending RPATH directory '%s' "
|
||||
"to introsepciton library search path",
|
||||
rpath_dir->str);
|
||||
g_irepository_prepend_search_path (rpath_dir->str);
|
||||
g_irepository_prepend_library_path (rpath_dir->str);
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_EXE_INTROSPECTION */
|
||||
|
||||
static void
|
||||
shell_introspection_init (void)
|
||||
{
|
||||
@ -137,6 +210,10 @@ shell_introspection_init (void)
|
||||
*/
|
||||
g_irepository_prepend_library_path (MUTTER_TYPELIB_DIR);
|
||||
g_irepository_prepend_library_path (GNOME_SHELL_PKGLIBDIR);
|
||||
|
||||
#ifdef HAVE_EXE_INTROSPECTION
|
||||
maybe_add_rpath_introspection_paths ();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
Loading…
Reference in New Issue
Block a user