diff options
Diffstat (limited to 'mesonbuild/compilers/compilers.py')
-rw-r--r-- | mesonbuild/compilers/compilers.py | 210 |
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 [] |