Skip to content

Commit

Permalink
test and fix generating/using pkgconfig libraries across prefix bound…
Browse files Browse the repository at this point in the history
…aries
  • Loading branch information
dankegel committed May 10, 2020
1 parent 30c4a77 commit 6474a7a
Show file tree
Hide file tree
Showing 21 changed files with 171 additions and 39 deletions.
16 changes: 9 additions & 7 deletions mesonbuild/backend/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,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 @@ -445,6 +446,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 @@ -1109,7 +1111,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.install_rpath, install_mode)
t.rpath_dirs_to_remove, t.install_rpath, install_mode)
d.targets.append(i)

if isinstance(t, (build.SharedLibrary, build.SharedModule, build.Executable)):
Expand All @@ -1126,14 +1128,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 @@ -1143,7 +1145,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 @@ -1156,7 +1158,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 @@ -1165,7 +1167,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
6 changes: 4 additions & 2 deletions mesonbuild/backend/ninjabackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -1354,7 +1354,8 @@ def generate_rust_target(self, target):
target_slashname_workaround_dir,
self.determine_rpath_dirs(target),
target.build_rpath,
target.install_rpath)
target.install_rpath,
target.rpath_dirs_to_remove)
# ... but then add rustc's sysroot to account for rustup
# installations
for rpath_arg in rpath_args:
Expand Down Expand Up @@ -2588,7 +2589,8 @@ def generate_link(self, target, outname, obj_list, linker, extra_args=None, stdl
target_slashname_workaround_dir,
self.determine_rpath_dirs(target),
target.build_rpath,
target.install_rpath)
target.install_rpath,
target.rpath_dirs_to_remove)
# 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
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,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
5 changes: 3 additions & 2 deletions mesonbuild/compilers/compilers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1077,9 +1077,10 @@ 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,
rpath_dirs_to_remove: T.Set[bytes]) -> T.List[str]:
return self.linker.build_rpath_args(
env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath)
env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath, rpath_dirs_to_remove)

def thread_flags(self, env):
return []
Expand Down
5 changes: 3 additions & 2 deletions mesonbuild/compilers/cuda.py
Original file line number Diff line number Diff line change
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]:
install_rpath: str,
rpath_dirs_to_remove: T.Set[bytes]) -> 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))
env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath, rpath_dirs_to_remove))

def linker_to_compiler_args(self, args):
return args
Expand Down
7 changes: 4 additions & 3 deletions mesonbuild/compilers/d.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,8 @@ def get_std_exe_link_args(self):
def gen_import_library_args(self, implibname):
return self.linker.import_library_args(implibname)

def build_rpath_args(self, env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
def build_rpath_args(self, env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath,
rpath_dirs_to_remove):
if self.info.is_windows():
return []

Expand All @@ -229,7 +230,7 @@ def build_rpath_args(self, env, build_dir, from_dir, rpath_paths, build_rpath, i
# 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):
env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath, rpath_dirs_to_remove):
if ',' in r:
a, b = r.split(',', maxsplit=1)
args.append(a)
Expand All @@ -239,7 +240,7 @@ def build_rpath_args(self, env, build_dir, from_dir, rpath_paths, build_rpath, i
return args

return super().build_rpath_args(
env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath)
env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath, rpath_dirs_to_remove)

def translate_args_to_nongnu(self, args):
dcargs = []
Expand Down
3 changes: 2 additions & 1 deletion mesonbuild/compilers/mixins/islinker.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +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]:
install_rpath: str,
rpath_dirs_to_remove: T.Set[bytes]) -> T.List[str]:
return []

def get_linker_debug_crt_args(self) -> T.List[str]:
Expand Down
25 changes: 18 additions & 7 deletions mesonbuild/linkers.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +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]:
install_rpath: str,
rpath_dirs_to_remove: T.Set[bytes]) -> T.List[str]:
return []

def thread_link_flags(self, env: 'Environment') -> T.List[str]:
Expand Down Expand Up @@ -444,7 +445,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]:
install_rpath: str,
rpath_dirs_to_remove: T.Set[bytes]) -> T.List[str]:
return []

def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
Expand Down Expand Up @@ -551,7 +553,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]:
install_rpath: str,
rpath_dirs_to_remove: T.Set[bytes]) -> T.List[str]:
m = env.machines[self.for_machine]
if m.is_windows() or m.is_cygwin():
return []
Expand All @@ -564,9 +567,13 @@ def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
# 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])
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 Down Expand Up @@ -676,7 +683,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]:
install_rpath: str,
rpath_dirs_to_remove: T.Set[bytes]) -> T.List[str]:
if not rpath_paths and not install_rpath and not build_rpath:
return []
# Ensure that there is enough space for install_name_tool in-place
Expand Down Expand Up @@ -834,7 +842,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]:
install_rpath: str,
rpath_dirs_to_remove: T.Set[bytes]) -> T.List[str]:
return []


Expand Down Expand Up @@ -933,7 +942,8 @@ 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,
rpath_dirs_to_remove: T.Set[bytes]) -> T.List[str]:
if not env.machines[self.for_machine].is_windows():
return ['-R' + os.path.join(build_dir, p) for p in rpath_paths]
return []
Expand Down Expand Up @@ -1086,7 +1096,8 @@ 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,
rpath_dirs_to_remove: T.Set[bytes]) -> T.List[str]:
if not rpath_paths and not install_rpath and not build_rpath:
return []
processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir)
Expand Down
2 changes: 1 addition & 1 deletion mesonbuild/minstall.py
Original file line number Diff line number Diff line change
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
32 changes: 24 additions & 8 deletions mesonbuild/scripts/depfixer.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,13 +290,13 @@ def fix_deps(self, prefix):
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)
Expand All @@ -305,7 +305,23 @@ def fix_rpathtype_entry(self, new_rpath, entrynum):
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
Expand Down Expand Up @@ -343,13 +359,13 @@ def remove_rpath_entry(self, entrynum):
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],
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand Down
Loading

0 comments on commit 6474a7a

Please sign in to comment.