diff options
Diffstat (limited to 'mesonbuild')
-rw-r--r-- | mesonbuild/backend/backends.py | 33 | ||||
-rw-r--r-- | mesonbuild/backend/ninjabackend.py | 7 | ||||
-rw-r--r-- | mesonbuild/build.py | 2 | ||||
-rw-r--r-- | mesonbuild/compilers/compilers.py | 2 | ||||
-rw-r--r-- | mesonbuild/compilers/cuda.py | 7 | ||||
-rw-r--r-- | mesonbuild/compilers/d.py | 9 | ||||
-rw-r--r-- | mesonbuild/compilers/mixins/islinker.py | 4 | ||||
-rw-r--r-- | mesonbuild/linkers.py | 49 | ||||
-rw-r--r-- | mesonbuild/minstall.py | 2 | ||||
-rw-r--r-- | mesonbuild/scripts/depfixer.py | 32 |
10 files changed, 98 insertions, 49 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 7f7c434..9d527cb 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -90,12 +90,13 @@ class InstallData: self.mesonintrospect = mesonintrospect class TargetInstallData: - def __init__(self, fname, outdir, aliases, strip, install_name_mappings, install_rpath, install_mode, optional=False): + def __init__(self, fname, outdir, aliases, strip, install_name_mappings, rpath_dirs_to_remove, install_rpath, install_mode, optional=False): self.fname = fname self.outdir = outdir self.aliases = aliases self.strip = strip self.install_name_mappings = install_name_mappings + self.rpath_dirs_to_remove = rpath_dirs_to_remove self.install_rpath = install_rpath self.install_mode = install_mode self.optional = optional @@ -443,6 +444,21 @@ class Backend: return True return False + def get_external_rpath_dirs(self, target): + dirs = set() + args = [] + # FIXME: is there a better way? + for lang in ['c', 'cpp']: + try: + args.extend(self.environment.coredata.get_external_link_args(target.for_machine, lang)) + except Exception: + pass + for arg in args: + if arg.startswith('-Wl,-rpath='): + for dir in arg.replace('-Wl,-rpath=','').split(':'): + dirs.add(dir) + return dirs + def rpaths_for_bundled_shared_libraries(self, target, exclude_system=True): paths = [] for dep in target.external_deps: @@ -457,6 +473,9 @@ class Backend: 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']: @@ -476,6 +495,7 @@ class Backend: result = OrderedSet() result.add('meson-out') result.update(self.rpaths_for_bundled_shared_libraries(target)) + target.rpath_dirs_to_remove.update([d.encode('utf8') for d in result]) return tuple(result) def object_filename_from_source(self, target, source): @@ -1140,6 +1160,7 @@ class Backend: mappings = t.get_link_deps_mapping(d.prefix, self.environment) i = TargetInstallData(self.get_target_filename(t), outdirs[0], t.get_aliases(), should_strip, mappings, + t.rpath_dirs_to_remove, t.install_rpath, install_mode) d.targets.append(i) @@ -1157,14 +1178,14 @@ class Backend: implib_install_dir = self.environment.get_import_lib_dir() # Install the import library; may not exist for shared modules i = TargetInstallData(self.get_target_filename_for_linking(t), - implib_install_dir, {}, False, {}, '', install_mode, + implib_install_dir, {}, False, {}, set(), '', install_mode, optional=isinstance(t, build.SharedModule)) d.targets.append(i) if not should_strip and t.get_debug_filename(): debug_file = os.path.join(self.get_target_dir(t), t.get_debug_filename()) i = TargetInstallData(debug_file, outdirs[0], - {}, False, {}, '', + {}, False, {}, set(), '', install_mode, optional=True) d.targets.append(i) # Install secondary outputs. Only used for Vala right now. @@ -1174,7 +1195,7 @@ class Backend: if outdir is False: continue f = os.path.join(self.get_target_dir(t), output) - i = TargetInstallData(f, outdir, {}, False, {}, None, install_mode) + i = TargetInstallData(f, outdir, {}, False, {}, set(), None, install_mode) d.targets.append(i) elif isinstance(t, build.CustomTarget): # If only one install_dir is specified, assume that all @@ -1187,7 +1208,7 @@ class Backend: if num_outdirs == 1 and num_out > 1: for output in t.get_outputs(): f = os.path.join(self.get_target_dir(t), output) - i = TargetInstallData(f, outdirs[0], {}, False, {}, None, install_mode, + i = TargetInstallData(f, outdirs[0], {}, False, {}, set(), None, install_mode, optional=not t.build_by_default) d.targets.append(i) else: @@ -1196,7 +1217,7 @@ class Backend: if outdir is False: continue f = os.path.join(self.get_target_dir(t), output) - i = TargetInstallData(f, outdir, {}, False, {}, None, install_mode, + i = TargetInstallData(f, outdir, {}, False, {}, set(), None, install_mode, optional=not t.build_by_default) d.targets.append(i) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 2aa5c2c..7300aaf 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -1348,7 +1348,8 @@ int dummy; self.get_target_dir(target)) else: target_slashname_workaround_dir = self.get_target_dir(target) - rpath_args = rustc.build_rpath_args(self.environment, + (rpath_args, target.rpath_dirs_to_remove) = \ + rustc.build_rpath_args(self.environment, self.environment.get_build_dir(), target_slashname_workaround_dir, self.determine_rpath_dirs(target), @@ -2580,12 +2581,14 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) self.get_target_dir(target)) else: target_slashname_workaround_dir = self.get_target_dir(target) - commands += linker.build_rpath_args(self.environment, + (rpath_args, target.rpath_dirs_to_remove) = \ + linker.build_rpath_args(self.environment, self.environment.get_build_dir(), target_slashname_workaround_dir, self.determine_rpath_dirs(target), target.build_rpath, target.install_rpath) + commands += rpath_args # Add libraries generated by custom targets custom_target_libraries = self.get_custom_target_provided_libraries(target) commands += extra_args diff --git a/mesonbuild/build.py b/mesonbuild/build.py index fdfca73..360285e 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -512,6 +512,8 @@ class BuildTarget(Target): self.d_features = {} self.pic = False self.pie = False + # Track build_rpath entries so we can remove them at install time + self.rpath_dirs_to_remove = set() # Sources can be: # 1. Pre-existing source files in the source tree # 2. Pre-existing sources generated by configure_file in the build tree diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 385ef5e..9575273 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -1077,7 +1077,7 @@ class Compiler: def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, rpath_paths: str, build_rpath: str, - install_rpath: str) -> T.List[str]: + install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: return self.linker.build_rpath_args( env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath) diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py index e839f53..4e89f5d 100644 --- a/mesonbuild/compilers/cuda.py +++ b/mesonbuild/compilers/cuda.py @@ -271,9 +271,10 @@ class CudaCompiler(Compiler): def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, rpath_paths: str, build_rpath: str, - install_rpath: str) -> T.List[str]: - return self._cook_link_args(self.host_compiler.build_rpath_args( - env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath)) + install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: + (rpath_args, rpath_dirs_to_remove) = self.host_compiler.build_rpath_args( + env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath) + return (self._cook_link_args(rpath_args), rpath_dirs_to_remove) def linker_to_compiler_args(self, args): return args diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index b8f29cc..d2d03a3 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -220,7 +220,7 @@ class DmdLikeCompilerMixin: def build_rpath_args(self, env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath): if self.info.is_windows(): - return [] + return ([], set()) # GNU ld, solaris ld, and lld acting like GNU ld if self.linker.id.startswith('ld'): @@ -228,15 +228,16 @@ class DmdLikeCompilerMixin: # do directly, each argument -rpath and the value to rpath, need to be # split into two separate arguments both prefaced with the -L=. args = [] - for r in super().build_rpath_args( - env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath): + (rpath_args, rpath_dirs_to_remove) = super().build_rpath_args( + env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath) + for r in rpath_args: if ',' in r: a, b = r.split(',', maxsplit=1) args.append(a) args.append(self.LINKER_PREFIX + b) else: args.append(r) - return args + return (args, rpath_dirs_to_remove) return super().build_rpath_args( env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath) diff --git a/mesonbuild/compilers/mixins/islinker.py b/mesonbuild/compilers/mixins/islinker.py index 681c816..bf1d339 100644 --- a/mesonbuild/compilers/mixins/islinker.py +++ b/mesonbuild/compilers/mixins/islinker.py @@ -107,8 +107,8 @@ class BasicLinkerIsCompilerMixin: def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, rpath_paths: str, build_rpath: str, - install_rpath: str) -> T.List[str]: - return [] + install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: + return ([], set()) def get_linker_debug_crt_args(self) -> T.List[str]: return [] diff --git a/mesonbuild/linkers.py b/mesonbuild/linkers.py index db735e7..f02c297 100644 --- a/mesonbuild/linkers.py +++ b/mesonbuild/linkers.py @@ -56,8 +56,8 @@ class StaticLinker: def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, rpath_paths: str, build_rpath: str, - install_rpath: str) -> T.List[str]: - return [] + install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: + return ([], set()) def thread_link_flags(self, env: 'Environment') -> T.List[str]: return [] @@ -444,8 +444,8 @@ class DynamicLinker(LinkerEnvVarsMixin, metaclass=abc.ABCMeta): def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, rpath_paths: str, build_rpath: str, - install_rpath: str) -> T.List[str]: - return [] + install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: + return ([], set()) def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, suffix: str, soversion: str, darwin_versions: T.Tuple[str, str], @@ -551,12 +551,12 @@ class GnuLikeDynamicLinkerMixin: def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, rpath_paths: str, build_rpath: str, - install_rpath: str) -> T.List[str]: + install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: m = env.machines[self.for_machine] if m.is_windows() or m.is_cygwin(): - return [] + return ([], set()) if not rpath_paths and not install_rpath and not build_rpath: - return [] + return ([], set()) args = [] origin_placeholder = '$ORIGIN' processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir) @@ -564,9 +564,14 @@ class GnuLikeDynamicLinkerMixin: # is *very* allergic to duplicate -delete_rpath arguments # when calling depfixer on installation. all_paths = mesonlib.OrderedSet([os.path.join(origin_placeholder, p) for p in processed_rpaths]) + rpath_dirs_to_remove = set() + for p in all_paths: + rpath_dirs_to_remove.add(p.encode('utf8')) # Build_rpath is used as-is (it is usually absolute). if build_rpath != '': all_paths.add(build_rpath) + for p in build_rpath.split(':'): + rpath_dirs_to_remove.add(p.encode('utf8')) # TODO: should this actually be "for (dragonfly|open)bsd"? if mesonlib.is_dragonflybsd() or mesonlib.is_openbsd(): @@ -590,7 +595,7 @@ class GnuLikeDynamicLinkerMixin: # TODO: should this actually be "for solaris/sunos"? if mesonlib.is_sunos(): - return args + return (args, rpath_dirs_to_remove) # Rpaths to use while linking must be absolute. These are not # written to the binary. Needed only with GNU ld: @@ -610,7 +615,7 @@ class GnuLikeDynamicLinkerMixin: for p in rpath_paths: args.extend(self._apply_prefix('-rpath-link,' + os.path.join(build_dir, p))) - return args + return (args, rpath_dirs_to_remove) class AppleDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): @@ -676,9 +681,9 @@ class AppleDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, rpath_paths: str, build_rpath: str, - install_rpath: str) -> T.List[str]: + install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: if not rpath_paths and not install_rpath and not build_rpath: - return [] + return ([], set()) # Ensure that there is enough space for install_name_tool in-place # editing of large RPATHs args = self._apply_prefix('-headerpad_max_install_names') @@ -692,7 +697,7 @@ class AppleDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): for rp in all_paths: args.extend(self._apply_prefix('-rpath,' + rp)) - return args + return (args, set()) class GnuDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, DynamicLinker): @@ -763,8 +768,8 @@ class WASMDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, Dyna def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, rpath_paths: str, build_rpath: str, - install_rpath: str) -> T.List[str]: - return [] + install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: + return ([], set()) class CcrxDynamicLinker(DynamicLinker): @@ -839,8 +844,8 @@ class Xc16DynamicLinker(DynamicLinker): def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, rpath_paths: str, build_rpath: str, - install_rpath: str) -> T.List[str]: - return [] + install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: + return ([], set()) class C2000DynamicLinker(DynamicLinker): @@ -938,10 +943,10 @@ class PGIDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, rpath_paths: str, build_rpath: str, - install_rpath: str) -> T.List[str]: + install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: if not env.machines[self.for_machine].is_windows(): - return ['-R' + os.path.join(build_dir, p) for p in rpath_paths] - return [] + return (['-R' + os.path.join(build_dir, p) for p in rpath_paths], set()) + return ([], set()) class PGIStaticLinker(StaticLinker): @@ -1091,9 +1096,9 @@ class SolarisDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, rpath_paths: str, build_rpath: str, - install_rpath: str) -> T.List[str]: + install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: if not rpath_paths and not install_rpath and not build_rpath: - return [] + return ([], set()) processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir) all_paths = mesonlib.OrderedSet([os.path.join('$ORIGIN', p) for p in processed_rpaths]) if build_rpath != '': @@ -1108,7 +1113,7 @@ class SolarisDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): paths = padding else: paths = paths + ':' + padding - return self._apply_prefix('-rpath,{}'.format(paths)) + return (self._apply_prefix('-rpath,{}'.format(paths)), set()) def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, suffix: str, soversion: str, darwin_versions: T.Tuple[str, str], diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py index 9c64429..0be01fe 100644 --- a/mesonbuild/minstall.py +++ b/mesonbuild/minstall.py @@ -512,7 +512,7 @@ class Installer: if file_copied: self.did_install_something = True try: - depfixer.fix_rpath(outname, install_rpath, final_path, + depfixer.fix_rpath(outname, t.rpath_dirs_to_remove, install_rpath, final_path, install_name_mappings, verbose=False) except SystemExit as e: if isinstance(e.code, int) and e.code == 0: diff --git a/mesonbuild/scripts/depfixer.py b/mesonbuild/scripts/depfixer.py index 5ba3a97..a3a3eff 100644 --- a/mesonbuild/scripts/depfixer.py +++ b/mesonbuild/scripts/depfixer.py @@ -290,13 +290,13 @@ class Elf(DataSizes): self.bf.seek(offset) self.bf.write(newname) - def fix_rpath(self, new_rpath): + def fix_rpath(self, rpath_dirs_to_remove, new_rpath): # The path to search for can be either rpath or runpath. # Fix both of them to be sure. - self.fix_rpathtype_entry(new_rpath, DT_RPATH) - self.fix_rpathtype_entry(new_rpath, DT_RUNPATH) + self.fix_rpathtype_entry(rpath_dirs_to_remove, new_rpath, DT_RPATH) + self.fix_rpathtype_entry(rpath_dirs_to_remove, new_rpath, DT_RUNPATH) - def fix_rpathtype_entry(self, new_rpath, entrynum): + def fix_rpathtype_entry(self, rpath_dirs_to_remove, new_rpath, entrynum): if isinstance(new_rpath, str): new_rpath = new_rpath.encode('utf8') rp_off = self.get_entry_offset(entrynum) @@ -305,7 +305,23 @@ class Elf(DataSizes): print('File does not have rpath. It should be a fully static executable.') return self.bf.seek(rp_off) + old_rpath = self.read_str() + new_rpaths = [] + if new_rpath: + new_rpaths.append(new_rpath) + if old_rpath: + # Filter out build-only rpath entries + # added by get_link_dep_subdirs() or + # specified by user with build_rpath. + for dir in old_rpath.split(b':'): + if not (dir in rpath_dirs_to_remove or + dir == (b'X' * len(dir))): + new_rpaths.append(dir) + + # Prepend user-specified new entries while preserving the ones that came from pkgconfig etc. + new_rpath = b':'.join(new_rpaths) + if len(old_rpath) < len(new_rpath): sys.exit("New rpath must not be longer than the old one.") # The linker does read-only string deduplication. If there is a @@ -343,13 +359,13 @@ class Elf(DataSizes): entry.write(self.bf) return None -def fix_elf(fname, new_rpath, verbose=True): +def fix_elf(fname, rpath_dirs_to_remove, new_rpath, verbose=True): with Elf(fname, verbose) as e: if new_rpath is None: e.print_rpath() e.print_runpath() else: - e.fix_rpath(new_rpath) + e.fix_rpath(rpath_dirs_to_remove, new_rpath) def get_darwin_rpaths_to_remove(fname): out = subprocess.check_output(['otool', '-l', fname], @@ -430,7 +446,7 @@ def fix_jar(fname): f.truncate() subprocess.check_call(['jar', 'ufm', fname, 'META-INF/MANIFEST.MF']) -def fix_rpath(fname, new_rpath, final_path, install_name_mappings, verbose=True): +def fix_rpath(fname, rpath_dirs_to_remove, new_rpath, final_path, install_name_mappings, verbose=True): global INSTALL_NAME_TOOL # Static libraries, import libraries, debug information, headers, etc # never have rpaths @@ -441,7 +457,7 @@ def fix_rpath(fname, new_rpath, final_path, install_name_mappings, verbose=True) if fname.endswith('.jar'): fix_jar(fname) return - fix_elf(fname, new_rpath, verbose) + fix_elf(fname, rpath_dirs_to_remove, new_rpath, verbose) return except SystemExit as e: if isinstance(e.code, int) and e.code == 0: |