Test that system shlibs with undefined symbols can be found

pull/3921/merge
Nirbheek Chauhan 6 years ago committed by Nirbheek Chauhan
parent bb5f2ca3da
commit 5e93393cd9
  1. 36
      run_tests.py
  2. 51
      run_unittests.py
  3. 13
      test cases/unit/39 external, internal library rpath/built library/meson.build
  4. 6
      test cases/unit/39 external, internal library rpath/external library/bar.c
  5. 17
      test cases/unit/39 external, internal library rpath/external library/meson.build

@ -31,7 +31,32 @@ from mesonbuild import mesonlib
from mesonbuild import mesonmain from mesonbuild import mesonmain
from mesonbuild import mtest from mesonbuild import mtest
from mesonbuild import mlog from mesonbuild import mlog
from mesonbuild.environment import detect_ninja from mesonbuild.environment import Environment, detect_ninja
# Fake classes and objects for mocking
class FakeBuild:
def __init__(self, env):
self.environment = env
class FakeCompilerOptions:
def __init__(self):
self.value = []
def get_fake_options(prefix):
import argparse
opts = argparse.Namespace()
opts.cross_file = None
opts.wrap_mode = None
opts.prefix = prefix
opts.cmd_line_options = {}
return opts
def get_fake_env(sdir, bdir, prefix):
env = Environment(sdir, bdir, get_fake_options(prefix))
env.coredata.compiler_options['c_args'] = FakeCompilerOptions()
return env
Backend = Enum('Backend', 'ninja vs xcode') Backend = Enum('Backend', 'ninja vs xcode')
@ -148,15 +173,6 @@ def ensure_backend_detects_changes(backend):
if backend is Backend.ninja: if backend is Backend.ninja:
time.sleep(1) time.sleep(1)
def get_fake_options(prefix):
import argparse
opts = argparse.Namespace()
opts.cross_file = None
opts.wrap_mode = None
opts.prefix = prefix
opts.cmd_line_options = {}
return opts
def run_mtest_inprocess(commandlist): def run_mtest_inprocess(commandlist):
old_stdout = sys.stdout old_stdout = sys.stdout
sys.stdout = mystdout = StringIO() sys.stdout = mystdout = StringIO()

