Skip to content

Commit 9c2c2ea

Browse files
committed
Always check if found libraries are linkable
We don't always check if a library is actually linkable because of concerns that a library may not be standalone, so linking against it may still have unresolved references. We can workaround that by building a shared library as a test rather than an executable, and in fact we already do that in a bunch of cases since bb5f2ca. This comes up in particular with Fedora and dependency('atomic') because on x86_64, they provide a libatomic.so linker script (so our file existence check passes), but trying to use it later on will fail if the backing package isn't installed. The _test_all_naming unittest has been tweaked because we were using a blank file rather than an actual shared library, which (as expected), now fails. I've also added a test for dependency('atomic') providing a result that can actually be linked against. I've not made it check generally whether dependency('atomic') finds something when we expect to (at least for now) as it'll involve some CI whack-a-mole. _get_file_from_list has not been deleted because the Ninja backend's guess_library_absolute_path uses it. We might be able to change it to also use a link test but I've left that alone. Bug: https://bugzilla.redhat.com/show_bug.cgi?id=2352531 Bug: #14946 Closes: #10936
1 parent ca8b6eb commit 9c2c2ea

File tree

4 files changed

+48
-11
lines changed

4 files changed

+48
-11
lines changed

mesonbuild/compilers/mixins/clike.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,10 +1090,8 @@ def _get_trials_from_pattern(cls, pattern: str, directory: str, libname: str) ->
10901090
@staticmethod
10911091
def _get_file_from_list(env: Environment, paths: T.List[str]) -> T.Optional[Path]:
10921092
'''
1093-
We just check whether the library exists. We can't do a link check
1094-
because the library might have unresolved symbols that require other
1095-
libraries. On macOS we check if the library matches our target
1096-
architecture.
1093+
Check whether the library exists by filename. On macOS, we also
1094+
check if the library matches our target architecture.
10971095
'''
10981096
for p in paths:
10991097
if os.path.isfile(p):
@@ -1152,12 +1150,21 @@ def _find_library_real(self, libname: str, env: 'Environment', extra_dirs: T.Lis
11521150
trials = self._get_trials_from_pattern(p, d, libname)
11531151
if not trials:
11541152
continue
1155-
trial = self._get_file_from_list(env, trials)
1156-
if not trial:
1153+
1154+
trial_result = ""
1155+
for trial in trials:
1156+
largs = self.get_linker_always_args() + self.get_allow_undefined_link_args()
1157+
extra_args = [trial] + self.linker_to_compiler_args(largs)
1158+
1159+
if self.links(code, env, extra_args=extra_args, disable_cache=True)[0]:
1160+
trial_result = trial
1161+
break
1162+
1163+
if not trial_result:
11571164
continue
1158-
if libname.startswith('lib') and trial.name.startswith(libname) and lib_prefix_warning:
1165+
if libname.startswith('lib') and trial_result.startswith(libname) and lib_prefix_warning:
11591166
mlog.warning(f'find_library({libname!r}) starting in "lib" only works by accident and is not portable')
1160-
return [trial.as_posix()]
1167+
return [Path(trial_result).as_posix()]
11611168
return None
11621169

11631170
def _find_library_impl(self, libname: str, env: 'Environment', extra_dirs: T.List[str],

test cases/common/285 atomic/a.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
int main(void) {
2+
return 0;
3+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
project('meson system dependency', 'c', meson_version: '>=1.7.0')
2+
3+
cc = meson.get_compiler('c')
4+
5+
# We could check if dependency('atomic') actually finds something when
6+
# we 'know' it exists (MESON_SKIP_TEST) but that's likely to be brittle,
7+
# so don't bother (for now, at least).
8+
atomic = dependency('atomic', required : false)
9+
10+
# If the dependency provider says it found something, make sure it can
11+
# be linked against (https://github.com/mesonbuild/meson/issues/14946).
12+
dependencies = [
13+
atomic
14+
]
15+
16+
exe = executable(
17+
'a',
18+
'a.c',
19+
dependencies : dependencies,
20+
install : false,
21+
)
22+
23+
test('basic', exe)

unittests/internaltests.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -551,10 +551,14 @@ def _test_all_naming(self, cc, env, patterns, platform):
551551
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',
552552
'libbar.so.7.10', 'libbar.so.7.9', 'libbar.so.7.9.3']:
553553
libpath = Path(tmpdir) / i
554-
libpath.write_text('', encoding='utf-8')
555-
found = cc._find_library_real('foo', env, [tmpdir], '', LibType.PREFER_SHARED, lib_prefix_warning=True, ignore_system_dirs=False)
554+
src = libpath.with_suffix('.c')
555+
with src.open('w', encoding='utf-8') as f:
556+
f.write('int meson_foobar (void) { return 0; }')
557+
subprocess.check_call(['gcc', src, '-o', libpath, '-shared'])
558+
559+
found = cc._find_library_real('foo', env, [tmpdir], 'int main(void) { return 0; };', LibType.PREFER_SHARED, lib_prefix_warning=True, ignore_system_dirs=False)
556560
self.assertEqual(os.path.basename(found[0]), 'libfoo.so.54.0')
557-
found = cc._find_library_real('bar', env, [tmpdir], '', LibType.PREFER_SHARED, lib_prefix_warning=True, ignore_system_dirs=False)
561+
found = cc._find_library_real('bar', env, [tmpdir], 'int main(void) { return 0; };', LibType.PREFER_SHARED, lib_prefix_warning=True, ignore_system_dirs=False)
558562
self.assertEqual(os.path.basename(found[0]), 'libbar.so.7.10')
559563

560564
def test_find_library_patterns(self):

0 commit comments

Comments
 (0)