Let .pc files specify rpath.

Fixes #4027
pull/7103/head
Dan Kegel 5 years ago
parent efb86088bc
commit d7235c5905
  1. 15
      mesonbuild/backend/backends.py
  2. 7
      mesonbuild/backend/ninjabackend.py
  3. 2
      mesonbuild/build.py
  4. 2
      mesonbuild/compilers/compilers.py
  5. 7
      mesonbuild/compilers/cuda.py
  6. 9
      mesonbuild/compilers/d.py
  7. 4
      mesonbuild/compilers/mixins/islinker.py
  8. 49
      mesonbuild/linkers.py
  9. 2
      mesonbuild/minstall.py
  10. 32
      mesonbuild/scripts/depfixer.py
  11. 59
      run_unittests.py
  12. 5
      test cases/unit/40 external, internal library rpath/built library/meson.build
  13. 6
      test cases/unit/40 external, internal library rpath/external library/meson.build
  14. 8
      test cases/unit/76 pkgconfig prefixes/client/client.c
  15. 3
      test cases/unit/76 pkgconfig prefixes/client/meson.build
  16. 5
      test cases/unit/76 pkgconfig prefixes/val1/meson.build
  17. 3
      test cases/unit/76 pkgconfig prefixes/val1/val1.c
  18. 1
      test cases/unit/76 pkgconfig prefixes/val1/val1.h
  19. 8
      test cases/unit/76 pkgconfig prefixes/val2/meson.build
  20. 4
      test cases/unit/76 pkgconfig prefixes/val2/val2.c
  21. 1
      test cases/unit/76 pkgconfig prefixes/val2/val2.h

@ -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
@ -476,6 +477,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 +1142,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 +1160,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 +1177,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 +1190,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 +1199,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

@ -511,6 +511,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
@ -6390,13 +6390,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
@ -6413,6 +6415,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; }
Loading…
Cancel
Save