aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesonbuild/backend/ninjabackend.py5
-rw-r--r--mesonbuild/compilers/c.py28
-rw-r--r--mesonbuild/mesonlib.py18
-rwxr-xr-xrun_tests.py1
-rwxr-xr-xrun_unittests.py72
5 files changed, 85 insertions, 39 deletions
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 493fc0d..9b215b2 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -2347,15 +2347,14 @@ rule FORTRAN_DEP_HACK%s
target_args = self.build_target_link_arguments(linker, target.link_whole_targets)
return linker.get_link_whole_for(target_args) if len(target_args) else []
- @staticmethod
@lru_cache(maxsize=None)
- def guess_library_absolute_path(linker, libname, search_dirs, patterns):
+ def guess_library_absolute_path(self, linker, libname, search_dirs, patterns):
for d in search_dirs:
for p in patterns:
trial = CCompiler._get_trials_from_pattern(p, d, libname)
if not trial:
continue
- trial = CCompiler._get_file_from_list(trial)
+ trial = CCompiler._get_file_from_list(self.environment, trial)
if not trial:
continue
# Return the first result
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py
index 0a90c8c..a591183 100644
--- a/mesonbuild/compilers/c.py
+++ b/mesonbuild/compilers/c.py
@@ -27,6 +27,7 @@ from . import compilers
from ..mesonlib import (
EnvironmentException, MesonException, version_compare, Popen_safe, listify,
for_windows, for_darwin, for_cygwin, for_haiku, for_openbsd,
+ darwin_get_object_archs
)
from .c_function_attributes import C_FUNC_ATTRIBUTES
@@ -980,10 +981,28 @@ class CCompiler(Compiler):
return [f.as_posix()]
@staticmethod
- def _get_file_from_list(files: List[str]) -> str:
+ def _get_file_from_list(env, files: List[str]) -> str:
+ '''
+ We just check whether the library exists. We can't do a link check
+ because the library might have unresolved symbols that require other
+ libraries. On macOS we check if the library matches our target
+ architecture.
+ '''
+ # If not building on macOS for Darwin, do a simple file check
+ if not env.machines.host.is_darwin() or not env.machines.build.is_darwin():
+ for f in files:
+ if os.path.isfile(f):
+ return f
+ # Run `lipo` and check if the library supports the arch we want
for f in files:
- if os.path.isfile(f):
+ if not os.path.isfile(f):
+ continue
+ archs = darwin_get_object_archs(f)
+ if archs and env.machines.host.cpu_family in archs:
return f
+ else:
+ mlog.debug('Rejected {}, supports {} but need {}'
+ .format(f, archs, env.machines.host.cpu_family))
return None
@functools.lru_cache()
@@ -1024,10 +1043,7 @@ class CCompiler(Compiler):
trial = self._get_trials_from_pattern(p, d, libname)
if not trial:
continue
- # We just check whether the library exists. We can't do a link
- # check because the library might have unresolved symbols that
- # require other libraries.
- trial = self._get_file_from_list(trial)
+ trial = self._get_file_from_list(env, trial)
if not trial:
continue
return [trial]
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
index 5529ce4..09228dc 100644
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -461,6 +461,24 @@ def exe_exists(arglist):
pass
return False
+lru_cache(maxsize=None)
+def darwin_get_object_archs(objpath):
+ '''
+ For a specific object (executable, static library, dylib, etc), run `lipo`
+ to fetch the list of archs supported by it. Supports both thin objects and
+ 'fat' objects.
+ '''
+ _, stdo, stderr = Popen_safe(['lipo', '-archs', objpath])
+ if not stdo:
+ mlog.debug('lipo {}: {}'.format(objpath, stderr))
+ return None
+ # Convert from lipo-style archs to meson-style CPUs
+ stdo = stdo.replace('i386', 'x86')
+ # Add generic name for armv7 and armv7s
+ if 'armv7' in stdo:
+ stdo += ' arm'
+ return stdo.split()
+
def detect_vcs(source_dir):
vcs_systems = [
dict(name = 'git', cmd = 'git', repo_dir = '.git', get_rev = 'git describe --dirty=+', rev_regex = '(.*)', dep = '.git/logs/HEAD'),
diff --git a/run_tests.py b/run_tests.py
index 943e16f..20cb4e2 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -81,6 +81,7 @@ def get_fake_env(sdir='', bdir=None, prefix='', opts=None):
opts = get_fake_options(prefix)
env = Environment(sdir, bdir, opts)
env.coredata.compiler_options['c_args'] = FakeCompilerOptions()
+ env.machines.host.cpu_family = 'x86_64' # Used on macOS inside find_library
return env
diff --git a/run_unittests.py b/run_unittests.py
index b8b3192..72ab062 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -45,7 +45,7 @@ from mesonbuild.interpreter import Interpreter, ObjectHolder
from mesonbuild.mesonlib import (
is_windows, is_osx, is_cygwin, is_dragonflybsd, is_openbsd, is_haiku,
windows_proof_rmtree, python_command, version_compare,
- BuildDirLock, Version
+ BuildDirLock, Version, PerMachine
)
from mesonbuild.environment import detect_ninja
from mesonbuild.mesonlib import MesonException, EnvironmentException
@@ -781,6 +781,17 @@ class InternalTests(unittest.TestCase):
https://github.com/mesonbuild/meson/issues/3951
'''
+ def create_static_lib(name):
+ if not is_osx():
+ name.open('w').close()
+ return
+ src = name.with_suffix('.c')
+ out = name.with_suffix('.o')
+ with src.open('w') as f:
+ f.write('int meson_foobar (void) { return 0; }')
+ subprocess.check_call(['clang', '-c', str(src), '-o', str(out)])
+ subprocess.check_call(['ar', 'csr', str(name), str(out)])
+
with tempfile.TemporaryDirectory() as tmpdir:
pkgbin = ExternalProgram('pkg-config', command=['pkg-config'], silent=True)
env = get_fake_env()
@@ -792,16 +803,16 @@ class InternalTests(unittest.TestCase):
p1.mkdir()
p2.mkdir()
# libfoo.a is in one prefix
- (p1 / 'libfoo.a').open('w').close()
+ create_static_lib(p1 / 'libfoo.a')
# libbar.a is in both prefixes
- (p1 / 'libbar.a').open('w').close()
- (p2 / 'libbar.a').open('w').close()
+ create_static_lib(p1 / 'libbar.a')
+ create_static_lib(p2 / 'libbar.a')
# Ensure that we never statically link to these
- (p1 / 'libpthread.a').open('w').close()
- (p1 / 'libm.a').open('w').close()
- (p1 / 'libc.a').open('w').close()
- (p1 / 'libdl.a').open('w').close()
- (p1 / 'librt.a').open('w').close()
+ create_static_lib(p1 / 'libpthread.a')
+ create_static_lib(p1 / 'libm.a')
+ create_static_lib(p1 / 'libc.a')
+ create_static_lib(p1 / 'libdl.a')
+ create_static_lib(p1 / 'librt.a')
def fake_call_pkgbin(self, args, env=None):
if '--libs' not in args:
@@ -815,30 +826,31 @@ class InternalTests(unittest.TestCase):
old_call = PkgConfigDependency._call_pkgbin
old_check = PkgConfigDependency.check_pkgconfig
- old_pkgbin = PkgConfigDependency.class_pkgbin
PkgConfigDependency._call_pkgbin = fake_call_pkgbin
PkgConfigDependency.check_pkgconfig = lambda x, _: pkgbin
# Test begins
- kwargs = {'required': True, 'silent': True}
- foo_dep = PkgConfigDependency('foo', env, kwargs)
- self.assertEqual(foo_dep.get_link_args(),
- [(p1 / 'libfoo.a').as_posix(), (p2 / 'libbar.a').as_posix()])
- bar_dep = PkgConfigDependency('bar', env, kwargs)
- self.assertEqual(bar_dep.get_link_args(), [(p2 / 'libbar.a').as_posix()])
- internal_dep = PkgConfigDependency('internal', env, kwargs)
- if compiler.get_argument_syntax() == 'msvc':
- self.assertEqual(internal_dep.get_link_args(), [])
- else:
- link_args = internal_dep.get_link_args()
- for link_arg in link_args:
- for lib in ('pthread', 'm', 'c', 'dl', 'rt'):
- self.assertNotIn('lib{}.a'.format(lib), link_arg, msg=link_args)
- # Test ends
- PkgConfigDependency._call_pkgbin = old_call
- PkgConfigDependency.check_pkgconfig = old_check
- # Reset dependency class to ensure that in-process configure doesn't mess up
- PkgConfigDependency.pkgbin_cache = {}
- PkgConfigDependency.class_pkgbin = old_pkgbin
+ try:
+ kwargs = {'required': True, 'silent': True}
+ foo_dep = PkgConfigDependency('foo', env, kwargs)
+ self.assertEqual(foo_dep.get_link_args(),
+ [(p1 / 'libfoo.a').as_posix(), (p2 / 'libbar.a').as_posix()])
+ bar_dep = PkgConfigDependency('bar', env, kwargs)
+ self.assertEqual(bar_dep.get_link_args(), [(p2 / 'libbar.a').as_posix()])
+ internal_dep = PkgConfigDependency('internal', env, kwargs)
+ if compiler.get_argument_syntax() == 'msvc':
+ self.assertEqual(internal_dep.get_link_args(), [])
+ else:
+ link_args = internal_dep.get_link_args()
+ for link_arg in link_args:
+ for lib in ('pthread', 'm', 'c', 'dl', 'rt'):
+ self.assertNotIn('lib{}.a'.format(lib), link_arg, msg=link_args)
+ finally:
+ # Test ends
+ PkgConfigDependency._call_pkgbin = old_call
+ PkgConfigDependency.check_pkgconfig = old_check
+ # Reset dependency class to ensure that in-process configure doesn't mess up
+ PkgConfigDependency.pkgbin_cache = {}
+ PkgConfigDependency.class_pkgbin = PerMachine(None, None, None)
def test_version_compare(self):
comparefunc = mesonbuild.mesonlib.version_compare_many