Skip to content

Commit

Permalink
Let .pc files specify rpath.
Browse files Browse the repository at this point in the history
Fixes #4027
  • Loading branch information
dankegel committed May 16, 2020
1 parent efb8608 commit d7235c5
Show file tree
Hide file tree
Showing 21 changed files with 177 additions and 55 deletions.
15 changes: 9 additions & 6 deletions mesonbuild/backend/backends.py
Expand Up @@ -90,12 +90,13 @@ def __init__(self, source_dir, build_dir, prefix, strip_bin,
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
Expand Down Expand Up @@ -476,6 +477,7 @@ def determine_rpath_dirs(self, target):
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):
Expand Down Expand Up @@ -1140,6 +1142,7 @@ def generate_target_install(self, d):
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)

Expand All @@ -1157,14 +1160,14 @@ def generate_target_install(self, d):
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.
Expand All @@ -1174,7 +1177,7 @@ def generate_target_install(self, d):
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
Expand All @@ -1187,7 +1190,7 @@ def generate_target_install(self, d):
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:
Expand All @@ -1196,7 +1199,7 @@ def generate_target_install(self, d):
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)

Expand Down
7 changes: 5 additions & 2 deletions mesonbuild/backend/ninjabackend.py
Expand Up @@ -1348,7 +1348,8 @@ def generate_rust_target(self, target):
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),
Expand Down Expand Up @@ -2580,12 +2581,14 @@ def generate_link(self, target, outname, obj_list, linker, extra_args=None, stdl
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
Expand Down
2 changes: 2 additions & 0 deletions mesonbuild/build.py
Expand Up @@ -511,6 +511,8 @@ def __init__(self, name, subdir, subproject, for_machine: MachineChoice, sources
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
Expand Down
2 changes: 1 addition & 1 deletion mesonbuild/compilers/compilers.py
Expand Up @@ -1077,7 +1077,7 @@ def get_instruction_set_args(self, instruction_set):

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)

Expand Down
7 changes: 4 additions & 3 deletions mesonbuild/compilers/cuda.py
Expand Up @@ -271,9 +271,10 @@ def get_buildtype_linker_args(self, buildtype):

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
Expand Down
9 changes: 5 additions & 4 deletions mesonbuild/compilers/d.py
Expand Up @@ -220,23 +220,24 @@ def gen_import_library_args(self, implibname):

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'):
# The way that dmd and ldc pass rpath to gcc is different than we would
# 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)
Expand Down
4 changes: 2 additions & 2 deletions mesonbuild/compilers/mixins/islinker.py
Expand Up @@ -107,8 +107,8 @@ def get_soname_args(self, for_machine: 'mesonlib.MachineChoice',

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 []
Expand Down
49 changes: 27 additions & 22 deletions mesonbuild/linkers.py
Expand Up @@ -56,8 +56,8 @@ def get_coverage_link_args(self) -> T.List[str]:

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 []
Expand Down Expand Up @@ -444,8 +444,8 @@ def get_debug_crt_args(self) -> T.List[str]:

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],
Expand Down Expand Up @@ -551,22 +551,27 @@ def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,

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)
# Need to deduplicate rpaths, as macOS's install_name_tool
# 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():
Expand All @@ -590,7 +595,7 @@ def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,

# 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:
Expand All @@ -610,7 +615,7 @@ def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
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):
Expand Down Expand Up @@ -676,9 +681,9 @@ def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,

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')
Expand All @@ -692,7 +697,7 @@ def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
for rp in all_paths:
args.extend(self._apply_prefix('-rpath,' + rp))

return args
return (args, set())


class GnuDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, DynamicLinker):
Expand Down Expand Up @@ -763,8 +768,8 @@ def get_asneeded_args(self) -> T.List[str]:

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):
Expand Down Expand Up @@ -839,8 +844,8 @@ def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,

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):
Expand Down Expand Up @@ -938,10 +943,10 @@ def get_std_shared_lib_args(self) -> T.List[str]:

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):
Expand Down Expand Up @@ -1091,9 +1096,9 @@ def fatal_warnings(self) -> T.List[str]:

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 != '':
Expand All @@ -1108,7 +1113,7 @@ def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
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],
Expand Down
2 changes: 1 addition & 1 deletion mesonbuild/minstall.py
Expand Up @@ -512,7 +512,7 @@ def install_targets(self, d):
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:
Expand Down

0 comments on commit d7235c5

Please sign in to comment.