diff options
author | Nirbheek Chauhan <nirbheek.chauhan@gmail.com> | 2018-07-09 09:45:02 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-07-09 09:45:02 -0700 |
commit | 8cfb8fd02c86e1667ded9a7841d77204f96a4a6d (patch) | |
tree | 8f268877d97a6fd07631353a01d0594442315dd0 /mesonbuild/compilers | |
parent | 28a2e658f884443ae0afbf3ea8929c8c2005b34c (diff) | |
download | meson-8cfb8fd02c86e1667ded9a7841d77204f96a4a6d.zip meson-8cfb8fd02c86e1667ded9a7841d77204f96a4a6d.tar.gz meson-8cfb8fd02c86e1667ded9a7841d77204f96a4a6d.tar.bz2 |
Fix searching of shared libraries on OpenBSD (#3851)
* get_library_naming: Use templates instead of suffix/prefix pairs
This commit does not change functionality, and merely sets the
groundwork for a more flexibly naming implementation.
* find_library: Fix manual searching on OpenBSD
On OpenBSD, shared libraries are called libfoo.so.X.Y where X is the
major version and Y is the minor version. We were assuming that it's
libfoo.so and not finding shared libraries at all while doing manual
searching, which meant we'd link statically instead.
See: https://www.openbsd.org/faq/ports/specialtopics.html#SharedLibs
Now we use file globbing to do searching, and pick the first one
that's a real file.
Closes https://github.com/mesonbuild/meson/issues/3844
* find_library: Fix priority of library search in OpenBSD
Also add unit tests for the library naming function so that it's
absolutely clear what the priority list of naming is.
Testing is done with mocking on Linux to ensure that local testing
is easy
Diffstat (limited to 'mesonbuild/compilers')
-rw-r--r-- | mesonbuild/compilers/c.py | 108 | ||||
-rw-r--r-- | mesonbuild/compilers/fortran.py | 7 |
2 files changed, 79 insertions, 36 deletions
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 8af7abc..b62155b 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -12,14 +12,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -import subprocess, os.path, re +import re +import glob +import os.path +import subprocess from .. import mlog from .. import coredata from . import compilers from ..mesonlib import ( EnvironmentException, version_compare, Popen_safe, listify, - for_windows, for_darwin, for_cygwin, for_haiku, + for_windows, for_darwin, for_cygwin, for_haiku, for_openbsd, ) from .compilers import ( @@ -800,6 +803,22 @@ class CCompiler(Compiler): return False raise RuntimeError('BUG: {!r} check failed unexpectedly'.format(n)) + def _get_patterns(self, env, prefixes, suffixes, shared=False): + patterns = [] + for p in prefixes: + for s in suffixes: + patterns.append(p + '{}.' + s) + if shared and for_openbsd(self.is_cross, env): + # Shared libraries on OpenBSD can be named libfoo.so.X.Y: + # https://www.openbsd.org/faq/ports/specialtopics.html#SharedLibs + # + # This globbing is probably the best matching we can do since regex + # is expensive. It's wrong in many edge cases, but it will match + # correctly-named libraries and hopefully no one on OpenBSD names + # their files libfoo.so.9a.7b.1.0 + patterns.append('lib{}.so.[0-9]*.[0-9]*') + return patterns + def get_library_naming(self, env, libtype, strict=False): ''' Get library prefixes and suffixes for the target platform ordered by @@ -830,18 +849,37 @@ class CCompiler(Compiler): else: # Linux/BSDs shlibext = ['so'] + patterns = [] # Search priority if libtype in ('default', 'shared-static'): - suffixes = shlibext + stlibext + patterns += self._get_patterns(env, prefixes, shlibext, True) + patterns += self._get_patterns(env, prefixes, stlibext, False) elif libtype == 'static-shared': - suffixes = stlibext + shlibext + patterns += self._get_patterns(env, prefixes, stlibext, False) + patterns += self._get_patterns(env, prefixes, shlibext, True) elif libtype == 'shared': - suffixes = shlibext + patterns += self._get_patterns(env, prefixes, shlibext, True) elif libtype == 'static': - suffixes = stlibext + patterns += self._get_patterns(env, prefixes, stlibext, False) else: raise AssertionError('BUG: unknown libtype {!r}'.format(libtype)) - return prefixes, suffixes + return patterns + + @staticmethod + def _get_trials_from_pattern(pattern, directory, libname): + f = os.path.join(directory, pattern.format(libname)) + if '*' in pattern: + # NOTE: globbing matches directories and broken symlinks + # so we have to do an isfile test on it later + return glob.glob(f) + return [f] + + @staticmethod + def _get_file_from_list(files): + for f in files: + if os.path.isfile(f): + return f + return None def find_library_real(self, libname, env, extra_dirs, code, libtype): # First try if we can just add the library as -l. @@ -851,36 +889,38 @@ class CCompiler(Compiler): args = ['-l' + libname] if self.links(code, env, extra_args=args): return args - # Search in the system libraries too - system_dirs = self.get_library_dirs() # Not found or we want to use a specific libtype? Try to find the # library file itself. - prefixes, suffixes = self.get_library_naming(env, libtype) - # Triply-nested loops! + patterns = self.get_library_naming(env, libtype) for d in extra_dirs: - for suffix in suffixes: - for prefix in prefixes: - trial = os.path.join(d, prefix + libname + '.' + suffix) - if os.path.isfile(trial): - return [trial] - for d in system_dirs: - for suffix in suffixes: - for prefix in prefixes: - trial = os.path.join(d, prefix + libname + '.' + suffix) - # When searching the system paths used by the compiler, we - # need to check linking with link-whole, as static libs - # (.a) need to be checked to ensure they are the right - # architecture, e.g. 32bit or 64-bit. - # Just a normal test link won't work as the .a file doesn't - # seem to be checked by linker if there are no unresolved - # symbols from the main C file. - extra_link_args = self.get_link_whole_for([trial]) - extra_link_args = self.linker_to_compiler_args(extra_link_args) - if (os.path.isfile(trial) and - self.links(code, env, - extra_args=extra_link_args)): - return [trial] - # XXX: For OpenBSD and macOS we (may) need to search for libfoo.x{,.y.z}.ext + for p in patterns: + trial = self._get_trials_from_pattern(p, d, libname) + if not trial: + continue + trial = self._get_file_from_list(trial) + if not trial: + continue + return [trial] + # Search in the system libraries too + for d in self.get_library_dirs(): + for p in patterns: + trial = self._get_trials_from_pattern(p, d, libname) + if not trial: + continue + trial = self._get_file_from_list(trial) + if not trial: + continue + # When searching the system paths used by the compiler, we + # need to check linking with link-whole, as static libs + # (.a) need to be checked to ensure they are the right + # architecture, e.g. 32bit or 64-bit. + # Just a normal test link won't work as the .a file doesn't + # seem to be checked by linker if there are no unresolved + # symbols from the main C file. + extra_link_args = self.get_link_whole_for([trial]) + extra_link_args = self.linker_to_compiler_args(extra_link_args) + if self.links(code, env, extra_args=extra_link_args): + return [trial] return None def find_library_impl(self, libname, env, extra_dirs, code, libtype): diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index 6254a6a..d6e41e3 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -173,8 +173,11 @@ class FortranCompiler(Compiler): def run(self, code, env, extra_args=None, dependencies=None): return CCompiler.run(self, code, env, extra_args, dependencies) - def get_library_naming(self, env, libtype, strict=False): - return CCompiler.get_library_naming(self, env, libtype, strict) + def _get_patterns(self, *args, **kwargs): + return CCompiler._get_patterns(self, *args, **kwargs) + + def get_library_naming(self, *args, **kwargs): + return CCompiler.get_library_naming(self, *args, **kwargs) def find_library_real(self, *args): return CCompiler.find_library_real(self, *args) |