compilers: Consolidate language suffix mapping

Instead of spreading it across the entire file and re-implementing
can_compile for each compiler, consolidate it in one dictionary which
the base compiler class can refer to based on self.language set by the
child class.

This has fixed a number of hidden and unreported bugs due to bitrotten
can_compiler implementations.
pull/814/head
Nirbheek Chauhan 8 years ago
parent 5ebc77f722
commit ece29e32a8
  1. 185
      mesonbuild/compilers.py

@ -23,12 +23,27 @@ from . import coredata
about. To support a new compiler, add its information below.
Also add corresponding autodetection code in environment.py."""
header_suffixes = ['h', 'hh', 'hpp', 'hxx', 'H', 'ipp', 'moc', 'vapi', 'di']
cpp_suffixes = ['cc', 'cpp', 'cxx', 'h', 'hh', 'hpp', 'ipp', 'hxx', 'c++']
c_suffixes = ['c']
clike_suffixes = c_suffixes + cpp_suffixes
obj_suffixes = ['o', 'obj', 'res']
lib_suffixes = ['a', 'lib', 'dll', 'dylib', 'so']
header_suffixes = ('h', 'hh', 'hpp', 'hxx', 'H', 'ipp', 'moc', 'vapi', 'di')
obj_suffixes = ('o', 'obj', 'res')
lib_suffixes = ('a', 'lib', 'dll', 'dylib', 'so')
# Mapping of language to suffixes of files that should always be in that language
# This means we can't include .h headers here since they could be C, C++, ObjC, etc.
lang_suffixes = {
'c': ('c',),
'cpp': ('cpp', 'cc', 'cxx', 'c++', 'hh', 'hpp', 'ipp', 'hxx'),
'fortran': ('f', 'f90', 'f95'),
'd': ('d', 'di'),
'objc': ('m',),
'objcpp': ('mm',),
'rust': ('rs',),
'vala': ('vala', 'vapi'),
'cs': ('cs',),
'swift': ('swift',),
'java': ('java',),
}
cpp_suffixes = lang_suffixes['cpp'] + ('h',)
c_suffixes = lang_suffixes['c'] + ('h',)
clike_suffixes = lang_suffixes['c'] + lang_suffixes['cpp'] + ('h',)
def is_header(fname):
if hasattr(fname, 'fname'):
@ -300,9 +315,23 @@ class Compiler():
self.exelist = exelist
else:
raise TypeError('Unknown argument to Compiler')
# In case it's been overriden by a child class already
if not hasattr(self, 'file_suffixes'):
self.file_suffixes = lang_suffixes[self.language]
if not hasattr(self, 'can_compile_suffixes'):
self.can_compile_suffixes = set(self.file_suffixes)
self.default_suffix = self.file_suffixes[0]
self.version = version
self.base_options = []
def can_compile(self, src):
if hasattr(src, 'fname'):
src = src.fname
suffix = os.path.splitext(src)[1].lower()
if suffix and suffix[1:] in self.can_compile_suffixes:
return True
return False
def get_always_args(self):
return []
@ -391,11 +420,13 @@ class Compiler():
class CCompiler(Compiler):
def __init__(self, exelist, version, is_cross, exe_wrapper=None):
# If a child ObjC or CPP class has already set it, don't set it ourselves
if not hasattr(self, 'language'):
self.language = 'c'
super().__init__(exelist, version)
self.language = 'c'
self.default_suffix = 'c'
self.id = 'unknown'
self.is_cross = is_cross
self.can_compile_suffixes.add('h')
if isinstance(exe_wrapper, str):
self.exe_wrapper = [exe_wrapper]
else:
@ -502,12 +533,6 @@ class CCompiler(Compiler):
return libstr.split(':')
return []
def can_compile(self, filename):
suffix = filename.split('.')[-1]
if suffix == 'c' or suffix == 'h':
return True
return False
def get_pic_args(self):
return ['-fPIC']
@ -976,15 +1001,10 @@ void bar() {
class CPPCompiler(CCompiler):
def __init__(self, exelist, version, is_cross, exe_wrap):
# If a child ObjCPP class has already set it, don't set it ourselves
if not hasattr(self, 'language'):
self.language = 'cpp'
CCompiler.__init__(self, exelist, version, is_cross, exe_wrap)
self.language = 'cpp'
self.default_suffix = 'cpp'
def can_compile(self, filename):
suffix = filename.split('.')[-1]
if suffix in cpp_suffixes:
return True
return False
def sanity_check(self, work_dir, environment):
code = 'class breakCCompiler;int main(int argc, char **argv) { return 0; }\n'
@ -992,15 +1012,8 @@ class CPPCompiler(CCompiler):
class ObjCCompiler(CCompiler):
def __init__(self, exelist, version, is_cross, exe_wrap):
CCompiler.__init__(self, exelist, version, is_cross, exe_wrap)
self.language = 'objc'
self.default_suffix = 'm'
def can_compile(self, filename):
suffix = filename.split('.')[-1]
if suffix == 'm' or suffix == 'h':
return True
return False
CCompiler.__init__(self, exelist, version, is_cross, exe_wrap)
def sanity_check(self, work_dir, environment):
# TODO try to use sanity_check_impl instead of duplicated code
@ -1026,15 +1039,8 @@ class ObjCCompiler(CCompiler):
class ObjCPPCompiler(CPPCompiler):
def __init__(self, exelist, version, is_cross, exe_wrap):
CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap)
self.language = 'objcpp'
self.default_suffix = 'mm'
def can_compile(self, filename):
suffix = filename.split('.')[-1]
if suffix == 'mm' or suffix == 'h':
return True
return False
CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap)
def sanity_check(self, work_dir, environment):
# TODO try to use sanity_check_impl instead of duplicated code
@ -1061,9 +1067,8 @@ class ObjCPPCompiler(CPPCompiler):
class MonoCompiler(Compiler):
def __init__(self, exelist, version):
super().__init__(exelist, version)
self.language = 'cs'
self.default_suffix = 'cs'
super().__init__(exelist, version)
self.id = 'mono'
self.monorunner = 'mono'
@ -1124,12 +1129,6 @@ class MonoCompiler(Compiler):
def get_std_shared_lib_link_args(self):
return []
def can_compile(self, filename):
suffix = filename.split('.')[-1]
if suffix == 'cs':
return True
return False
def get_pic_args(self):
return []
@ -1170,9 +1169,8 @@ class MonoCompiler(Compiler):
class JavaCompiler(Compiler):
def __init__(self, exelist, version):
super().__init__(exelist, version)
self.language = 'java'
self.default_suffix = 'java'
super().__init__(exelist, version)
self.id = 'unknown'
self.javarunner = 'java'
@ -1232,12 +1230,6 @@ class JavaCompiler(Compiler):
def get_std_shared_lib_link_args(self):
return []
def can_compile(self, filename):
suffix = filename.split('.')[-1]
if suffix == 'java':
return True
return False
def get_pic_args(self):
return []
@ -1279,10 +1271,10 @@ class JavaCompiler(Compiler):
class ValaCompiler(Compiler):
def __init__(self, exelist, version):
self.language = 'vala'
super().__init__(exelist, version)
self.version = version
self.id = 'unknown'
self.language = 'vala'
self.is_cross = False
def name_string(self):
@ -1313,10 +1305,6 @@ class ValaCompiler(Compiler):
if pc.returncode != 0:
raise EnvironmentException('Vala compiler %s can not compile programs.' % self.name_string())
def can_compile(self, filename):
suffix = filename.split('.')[-1]
return suffix in ('vala', 'vapi')
def get_buildtype_args(self, buildtype):
if buildtype == 'debug' or buildtype == 'debugoptimized' or buildtype == 'minsize':
return ['--debug']
@ -1324,9 +1312,9 @@ class ValaCompiler(Compiler):
class RustCompiler(Compiler):
def __init__(self, exelist, version):
self.language = 'rust'
super().__init__(exelist, version)
self.id = 'unknown'
self.language = 'rust'
def needs_static_linker(self):
return False
@ -1357,9 +1345,6 @@ class RustCompiler(Compiler):
if subprocess.call(output_name) != 0:
raise EnvironmentException('Executables created by Rust compiler %s are not runnable.' % self.name_string())
def can_compile(self, fname):
return fname.endswith('.rs')
def get_dependency_gen_args(self, outfile):
return ['--dep-info', outfile]
@ -1368,10 +1353,10 @@ class RustCompiler(Compiler):
class SwiftCompiler(Compiler):
def __init__(self, exelist, version):
self.language = 'swift'
super().__init__(exelist, version)
self.version = version
self.id = 'llvm'
self.language = 'swift'
self.is_cross = False
def get_id(self):
@ -1455,15 +1440,11 @@ class SwiftCompiler(Compiler):
if subprocess.call(output_name) != 0:
raise EnvironmentException('Executables created by Swift compiler %s are not runnable.' % self.name_string())
def can_compile(self, filename):
suffix = filename.split('.')[-1]
return suffix in ('swift')
class DCompiler(Compiler):
def __init__(self, exelist, version, is_cross):
self.language = 'd'
super().__init__(exelist, version)
self.id = 'unknown'
self.language = 'd'
self.is_cross = is_cross
def sanity_check(self, work_dir, environment):
@ -1495,10 +1476,6 @@ class DCompiler(Compiler):
def get_language(self):
return self.language
def can_compile(self, fname):
suffix = fname.split('.')[-1]
return suffix in ('d', 'di')
def get_linker_exelist(self):
return self.exelist[:]
@ -1901,17 +1878,11 @@ class VisualStudioCCompiler(CCompiler):
class VisualStudioCPPCompiler(VisualStudioCCompiler):
def __init__(self, exelist, version, is_cross, exe_wrap):
VisualStudioCCompiler.__init__(self, exelist, version, is_cross, exe_wrap)
self.language = 'cpp'
VisualStudioCCompiler.__init__(self, exelist, version, is_cross, exe_wrap)
self.default_suffix = 'cpp'
self.base_options = ['b_pch'] # FIXME add lto, pgo and the like
def can_compile(self, filename):
suffix = filename.split('.')[-1]
if suffix in cpp_suffixes:
return True
return False
def get_options(self):
return {'cpp_eh' : coredata.UserComboOption('cpp_eh',
'C++ exception handling type.',
@ -2006,13 +1977,12 @@ class GnuCCompiler(GnuCompiler, CCompiler):
def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None):
CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper)
GnuCompiler.__init__(self, gcc_type)
# Gcc can do asm, too.
self.can_compile_suffixes.add('s')
self.warn_args = {'1': ['-Wall', '-Winvalid-pch'],
'2': ['-Wall', '-Wextra', '-Winvalid-pch'],
'3' : ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch']}
def can_compile(self, filename):
return super().can_compile(filename) or filename.split('.')[-1].lower() == 's' # Gcc can do asm, too.
def get_options(self):
opts = {'c_std' : coredata.UserComboOption('c_std', 'C language standard to use',
['none', 'c89', 'c99', 'c11', 'gnu89', 'gnu99', 'gnu11'],
@ -2125,6 +2095,8 @@ class ClangCCompiler(ClangCompiler, CCompiler):
def __init__(self, exelist, version, clang_type, is_cross, exe_wrapper=None):
CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper)
ClangCompiler.__init__(self, clang_type)
# Clang can do asm, too.
self.can_compile_suffixes.add('s')
self.warn_args = {'1': ['-Wall', '-Winvalid-pch'],
'2': ['-Wall', '-Wextra', '-Winvalid-pch'],
'3' : ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch']}
@ -2147,9 +2119,6 @@ class ClangCCompiler(ClangCompiler, CCompiler):
def has_argument(self, arg, env):
return super().has_argument(['-Werror=unknown-warning-option', arg], env)
def can_compile(self, filename):
return super().can_compile(filename) or filename.split('.')[-1].lower() == 's' # Clang can do asm, too.
class ClangCPPCompiler(ClangCompiler, CPPCompiler):
def __init__(self, exelist, version, cltype, is_cross, exe_wrapper=None):
@ -2177,9 +2146,6 @@ class ClangCPPCompiler(ClangCompiler, CPPCompiler):
def has_argument(self, arg, env):
return super().has_argument(['-Werror=unknown-warning-option', arg], env)
def can_compile(self, filename):
return super().can_compile(filename) or filename.split('.')[-1].lower() == 's' # Clang can do asm, too.
class ClangObjCCompiler(GnuObjCCompiler):
def __init__(self, exelist, version, cltype, is_cross, exe_wrapper=None):
super().__init__(exelist, version, is_cross, exe_wrapper)
@ -2202,10 +2168,10 @@ class ClangObjCPPCompiler(GnuObjCPPCompiler):
class FortranCompiler(Compiler):
def __init__(self, exelist, version, is_cross, exe_wrapper=None):
self.language = 'fortran'
super().__init__(exelist, version)
self.is_cross = is_cross
self.exe_wrapper = exe_wrapper
self.language = 'fortran'
# Not really correct but I don't have Fortran compilers to test with. Sorry.
self.gcc_type = GCC_STANDARD
self.id = "IMPLEMENTATION CLASSES MUST SET THIS"
@ -2291,14 +2257,6 @@ end program prog
def get_linker_output_args(self, outputname):
return ['-o', outputname]
def can_compile(self, src):
if hasattr(src, 'fname'):
src = src.fname
suffix = os.path.splitext(src)[1].lower()
if suffix == '.f' or suffix == '.f95' or suffix == '.f90':
return True
return False
def get_include_args(self, path, is_system):
return ['-I' + path]
@ -2381,18 +2339,13 @@ class IntelFortranCompiler(FortranCompiler):
std_warn_args = ['-warn', 'all']
def __init__(self, exelist, version, is_cross, exe_wrapper=None):
self.file_suffixes = ('f', 'f90')
super().__init__(exelist, version, is_cross, exe_wrapper=None)
self.id = 'intel'
def get_module_outdir_args(self, path):
return ['-module', path]
def can_compile(self, src):
suffix = os.path.splitext(src)[1].lower()
if suffix == '.f' or suffix == '.f90':
return True
return False
def get_warn_args(self, level):
return IntelFortranCompiler.std_warn_args
@ -2406,12 +2359,6 @@ class PathScaleFortranCompiler(FortranCompiler):
def get_module_outdir_args(self, path):
return ['-module', path]
def can_compile(self, src):
suffix = os.path.splitext(src)[1].lower()
if suffix == '.f' or suffix == '.f90' or suffix == '.f95':
return True
return False
def get_std_warn_args(self, level):
return PathScaleFortranCompiler.std_warn_args
@ -2425,12 +2372,6 @@ class PGIFortranCompiler(FortranCompiler):
def get_module_outdir_args(self, path):
return ['-module', path]
def can_compile(self, src):
suffix = os.path.splitext(src)[1].lower()
if suffix == '.f' or suffix == '.f90' or suffix == '.f95':
return True
return False
def get_warn_args(self, level):
return PGIFortranCompiler.std_warn_args
@ -2445,12 +2386,6 @@ class Open64FortranCompiler(FortranCompiler):
def get_module_outdir_args(self, path):
return ['-module', path]
def can_compile(self, src):
suffix = os.path.splitext(src)[1].lower()
if suffix == '.f' or suffix == '.f90' or suffix == '.f95':
return True
return False
def get_warn_args(self, level):
return Open64FortranCompiler.std_warn_args
@ -2467,12 +2402,6 @@ class NAGFortranCompiler(FortranCompiler):
def get_always_args(self):
return []
def can_compile(self, src):
suffix = os.path.splitext(src)[1].lower()
if suffix == '.f' or suffix == '.f90' or suffix == '.f95':
return True
return False
def get_warn_args(self, level):
return NAGFortranCompiler.std_warn_args

Loading…
Cancel
Save