Test that binaries that use external libraries work

When we link to an external library either with find_library() without
any dirs:, or with dependency(), we should be able to run uninstalled
out of the box without having to set any environment variables or other
shenanigans.

This is especially important on macOS because only the system frameworks
directory is in the default runtime path, and all other frameworks and
libraries need to be found with RPATH or absolute path to the dylib.
pull/3750/head
Nirbheek Chauhan 7 years ago committed by Nirbheek Chauhan
parent 6e2ee24619
commit 5467eed186
  1. 2
      .travis.yml
  2. 65
      run_unittests.py
  3. 7
      test cases/unit/33 external, internal library rpath/built library/bar.c
  4. 11
      test cases/unit/33 external, internal library rpath/built library/meson.build
  5. 1
      test cases/unit/33 external, internal library rpath/built library/meson_options.txt
  6. 7
      test cases/unit/33 external, internal library rpath/built library/prog.c
  7. 4
      test cases/unit/33 external, internal library rpath/external library/faa.c
  8. 4
      test cases/unit/33 external, internal library rpath/external library/foo.c
  9. 9
      test cases/unit/33 external, internal library rpath/external library/meson.build

@ -42,7 +42,7 @@ before_install:
- python ./skip_ci.py --base-branch-env=TRAVIS_BRANCH --is-pull-env=TRAVIS_PULL_REQUEST
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew uninstall python mercurial; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install python@2 python@3 mercurial qt; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install python@2 python@3 mercurial qt pkg-config; fi
# Use a Ninja with QuLogic's patch: https://github.com/ninja-build/ninja/issues/1219
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then mkdir -p $HOME/tools; curl -L http://nirbheek.in/files/binaries/ninja/macos/ninja -o $HOME/tools/ninja; chmod +x $HOME/tools/ninja; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker pull jpakkane/mesonci:bionic; fi

@ -74,6 +74,19 @@ def get_soname(fname):
def get_rpath(fname):
return get_dynamic_section_entry(fname, r'(?:rpath|runpath)')
def skipIfNoPkgconfig(f):
'''
Skip this test if no pkg-config is found, unless we're on Travis CI
This allows users to run our test suite without having pkg-config installed
on, f.ex., macOS, while ensuring that our Travis CI does not silently skip
the test because of misconfiguration.
'''
def wrapped(*args, **kwargs):
if 'TRAVIS' not in os.environ and shutil.which('pkg-config') is None:
raise unittest.SkipTest('pkg-config not found')
return f(*args, **kwargs)
return wrapped
class InternalTests(unittest.TestCase):
@ -484,7 +497,7 @@ class BasePlatformTests(unittest.TestCase):
src_root = os.path.join(os.getcwd(), src_root)
self.src_root = src_root
self.prefix = '/usr'
self.libdir = os.path.join(self.prefix, 'lib')
self.libdir = 'lib'
# Get the backend
# FIXME: Extract this from argv?
self.backend = getattr(Backend, os.environ.get('MESON_UNIT_TEST_BACKEND', 'ninja'))
@ -1656,6 +1669,7 @@ int main(int argc, char **argv) {
if os.path.splitext(fname)[1] not in ['.c', '.h']:
os.unlink(fname)
@skipIfNoPkgconfig
def test_pkgconfig_static(self):
'''
Test that the we prefer static libraries when `static: true` is
@ -1666,8 +1680,6 @@ int main(int argc, char **argv) {
since system libraries -lm will never be found statically.
https://github.com/mesonbuild/meson/issues/2785
'''
if not shutil.which('pkg-config'):
raise unittest.SkipTest('pkg-config not found')
(cc, stlinker, objext, shext) = self.detect_prebuild_env()
testdir = os.path.join(self.unit_test_dir, '17 pkgconfig static')
source = os.path.join(testdir, 'foo.c')
@ -1699,9 +1711,8 @@ int main(int argc, char **argv) {
if os.path.splitext(fname)[1] not in ['.c', '.h', '.in']:
os.unlink(fname)
@skipIfNoPkgconfig
def test_pkgconfig_gen_escaping(self):
if not shutil.which('pkg-config'):
raise unittest.SkipTest('pkg-config not found')
testdir = os.path.join(self.common_test_dir, '51 pkgconfig-gen')
prefix = '/usr/with spaces'
libdir = 'lib'
@ -2264,9 +2275,8 @@ class FailureTests(BasePlatformTests):
out = self.init(self.srcdir, extra_args=extra_args, inprocess=True)
self.assertRegex(out, match)
@skipIfNoPkgconfig
def test_dependency(self):
if not shutil.which('pkg-config'):
raise unittest.SkipTest('pkg-config not found')
if subprocess.call(['pkg-config', '--exists', 'zlib']) != 0:
raise unittest.SkipTest('zlib not found with pkg-config')
a = (("dependency('zlib', method : 'fail')", "'fail' is invalid"),
@ -2660,13 +2670,12 @@ class LinuxlikeTests(BasePlatformTests):
self.assertIn(" -Werror ", vala_command)
self.assertIn(" -Werror ", c_command)
@skipIfNoPkgconfig
def test_qt5dependency_pkgconfig_detection(self):
'''
Test that qt4 and qt5 detection with pkgconfig works.
'''
# Verify Qt4 or Qt5 can be found with pkg-config
if not shutil.which('pkg-config'):
raise unittest.SkipTest('pkg-config not found')
qt4 = subprocess.call(['pkg-config', '--exists', 'QtCore'])
qt5 = subprocess.call(['pkg-config', '--exists', 'Qt5Core'])
if qt4 != 0 or qt5 != 0:
@ -3206,7 +3215,7 @@ endian = 'little'
self.build()
mesonbuild.modules.gnome.native_glib_version = None
@unittest.skipIf(shutil.which('pkg-config') is None, 'Pkg-config not found.')
@skipIfNoPkgconfig
def test_pkgconfig_usage(self):
testdir1 = os.path.join(self.unit_test_dir, '24 pkgconfig usage/dependency')
testdir2 = os.path.join(self.unit_test_dir, '24 pkgconfig usage/dependee')
@ -3242,7 +3251,7 @@ endian = 'little'
self.assertTrue(os.path.isfile(test_exe))
subprocess.check_call(test_exe, env=myenv)
@unittest.skipIf(shutil.which('pkg-config') is None, 'Pkg-config not found.')
@skipIfNoPkgconfig
def test_pkgconfig_internal_libraries(self):
'''
'''
@ -3263,7 +3272,7 @@ endian = 'little'
self.init(os.path.join(testdirbase, 'app'))
self.build()
@unittest.skipIf(shutil.which('pkg-config') is None, 'Pkg-config not found.')
@skipIfNoPkgconfig
def test_pkgconfig_formatting(self):
testdir = os.path.join(self.unit_test_dir, '31 pkgconfig format')
self.init(testdir)
@ -3271,7 +3280,7 @@ endian = 'little'
myenv['PKG_CONFIG_PATH'] = self.privatedir
stdo = subprocess.check_output(['pkg-config', '--libs-only-l', 'libsomething'], env=myenv)
deps = [b'-lgobject-2.0', b'-lgio-2.0', b'-lglib-2.0', b'-lsomething']
if is_windows() or is_cygwin():
if is_windows() or is_cygwin() or is_osx():
# On Windows, libintl is a separate library
deps.append(b'-lintl')
self.assertEqual(set(deps), set(stdo.split()))
@ -3323,6 +3332,36 @@ endian = 'little'
self.build()
self.run_tests()
@skipIfNoPkgconfig
def test_uninstalled_usage_external_library(self):
'''
Test that uninstalled usage of an external library (from the system or
PkgConfigDependency) works. On Linux/BSD/macOS it tests if RPATHs are
set correctly.
TODO: On Windows, this can test whether PATH is set properly
The system library is found with cc.find_library() and pkg-config deps.
'''
oldprefix = self.prefix
# Install external library so we can find it
testdir = os.path.join(self.unit_test_dir, '33 external, internal library rpath', 'external library')
installdir = self.installdir
self.prefix = installdir
self.init(testdir)
self.build()
self.install(use_destdir=False)
self.prefix = oldprefix
# New builddir for the consumer
self.new_builddir()
os.environ['LIBRARY_PATH'] = os.path.join(installdir, self.libdir)
os.environ['PKG_CONFIG_PATH'] = os.path.join(installdir, self.libdir, 'pkgconfig')
testdir = os.path.join(self.unit_test_dir, '33 external, internal library rpath', 'built library')
self.init(testdir)
self.build()
self.run_tests()
class LinuxArmCrossCompileTests(BasePlatformTests):
'''
Tests that verify cross-compilation to Linux/ARM

@ -0,0 +1,7 @@
int foo_system_value (void);
int faa_system_value (void);
int bar_built_value (int in)
{
return faa_system_value() + foo_system_value() + in;
}

@ -0,0 +1,11 @@
project('built library', 'c')
cc = meson.get_compiler('c')
foo_system_dep = cc.find_library('foo_in_system')
faa_pkg_dep = dependency('faa_pkg')
l = shared_library('bar_built', 'bar.c',
dependencies : [foo_system_dep, faa_pkg_dep])
e = executable('prog', 'prog.c', link_with: l)
test('testprog', e)

@ -0,0 +1 @@
option('foo_system_path', type: 'string', value: '')

@ -0,0 +1,7 @@
int bar_built_value (int in);
int main (int argc, char *argv[])
{
// this will evaluate to 0
return bar_built_value(10) - (42 + 1969 + 10);
}

@ -0,0 +1,4 @@
int faa_system_value (void)
{
return 1969;
}

@ -0,0 +1,9 @@
project('system library', 'c')
shared_library('foo_in_system', 'foo.c', install : true)
l = shared_library('faa_pkg', 'faa.c', install: true)
pkg = import('pkgconfig')
pkg.generate(name: 'faa_pkg',
libraries: l,
description: 'FAA, a pkg-config test library')
Loading…
Cancel
Save