summaryrefslogtreecommitdiff
path: root/mesonbuild/compilers/compilers.py
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild/compilers/compilers.py')
-rw-r--r--mesonbuild/compilers/compilers.py210
1 files changed, 192 insertions, 18 deletions
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index a28a225f3..37326d880 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -55,7 +55,6 @@ for _l in clike_langs:
clike_suffixes += lang_suffixes[_l]
clike_suffixes += ('h', 'll', 's')
-# XXX: Use this in is_library()?
soregex = re.compile(r'.*\.so(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?$')
# All these are only for C-like languages; see `clike_langs` above.
@@ -102,6 +101,10 @@ def is_object(fname):
def is_library(fname):
if hasattr(fname, 'fname'):
fname = fname.fname
+
+ if soregex.match(fname):
+ return True
+
suffix = fname.split('.')[-1]
return suffix in lib_suffixes
@@ -113,6 +116,13 @@ gnulike_buildtype_args = {'plain': [],
'release': ['-O3'],
'minsize': ['-Os', '-g']}
+arm_buildtype_args = {'plain': [],
+ 'debug': ['-O0', '--debug'],
+ 'debugoptimized': ['-O1', '--debug'],
+ 'release': ['-O3', '-Otime'],
+ 'minsize': ['-O3', '-Ospace'],
+ }
+
msvc_buildtype_args = {'plain': [],
'debug': ["/MDd", "/ZI", "/Ob0", "/Od", "/RTC1"],
'debugoptimized': ["/MD", "/Zi", "/O2", "/Ob1"],
@@ -134,6 +144,13 @@ gnulike_buildtype_linker_args = {'plain': [],
'minsize': [],
}
+arm_buildtype_linker_args = {'plain': [],
+ 'debug': [],
+ 'debugoptimized': [],
+ 'release': [],
+ 'minsize': [],
+ }
+
msvc_buildtype_linker_args = {'plain': [],
'debug': [],
'debugoptimized': [],
@@ -526,15 +543,22 @@ class CompilerArgs(list):
def append_direct(self, arg):
'''
Append the specified argument without any reordering or de-dup
+ except for absolute paths where the order of include search directories
+ is not relevant
'''
- super().append(arg)
+ if os.path.isabs(arg):
+ self.append(arg)
+ else:
+ super().append(arg)
def extend_direct(self, iterable):
'''
Extend using the elements in the specified iterable without any
- reordering or de-dup
+ reordering or de-dup except for absolute paths where the order of
+ include search directories is not relevant
'''
- super().extend(iterable)
+ for elem in iterable:
+ self.append_direct(elem)
def __add__(self, args):
new = CompilerArgs(self, self.compiler)
@@ -601,6 +625,8 @@ class Compiler:
# Libraries to ignore in find_library() since they are provided by the
# compiler or the C library. Currently only used for MSVC.
ignore_libs = ()
+ # Cache for the result of compiler checks which can be cached
+ compiler_check_cache = {}
def __init__(self, exelist, version, **kwargs):
if isinstance(exelist, str):
@@ -659,6 +685,12 @@ class Compiler:
def get_always_args(self):
return []
+ def can_linker_accept_rsp(self):
+ """
+ Determines whether the linker can accept arguments using the @rsp syntax.
+ """
+ return mesonlib.is_windows()
+
def get_linker_always_args(self):
return []
@@ -753,9 +785,23 @@ class Compiler:
return os.path.join(dirname, 'output.' + suffix)
@contextlib.contextmanager
- def compile(self, code, extra_args=None, mode='link'):
+ def compile(self, code, extra_args=None, mode='link', want_output=False):
if extra_args is None:
+ textra_args = None
extra_args = []
+ else:
+ textra_args = tuple(extra_args)
+ key = (code, textra_args, mode)
+ if not want_output:
+ if key in self.compiler_check_cache:
+ p = self.compiler_check_cache[key]
+ mlog.debug('Using cached compile:')
+ mlog.debug('Cached command line: ', ' '.join(p.commands), '\n')
+ mlog.debug('Code:\n', code)
+ mlog.debug('Cached compiler stdout:\n', p.stdo)
+ mlog.debug('Cached compiler stderr:\n', p.stde)
+ yield p
+ raise StopIteration
try:
with tempfile.TemporaryDirectory() as tmpdirname:
if isinstance(code, str):
@@ -765,7 +811,6 @@ class Compiler:
ofile.write(code)
elif isinstance(code, mesonlib.File):
srcname = code.fname
- output = self._get_compile_output(tmpdirname, mode)
# Construct the compiler command-line
commands = CompilerArgs(self)
@@ -778,6 +823,7 @@ class Compiler:
if mode == 'preprocess':
commands += self.get_preprocess_only_args()
else:
+ output = self._get_compile_output(tmpdirname, mode)
commands += self.get_output_args(output)
# Generate full command-line with the exelist
commands = self.get_exelist() + commands.to_native()
@@ -788,8 +834,12 @@ class Compiler:
p, p.stdo, p.stde = Popen_safe(commands, cwd=tmpdirname)
mlog.debug('Compiler stdout:\n', p.stdo)
mlog.debug('Compiler stderr:\n', p.stde)
+ p.commands = commands
p.input_name = srcname
- p.output_name = output
+ if want_output:
+ p.output_name = output
+ else:
+ self.compiler_check_cache[key] = p
yield p
except (PermissionError, OSError):
# On Windows antivirus programs and the like hold on to files so
@@ -887,6 +937,9 @@ class Compiler:
def thread_flags(self, env):
return []
+ def openmp_flags(self):
+ raise EnvironmentException('Language %s does not support OpenMP flags.' % self.get_display_language())
+
GCC_STANDARD = 0
GCC_OSX = 1
@@ -909,14 +962,16 @@ ICC_WIN = 2
GNU_LD_AS_NEEDED = '-Wl,--as-needed'
APPLE_LD_AS_NEEDED = '-Wl,-dead_strip_dylibs'
-def get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion, is_shared_module):
+def get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion, version, is_shared_module):
if soversion is None:
sostr = ''
else:
sostr = '.' + soversion
- if gcc_type in (GCC_STANDARD, GCC_MINGW, GCC_CYGWIN):
- # Might not be correct for mingw but seems to work.
+ if gcc_type == GCC_STANDARD:
return ['-Wl,-soname,%s%s.%s%s' % (prefix, shlib_name, suffix, sostr)]
+ elif gcc_type in (GCC_MINGW, GCC_CYGWIN):
+ # For PE/COFF the soname argument has no effect with GNU LD
+ return []
elif gcc_type == GCC_OSX:
if is_shared_module:
return []
@@ -924,7 +979,15 @@ def get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion, i
if soversion is not None:
install_name += '.' + soversion
install_name += '.dylib'
- return ['-install_name', os.path.join('@rpath', install_name)]
+ args = ['-install_name', os.path.join('@rpath', install_name)]
+ if version and len(version.split('.')) == 3:
+ splitted = version.split('.')
+ major = int(splitted[0])
+ minor = int(splitted[1])
+ revision = int(splitted[2])
+ args += ['-compatibility_version', '%d' % (major + minor + 1)]
+ args += ['-current_version', '%d.%d' % (major + minor + 1, revision)]
+ return args
else:
raise RuntimeError('Not implemented yet.')
@@ -980,7 +1043,7 @@ def gnulike_default_include_dirs(compiler, lang):
stdout=subprocess.PIPE,
env=env
)
- stderr = p.stderr.read().decode('utf-8')
+ stderr = p.stderr.read().decode('utf-8', errors='replace')
parse_state = 0
paths = []
for line in stderr.split('\n'):
@@ -1062,8 +1125,8 @@ class GnuCompiler:
def split_shlib_to_parts(self, fname):
return os.path.dirname(fname), fname
- def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module):
- return get_gcc_soname_args(self.gcc_type, prefix, shlib_name, suffix, path, soversion, is_shared_module)
+ def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, version, is_shared_module):
+ return get_gcc_soname_args(self.gcc_type, prefix, shlib_name, suffix, path, soversion, version, is_shared_module)
def get_std_shared_lib_link_args(self):
return ['-shared']
@@ -1092,6 +1155,32 @@ class GnuCompiler:
def get_default_include_dirs(self):
return gnulike_default_include_dirs(self.exelist, self.language)
+ def openmp_flags(self):
+ return ['-fopenmp']
+
+
+class ElbrusCompiler(GnuCompiler):
+ # Elbrus compiler is nearly like GCC, but does not support
+ # PCH, LTO, sanitizers and color output as of version 1.21.x.
+ def __init__(self, gcc_type, defines):
+ GnuCompiler.__init__(self, gcc_type, defines)
+ self.id = 'lcc'
+ self.base_options = ['b_pgo', 'b_coverage',
+ '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]
+ for line in stdo.split('\n'):
+ if line.startswith('libraries:'):
+ # lcc does not include '=' in --print-search-dirs output.
+ libstr = line.split(' ', 1)[1]
+ return libstr.split(':')
+ return []
+
+
class ClangCompiler:
def __init__(self, clang_type):
@@ -1138,7 +1227,7 @@ class ClangCompiler:
# so it might change semantics at any time.
return ['-include-pch', os.path.join(pch_dir, self.get_pch_name(header))]
- def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module):
+ def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, version, is_shared_module):
if self.clang_type == CLANG_STANDARD:
gcc_type = GCC_STANDARD
elif self.clang_type == CLANG_OSX:
@@ -1147,7 +1236,7 @@ class ClangCompiler:
gcc_type = GCC_MINGW
else:
raise MesonException('Unreachable code when converting clang type to gcc type.')
- return get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion, is_shared_module)
+ return get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion, version, is_shared_module)
def has_multi_arguments(self, args, env):
myargs = ['-Werror=unknown-warning-option', '-Werror=unused-command-line-argument']
@@ -1187,6 +1276,15 @@ class ClangCompiler:
def get_default_include_dirs(self):
return gnulike_default_include_dirs(self.exelist, self.language)
+ def openmp_flags(self):
+ if version_compare(self.version, '>=3.8.0'):
+ return ['-fopenmp']
+ elif version_compare(self.version, '>=3.7.0'):
+ return ['-fopenmp=libomp']
+ else:
+ # Shouldn't work, but it'll be checked explicitly in the OpenMP dependency.
+ return []
+
# Tested on linux for ICC 14.0.3, 15.0.6, 16.0.4, 17.0.1
class IntelCompiler:
@@ -1221,7 +1319,7 @@ class IntelCompiler:
def split_shlib_to_parts(self, fname):
return os.path.dirname(fname), fname
- def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module):
+ def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, version, is_shared_module):
if self.icc_type == ICC_STANDARD:
gcc_type = GCC_STANDARD
elif self.icc_type == ICC_OSX:
@@ -1230,7 +1328,7 @@ class IntelCompiler:
gcc_type = GCC_MINGW
else:
raise MesonException('Unreachable code when converting icc type to gcc type.')
- return get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion, is_shared_module)
+ return get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion, version, is_shared_module)
# TODO: centralise this policy more globally, instead
# of fragmenting it into GnuCompiler and ClangCompiler
@@ -1248,3 +1346,79 @@ class IntelCompiler:
def get_default_include_dirs(self):
return gnulike_default_include_dirs(self.exelist, self.language)
+
+ def openmp_flags(self):
+ if version_compare(self.version, '>=15.0.0'):
+ return ['-qopenmp']
+ else:
+ return ['-openmp']
+
+
+class ArmCompiler:
+ # Functionality that is common to all ARM family compilers.
+ def __init__(self):
+ if not self.is_cross:
+ raise EnvironmentException('armcc supports only cross-compilation.')
+ self.id = 'arm'
+ default_warn_args = []
+ self.warn_args = {'1': default_warn_args,
+ '2': default_warn_args + [],
+ '3': default_warn_args + []}
+ # Assembly
+ self.can_compile_suffixes.add('s')
+
+ def can_linker_accept_rsp(self):
+ return False
+
+ def get_pic_args(self):
+ # FIXME: Add /ropi, /rwpi, /fpic etc. qualifiers to --apcs
+ return []
+
+ def get_buildtype_args(self, buildtype):
+ return arm_buildtype_args[buildtype]
+
+ def get_buildtype_linker_args(self, buildtype):
+ return arm_buildtype_linker_args[buildtype]
+
+ # Override CCompiler.get_always_args
+ def get_always_args(self):
+ return []
+
+ # Override CCompiler.get_dependency_gen_args
+ def get_dependency_gen_args(self, outtarget, outfile):
+ return []
+
+ # Override CCompiler.get_std_shared_lib_link_args
+ def get_std_shared_lib_link_args(self):
+ return []
+
+ def get_pch_use_args(self, pch_dir, header):
+ # FIXME: Add required arguments
+ # NOTE from armcc user guide:
+ # "Support for Precompiled Header (PCH) files is deprecated from ARM Compiler 5.05
+ # onwards on all platforms. Note that ARM Compiler on Windows 8 never supported
+ # PCH files."
+ return []
+
+ def get_pch_suffix(self):
+ # NOTE from armcc user guide:
+ # "Support for Precompiled Header (PCH) files is deprecated from ARM Compiler 5.05
+ # onwards on all platforms. Note that ARM Compiler on Windows 8 never supported
+ # PCH files."
+ return 'pch'
+
+ def thread_flags(self, env):
+ return []
+
+ def thread_link_flags(self, env):
+ return []
+
+ def get_linker_exelist(self):
+ args = ['armlink']
+ return args
+
+ def get_coverage_args(self):
+ return []
+
+ def get_coverage_link_args(self):
+ return []