diff --git a/bin/meson.build b/bin/meson.build index da4f5b95032bb960af383ab58f4c98db2af90c65..8761bde2f682be618c6971921dc426b9311cda61 100644 --- a/bin/meson.build +++ b/bin/meson.build @@ -26,6 +26,10 @@ executable( 'system-info.c', dependencies : [glib, libsteamrt_dep, json_glib], install : true, + # Use the adjacent libsteam-runtime-tools and json-glib, ignoring + # LD_LIBRARY_PATH even if set + build_rpath : bin_rpath, + install_rpath : bin_rpath, ) if get_option('man') diff --git a/debian/rules b/debian/rules index f419379e51aa90f684cc8a05ff45ca1885276b0f..9e30a9ef675c0a9099c270fcb9f53adcf840319e 100755 --- a/debian/rules +++ b/debian/rules @@ -38,6 +38,7 @@ override_dh_auto_configure: meson builddir \ --prefix=/usr \ --libexecdir=/usr/libexec \ + --libdir=lib/$(DEB_HOST_MULTIARCH) \ -Dgtk_doc=$(gtk_doc_has_cflags) \ -Dintrospection=false \ -Dmultiarch_tuple=$(DEB_HOST_MULTIARCH) \ diff --git a/helpers/meson.build b/helpers/meson.build index 3c37a53a09cd5589c26c7e31bc4ac65f7fdf557c..f0f475a59f6ea2885145506460e9d605ef84bb5d 100644 --- a/helpers/meson.build +++ b/helpers/meson.build @@ -26,6 +26,8 @@ executable( 'true.c', install : true, install_dir : pkglibexecdir, + # Deliberately no RPATH/RUNPATH here: it's unnecessary because this + # executable has no dependencies. ) executable( @@ -35,6 +37,9 @@ executable( dependencies : [json_glib, glib], install : true, install_dir : pkglibexecdir, + # Use json-glib and GLib from the adjacent libdir, ignoring LD_LIBRARY_PATH + build_rpath : pkglibexec_rpath, + install_rpath : pkglibexec_rpath, ) executable( @@ -43,6 +48,8 @@ executable( dependencies : [libdl], install : true, install_dir : pkglibexecdir, + # Deliberately no RPATH/RUNPATH here: we want to determine whether + # a game with no special linking would be able to load a library. ) executable( @@ -54,6 +61,9 @@ executable( get_option('libexecdir'), 'steam-runtime-tools-' + api_major, ) + # Deliberately no RPATH/RUNPATH here: we want to determine whether + # a game with no special linking would be able to use libvulkan + # and its associated drivers successfully. ) custom_target( diff --git a/meson.build b/meson.build index 046d480fc378a232b9a778e115053032ae19d6df..acc59c3f82b29e028c9d2c7c9ab8d466edeb0e8c 100644 --- a/meson.build +++ b/meson.build @@ -100,6 +100,19 @@ c_compiler = meson.get_compiler('c') supported_warning_cflags = c_compiler.get_supported_arguments(warning_cflags) add_project_arguments(supported_warning_cflags, language : 'c') +add_project_arguments( + c_compiler.get_supported_arguments( + '-Wl,-z,origin', + # Generate RPATH in preference to RUNPATH, even if RUNPATH is the + # linker's default. We want RPATH here, because it's used recursively + # for both direct and indirect dependencies: in particular we need + # to pick up the whole GLib family (GLib, GObject, GIO) from the same + # location. (It also bypasses LD_LIBRARY_PATH.) + '-Wl,-z,--disable-new-dtags', + ), + language : 'c', +) + foreach flag : no_warning_cflags supported_no_warning_cflags = c_compiler.get_supported_arguments([ '-Wno-error=' + flag, @@ -150,10 +163,28 @@ libdl = c_compiler.find_library('dl', required : false) project_include_dirs = include_directories('.') +# RPATH for executables installed in get_option('bindir'). +# This assumes that bindir is a single directory component (normally +# 'bin'), so that ../ gets us from get_option('bindir') to the prefix, +# and that libdir is relative. +bin_rpath = '${ORIGIN}/../' + get_option('libdir') +if get_option('prefix').endswith('/usr') + # Parts of the GLib family of libraries are in /lib + bin_rpath = bin_rpath + ':${ORIGIN}/../../' + get_option('libdir') +endif + pkglibexecdir = join_paths( get_option('libexecdir'), 'steam-runtime-tools-' + api_major, ) +# RPATH for executables installed in pkglibexecdir. +# This assumes that libexecdir is a single directory component (normally +# 'libexec'), so that ../../ gets us from pkglibexecdir to the prefix, +# and that libdir is relative +pkglibexec_rpath = '${ORIGIN}/../../' + get_option('libdir') +if get_option('prefix').endswith('/usr') + pkglibexec_rpath = pkglibexec_rpath + ':${ORIGIN}/../../../' + get_option('libdir') +endif if get_option('multiarch_tuple') != '' multiarch = get_option('multiarch_tuple') diff --git a/steam-runtime-tools/system-info.c b/steam-runtime-tools/system-info.c index ae2144d218b4577faf222b1e283b01c85a89f1c5..603f6a74130c230c5439deae7b029b6f156c075e 100644 --- a/steam-runtime-tools/system-info.c +++ b/steam-runtime-tools/system-info.c @@ -581,6 +581,9 @@ get_environ (SrtSystemInfo *self) return environ; } +/* Path components from ${prefix} to steamrt expectations */ +#define STEAMRT_EXPECTATIONS "lib", "steamrt", "expectations" + static gboolean ensure_expectations (SrtSystemInfo *self) { @@ -589,16 +592,26 @@ ensure_expectations (SrtSystemInfo *self) if (self->expectations == NULL) { const char *runtime; - const char *sysroot = "/"; - gchar *def; + gchar *def = NULL; runtime = g_environ_getenv (get_environ (self), "STEAM_RUNTIME"); if (runtime != NULL && runtime[0] == '/') - sysroot = runtime; + { + def = g_build_filename (runtime, "usr", STEAMRT_EXPECTATIONS, + NULL); + } + + if (def == NULL) + { + runtime = _srt_find_myself (NULL, NULL); + + if (runtime != NULL) + def = g_build_filename (runtime, STEAMRT_EXPECTATIONS, NULL); + } - def = g_build_filename (sysroot, "usr", "lib", "steamrt", - "expectations", NULL); + if (def == NULL) + def = g_build_filename ("/usr", STEAMRT_EXPECTATIONS, NULL); if (g_file_test (def, G_FILE_TEST_IS_DIR)) self->expectations = g_steal_pointer (&def); diff --git a/steam-runtime-tools/utils-internal.h b/steam-runtime-tools/utils-internal.h index 8f6b15e2d08cdb263a1686781c82e4e5de797142..dc74724aec8959a6aaf8fedc5edab45647eb4089 100644 --- a/steam-runtime-tools/utils-internal.h +++ b/steam-runtime-tools/utils-internal.h @@ -42,3 +42,5 @@ G_GNUC_INTERNAL GPtrArray *_srt_get_helper (const char *helpers_path, SrtHelperFlags flags, GError **error); gchar *_srt_filter_gameoverlayrenderer (const gchar *input); +G_GNUC_INTERNAL const char *_srt_find_myself (const char **helpers_path_out, + GError **error); diff --git a/steam-runtime-tools/utils.c b/steam-runtime-tools/utils.c index 00d7346326f0f5d9045b778bccc3e612ebf91d25..c3bb136320ba45f832e832f03b0dd0ef7ffbdf91 100644 --- a/steam-runtime-tools/utils.c +++ b/steam-runtime-tools/utils.c @@ -146,40 +146,35 @@ _srt_check_not_setuid (void) return !is_setuid; } -static gchar *global_helpers_path = NULL; - -static const char * -_srt_get_helpers_path (GError **error) +G_GNUC_INTERNAL const char * +_srt_find_myself (const char **helpers_path_out, + GError **error) { - const char *path; + static gchar *saved_prefix = NULL; + static gchar *saved_helpers_path = NULL; Dl_info ignored; struct link_map *map = NULL; - gchar *dir; + gchar *dir = NULL; g_return_val_if_fail (_srt_check_not_setuid (), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); + g_return_val_if_fail (helpers_path_out == NULL || *helpers_path_out == NULL, + NULL); - path = global_helpers_path; - - if (path != NULL) - goto out; - - path = g_getenv ("SRT_HELPERS_PATH"); - - if (path != NULL) + if (saved_prefix != NULL && saved_helpers_path != NULL) goto out; - if (dladdr1 (_srt_get_helpers_path, &ignored, (void **) &map, + if (dladdr1 (_srt_find_myself, &ignored, (void **) &map, RTLD_DL_LINKMAP) == 0 || map == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Unable to locate shared library containing " - "_srt_get_helpers_path()"); + "_srt_find_myself()"); goto out; } - g_debug ("Found _srt_get_helpers_path() in %s", map->l_name); + g_debug ("Found _srt_find_myself() in %s", map->l_name); dir = g_path_get_dirname (map->l_name); if (g_str_has_suffix (dir, "/lib/" _SRT_MULTIARCH)) @@ -198,16 +193,18 @@ _srt_get_helpers_path (GError **error) dir = g_strdup ("/usr"); } + saved_prefix = g_steal_pointer (&dir); /* deliberate one-per-process leak */ - global_helpers_path = g_build_filename ( - dir, "libexec", "steam-runtime-tools-" _SRT_API_MAJOR, + saved_helpers_path = g_build_filename ( + saved_prefix, "libexec", "steam-runtime-tools-" _SRT_API_MAJOR, NULL); - path = global_helpers_path; - - g_free (dir); out: - return path; + if (helpers_path_out != NULL) + *helpers_path_out = saved_helpers_path; + + g_free (dir); + return saved_prefix; } /* @@ -266,14 +263,13 @@ _srt_get_helper (const char *helpers_path, } if (helpers_path == NULL) - { - helpers_path = _srt_get_helpers_path (error); + helpers_path = g_getenv ("SRT_HELPERS_PATH"); - if (helpers_path == NULL) - { - g_ptr_array_unref (argv); - return NULL; - } + if (helpers_path == NULL + && _srt_find_myself (&helpers_path, error) == NULL) + { + g_ptr_array_unref (argv); + return NULL; } /* Prefer a helper from ${SRT_HELPERS_PATH} or diff --git a/tests/valgrind.supp b/tests/valgrind.supp index b6664283c14350df6561c8ceb790f9c41f110135..835990f895fade5a9903e2faa2592ce07b2515a1 100644 --- a/tests/valgrind.supp +++ b/tests/valgrind.supp @@ -4,7 +4,7 @@ Memcheck:Leak ... fun:g_build_filename - fun:_srt_get_helpers_path + fun:_srt_find_myself } # Dependencies