Merge pull request #7103 from dankegel/bug4027-rpath-remember

Let .pc files and LDFLAGS provide rpaths.
pull/7084/head
Jussi Pakkanen 5 years ago committed by GitHub
commit 751ea3df72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      docs/markdown/snippets/rpath_behavior.md
  2. 33
      mesonbuild/backend/backends.py
  3. 7
      mesonbuild/backend/ninjabackend.py
  4. 2
      mesonbuild/build.py
  5. 2
      mesonbuild/compilers/compilers.py
  6. 7
      mesonbuild/compilers/cuda.py
  7. 9
      mesonbuild/compilers/d.py
  8. 4
      mesonbuild/compilers/mixins/islinker.py
  9. 49
      mesonbuild/linkers.py
  10. 2
      mesonbuild/minstall.py
  11. 32
      mesonbuild/scripts/depfixer.py
  12. 92
      run_unittests.py
  13. 5
      test cases/unit/40 external, internal library rpath/built library/meson.build
  14. 6
      test cases/unit/40 external, internal library rpath/external library/meson.build
  15. 8
      test cases/unit/76 pkgconfig prefixes/client/client.c
  16. 3
      test cases/unit/76 pkgconfig prefixes/client/meson.build
  17. 5
      test cases/unit/76 pkgconfig prefixes/val1/meson.build
  18. 3
      test cases/unit/76 pkgconfig prefixes/val1/val1.c
  19. 1
      test cases/unit/76 pkgconfig prefixes/val1/val1.h
  20. 8
      test cases/unit/76 pkgconfig prefixes/val2/meson.build
  21. 4
      test cases/unit/76 pkgconfig prefixes/val2/val2.c
  22. 1
      test cases/unit/76 pkgconfig prefixes/val2/val2.h
  23. 3
      test cases/unit/77 global-rpath/meson.build
  24. 6
      test cases/unit/77 global-rpath/rpathified.cpp
  25. 5
      test cases/unit/77 global-rpath/yonder/meson.build
  26. 3
      test cases/unit/77 global-rpath/yonder/yonder.cpp
  27. 1
      test cases/unit/77 global-rpath/yonder/yonder.h

@ -0,0 +1,7 @@
## rpath removal now more careful
On Linux-like systems, meson adds rpath entries to allow running apps
in the build tree, and then removes those build-time-only
rpath entries when installing. Rpath entries may also come
in via LDFLAGS and via .pc files. Meson used to remove those
latter rpath entries by accident, but is now more careful.

@ -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)

@ -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

@ -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

@ -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)

@ -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

@ -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)

@ -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 []

@ -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],

@ -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:

@ -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:

