diff options
Diffstat (limited to 'mesonbuild/compilers/c.py')
-rw-r--r-- | mesonbuild/compilers/c.py | 84 |
1 files changed, 38 insertions, 46 deletions
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): |