diff options
author | Nirbheek Chauhan <nirbheek@centricular.com> | 2018-06-05 17:37:02 +0530 |
---|---|---|
committer | Nirbheek Chauhan <nirbheek.chauhan@gmail.com> | 2018-06-18 06:33:23 +0000 |
commit | 5467eed186c0576704b3d6de2e8d2d8a8ca6ad35 (patch) | |
tree | 7a34518aa7a5948647d7e8c59b771e99902f7dfe | |
parent | 6e2ee246197a8dd12e8f147975b79599dc881360 (diff) | |
download | meson-5467eed186c0576704b3d6de2e8d2d8a8ca6ad35.tar.gz |
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.
9 files changed, 96 insertions, 14 deletions
diff --git a/.travis.yml b/.travis.yml index 62385d68e..6f31f998e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/run_unittests.py b/run_unittests.py index 7c68904ea..c4d954727 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -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 diff --git a/test cases/unit/33 external, internal library rpath/built library/bar.c b/test cases/unit/33 external, internal library rpath/built library/bar.c new file mode 100644 index 000000000..4f5662ebd --- /dev/null +++ b/test cases/unit/33 external, internal library rpath/built library/bar.c @@ -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; +} diff --git a/test cases/unit/33 external, internal library rpath/built library/meson.build b/test cases/unit/33 external, internal library rpath/built library/meson.build new file mode 100644 index 000000000..cb58f09c4 --- /dev/null +++ b/test cases/unit/33 external, internal library rpath/built library/meson.build @@ -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) diff --git a/test cases/unit/33 external, internal library rpath/built library/meson_options.txt b/test cases/unit/33 external, internal library rpath/built library/meson_options.txt new file mode 100644 index 000000000..aa1d2ec9b --- /dev/null +++ b/test cases/unit/33 external, internal library rpath/built library/meson_options.txt @@ -0,0 +1 @@ +option('foo_system_path', type: 'string', value: '') diff --git a/test cases/unit/33 external, internal library rpath/built library/prog.c b/test cases/unit/33 external, internal library rpath/built library/prog.c new file mode 100644 index 000000000..e3d4cf63f --- /dev/null +++ b/test cases/unit/33 external, internal library rpath/built library/prog.c @@ -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); +} diff --git a/test cases/unit/33 external, internal library rpath/external library/faa.c b/test cases/unit/33 external, internal library rpath/external library/faa.c new file mode 100644 index 000000000..473357516 --- /dev/null +++ b/test cases/unit/33 external, internal library rpath/external library/faa.c @@ -0,0 +1,4 @@ +int faa_system_value (void) +{ + return 1969; +} diff --git a/test cases/unit/33 external, internal library rpath/external library/foo.c b/test cases/unit/33 external, internal library rpath/external library/foo.c new file mode 100644 index 000000000..a34e4a885 --- /dev/null +++ b/test cases/unit/33 external, internal library rpath/external library/foo.c @@ -0,0 +1,4 @@ +int foo_system_value (void) +{ + return 42; +} diff --git a/test cases/unit/33 external, internal library rpath/external library/meson.build b/test cases/unit/33 external, internal library rpath/external library/meson.build new file mode 100644 index 000000000..0e9f443f4 --- /dev/null +++ b/test cases/unit/33 external, internal library rpath/external library/meson.build @@ -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') |