@ -56,7 +56,7 @@ from mesonbuild.mesonlib import (
BuildDirLock, LibType, MachineChoice, PerMachine, Version, is_windows,
is_osx, is_cygwin, is_dragonflybsd, is_openbsd, is_haiku, is_sunos,
windows_proof_rmtree, python_command, version_compare, split_args,
quote_arg, relpath
quote_arg, relpath, is_linux
)
from mesonbuild.environment import detect_ninja
from mesonbuild.mesonlib import MesonException, EnvironmentException
@ -6080,6 +6080,39 @@ class LinuxlikeTests(BasePlatformTests):
install_rpath = get_rpath(os.path.join(self.installdir, 'usr/bin/progcxx'))
self.assertEqual(install_rpath, 'baz')
def test_global_rpath(self):
if is_cygwin():
raise unittest.SkipTest('Windows PE/COFF binaries do not use RPATH')
if is_osx():
raise unittest.SkipTest('Global RPATHs via LDFLAGS not yet supported on MacOS (does anybody need it?)')
testdir = os.path.join(self.unit_test_dir, '77 global-rpath')
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_libdir = os.path.join(yonder_prefix, self.libdir)
self.prefix = yonder_prefix
self.installdir = yonder_prefix
self.init(yonder_dir)
self.build()
self.install(use_destdir=False)
self.new_builddir()
# Build an app that uses that installed library.
# Supply the rpath to the installed library via LDFLAGS
# (as systems like buildroot and guix are wont to do)
# and verify install preserves that rpath.
env = {'LDFLAGS': '-Wl,-rpath=' + yonder_libdir,
'PKG_CONFIG_PATH': os.path.join(yonder_libdir, 'pkgconfig')}
self.init(testdir, override_envvars=env)
self.build()
self.install(use_destdir=False)
got_rpath = get_rpath(os.path.join(yonder_prefix, 'bin/rpathified'))
self.assertEqual(got_rpath, yonder_libdir)
@skip_if_not_base_option('b_sanitize')
def test_pch_with_address_sanitizer(self):
if is_cygwin():
@ -6391,13 +6424,15 @@ class LinuxlikeTests(BasePlatformTests):
self.build(override_envvars=env)
# test uninstalled
self.run_tests(override_envvars=env)
if not is_osx():
# Rest of the workflow only works on macOS
if not (is_osx() or is_linux()):
return
# test running after installation
self.install(use_destdir=False)
prog = os.path.join(self.installdir, 'bin', 'prog')
self._run([prog])
if not is_osx():
# Rest of the workflow only works on macOS
return
out = self._run(['otool', '-L', prog])
self.assertNotIn('@rpath', out)
## New builddir for testing that DESTDIR is not added to install_name
@ -6414,6 +6449,57 @@ class LinuxlikeTests(BasePlatformTests):
# Ensure that the otool output does not contain self.installdir
self.assertNotRegex(out, self.installdir + '.*dylib ')
@skipIfNoPkgconfig
def test_usage_pkgconfig_prefixes(self):
'''
Build and install two external libraries, to different prefixes,
then build and install a client program that finds them via pkgconfig,
and verify the installed client program runs.
'''
oldinstalldir = self.installdir
# Build and install both external libraries without DESTDIR
val1dir = os.path.join(self.unit_test_dir, '76 pkgconfig prefixes', 'val1')
val1prefix = os.path.join(oldinstalldir, 'val1')
self.prefix = val1prefix
self.installdir = val1prefix
self.init(val1dir)
self.build()
self.install(use_destdir=False)
self.new_builddir()
env1 = {}
env1['PKG_CONFIG_PATH'] = os.path.join(val1prefix, self.libdir, 'pkgconfig')
val2dir = os.path.join(self.unit_test_dir, '76 pkgconfig prefixes', 'val2')
val2prefix = os.path.join(oldinstalldir, 'val2')
self.prefix = val2prefix
self.installdir = val2prefix
self.init(val2dir, override_envvars=env1)
self.build()
self.install(use_destdir=False)
self.new_builddir()
# Build, install, and run the client program
env2 = {}
env2['PKG_CONFIG_PATH'] = os.path.join(val2prefix, self.libdir, 'pkgconfig')
testdir = os.path.join(self.unit_test_dir, '76 pkgconfig prefixes', 'client')
testprefix = os.path.join(oldinstalldir, 'client')
self.prefix = testprefix
self.installdir = testprefix
self.init(testdir, override_envvars=env2)
self.build()
self.install(use_destdir=False)
prog = os.path.join(self.installdir, 'bin', 'client')
env3 = {}
if is_cygwin():
env3['PATH'] = os.path.join(val1prefix, 'bin') + \
os.pathsep + \
os.path.join(val2prefix, 'bin') + \
os.pathsep + os.environ['PATH']
out = self._run([prog], override_envvars=env3).strip()
# Expected output is val1 + val2 = 3
self.assertEqual(out, '3')
def install_subdir_invalid_symlinks(self, testdir, subdir_path):
'''
Test that installation of broken symlinks works fine.

@ -18,4 +18,9 @@ l = shared_library('bar_built', 'bar.c',
if host_machine.system() == 'darwin'
e = executable('prog', 'prog.c', link_with: l, install: true)
test('testprog', e)
elif host_machine.system() == 'linux'
e = executable('prog', 'prog.c', link_with: l, install: true,
install_rpath: '$ORIGIN/..' / get_option('libdir'),
)
test('testprog', e)
endif

@ -4,16 +4,16 @@ shared_library('foo_in_system', 'foo.c', install : true)
l = shared_library('faa_pkg', 'faa.c', install: true)
if host_machine.system() == 'darwin'
frameworks = ['-framework', 'CoreFoundation', '-framework', 'CoreMedia']
ldflags = ['-framework', 'CoreFoundation', '-framework', 'CoreMedia']
allow_undef_args = ['-Wl,-undefined,dynamic_lookup']
else
frameworks = []
ldflags = ['-Wl,-rpath,${libdir}']
allow_undef_args = []
endif
pkg = import('pkgconfig')
pkg.generate(name: 'faa_pkg',
libraries: [l] + frameworks,
libraries: [l] + ldflags,
description: 'FAA, a pkg-config test library')
# cygwin DLLs can't have undefined symbols

@ -0,0 +1,8 @@
#include <val2.h>
#include <stdio.h>
int main(int argc, char **argv)
{
printf("%d\n", val2());
return 0;
}

@ -0,0 +1,3 @@
project('client', 'c')
val2_dep = dependency('val2')
executable('client', 'client.c', dependencies : [val2_dep], install: true)

@ -0,0 +1,5 @@
project('val1', 'c')
val1 = shared_library('val1', 'val1.c', install: true)
install_headers('val1.h')
pkgconfig = import('pkgconfig')
pkgconfig.generate(val1, libraries : ['-Wl,-rpath,${libdir}'])

@ -0,0 +1,3 @@
#include "val1.h"
int val1(void) { return 1; }

@ -0,0 +1,8 @@
project('val2', 'c')
val1_dep = dependency('val1')
val2 = shared_library('val2', 'val2.c',
dependencies : [val1_dep],
install: true)
install_headers('val2.h')
pkgconfig = import('pkgconfig')
pkgconfig.generate(val2, libraries : ['-Wl,-rpath,${libdir}'])

@ -0,0 +1,4 @@
#include "val1.h"
#include "val2.h"
int val2(void) { return val1() + 2; }

@ -0,0 +1,3 @@
project('global-rpath', 'cpp')
yonder_dep = dependency('yonder')
executable('rpathified', 'rpathified.cpp', dependencies: [yonder_dep], install: true)

@ -0,0 +1,6 @@
#include <yonder.h>
#include <string.h>
int main(int argc, char **argv)
{
return strcmp(yonder(), "AB54 6BR");
}

@ -0,0 +1,5 @@
project('yonder', 'cpp')
yonder = shared_library('yonder', 'yonder.cpp', install: true)
install_headers('yonder.h')
pkgconfig = import('pkgconfig')
pkgconfig.generate(yonder)

@ -0,0 +1,3 @@
#include "yonder.h"
char *yonder(void) { return "AB54 6BR"; }
Loading…
Cancel
Save