aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesonbuild/backend/backends.py10
-rw-r--r--mesonbuild/backend/ninjabackend.py2
-rw-r--r--mesonbuild/compilers/c.py84
-rw-r--r--mesonbuild/compilers/compilers.py24
-rw-r--r--mesonbuild/compilers/fortran.py11
-rw-r--r--mesonbuild/dependencies/boost.py2
6 files changed, 66 insertions, 67 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index 7ed97b2..df72eff 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -355,9 +355,9 @@ class Backend:
return l, stdlib_args
@staticmethod
- def _libdir_is_system(libdir, compilers):
+ def _libdir_is_system(libdir, compilers, env):
for cc in compilers.values():
- if libdir in cc.get_library_dirs():
+ if libdir in cc.get_library_dirs(env):
return True
return False
@@ -372,7 +372,7 @@ class Backend:
# The only link argument is an absolute path to a library file.
libpath = la[0]
libdir = os.path.dirname(libpath)
- if exclude_system and self._libdir_is_system(libdir, target.compilers):
+ if exclude_system and self._libdir_is_system(libdir, target.compilers, self.environment):
# No point in adding system paths.
continue
# Windows doesn't support rpaths, but we use this function to
@@ -612,8 +612,8 @@ class Backend:
# Get program and library dirs from all target compilers
if isinstance(target, build.BuildTarget):
for cc in target.compilers.values():
- paths.update(cc.get_program_dirs())
- paths.update(cc.get_library_dirs())
+ paths.update(cc.get_program_dirs(self.environment))
+ paths.update(cc.get_library_dirs(self.environment))
return list(paths)
def determine_windows_extra_paths(self, target, extra_bdeps, is_cross=False):
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index ace0693..824145a 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -2333,7 +2333,7 @@ rule FORTRAN_DEP_HACK%s
guessed_dependencies = []
# 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()
+ search_dirs = list(search_dirs) + linker.get_library_dirs(self.environment)
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:
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py
index c7092b8..0b169ca 100644
--- a/mesonbuild/compilers/c.py
+++ b/mesonbuild/compilers/c.py
@@ -16,6 +16,8 @@ import re
import glob
import os.path
import subprocess
+import functools
+import itertools
from pathlib import Path
from .. import mlog
@@ -49,6 +51,7 @@ gnu_compiler_internal_libs = ('m', 'c', 'pthread', 'dl', 'rt')
class CCompiler(Compiler):
+ # TODO: Replace this manual cache with functools.lru_cache
library_dirs_cache = {}
program_dirs_cache = {}
find_library_cache = {}
@@ -172,42 +175,47 @@ class CCompiler(Compiler):
def get_std_shared_lib_link_args(self):
return ['-shared']
- def get_library_dirs_real(self):
- env = os.environ.copy()
- env['LC_ALL'] = 'C'
- stdo = Popen_safe(self.exelist + ['--print-search-dirs'], env=env)[1]
+ @functools.lru_cache()
+ def _get_search_dirs(self, env):
+ extra_args = ['--print-search-dirs']
+ stdo = None
+ with self._build_wrapper('', env, extra_args, None, 'compile', True) as p:
+ stdo = p.stdo
+ return stdo
+
+ @staticmethod
+ def _split_fetch_real_dirs(pathstr, sep=':'):
paths = []
- for line in stdo.split('\n'):
- if line.startswith('libraries:'):
- libstr = line.split('=', 1)[1]
- paths = [os.path.realpath(p) for p in libstr.split(':') if os.path.exists(os.path.realpath(p))]
+ for p in pathstr.split(sep):
+ p = Path(p)
+ if p.exists():
+ paths.append(p.resolve().as_posix())
return paths
- def get_library_dirs(self):
- key = tuple(self.exelist)
+ def get_compiler_dirs(self, env, name):
+ '''
+ Get dirs from the compiler, either `libraries:` or `programs:`
+ '''
+ stdo = self._get_search_dirs(env)
+ for line in stdo.split('\n'):
+ if line.startswith(name + ':'):
+ return CCompiler._split_fetch_real_dirs(line.split('=', 1)[1])
+ return []
+
+ def get_library_dirs(self, env):
+ key = (tuple(self.exelist), env)
if key not in self.library_dirs_cache:
- self.library_dirs_cache[key] = self.get_library_dirs_real()
+ self.library_dirs_cache[key] = self.get_compiler_dirs(env, 'libraries')
return self.library_dirs_cache[key][:]
- def get_program_dirs_real(self):
- env = os.environ.copy()
- env['LC_ALL'] = 'C'
- stdo = Popen_safe(self.exelist + ['--print-search-dirs'], env=env)[1]
- paths = []
- for line in stdo.split('\n'):
- if line.startswith('programs:'):
- libstr = line.split('=', 1)[1]
- paths = [os.path.realpath(p) for p in libstr.split(':')]
- return paths
-
- def get_program_dirs(self):
+ def get_program_dirs(self, env):
'''
Programs used by the compiler. Also where toolchain DLLs such as
libstdc++-6.dll are found with MinGW.
'''
- key = tuple(self.exelist)
+ key = (tuple(self.exelist), env)
if key not in self.program_dirs_cache:
- self.program_dirs_cache[key] = self.get_program_dirs_real()
+ self.program_dirs_cache[key] = self.get_compiler_dirs(env, 'programs')
return self.program_dirs_cache[key][:]
def get_pic_args(self):
@@ -916,35 +924,19 @@ class CCompiler(Compiler):
# Not found or we want to use a specific libtype? Try to find the
# library file itself.
patterns = self.get_library_naming(env, libtype)
- for d in extra_dirs:
+ # Search in the specified dirs, and then in the system libraries
+ for d in itertools.chain(extra_dirs, self.get_library_dirs(env)):
for p in patterns:
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)
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/compilers.py b/mesonbuild/compilers/compilers.py
index b400478..34397aa 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -908,7 +908,7 @@ class Compiler:
def find_library(self, *args, **kwargs):
raise EnvironmentException('Language {} does not support library finding.'.format(self.get_display_language()))
- def get_library_dirs(self):
+ def get_library_dirs(self, *args, **kwargs):
return []
def has_multi_arguments(self, args, env):
@@ -995,7 +995,9 @@ class Compiler:
mlog.debug('Working directory: ', tmpdirname)
mlog.debug('Command line: ', ' '.join(commands), '\n')
mlog.debug('Code:\n', code)
- p, p.stdo, p.stde = Popen_safe(commands, cwd=tmpdirname)
+ os_env = os.environ.copy()
+ os_env['LC_ALL'] = 'C'
+ p, p.stdo, p.stde = Popen_safe(commands, cwd=tmpdirname, env=os_env)
mlog.debug('Compiler stdout:\n', p.stdo)
mlog.debug('Compiler stderr:\n', p.stde)
p.commands = commands
@@ -1353,10 +1355,12 @@ class ElbrusCompiler(GnuCompiler):
'b_ndebug', 'b_staticpic',
'b_lundef', 'b_asneeded']
- def get_library_dirs(self):
- env = os.environ.copy()
- env['LC_ALL'] = 'C'
- stdo = Popen_safe(self.exelist + ['--print-search-dirs'], env=env)[1]
+ # FIXME: use _build_wrapper to call this so that linker flags from the env
+ # get applied
+ def get_library_dirs(self, env):
+ os_env = os.environ.copy()
+ os_env['LC_ALL'] = 'C'
+ stdo = Popen_safe(self.exelist + ['--print-search-dirs'], env=os_env)[1]
paths = []
for line in stdo.split('\n'):
if line.startswith('libraries:'):
@@ -1366,10 +1370,10 @@ class ElbrusCompiler(GnuCompiler):
break
return paths
- def get_program_dirs(self):
- env = os.environ.copy()
- env['LC_ALL'] = 'C'
- stdo = Popen_safe(self.exelist + ['--print-search-dirs'], env=env)[1]
+ def get_program_dirs(self, env):
+ os_env = os.environ.copy()
+ os_env['LC_ALL'] = 'C'
+ stdo = Popen_safe(self.exelist + ['--print-search-dirs'], env=os_env)[1]
paths = []
for line in stdo.split('\n'):
if line.startswith('programs:'):
diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py
index 5648a6f..c384f7f 100644
--- a/mesonbuild/compilers/fortran.py
+++ b/mesonbuild/compilers/fortran.py
@@ -177,11 +177,14 @@ end program prog
def get_std_shared_lib_link_args(self):
return CCompiler.get_std_shared_lib_link_args(self)
- def get_library_dirs_real(self):
- return CCompiler.get_library_dirs_real(self)
+ def _get_search_dirs(self, *args, **kwargs):
+ return CCompiler._get_search_dirs(self, *args, **kwargs)
- def get_library_dirs(self):
- return CCompiler.get_library_dirs(self)
+ def get_compiler_dirs(self, *args, **kwargs):
+ return CCompiler.get_compiler_dirs(self, *args, **kwargs)
+
+ def get_library_dirs(self, *args, **kwargs):
+ return CCompiler.get_library_dirs(self, *args, **kwargs)
def get_pic_args(self):
return CCompiler.get_pic_args(self)
diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py
index 17f9240..b06f62d 100644
--- a/mesonbuild/dependencies/boost.py
+++ b/mesonbuild/dependencies/boost.py
@@ -443,7 +443,7 @@ class BoostDependency(ExternalDependency):
if self.libdir:
libdirs = [self.libdir]
elif self.boost_root is None:
- libdirs = mesonlib.get_library_dirs()
+ libdirs = mesonlib.get_library_dirs(self.env)
else:
libdirs = [os.path.join(self.boost_root, 'lib')]
for libdir in libdirs: