diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 624226d33c8d..5b0518b0ca37 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -824,7 +824,7 @@ def compile(self, code: 'mesonlib.FileOrString', if extra_args is None: extra_args = [] - with TemporaryDirectoryWinProof(dir=temp_dir) as tmpdirname: + with TemporaryDirectoryWinProof(dir=temp_dir if temp_dir else None) as tmpdirname: no_ccache = False if isinstance(code, str): srcname = os.path.join(tmpdirname, diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index 454f5fba80e6..d31332a68f42 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -1090,10 +1090,8 @@ def _get_trials_from_pattern(cls, pattern: str, directory: str, libname: str) -> @staticmethod def _get_file_from_list(env: Environment, paths: T.List[str]) -> T.Optional[Path]: ''' - 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. + Check whether the library exists by filename. On macOS, we also + check if the library matches our target architecture. ''' for p in paths: if os.path.isfile(p): @@ -1147,17 +1145,28 @@ def _find_library_real(self, libname: str, env: 'Environment', extra_dirs: T.Lis except (mesonlib.MesonException, KeyError): # TODO evaluate if catching KeyError is wanted here elf_class = 0 # Search in the specified dirs, and then in the system libraries + largs = self.get_linker_always_args() + self.get_allow_undefined_link_args() + lcargs = self.linker_to_compiler_args(largs) for d in itertools.chain(extra_dirs, [] if ignore_system_dirs else self.get_library_dirs(env, elf_class)): for p in patterns: trials = self._get_trials_from_pattern(p, d, libname) if not trials: continue - trial = self._get_file_from_list(env, trials) - if not trial: + + trial_result = "" + for trial in trials: + if not os.path.isfile(trial): + continue + extra_args = [trial] + lcargs + if self.links(code, env, extra_args=extra_args, disable_cache=True)[0]: + trial_result = trial + break + + if not trial_result: continue - if libname.startswith('lib') and trial.name.startswith(libname) and lib_prefix_warning: + if libname.startswith('lib') and trial_result.startswith(libname) and lib_prefix_warning: mlog.warning(f'find_library({libname!r}) starting in "lib" only works by accident and is not portable') - return [trial.as_posix()] + return [Path(trial_result).as_posix()] return None def _find_library_impl(self, libname: str, env: 'Environment', extra_dirs: T.List[str], diff --git a/test cases/common/285 atomic/a.c b/test cases/common/285 atomic/a.c new file mode 100644 index 000000000000..03b2213bb9a3 --- /dev/null +++ b/test cases/common/285 atomic/a.c @@ -0,0 +1,3 @@ +int main(void) { + return 0; +} diff --git a/test cases/common/285 atomic/meson.build b/test cases/common/285 atomic/meson.build new file mode 100644 index 000000000000..323b9ccb6694 --- /dev/null +++ b/test cases/common/285 atomic/meson.build @@ -0,0 +1,23 @@ +project('meson system dependency', 'c', meson_version: '>=1.7.0') + +cc = meson.get_compiler('c') + +# We could check if dependency('atomic') actually finds something when +# we 'know' it exists (MESON_SKIP_TEST) but that's likely to be brittle, +# so don't bother (for now, at least). +atomic = dependency('atomic', required : false) + +# If the dependency provider says it found something, make sure it can +# be linked against (https://github.com/mesonbuild/meson/issues/14946). +dependencies = [ + atomic +] + +exe = executable( + 'a', + 'a.c', + dependencies : dependencies, + install : false, +) + +test('basic', exe) diff --git a/unittests/internaltests.py b/unittests/internaltests.py index dfa797dc7d95..5f84cef1ae2a 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -551,10 +551,14 @@ def _test_all_naming(self, cc, env, patterns, platform): for i in ['libfoo.so.6.0', 'libfoo.so.5.0', 'libfoo.so.54.0', 'libfoo.so.66a.0b', 'libfoo.so.70.0.so.1', 'libbar.so.7.10', 'libbar.so.7.9', 'libbar.so.7.9.3']: libpath = Path(tmpdir) / i - libpath.write_text('', encoding='utf-8') - found = cc._find_library_real('foo', env, [tmpdir], '', LibType.PREFER_SHARED, lib_prefix_warning=True, ignore_system_dirs=False) + src = libpath.with_suffix('.c') + with src.open('w', encoding='utf-8') as f: + f.write('int meson_foobar (void) { return 0; }') + subprocess.check_call(['gcc', str(src), '-o', str(libpath), '-shared']) + + found = cc._find_library_real('foo', env, [tmpdir], 'int main(void) { return 0; }', LibType.PREFER_SHARED, lib_prefix_warning=True, ignore_system_dirs=False) self.assertEqual(os.path.basename(found[0]), 'libfoo.so.54.0') - found = cc._find_library_real('bar', env, [tmpdir], '', LibType.PREFER_SHARED, lib_prefix_warning=True, ignore_system_dirs=False) + found = cc._find_library_real('bar', env, [tmpdir], 'int main(void) { return 0; }', LibType.PREFER_SHARED, lib_prefix_warning=True, ignore_system_dirs=False) self.assertEqual(os.path.basename(found[0]), 'libbar.so.7.10') def test_find_library_patterns(self): @@ -610,17 +614,22 @@ def test_pkgconfig_parse_libs(self): https://github.com/mesonbuild/meson/issues/3951 ''' def create_static_lib(name): - if not is_osx(): - name.open('w', encoding='utf-8').close() - return src = name.with_suffix('.c') out = name.with_suffix('.o') with src.open('w', encoding='utf-8') as f: f.write('int meson_foobar (void) { return 0; }') # use of x86_64 is hardcoded in run_tests.py:get_fake_env() - subprocess.check_call(['clang', '-c', str(src), '-o', str(out), '-arch', 'x86_64']) + if is_osx(): + subprocess.check_call(['clang', '-c', str(src), '-o', str(out), '-arch', 'x86_64']) + else: + subprocess.check_call(['gcc', '-c', str(src), '-o', str(out)]) subprocess.check_call(['ar', 'csr', str(name), str(out)]) + # The test relies on some open-coded toolchain invocations for + # library creation in create_static_lib. + if is_windows() or is_cygwin(): + return + with tempfile.TemporaryDirectory() as tmpdir: pkgbin = ExternalProgram('pkg-config', command=['pkg-config'], silent=True) env = get_fake_env()