diff options
author | Nirbheek Chauhan <nirbheek@centricular.com> | 2021-11-15 17:44:34 +0530 |
---|---|---|
committer | Nirbheek Chauhan <nirbheek.chauhan@gmail.com> | 2021-12-22 12:12:11 +0530 |
commit | 06b1132f82eaaf805021b4b088701d9754e2af38 (patch) | |
tree | f0d27ceae0864a09cba5ac5a8295d3c0345b6459 /mesonbuild/backend/backends.py | |
parent | 95a4c6a62a925fc888e7c07ae3d9937c87e1c759 (diff) | |
download | meson-06b1132f82eaaf805021b4b088701d9754e2af38.zip meson-06b1132f82eaaf805021b4b088701d9754e2af38.tar.gz meson-06b1132f82eaaf805021b4b088701d9754e2af38.tar.bz2 |
Set RPATH for all non-system libs with absolute paths
If a pkg-config dependency has multiple libraries in it, which is the
most common case when it has a Requires: directive, or when it has
multiple -l args in Libs: (rare), then we don't add -Wl,-rpath
directives to it when linking.
The existing test wasn't catching it because it was linking to
a pkgconfig file with a single library in it. Update the test to
demonstrate this.
This function was originally added for shared libraries in the source
directory, which explains the name:
https://github.com/mesonbuild/meson/pull/2397
However, since now it is also used for linking to *all* non-system
shared libraries that we link to with absolute paths:
https://github.com/mesonbuild/meson/pull/3092
But that PR is incomplete / wrong, because only adding RPATHs for
dependencies that specify a single library, which is simply
inconsistent. Things will work for some dependencies and not work for
others, with no logical reason for it.
We should add RPATHs for *all* libraries. There are no special length
limits for RPATHs that I can find.
For ELF, DT_RPATH or DT_RUNPATH are used, which are just stored in
a string table (DT_STRTAB). The maximum length is only a problem when
editing pre-existing tags.
For Mach-O, each RPATH is stored in a separate LC_RPATH entry so there
are no length issues there either.
Fixes https://github.com/mesonbuild/meson/issues/9543
Fixes https://github.com/mesonbuild/meson/issues/4372
Diffstat (limited to 'mesonbuild/backend/backends.py')
-rw-r--r-- | mesonbuild/backend/backends.py | 55 |
1 files changed, 27 insertions, 28 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 4b368e7..177f24a 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -751,37 +751,36 @@ class Backend: return dirs @lru_cache(maxsize=None) - def rpaths_for_bundled_shared_libraries(self, target: build.BuildTarget, exclude_system: bool = True) -> 'ImmutableListProtocol[str]': - paths: T.List[str] = [] + def rpaths_for_non_system_absolute_shared_libraries(self, target: build.BuildTarget, exclude_system: bool = True) -> 'ImmutableListProtocol[str]': + paths: OrderedSet[str] = OrderedSet() for dep in target.external_deps: if not isinstance(dep, (dependencies.ExternalLibrary, dependencies.PkgConfigDependency)): continue - la = dep.link_args - if len(la) != 1 or not os.path.isabs(la[0]): - continue - # The only link argument is an absolute path to a library file. - libpath = la[0] - libdir = os.path.dirname(libpath) - if exclude_system and self._libdir_is_system(libdir, target.compilers, self.environment): - # No point in adding system paths. - continue - # Don't remove rpaths specified in LDFLAGS. - if libdir in self.get_external_rpath_dirs(target): - continue - # Windows doesn't support rpaths, but we use this function to - # emulate rpaths by setting PATH, so also accept DLLs here - if os.path.splitext(libpath)[1] not in ['.dll', '.lib', '.so', '.dylib']: - continue - if libdir.startswith(self.environment.get_source_dir()): - rel_to_src = libdir[len(self.environment.get_source_dir()) + 1:] - assert not os.path.isabs(rel_to_src), f'rel_to_src: {rel_to_src} is absolute' - paths.append(os.path.join(self.build_to_src, rel_to_src)) - else: - paths.append(libdir) + for libpath in dep.link_args: + # For all link args that are absolute paths to a library file, add RPATH args + if not os.path.isabs(libpath): + continue + libdir = os.path.dirname(libpath) + if exclude_system and self._libdir_is_system(libdir, target.compilers, self.environment): + # No point in adding system paths. + continue + # Don't remove rpaths specified in LDFLAGS. + if libdir in self.get_external_rpath_dirs(target): + continue + # Windows doesn't support rpaths, but we use this function to + # emulate rpaths by setting PATH, so also accept DLLs here + if os.path.splitext(libpath)[1] not in ['.dll', '.lib', '.so', '.dylib']: + continue + if libdir.startswith(self.environment.get_source_dir()): + rel_to_src = libdir[len(self.environment.get_source_dir()) + 1:] + assert not os.path.isabs(rel_to_src), f'rel_to_src: {rel_to_src} is absolute' + paths.add(os.path.join(self.build_to_src, rel_to_src)) + else: + paths.add(libdir) for i in chain(target.link_targets, target.link_whole_targets): if isinstance(i, build.BuildTarget): - paths.extend(self.rpaths_for_bundled_shared_libraries(i, exclude_system)) - return paths + paths.update(self.rpaths_for_non_system_absolute_shared_libraries(i, exclude_system)) + return list(paths) # This may take other types def determine_rpath_dirs(self, target: T.Union[build.BuildTarget, build.CustomTarget, build.CustomTargetIndex] @@ -794,7 +793,7 @@ class Backend: result = OrderedSet() result.add('meson-out') if isinstance(target, build.BuildTarget): - result.update(self.rpaths_for_bundled_shared_libraries(target)) + result.update(self.rpaths_for_non_system_absolute_shared_libraries(target)) target.rpath_dirs_to_remove.update([d.encode('utf-8') for d in result]) return tuple(result) @@ -1072,7 +1071,7 @@ class Backend: if isinstance(target, build.BuildTarget): prospectives.update(target.get_transitive_link_deps()) # External deps - for deppath in self.rpaths_for_bundled_shared_libraries(target, exclude_system=False): + for deppath in self.rpaths_for_non_system_absolute_shared_libraries(target, exclude_system=False): result.add(os.path.normpath(os.path.join(self.environment.get_build_dir(), deppath))) for bdep in extra_bdeps: prospectives.add(bdep) |