@ -41,24 +41,16 @@ from mesonbuild.mesonlib import (
windows_proof_rmtree, python_command, version_compare, windows_proof_rmtree, python_command, version_compare,
grab_leading_numbers, BuildDirLock grab_leading_numbers, BuildDirLock
) )
from mesonbuild.environment import Environment, detect_ninja from mesonbuild.environment import detect_ninja
from mesonbuild.mesonlib import MesonException, EnvironmentException from mesonbuild.mesonlib import MesonException, EnvironmentException
from mesonbuild.dependencies import PkgConfigDependency, ExternalProgram from mesonbuild.dependencies import PkgConfigDependency, ExternalProgram
import mesonbuild.modules.pkgconfig import mesonbuild.modules.pkgconfig
from run_tests import exe_suffix, get_fake_options, get_meson_script from run_tests import exe_suffix, get_fake_env, get_meson_script
from run_tests import get_builddir_target_args, get_backend_commands, Backend from run_tests import get_builddir_target_args, get_backend_commands, Backend
from run_tests import ensure_backend_detects_changes, run_configure_inprocess from run_tests import ensure_backend_detects_changes, run_configure_inprocess
from run_tests import run_mtest_inprocess from run_tests import run_mtest_inprocess
from run_tests import FakeBuild, FakeCompilerOptions
# Fake classes for mocking
class FakeBuild:
def __init__(self, env):
self.environment = env
class FakeCompilerOptions:
def __init__(self):
self.value = []
def get_dynamic_section_entry(fname, entry): def get_dynamic_section_entry(fname, entry):
if is_cygwin() or is_osx(): if is_cygwin() or is_osx():
@ -563,7 +555,7 @@ class InternalTests(unittest.TestCase):
'windows-mingw': {'shared': ['lib{}.dll.a', 'lib{}.lib', 'lib{}.dll', 'windows-mingw': {'shared': ['lib{}.dll.a', 'lib{}.lib', 'lib{}.dll',
'{}.dll.a', '{}.lib', '{}.dll'], '{}.dll.a', '{}.lib', '{}.dll'],
'static': msvc_static}} 'static': msvc_static}}
env = Environment('', '', get_fake_options('')) env = get_fake_env('', '', '')
cc = env.detect_c_compiler(False) cc = env.detect_c_compiler(False)
if is_osx(): if is_osx():
self._test_all_naming(cc, env, patterns, 'darwin') self._test_all_naming(cc, env, patterns, 'darwin')
@ -606,7 +598,7 @@ class InternalTests(unittest.TestCase):
''' '''
with tempfile.TemporaryDirectory() as tmpdir: with tempfile.TemporaryDirectory() as tmpdir:
pkgbin = ExternalProgram('pkg-config', command=['pkg-config'], silent=True) pkgbin = ExternalProgram('pkg-config', command=['pkg-config'], silent=True)
env = Environment('', '', get_fake_options('')) env = get_fake_env('', '', '')
compiler = env.detect_c_compiler(False) compiler = env.detect_c_compiler(False)
env.coredata.compilers = {'c': compiler} env.coredata.compilers = {'c': compiler}
env.coredata.compiler_options['c_link_args'] = FakeCompilerOptions() env.coredata.compiler_options['c_link_args'] = FakeCompilerOptions()
@ -692,7 +684,7 @@ class DataTests(unittest.TestCase):
with open('docs/markdown/Builtin-options.md') as f: with open('docs/markdown/Builtin-options.md') as f:
md = f.read() md = f.read()
self.assertIsNotNone(md) self.assertIsNotNone(md)
env = Environment('', '', get_fake_options('')) env = get_fake_env('', '', '')
# FIXME: Support other compilers # FIXME: Support other compilers
cc = env.detect_c_compiler(False) cc = env.detect_c_compiler(False)
cpp = env.detect_cpp_compiler(False) cpp = env.detect_cpp_compiler(False)
@ -738,7 +730,7 @@ class DataTests(unittest.TestCase):
Ensure that syntax highlighting files were updated for new functions in Ensure that syntax highlighting files were updated for new functions in
the global namespace in build files. the global namespace in build files.
''' '''
env = Environment('', '', get_fake_options('')) env = get_fake_env('', '', '')
interp = Interpreter(FakeBuild(env), mock=True) interp = Interpreter(FakeBuild(env), mock=True)
with open('data/syntax-highlighting/vim/syntax/meson.vim') as f: with open('data/syntax-highlighting/vim/syntax/meson.vim') as f:
res = re.search(r'syn keyword mesonBuiltin(\s+\\\s\w+)+', f.read(), re.MULTILINE) res = re.search(r'syn keyword mesonBuiltin(\s+\\\s\w+)+', f.read(), re.MULTILINE)
@ -1172,7 +1164,7 @@ class AllPlatformTests(BasePlatformTests):
https://github.com/mesonbuild/meson/issues/1355 https://github.com/mesonbuild/meson/issues/1355
''' '''
testdir = os.path.join(self.common_test_dir, '3 static') testdir = os.path.join(self.common_test_dir, '3 static')
env = Environment(testdir, self.builddir, get_fake_options(self.prefix)) env = get_fake_env(testdir, self.builddir, self.prefix)
cc = env.detect_c_compiler(False) cc = env.detect_c_compiler(False)
static_linker = env.detect_static_linker(cc) static_linker = env.detect_static_linker(cc)
if is_windows(): if is_windows():
@ -1459,7 +1451,7 @@ class AllPlatformTests(BasePlatformTests):
if not is_windows(): if not is_windows():
langs += [('objc', 'OBJC'), ('objcpp', 'OBJCXX')] langs += [('objc', 'OBJC'), ('objcpp', 'OBJCXX')]
testdir = os.path.join(self.unit_test_dir, '5 compiler detection') testdir = os.path.join(self.unit_test_dir, '5 compiler detection')
env = Environment(testdir, self.builddir, get_fake_options(self.prefix)) env = get_fake_env(testdir, self.builddir, self.prefix)
for lang, evar in langs: for lang, evar in langs:
# Detect with evar and do sanity checks on that # Detect with evar and do sanity checks on that
if evar in os.environ: if evar in os.environ:
@ -1561,7 +1553,7 @@ class AllPlatformTests(BasePlatformTests):
def test_always_prefer_c_compiler_for_asm(self): def test_always_prefer_c_compiler_for_asm(self):
testdir = os.path.join(self.common_test_dir, '138 c cpp and asm') testdir = os.path.join(self.common_test_dir, '138 c cpp and asm')
# Skip if building with MSVC # Skip if building with MSVC
env = Environment(testdir, self.builddir, get_fake_options(self.prefix)) env = get_fake_env(testdir, self.builddir, self.prefix)
if env.detect_c_compiler(False).get_id() == 'msvc': if env.detect_c_compiler(False).get_id() == 'msvc':
raise unittest.SkipTest('MSVC can\'t compile assembly') raise unittest.SkipTest('MSVC can\'t compile assembly')
self.init(testdir) self.init(testdir)
@ -1819,7 +1811,7 @@ int main(int argc, char **argv) {
self.assertPathExists(os.path.join(testdir, i)) self.assertPathExists(os.path.join(testdir, i))
def detect_prebuild_env(self): def detect_prebuild_env(self):
env = Environment('', self.builddir, get_fake_options(self.prefix)) env = get_fake_env('', self.builddir, self.prefix)
cc = env.detect_c_compiler(False) cc = env.detect_c_compiler(False)
stlinker = env.detect_static_linker(cc) stlinker = env.detect_static_linker(cc)
if mesonbuild.mesonlib.is_windows(): if mesonbuild.mesonlib.is_windows():
@ -1985,7 +1977,7 @@ int main(int argc, char **argv) {
'--libdir=' + libdir]) '--libdir=' + libdir])
# Find foo dependency # Find foo dependency
os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir
env = Environment(testdir, self.builddir, get_fake_options(self.prefix)) env = get_fake_env(testdir, self.builddir, self.prefix)
kwargs = {'required': True, 'silent': True} kwargs = {'required': True, 'silent': True}
foo_dep = PkgConfigDependency('libfoo', env, kwargs) foo_dep = PkgConfigDependency('libfoo', env, kwargs)
# Ensure link_args are properly quoted # Ensure link_args are properly quoted
@ -2292,7 +2284,7 @@ recommended as it is not supported on some platforms''')
testdirbase = os.path.join(self.unit_test_dir, '29 guessed linker dependencies') testdirbase = os.path.join(self.unit_test_dir, '29 guessed linker dependencies')
testdirlib = os.path.join(testdirbase, 'lib') testdirlib = os.path.join(testdirbase, 'lib')
extra_args = None extra_args = None
env = Environment(testdirlib, self.builddir, get_fake_options(self.prefix)) env = get_fake_env(testdirlib, self.builddir, self.prefix)
if env.detect_c_compiler(False).get_id() != 'msvc': if env.detect_c_compiler(False).get_id() != 'msvc':
# static libraries are not linkable with -l with msvc because meson installs them # static libraries are not linkable with -l with msvc because meson installs them
# as .a files which unix_args_to_native will not know as it expects libraries to use # as .a files which unix_args_to_native will not know as it expects libraries to use
@ -2746,7 +2738,7 @@ class FailureTests(BasePlatformTests):
''' '''
Test that when we can't detect objc or objcpp, we fail gracefully. Test that when we can't detect objc or objcpp, we fail gracefully.
''' '''
env = Environment('', self.builddir, get_fake_options(self.prefix)) env = get_fake_env('', self.builddir, self.prefix)
try: try:
env.detect_objc_compiler(False) env.detect_objc_compiler(False)
env.detect_objcpp_compiler(False) env.detect_objcpp_compiler(False)
@ -2883,7 +2875,7 @@ class WindowsTests(BasePlatformTests):
ExternalLibraryHolder from build files. ExternalLibraryHolder from build files.
''' '''
testdir = os.path.join(self.platform_test_dir, '1 basic') testdir = os.path.join(self.platform_test_dir, '1 basic')
env = Environment(testdir, self.builddir, get_fake_options(self.prefix)) env = get_fake_env(testdir, self.builddir, self.prefix)
cc = env.detect_c_compiler(False) cc = env.detect_c_compiler(False)
if cc.id != 'msvc': if cc.id != 'msvc':
raise unittest.SkipTest('Not using MSVC') raise unittest.SkipTest('Not using MSVC')
@ -2896,7 +2888,7 @@ class WindowsTests(BasePlatformTests):
testdir = os.path.join(self.platform_test_dir, '5 resources') testdir = os.path.join(self.platform_test_dir, '5 resources')
# resource compiler depfile generation is not yet implemented for msvc # resource compiler depfile generation is not yet implemented for msvc
env = Environment(testdir, self.builddir, get_fake_options(self.prefix)) env = get_fake_env(testdir, self.builddir, self.prefix)
depfile_works = env.detect_c_compiler(False).get_id() != 'msvc' depfile_works = env.detect_c_compiler(False).get_id() != 'msvc'
self.init(testdir) self.init(testdir)
@ -2985,7 +2977,7 @@ class LinuxlikeTests(BasePlatformTests):
''' '''
testdir = os.path.join(self.common_test_dir, '48 pkgconfig-gen') testdir = os.path.join(self.common_test_dir, '48 pkgconfig-gen')
self.init(testdir) self.init(testdir)
env = Environment(testdir, self.builddir, get_fake_options(self.prefix)) env = get_fake_env(testdir, self.builddir, self.prefix)
kwargs = {'required': True, 'silent': True} kwargs = {'required': True, 'silent': True}
os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir
foo_dep = PkgConfigDependency('libfoo', env, kwargs) foo_dep = PkgConfigDependency('libfoo', env, kwargs)
@ -3241,7 +3233,7 @@ class LinuxlikeTests(BasePlatformTests):
an ordinary test because it requires passing options to meson. an ordinary test because it requires passing options to meson.
''' '''
testdir = os.path.join(self.common_test_dir, '1 trivial') testdir = os.path.join(self.common_test_dir, '1 trivial')
env = Environment(testdir, self.builddir, get_fake_options(self.prefix)) env = get_fake_env(testdir, self.builddir, self.prefix)
cc = env.detect_c_compiler(False) cc = env.detect_c_compiler(False)
self._test_stds_impl(testdir, cc, 'c') self._test_stds_impl(testdir, cc, 'c')
@ -3251,7 +3243,7 @@ class LinuxlikeTests(BasePlatformTests):
be an ordinary test because it requires passing options to meson. be an ordinary test because it requires passing options to meson.
''' '''
testdir = os.path.join(self.common_test_dir, '2 cpp') testdir = os.path.join(self.common_test_dir, '2 cpp')
env = Environment(testdir, self.builddir, get_fake_options(self.prefix)) env = get_fake_env(testdir, self.builddir, self.prefix)
cpp = env.detect_cpp_compiler(False) cpp = env.detect_cpp_compiler(False)
self._test_stds_impl(testdir, cpp, 'cpp') self._test_stds_impl(testdir, cpp, 'cpp')
@ -3796,8 +3788,6 @@ endian = 'little'
The system library is found with cc.find_library() and pkg-config deps. The system library is found with cc.find_library() and pkg-config deps.
''' '''
if not is_osx():
raise unittest.SkipTest('workflow currently only works on macOS')
oldprefix = self.prefix oldprefix = self.prefix
# Install external library so we can find it # Install external library so we can find it
testdir = os.path.join(self.unit_test_dir, '39 external, internal library rpath', 'external library') testdir = os.path.join(self.unit_test_dir, '39 external, internal library rpath', 'external library')
@ -3820,6 +3810,9 @@ endian = 'little'
self.build() self.build()
# test uninstalled # test uninstalled
self.run_tests() self.run_tests()
if not is_osx():
# Rest of the workflow only works on macOS
return
# test running after installation # test running after installation
self.install(use_destdir=False) self.install(use_destdir=False)
prog = os.path.join(self.installdir, 'bin', 'prog') prog = os.path.join(self.installdir, 'bin', 'prog')

@ -1,12 +1,21 @@
project('built library', 'c') project('built library', 'c')
cc = meson.get_compiler('c') cc = meson.get_compiler('c')
if host_machine.system() != 'cygwin'
# bar_in_system has undefined symbols, but still must be found
bar_system_dep = cc.find_library('bar_in_system')
endif
foo_system_dep = cc.find_library('foo_in_system') foo_system_dep = cc.find_library('foo_in_system')
faa_pkg_dep = dependency('faa_pkg') faa_pkg_dep = dependency('faa_pkg')
l = shared_library('bar_built', 'bar.c', l = shared_library('bar_built', 'bar.c',
install: true, install: true,
dependencies : [foo_system_dep, faa_pkg_dep]) dependencies : [foo_system_dep, faa_pkg_dep])
e = executable('prog', 'prog.c', link_with: l, install: true) if host_machine.system() == 'darwin'
test('testprog', e) e = executable('prog', 'prog.c', link_with: l, install: true)
test('testprog', e)
endif

@ -0,0 +1,6 @@
int some_undefined_func (void);
int bar_system_value (void)
{
return some_undefined_func ();
}

@ -1,9 +1,22 @@
project('system library', 'c') project('system library', 'c', default_options : ['b_lundef=false'])
shared_library('foo_in_system', 'foo.c', install : true) shared_library('foo_in_system', 'foo.c', install : true)
l = shared_library('faa_pkg', 'faa.c', install: true) l = shared_library('faa_pkg', 'faa.c', install: true)
if host_machine.system() == 'darwin'
frameworks = ['-framework', 'CoreFoundation', '-framework', 'CoreMedia']
allow_undef_args = ['-Wl,-undefined,dynamic_lookup']
else
frameworks = []
allow_undef_args = []
endif
pkg = import('pkgconfig') pkg = import('pkgconfig')
pkg.generate(name: 'faa_pkg', pkg.generate(name: 'faa_pkg',
libraries: [l, '-framework', 'CoreFoundation', '-framework', 'CoreMedia'], libraries: [l] + frameworks,
description: 'FAA, a pkg-config test library') description: 'FAA, a pkg-config test library')
# cygwin DLLs can't have undefined symbols
if host_machine.system() != 'cygwin'
shared_library('bar_in_system', 'bar.c', install : true, link_args : allow_undef_args)
endif

Loading…
Cancel
Save