Skip to content

Commit

Permalink
backends: Use raw_link_args to check for the need of RPATH
Browse files Browse the repository at this point in the history
Function rpaths_for_bundled_shared_libraries assumes it needs RPATH when
linking arguments of an external dependency has exactly one argument and
the only argument is an absolute path to a library file. This was mostly
fine because almost all .pc files use a -L -l pair instead of the full
path of the library, which means pkg-config dependencies almost always
have at least two arguments. However, there are patches landed in the
meson 0.47 cycle which convert -L -l pair returned by pkg-config to the
absolute path of library. If the output of pkg-config includes exactly
one -L argument and one -l argument, it will be converted to exactly one
absolute path by meson and rpaths_for_bundled_shared_libraries will
assume it needs RPATH. Since meson passes both -rpath and -rpath-link to
the linker and -rpath-link has precedence over LD_LIBRARY_PATH, it
changes the search order of dependent libraries in an unexpected way and
it causes a lot of linking troubles in JHBuild environments on FreeBSD.

To make the method behave like the old way of using -L -l pairs and
avoid library path order problems, we use raw_link_args instead of
link_args here. raw_link_args stores the unmodified output of pkg-config
and it is much less likely to accidentally match the rule currently used
by the method.

Works around #4270.
  • Loading branch information
lantw44 committed Aug 29, 2021
1 parent f407ad5 commit b88e59d
Show file tree
Hide file tree
Showing 5 changed files with 16 additions and 11 deletions.
2 changes: 1 addition & 1 deletion mesonbuild/backend/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,7 @@ def rpaths_for_bundled_shared_libraries(self, target: build.BuildTarget, exclude
for dep in target.external_deps:
if not isinstance(dep, (dependencies.ExternalLibrary, dependencies.PkgConfigDependency)):
continue
la = dep.link_args
la = dep.get_link_args(raw=True)
if len(la) != 1 or not os.path.isabs(la[0]):
continue
# The only link argument is an absolute path to a library file.
Expand Down
4 changes: 3 additions & 1 deletion test cases/unit/80 global-rpath/meson.build
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
project('global-rpath', 'cpp')
yonder_dep = dependency('yonder')
cpp = meson.get_compiler('cpp')
yonder_libdir = get_option('yonder_libdir')
yonder_dep = cpp.find_library('yonder', dirs: [yonder_libdir])
executable('rpathified', 'rpathified.cpp', dependencies: [yonder_dep], install: true)
1 change: 1 addition & 0 deletions test cases/unit/80 global-rpath/meson_options.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
option('yonder_libdir', type: 'string')
2 changes: 0 additions & 2 deletions test cases/unit/80 global-rpath/yonder/meson.build
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
project('yonder', 'cpp')
yonder = shared_library('yonder', 'yonder.cpp', install: true)
install_headers('yonder.h')
pkgconfig = import('pkgconfig')
pkgconfig.generate(yonder)
18 changes: 11 additions & 7 deletions unittests/linuxliketests.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,13 +247,15 @@ def test_pkgconfig_uninstalled(self):
self.init(testdir)
self.build()

libdir = self.builddir
os.environ['PKG_CONFIG_LIBDIR'] = os.path.join(self.builddir, 'meson-uninstalled')
if is_cygwin():
os.environ['PATH'] += os.pathsep + self.builddir
os.environ['PATH'] += os.pathsep + libdir

self.new_builddir()
meson_args = [f'-Dc_link_args=-Wl,-rpath,{libdir}']
testdir = os.path.join(self.common_test_dir, '44 pkgconfig-gen', 'dependencies')
self.init(testdir)
self.init(testdir, extra_args=meson_args)
self.build()
self.run_tests()

Expand Down Expand Up @@ -929,9 +931,9 @@ def test_global_rpath(self):
oldinstalldir = self.installdir

# Build and install an external library without DESTDIR.
# The external library generates a .pc file without an rpath.
yonder_dir = os.path.join(testdir, 'yonder')
yonder_prefix = os.path.join(oldinstalldir, 'yonder')
yonder_includedir = os.path.join(yonder_prefix, 'include')
yonder_libdir = os.path.join(yonder_prefix, self.libdir)
self.prefix = yonder_prefix
self.installdir = yonder_prefix
Expand All @@ -955,13 +957,15 @@ def test_global_rpath(self):
# (as systems like buildroot and guix are wont to do)
# and verify install preserves that rpath.
self.new_builddir()
env = {'LDFLAGS': rpath_format + yonder_libdir,
meson_args = [f'-Dyonder_libdir={yonder_libdir}']
env = {'CPPFLAGS': '-I' + yonder_includedir,
'LDFLAGS': rpath_format + yonder_libdir,
'PKG_CONFIG_PATH': os.path.join(yonder_libdir, 'pkgconfig')}
if exception:
with self.assertRaises(subprocess.CalledProcessError):
self.init(testdir, override_envvars=env)
self.init(testdir, extra_args=meson_args, override_envvars=env)
continue
self.init(testdir, override_envvars=env)
self.init(testdir, extra_args=meson_args, override_envvars=env)
self.build()
self.install(use_destdir=False)
got_rpath = get_rpath(os.path.join(yonder_prefix, 'bin/rpathified'))
Expand Down Expand Up @@ -1526,7 +1530,7 @@ def test_static_link(self):
# Test that installed libraries works
self.new_builddir()
self.prefix = oldprefix
meson_args = [f'-Dc_link_args=-L{libdir}',
meson_args = [f'-Dc_link_args=-L{libdir} -Wl,-rpath,{libdir}',
'--fatal-meson-warnings']
testdir = os.path.join(self.unit_test_dir, '67 static link')
env = {'PKG_CONFIG_LIBDIR': os.path.join(libdir, 'pkgconfig')}
Expand Down

0 comments on commit b88e59d

Please sign in to comment.