find_library: Use _build_wrapper to get library dirs

This means that we will take into account all the flags set in the
cross file when fetching the list of library dirs, which means we
won't incorrectly look for 64-bit libraries when building for 32-bit.

Signed-off-by: Nirbheek Chauhan <nirbheek@centricular.com>

Closes https://github.com/mesonbuild/meson/issues/3881
pull/3921/merge
Bruce Richardson 7 years ago committed by Nirbheek Chauhan
parent 05b54b4767
commit 8c9296e8e6
  1. 10
      mesonbuild/backend/backends.py
  2. 2
      mesonbuild/backend/ninjabackend.py
  3. 84
      mesonbuild/compilers/c.py
  4. 24
      mesonbuild/compilers/compilers.py
  5. 11
      mesonbuild/compilers/fortran.py
  6. 2
      mesonbuild/dependencies/boost.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):

@ -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:

@ -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):

@ -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:'):

@ -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)

@ -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:

Loading…
Cancel
Save