summaryrefslogtreecommitdiff
path: root/mesonbuild/compilers
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild/compilers')
-rw-r--r--mesonbuild/compilers/c.py116
-rw-r--r--mesonbuild/compilers/compilers.py51
-rw-r--r--mesonbuild/compilers/d.py2
-rw-r--r--mesonbuild/compilers/fortran.py14
4 files changed, 109 insertions, 74 deletions
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py
index c7092b8c5..436f69982 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 = {}
@@ -144,6 +147,30 @@ class CCompiler(Compiler):
'''
return self.get_no_optimization_args()
+ def get_allow_undefined_link_args(self):
+ '''
+ Get args for allowing undefined symbols when linking to a shared library
+ '''
+ if self.id == 'clang':
+ if self.clang_type == compilers.CLANG_OSX:
+ # Apple ld
+ return ['-Wl,-undefined,dynamic_lookup']
+ else:
+ # GNU ld and LLVM lld
+ return ['-Wl,--allow-shlib-undefined']
+ elif self.id == 'gcc':
+ if self.gcc_type == compilers.GCC_OSX:
+ # Apple ld
+ return ['-Wl,-undefined,dynamic_lookup']
+ else:
+ # GNU ld and LLVM lld
+ return ['-Wl,--allow-shlib-undefined']
+ elif self.id == 'msvc':
+ # link.exe
+ return ['/FORCE:UNRESOLVED']
+ # FIXME: implement other linkers
+ return []
+
def get_output_args(self, target):
return ['-o', target]
@@ -172,42 +199,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):
@@ -908,7 +940,8 @@ class CCompiler(Compiler):
# Only try to find std libs if no extra dirs specified.
if not extra_dirs or libname in self.internal_libs:
args = ['-l' + libname]
- if self.links(code, env, extra_args=args):
+ largs = self.linker_to_compiler_args(self.get_allow_undefined_link_args())
+ if self.links(code, env, extra_args=(args + largs)):
return args
# Don't do a manual search for internal libs
if libname in self.internal_libs:
@@ -916,35 +949,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):
@@ -1230,7 +1247,10 @@ class VisualStudioCCompiler(CCompiler):
return ['/MDd']
def get_buildtype_args(self, buildtype):
- return compilers.msvc_buildtype_args[buildtype]
+ args = compilers.msvc_buildtype_args[buildtype]
+ if version_compare(self.version, '<18.0'):
+ args = [arg for arg in args if arg != '/Gw']
+ return args
def get_buildtype_linker_args(self, buildtype):
return compilers.msvc_buildtype_linker_args[buildtype]
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index 47c222d56..352c49ee8 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -145,8 +145,8 @@ arm_buildtype_args = {'plain': [],
msvc_buildtype_args = {'plain': [],
'debug': ["/ZI", "/Ob0", "/Od", "/RTC1"],
'debugoptimized': ["/Zi", "/Ob1"],
- 'release': ["/Ob2"],
- 'minsize': ["/Zi", "/Ob1"],
+ 'release': ["/Ob2", "/Gw"],
+ 'minsize': ["/Zi", "/Gw"],
}
apple_buildtype_linker_args = {'plain': [],
@@ -267,7 +267,7 @@ msvc_optimization_args = {'0': [],
'1': ['/O1'],
'2': ['/O2'],
'3': ['/O3'],
- 's': ['/Os'],
+ 's': ['/O1'], # Implies /Os.
}
clike_debug_args = {False: [],
@@ -611,27 +611,32 @@ class CompilerArgs(list):
return True
return False
- def to_native(self):
+ def to_native(self, copy=False):
# Check if we need to add --start/end-group for circular dependencies
# between static libraries, and for recursively searching for symbols
# needed by static libraries that are provided by object files or
# shared libraries.
+ if copy:
+ new = self.copy()
+ else:
+ new = self
if get_compiler_uses_gnuld(self.compiler):
global soregex
group_start = -1
- for each in self:
+ group_end = -1
+ for i, each in enumerate(new):
if not each.startswith('-l') and not each.endswith('.a') and \
not soregex.match(each):
continue
- i = self.index(each)
+ group_end = i
if group_start < 0:
# First occurrence of a library
group_start = i
if group_start >= 0:
# Last occurrence of a library
- self.insert(i + 1, '-Wl,--end-group')
- self.insert(group_start, '-Wl,--start-group')
- return self.compiler.unix_args_to_native(self)
+ new.insert(group_end + 1, '-Wl,--end-group')
+ new.insert(group_start, '-Wl,--start-group')
+ return self.compiler.unix_args_to_native(new)
def append_direct(self, arg):
'''
@@ -867,11 +872,11 @@ class Compiler:
self.language + '_args': coredata.UserArrayOption(
self.language + '_args',
description + ' compiler',
- compile_args, shlex_split=True, user_input=True),
+ compile_args, shlex_split=True, user_input=True, allow_dups=True),
self.language + '_link_args': coredata.UserArrayOption(
self.language + '_link_args',
description + ' linker',
- link_args, shlex_split=True, user_input=True),
+ link_args, shlex_split=True, user_input=True, allow_dups=True),
})
return opts
@@ -917,7 +922,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):
@@ -1004,7 +1009,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
@@ -1362,10 +1369,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:'):
@@ -1375,10 +1384,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/d.py b/mesonbuild/compilers/d.py
index 7d682ec0f..a03af3e57 100644
--- a/mesonbuild/compilers/d.py
+++ b/mesonbuild/compilers/d.py
@@ -269,7 +269,7 @@ class DCompiler(Compiler):
continue
dcargs.append('-L' + la.strip())
continue
- elif arg.startswith('-install-name'):
+ elif arg.startswith('-install_name'):
dcargs.append('-L' + arg)
continue
elif arg.startswith('-link-defaultlib') or arg.startswith('-linker'):
diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py
index 5648a6f46..1ee1fcb56 100644
--- a/mesonbuild/compilers/fortran.py
+++ b/mesonbuild/compilers/fortran.py
@@ -144,6 +144,9 @@ end program prog
def get_compiler_check_args(self):
return CCompiler.get_compiler_check_args(self)
+ def get_allow_undefined_link_args(self):
+ return CCompiler.get_allow_undefined_link_args(self)
+
def get_output_args(self, target):
return CCompiler.get_output_args(self, target)
@@ -177,11 +180,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_compiler_dirs(self, *args, **kwargs):
+ return CCompiler.get_compiler_dirs(self, *args, **kwargs)
- def get_library_dirs(self):
- return CCompiler.get_library_dirs(self)
+ 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)