aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild')
-rw-r--r--mesonbuild/backend/ninjabackend.py45
-rw-r--r--mesonbuild/compilers/c.py108
-rw-r--r--mesonbuild/compilers/fortran.py7
-rw-r--r--mesonbuild/mesonlib.py12
4 files changed, 119 insertions, 53 deletions
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 3ee543d..09c4904 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -12,7 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import os, pickle, re, shlex, subprocess
+import os
+import re
+import shlex
+import pickle
+import subprocess
from collections import OrderedDict
import itertools
from pathlib import PurePath
@@ -24,7 +28,7 @@ from .. import build
from .. import mlog
from .. import dependencies
from .. import compilers
-from ..compilers import CompilerArgs, get_macos_dylib_install_name
+from ..compilers import CompilerArgs, CCompiler, get_macos_dylib_install_name
from ..linkers import ArLinker
from ..mesonlib import File, MesonException, OrderedSet
from ..mesonlib import get_compiler_for_source, has_path_sep
@@ -2476,13 +2480,18 @@ 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 []
- def guess_library_absolute_path(self, libname, search_dirs, prefixes, suffixes):
- for directory in search_dirs:
- for suffix in suffixes:
- for prefix in prefixes:
- trial = os.path.join(directory, prefix + libname + '.' + suffix)
- if os.path.isfile(trial):
- return trial
+ @staticmethod
+ def guess_library_absolute_path(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)
+ if not trial:
+ continue
+ # Return the first result
+ return trial
def guess_external_link_dependencies(self, linker, target, commands, internal):
# Ideally the linker would generate dependency information that could be used.
@@ -2531,17 +2540,19 @@ rule FORTRAN_DEP_HACK%s
# TODO The get_library_naming requirement currently excludes link targets that use d or fortran as their main linker
if hasattr(linker, 'get_library_naming'):
search_dirs = list(search_dirs) + linker.get_library_dirs()
- prefixes_static, suffixes_static = linker.get_library_naming(self.environment, 'static', strict=True)
- prefixes_shared, suffixes_shared = linker.get_library_naming(self.environment, 'shared', strict=True)
+ static_patterns = linker.get_library_naming(self.environment, 'static', strict=True)
+ shared_patterns = linker.get_library_naming(self.environment, 'shared', strict=True)
for libname in libs:
# be conservative and record most likely shared and static resolution, because we don't know exactly
# which one the linker will prefer
- static_resolution = self.guess_library_absolute_path(libname, search_dirs, prefixes_static, suffixes_static)
- shared_resolution = self.guess_library_absolute_path(libname, search_dirs, prefixes_shared, suffixes_shared)
- if static_resolution:
- guessed_dependencies.append(os.path.realpath(static_resolution))
- if shared_resolution:
- guessed_dependencies.append(os.path.realpath(shared_resolution))
+ staticlibs = self.guess_library_absolute_path(linker, libname,
+ search_dirs, static_patterns)
+ sharedlibs = self.guess_library_absolute_path(linker, libname,
+ search_dirs, shared_patterns)
+ if staticlibs:
+ guessed_dependencies.append(os.path.realpath(staticlibs))
+ if sharedlibs:
+ guessed_dependencies.append(os.path.realpath(sharedlibs))
return guessed_dependencies + absolute_libs
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)
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
index efb8d11..e8e5049 100644
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -363,6 +363,18 @@ def for_haiku(is_cross, env):
return env.cross_info.config['host_machine']['system'] == 'haiku'
return False
+def for_openbsd(is_cross, env):
+ """
+ Host machine is OpenBSD?
+
+ Note: 'host' is the machine on which compiled binaries will run
+ """
+ if not is_cross:
+ return is_openbsd()
+ elif env.cross_info.has_host():
+ return env.cross_info.config['host_machine']['system'] == 'openbsd'
+ return False
+
def exe_exists(arglist):
try:
p = subprocess.Popen(arglist, stdout=subprocess.PIPE, stderr=subprocess.PIPE)