diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index a086d37a8..e7165d257 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -1689,7 +1689,7 @@ int dummy; else: expdir = basedir srctreedir = os.path.normpath(os.path.join(self.environment.get_build_dir(), self.build_to_src, expdir)) - sargs = swiftc.get_include_args(srctreedir) + sargs = swiftc.get_include_args(srctreedir, False) compile_args += sargs link_args = swiftc.get_output_args(os.path.join(self.environment.get_build_dir(), self.get_target_filename(target))) link_args += self.build.get_project_link_args(swiftc, target.subproject, target.for_machine) @@ -1700,7 +1700,7 @@ int dummy; abs_module_dirs = self.determine_swift_dep_dirs(target) module_includes = [] for x in abs_module_dirs: - module_includes += swiftc.get_include_args(x) + module_includes += swiftc.get_include_args(x, False) link_deps = self.get_swift_link_deps(target) abs_link_deps = [os.path.join(self.environment.get_build_dir(), x) for x in link_deps] for d in target.link_targets: diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 091a000ef..95c469873 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -39,13 +39,22 @@ from .compilers import ( ) if T.TYPE_CHECKING: + from ..coredata import OptionDictType + from ..dependencies import Dependency, ExternalProgram from ..envconfig import MachineInfo + from ..environment import Environment + from ..linkers import DynamicLinker + + CompilerMixinBase = Compiler +else: + CompilerMixinBase = object + class CCompiler(CLikeCompiler, Compiler): @staticmethod - def attribute_check_func(name): + def attribute_check_func(name: str) -> str: try: return C_FUNC_ATTRIBUTES[name] except KeyError: @@ -53,20 +62,26 @@ class CCompiler(CLikeCompiler, Compiler): language = 'c' - def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, - info: 'MachineInfo', exe_wrapper: T.Optional[str] = None, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): # If a child ObjC or CPP class has already set it, don't set it ourselves - Compiler.__init__(self, exelist, version, for_machine, info, is_cross=is_cross, **kwargs) + Compiler.__init__(self, exelist, version, for_machine, info, + is_cross=is_cross, full_version=full_version, linker=linker) CLikeCompiler.__init__(self, exe_wrapper) - def get_no_stdinc_args(self): + def get_no_stdinc_args(self) -> T.List[str]: return ['-nostdinc'] - def sanity_check(self, work_dir, environment): + def sanity_check(self, work_dir: str, environment: 'Environment') -> None: code = 'int main(void) { int class=0; return class; }\n' return self._sanity_check_impl(work_dir, environment, 'sanitycheckc.c', code) - def has_header_symbol(self, hname, symbol, prefix, env, *, extra_args=None, dependencies=None): + def has_header_symbol(self, hname: str, symbol: str, prefix: str, + env: 'Environment', *, + extra_args: T.Optional[T.List[str]] = None, + dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: fargs = {'prefix': prefix, 'header': hname, 'symbol': symbol} t = '''{prefix} #include <{header}> @@ -87,10 +102,12 @@ class ClangCCompiler(ClangCompiler, CCompiler): _C18_VERSION = '>=8.0.0' _C2X_VERSION = '>=9.0.0' - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, - defines: T.Optional[T.List[str]] = None, **kwargs): - CCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + defines: T.Optional[T.Dict[str, str]] = None, + full_version: T.Optional[str] = None): + CCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) ClangCompiler.__init__(self, defines) default_warn_args = ['-Wall', '-Winvalid-pch'] self.warn_args = {'0': [], @@ -98,7 +115,7 @@ class ClangCCompiler(ClangCompiler, CCompiler): '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = CCompiler.get_options(self) c_stds = ['c89', 'c99', 'c11'] g_stds = ['gnu89', 'gnu99', 'gnu11'] @@ -129,16 +146,21 @@ class ClangCCompiler(ClangCompiler, CCompiler): }) return opts - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] std = options['std'] if std.value != 'none': args.append('-std=' + std.value) return args - def get_option_link_args(self, options): + def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: if self.info.is_windows() or self.info.is_cygwin(): - return options['winlibs'].value[:] + # without a typedict mypy can't understand this. + libs = options['winlibs'].value.copy() + assert isinstance(libs, list) + for l in libs: + assert isinstance(l, str) + return libs return [] @@ -156,21 +178,26 @@ class AppleClangCCompiler(ClangCCompiler): class EmscriptenCCompiler(EmscriptenMixin, LinkerEnvVarsMixin, ClangCCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross: bool, info: 'MachineInfo', exe_wrapper=None, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + defines: T.Optional[T.Dict[str, str]] = None, + full_version: T.Optional[str] = None): if not is_cross: raise MesonException('Emscripten compiler can only be used for cross compilation.') - ClangCCompiler.__init__(self, exelist=exelist, version=version, - for_machine=for_machine, is_cross=is_cross, - info=info, exe_wrapper=exe_wrapper, **kwargs) + ClangCCompiler.__init__(self, exelist, version, for_machine, is_cross, + info, exe_wrapper=exe_wrapper, linker=linker, + defines=defines, full_version=full_version) self.id = 'emscripten' class ArmclangCCompiler(ArmclangCompiler, CCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): CCompiler.__init__(self, exelist, version, for_machine, is_cross, - info, exe_wrapper, **kwargs) + info, exe_wrapper, linker=linker, full_version=full_version) ArmclangCompiler.__init__(self) default_warn_args = ['-Wall', '-Winvalid-pch'] self.warn_args = {'0': [], @@ -178,7 +205,7 @@ class ArmclangCCompiler(ArmclangCompiler, CCompiler): '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = CCompiler.get_options(self) opts.update({ 'std': coredata.UserComboOption( @@ -189,14 +216,14 @@ class ArmclangCCompiler(ArmclangCompiler, CCompiler): }) return opts - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] std = options['std'] if std.value != 'none': args.append('-std=' + std.value) return args - def get_option_link_args(self, options): + def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: return [] @@ -205,11 +232,12 @@ class GnuCCompiler(GnuCompiler, CCompiler): _C18_VERSION = '>=8.0.0' _C2X_VERSION = '>=9.0.0' - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, - defines=None, **kwargs): - CCompiler.__init__(self, exelist, version, for_machine, is_cross, - info, exe_wrapper, **kwargs) + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + defines: T.Optional[T.Dict[str, str]] = None, + full_version: T.Optional[str] = None): + CCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version) GnuCompiler.__init__(self, defines) default_warn_args = ['-Wall', '-Winvalid-pch'] self.warn_args = {'0': [], @@ -217,7 +245,7 @@ class GnuCCompiler(GnuCompiler, CCompiler): '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = CCompiler.get_options(self) c_stds = ['c89', 'c99', 'c11'] g_stds = ['gnu89', 'gnu99', 'gnu11'] @@ -243,49 +271,61 @@ class GnuCCompiler(GnuCompiler, CCompiler): }) return opts - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] std = options['std'] if std.value != 'none': args.append('-std=' + std.value) return args - def get_option_link_args(self, options): + def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: if self.info.is_windows() or self.info.is_cygwin(): - return options['winlibs'].value[:] + # without a typeddict mypy can't figure this out + libs = options['winlibs'].value.copy() + assert isinstance(libs, list) + for l in libs: + assert isinstance(l, str) + return libs return [] - def get_pch_use_args(self, pch_dir, header): + def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: return ['-fpch-preprocess', '-include', os.path.basename(header)] class PGICCompiler(PGICompiler, CCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): CCompiler.__init__(self, exelist, version, for_machine, is_cross, - info, exe_wrapper, **kwargs) + info, exe_wrapper, linker=linker, full_version=full_version) PGICompiler.__init__(self) class NvidiaHPC_CCompiler(PGICompiler, CCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): CCompiler.__init__(self, exelist, version, for_machine, is_cross, - info, exe_wrapper, **kwargs) + info, exe_wrapper, linker=linker, full_version=full_version) PGICompiler.__init__(self) self.id = 'nvidia_hpc' class ElbrusCCompiler(GnuCCompiler, ElbrusCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, - defines=None, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + defines: T.Optional[T.Dict[str, str]] = None, + full_version: T.Optional[str] = None): GnuCCompiler.__init__(self, exelist, version, for_machine, is_cross, - info, exe_wrapper, defines, **kwargs) + info, exe_wrapper, defines=defines, + linker=linker, full_version=full_version) ElbrusCompiler.__init__(self) # It does support some various ISO standards and c/gnu 90, 9x, 1x in addition to those which GNU CC supports. - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = CCompiler.get_options(self) opts.update({ 'std': coredata.UserComboOption( @@ -302,7 +342,9 @@ class ElbrusCCompiler(GnuCCompiler, ElbrusCompiler): # Elbrus C compiler does not have lchmod, but there is only linker warning, not compiler error. # So we should explicitly fail at this case. - def has_function(self, funcname, prefix, env, *, extra_args=None, dependencies=None): + def has_function(self, funcname: str, prefix: str, env: 'Environment', *, + extra_args: T.Optional[T.List[str]] = None, + dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: if funcname == 'lchmod': return False, False else: @@ -312,10 +354,12 @@ class ElbrusCCompiler(GnuCCompiler, ElbrusCompiler): class IntelCCompiler(IntelGnuLikeCompiler, CCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): CCompiler.__init__(self, exelist, version, for_machine, is_cross, - info, exe_wrapper, **kwargs) + info, exe_wrapper, linker=linker, full_version=full_version) IntelGnuLikeCompiler.__init__(self) self.lang_header = 'c-header' default_warn_args = ['-Wall', '-w3', '-diag-disable:remark'] @@ -324,7 +368,7 @@ class IntelCCompiler(IntelGnuLikeCompiler, CCompiler): '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra']} - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = CCompiler.get_options(self) c_stds = ['c89', 'c99'] g_stds = ['gnu89', 'gnu99'] @@ -339,7 +383,7 @@ class IntelCCompiler(IntelGnuLikeCompiler, CCompiler): }) return opts - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] std = options['std'] if std.value != 'none': @@ -347,11 +391,11 @@ class IntelCCompiler(IntelGnuLikeCompiler, CCompiler): return args -class VisualStudioLikeCCompilerMixin: +class VisualStudioLikeCCompilerMixin(CompilerMixinBase): """Shared methods that apply to MSVC-like C compilers.""" - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = super().get_options() opts.update({ 'winlibs': coredata.UserArrayOption( @@ -361,20 +405,28 @@ class VisualStudioLikeCCompilerMixin: }) return opts - def get_option_link_args(self, options): - return options['winlibs'].value[:] + def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: + # need a TypeDict to make this work + libs = options['winlibs'].value.copy() + assert isinstance(libs, list) + for l in libs: + assert isinstance(l, str) + return libs class VisualStudioCCompiler(MSVCCompiler, VisualStudioLikeCCompilerMixin, CCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrap, target: str, - **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, + is_cross: bool, info: 'MachineInfo', target: str, + exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): CCompiler.__init__(self, exelist, version, for_machine, is_cross, - info, exe_wrap, **kwargs) + info, exe_wrapper, linker=linker, + full_version=full_version) MSVCCompiler.__init__(self, target) - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = super().get_options() c_stds = ['none', 'c89', 'c99', 'c11'] opts.update({ @@ -386,7 +438,7 @@ class VisualStudioCCompiler(MSVCCompiler, VisualStudioLikeCCompilerMixin, CCompi }) return opts - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] std = options['std'] # As of MVSC 16.7, /std:c11 is the only valid C standard option. @@ -396,10 +448,14 @@ class VisualStudioCCompiler(MSVCCompiler, VisualStudioLikeCCompilerMixin, CCompi class ClangClCCompiler(ClangClCompiler, VisualStudioLikeCCompilerMixin, CCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrap, target, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, + is_cross: bool, info: 'MachineInfo', target: str, + exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): CCompiler.__init__(self, exelist, version, for_machine, is_cross, - info, exe_wrap, **kwargs) + info, exe_wrapper, linker=linker, + full_version=full_version) ClangClCompiler.__init__(self, target) @@ -407,13 +463,17 @@ class IntelClCCompiler(IntelVisualStudioLikeCompiler, VisualStudioLikeCCompilerM """Intel "ICL" compiler abstraction.""" - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrap, target, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, + is_cross: bool, info: 'MachineInfo', target: str, + exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): CCompiler.__init__(self, exelist, version, for_machine, is_cross, - info, exe_wrap, **kwargs) + info, exe_wrapper, linker=linker, + full_version=full_version) IntelVisualStudioLikeCompiler.__init__(self, target) - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = super().get_options() c_stds = ['none', 'c89', 'c99', 'c11'] opts.update({ @@ -425,7 +485,7 @@ class IntelClCCompiler(IntelVisualStudioLikeCompiler, VisualStudioLikeCCompilerM }) return opts - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] std = options['std'] if std.value == 'c89': @@ -436,13 +496,17 @@ class IntelClCCompiler(IntelVisualStudioLikeCompiler, VisualStudioLikeCCompilerM class ArmCCompiler(ArmCompiler, CCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, + is_cross: bool, info: 'MachineInfo', + exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): CCompiler.__init__(self, exelist, version, for_machine, is_cross, - info, exe_wrapper, **kwargs) + info, exe_wrapper, linker=linker, + full_version=full_version) ArmCompiler.__init__(self) - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = CCompiler.get_options(self) opts.update({ 'std': coredata.UserComboOption( @@ -453,7 +517,7 @@ class ArmCCompiler(ArmCompiler, CCompiler): }) return opts - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] std = options['std'] if std.value != 'none': @@ -462,17 +526,20 @@ class ArmCCompiler(ArmCompiler, CCompiler): class CcrxCCompiler(CcrxCompiler, CCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, + is_cross: bool, info: 'MachineInfo', + exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): CCompiler.__init__(self, exelist, version, for_machine, is_cross, - info, exe_wrapper, **kwargs) + info, exe_wrapper, linker=linker, full_version=full_version) CcrxCompiler.__init__(self) # Override CCompiler.get_always_args - def get_always_args(self): + def get_always_args(self) -> T.List[str]: return ['-nologo'] - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = CCompiler.get_options(self) opts.update({ 'std': coredata.UserComboOption( @@ -483,10 +550,10 @@ class CcrxCCompiler(CcrxCompiler, CCompiler): }) return opts - def get_no_stdinc_args(self): + def get_no_stdinc_args(self) -> T.List[str]: return [] - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] std = options['std'] if std.value == 'c89': @@ -495,42 +562,45 @@ class CcrxCCompiler(CcrxCompiler, CCompiler): args.append('-lang=c99') return args - def get_compile_only_args(self): + def get_compile_only_args(self) -> T.List[str]: return [] - def get_no_optimization_args(self): + def get_no_optimization_args(self) -> T.List[str]: return ['-optimize=0'] - def get_output_args(self, target): + def get_output_args(self, target: str) -> T.List[str]: return ['-output=obj=%s' % target] - def get_werror_args(self): + def get_werror_args(self) -> T.List[str]: return ['-change_message=error'] - def get_include_args(self, path, is_system): + def get_include_args(self, path: str, is_system: bool) -> T.List[str]: if path == '': path = '.' return ['-include=' + path] class Xc16CCompiler(Xc16Compiler, CCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, + is_cross: bool, info: 'MachineInfo', + exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): CCompiler.__init__(self, exelist, version, for_machine, is_cross, - info, exe_wrapper, **kwargs) + info, exe_wrapper, linker=linker, full_version=full_version) Xc16Compiler.__init__(self) - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = CCompiler.get_options(self) opts.update({'c_std': coredata.UserComboOption('C language standard to use', ['none', 'c89', 'c99', 'gnu89', 'gnu99'], 'none')}) return opts - def get_no_stdinc_args(self): + def get_no_stdinc_args(self) -> T.List[str]: return [] - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] std = options['c_std'] if std.value != 'none': @@ -538,95 +608,101 @@ class Xc16CCompiler(Xc16Compiler, CCompiler): args.append('-std=' + std.value) return args - def get_compile_only_args(self): + def get_compile_only_args(self) -> T.List[str]: return [] - def get_no_optimization_args(self): + def get_no_optimization_args(self) -> T.List[str]: return ['-O0'] - def get_output_args(self, target): + def get_output_args(self, target: str) -> T.List[str]: return ['-o%s' % target] - def get_werror_args(self): + def get_werror_args(self) -> T.List[str]: return ['-change_message=error'] - def get_include_args(self, path, is_system): + def get_include_args(self, path: str, is_system: bool) -> T.List[str]: if path == '': path = '.' return ['-I' + path] class CompCertCCompiler(CompCertCompiler, CCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, + is_cross: bool, info: 'MachineInfo', + exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): CCompiler.__init__(self, exelist, version, for_machine, is_cross, - info, exe_wrapper, **kwargs) + info, exe_wrapper, linker=linker, full_version=full_version) CompCertCompiler.__init__(self) - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = CCompiler.get_options(self) opts.update({'c_std': coredata.UserComboOption('C language standard to use', ['none', 'c89', 'c99'], 'none')}) return opts - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: return [] - def get_no_optimization_args(self): + def get_no_optimization_args(self) -> T.List[str]: return ['-O0'] - def get_output_args(self, target): + def get_output_args(self, target: str) -> T.List[str]: return ['-o{}'.format(target)] - def get_werror_args(self): + def get_werror_args(self) -> T.List[str]: return ['-Werror'] - def get_include_args(self, path, is_system): + def get_include_args(self, path: str, is_system: bool) -> T.List[str]: if path == '': path = '.' return ['-I' + path] class C2000CCompiler(C2000Compiler, CCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, + is_cross: bool, info: 'MachineInfo', + exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): CCompiler.__init__(self, exelist, version, for_machine, is_cross, - info, exe_wrapper, **kwargs) + info, exe_wrapper, linker=linker, full_version=full_version) C2000Compiler.__init__(self) # Override CCompiler.get_always_args - def get_always_args(self): + def get_always_args(self) -> T.List[str]: return [] - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = CCompiler.get_options(self) opts.update({'c_std': coredata.UserComboOption('C language standard to use', ['none', 'c89', 'c99', 'c11'], 'none')}) return opts - def get_no_stdinc_args(self): + def get_no_stdinc_args(self) -> T.List[str]: return [] - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] std = options['c_std'] if std.value != 'none': args.append('--' + std.value) return args - def get_compile_only_args(self): + def get_compile_only_args(self) -> T.List[str]: return [] - def get_no_optimization_args(self): + def get_no_optimization_args(self) -> T.List[str]: return ['-Ooff'] - def get_output_args(self, target): + def get_output_args(self, target: str) -> T.List[str]: return ['--output_file=%s' % target] - def get_werror_args(self): + def get_werror_args(self) -> T.List[str]: return ['-change_message=error'] - def get_include_args(self, path, is_system): + def get_include_args(self, path: str, is_system: bool) -> T.List[str]: if path == '': path = '.' return ['--include_path=' + path] diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 12643b0a5..4b48e3146 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -14,6 +14,7 @@ import abc import contextlib, os.path, re, tempfile +import enum import itertools import typing as T from functools import lru_cache @@ -165,6 +166,14 @@ def is_known_suffix(fname: 'mesonlib.FileOrString') -> bool: return suffix in all_suffixes + +class CompileCheckMode(enum.Enum): + + PREPROCESS = 'preprocess' + COMPILE = 'compile' + LINK = 'link' + + cuda_buildtype_args = {'plain': [], 'debug': [], 'debugoptimized': [], @@ -452,6 +461,7 @@ class Compiler(metaclass=abc.ABCMeta): if T.TYPE_CHECKING: language = 'unset' id = '' + warn_args = {} # type: T.Dict[str, T.List[str]] def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, info: 'MachineInfo', @@ -632,20 +642,6 @@ class Compiler(metaclass=abc.ABCMeta): dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: raise EnvironmentException('Language %s does not support header symbol checks.' % self.get_display_language()) - def compiles(self, code: str, env: 'Environment', *, - extra_args: T.Union[None, T.List[str], CompilerArgs] = None, - dependencies: T.Optional[T.List['Dependency']] = None, - mode: str = 'compile', - disable_cache: bool = False) -> T.Tuple[bool, bool]: - raise EnvironmentException('Language %s does not support compile checks.' % self.get_display_language()) - - def links(self, code: str, env: 'Environment', *, - extra_args: T.Union[None, T.List[str], CompilerArgs] = None, - dependencies: T.Optional[T.List['Dependency']] = None, - mode: str = 'compile', - disable_cache: bool = False) -> T.Tuple[bool, bool]: - raise EnvironmentException('Language %s does not support link checks.' % self.get_display_language()) - def run(self, code: str, env: 'Environment', *, extra_args: T.Optional[T.List[str]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> RunResult: @@ -715,14 +711,16 @@ class Compiler(metaclass=abc.ABCMeta): suffix = 'obj' return os.path.join(dirname, 'output.' + suffix) - def get_compiler_args_for_mode(self, mode: str) -> T.List[str]: + def get_compiler_args_for_mode(self, mode: CompileCheckMode) -> T.List[str]: # TODO: mode should really be an enum args = [] # type: T.List[str] args += self.get_always_args() - if mode == 'compile': + if mode is CompileCheckMode.COMPILE: args += self.get_compile_only_args() - if mode == 'preprocess': + elif mode is CompileCheckMode.PREPROCESS: args += self.get_preprocess_only_args() + else: + assert mode is CompileCheckMode.LINK return args def compiler_args(self, args: T.Optional[T.Iterable[str]] = None) -> CompilerArgs: @@ -760,7 +758,7 @@ class Compiler(metaclass=abc.ABCMeta): if mode != 'preprocess': output = self._get_compile_output(tmpdirname, mode) commands += self.get_output_args(output) - commands.extend(self.get_compiler_args_for_mode(mode)) + commands.extend(self.get_compiler_args_for_mode(CompileCheckMode(mode))) # extra_args must be last because it could contain '/link' to # pass args to VisualStudio's linker. In that case everything # in the command line after '/link' is given to the linker. @@ -862,6 +860,9 @@ class Compiler(metaclass=abc.ABCMeta): def thread_flags(self, env: 'Environment') -> T.List[str]: return [] + def thread_link_flags(self, env: 'Environment') -> T.List[str]: + return self.linker.thread_flags(env) + def openmp_flags(self) -> T.List[str]: raise EnvironmentException('Language %s does not support OpenMP flags.' % self.get_display_language()) @@ -953,6 +954,9 @@ class Compiler(metaclass=abc.ABCMeta): def bitcode_args(self) -> T.List[str]: return self.linker.bitcode_args() + def get_buildtype_args(self, buildtype: str) -> T.List[str]: + raise EnvironmentException('{} does not implement get_buildtype_args'.format(self.id)) + def get_buildtype_linker_args(self, buildtype: str) -> T.List[str]: return self.linker.get_buildtype_args(buildtype) @@ -1047,6 +1051,153 @@ class Compiler(metaclass=abc.ABCMeta): def name_string(self) -> str: return ' '.join(self.exelist) + @abc.abstractmethod + def sanity_check(self, work_dir: str, environment: 'Environment') -> None: + """Check that this compiler actually works. + + This should provide a simple compile/link test. Somthing as simple as: + ```python + main(): return 0 + ``` + is good enough here. + """ + + def split_shlib_to_parts(self, fname: str) -> T.Tuple[T.Optional[str], str]: + return None, fname + + def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: + return [] + + def get_std_exe_link_args(self) -> T.List[str]: + # TODO: is this a linker property? + return [] + + def get_include_args(self, path: str, is_system: bool) -> T.List[str]: + return [] + + def depfile_for_object(self, objfile: str) -> str: + return objfile + '.' + self.get_depfile_suffix() + + def get_depfile_suffix(self) -> str: + raise EnvironmentError('{} does not implement get_depfile_suffix'.format(self.id)) + + def get_no_stdinc_args(self) -> T.List[str]: + """Arguments to turn off default inclusion of standard libraries.""" + return [] + + def get_warn_args(self, level: str) -> T.List[str]: + return [] + + def get_werror_args(self) -> T.List[str]: + return [] + + @abc.abstractmethod + def get_optimization_args(self, optimization_level: str) -> T.List[str]: + pass + + def get_module_incdir_args(self) -> T.Tuple[str, ...]: + raise EnvironmentError('{} does not implement get_module_incdir_args'.format(self.id)) + + def get_module_outdir_args(self, path: str) -> T.List[str]: + raise EnvironmentError('{} does not implement get_module_outdir_args'.format(self.id)) + + def module_name_to_filename(self, module_name: str) -> str: + raise EnvironmentError('{} does not implement module_name_to_filename'.format(self.id)) + + def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: + """Arguments to pass the compiler and/or linker for checks. + + The default implementation turns off optimizations. mode should be + one of: + + Examples of things that go here: + - extra arguments for error checking + """ + return self.get_no_optimization_args() + + def get_no_optimization_args(self) -> T.List[str]: + """Arguments to the compiler to turn off all optimizations.""" + return [] + + def build_wrapper_args(self, env: 'Environment', + extra_args: T.Union[None, CompilerArgs, T.List[str]], + dependencies: T.Optional[T.List['Dependency']], + mode: CompileCheckMode = CompileCheckMode.COMPILE) -> CompilerArgs: + """Arguments to pass the build_wrapper helper. + + This generally needs to be set on a per-language baises. It provides + a hook for languages to handle dependencies and extra args. The base + implementation handles the most common cases, namely adding the + check_arguments, unwrapping dependencies, and appending extra args. + """ + if callable(extra_args): + extra_args = extra_args(mode) + if extra_args is None: + extra_args = [] + if dependencies is None: + dependencies = [] + + # Collect compiler arguments + args = self.compiler_args(self.get_compiler_check_args(mode)) + for d in dependencies: + # Add compile flags needed by dependencies + args += d.get_compile_args() + if mode is CompileCheckMode.LINK: + # Add link flags needed to find dependencies + args += d.get_link_args() + + if mode is CompileCheckMode.COMPILE: + # Add DFLAGS from the env + args += env.coredata.get_external_args(self.for_machine, self.language) + elif mode is CompileCheckMode.LINK: + # Add LDFLAGS from the env + args += env.coredata.get_external_link_args(self.for_machine, self.language) + # extra_args must override all other arguments, so we add them last + args += extra_args + return args + + @contextlib.contextmanager + def _build_wrapper(self, code: str, env: 'Environment', + extra_args: T.Union[None, CompilerArgs, T.List[str]] = None, + dependencies: T.Optional[T.List['Dependency']] = None, + mode: str = 'compile', want_output: bool = False, + disable_cache: bool = False, + temp_dir: str = None) -> T.Iterator[T.Optional[CompileResult]]: + """Helper for getting a cacched value when possible. + + This method isn't meant to be called externally, it's mean to be + wrapped by other methods like compiles() and links(). + """ + args = self.build_wrapper_args(env, extra_args, dependencies, CompileCheckMode(mode)) + if disable_cache or want_output: + with self.compile(code, extra_args=args, mode=mode, want_output=want_output, temp_dir=env.scratch_dir) as r: + yield r + else: + with self.cached_compile(code, env.coredata, extra_args=args, mode=mode, temp_dir=env.scratch_dir) as r: + yield r + + def compiles(self, code: str, env: 'Environment', *, + extra_args: T.Union[None, T.List[str], CompilerArgs] = None, + dependencies: T.Optional[T.List['Dependency']] = None, + mode: str = 'compile', + disable_cache: bool = False) -> T.Tuple[bool, bool]: + with self._build_wrapper(code, env, extra_args, dependencies, mode, disable_cache=disable_cache) as p: + return p.returncode == 0, p.cached + + + def links(self, code: str, env: 'Environment', *, + extra_args: T.Union[None, T.List[str], CompilerArgs] = None, + dependencies: T.Optional[T.List['Dependency']] = None, + mode: str = 'compile', + disable_cache: bool = False) -> T.Tuple[bool, bool]: + return self.compiles(code, env, extra_args=extra_args, + dependencies=dependencies, mode='link', disable_cache=disable_cache) + + def get_feature_args(self, kwargs: T.Dict[str, T.Any], build_to_src: str) -> T.List[str]: + """Used by D for extra language features.""" + # TODO: using a TypeDict here would improve this + raise EnvironmentError('{} does not implement get_feature_args'.format(self.id)) + def get_args_from_envvars(lang: str, for_machine: MachineChoice, diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index b5dbdda12..0c63b302b 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -26,6 +26,7 @@ from .compilers import ( gnu_winlibs, msvc_winlibs, Compiler, + CompileCheckMode, ) from .c_function_attributes import CXX_FUNC_ATTRIBUTES, C_FUNC_ATTRIBUTES from .mixins.clike import CLikeCompiler @@ -41,10 +42,17 @@ from .mixins.pgi import PGICompiler from .mixins.emscripten import EmscriptenMixin if T.TYPE_CHECKING: + from ..coredata import OptionDictType + from ..dependencies import Dependency, ExternalProgram from ..envconfig import MachineInfo + from ..environment import Environment + from ..linkers import DynamicLinker + from .mixins.clike import CLikeCompiler as CompilerMixinBase +else: + CompilerMixinBase = object -def non_msvc_eh_options(eh, args): +def non_msvc_eh_options(eh: str, args: T.List[str]) -> None: if eh == 'none': args.append('-fno-exceptions') elif eh == 's' or eh == 'c': @@ -54,7 +62,7 @@ def non_msvc_eh_options(eh, args): class CPPCompiler(CLikeCompiler, Compiler): @classmethod - def attribute_check_func(cls, name): + def attribute_check_func(cls, name: str) -> str: try: return CXX_FUNC_ATTRIBUTES.get(name, C_FUNC_ATTRIBUTES[name]) except KeyError: @@ -62,30 +70,37 @@ class CPPCompiler(CLikeCompiler, Compiler): language = 'cpp' - def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, - info: 'MachineInfo', exe_wrap: T.Optional[str] = None, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): # If a child ObjCPP class has already set it, don't set it ourselves - Compiler.__init__(self, exelist, version, for_machine, info, is_cross=is_cross, **kwargs) - CLikeCompiler.__init__(self, exe_wrap) + Compiler.__init__(self, exelist, version, for_machine, info, + is_cross=is_cross, linker=linker, + full_version=full_version) + CLikeCompiler.__init__(self, exe_wrapper) @staticmethod - def get_display_language(): + def get_display_language() -> str: return 'C++' - def get_no_stdinc_args(self): + def get_no_stdinc_args(self) -> T.List[str]: return ['-nostdinc++'] - def sanity_check(self, work_dir, environment): + def sanity_check(self, work_dir: str, environment: 'Environment') -> None: code = 'class breakCCompiler;int main(void) { return 0; }\n' return self._sanity_check_impl(work_dir, environment, 'sanitycheckcpp.cc', code) - def get_compiler_check_args(self): + def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: # -fpermissive allows non-conforming code to compile which is necessary # for many C++ checks. Particularly, the has_header_symbol check is # too strict without this and always fails. - return super().get_compiler_check_args() + ['-fpermissive'] + return super().get_compiler_check_args(mode) + ['-fpermissive'] - def has_header_symbol(self, hname, symbol, prefix, env, *, extra_args=None, dependencies=None): + def has_header_symbol(self, hname: str, symbol: str, prefix: str, + env: 'Environment', *, + extra_args: T.Optional[T.List[str]] = None, + dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: # Check if it's a C-like symbol found, cached = super().has_header_symbol(hname, symbol, prefix, env, extra_args=extra_args, @@ -103,7 +118,7 @@ class CPPCompiler(CLikeCompiler, Compiler): return self.compiles(t.format(**fargs), env, extra_args=extra_args, dependencies=dependencies) - def _test_cpp_std_arg(self, cpp_std_value): + def _test_cpp_std_arg(self, cpp_std_value: str) -> bool: # Test whether the compiler understands a -std=XY argument assert(cpp_std_value.startswith('-std=')) @@ -122,7 +137,7 @@ class CPPCompiler(CLikeCompiler, Compiler): return False @functools.lru_cache() - def _find_best_cpp_std(self, cpp_std): + def _find_best_cpp_std(self, cpp_std: str) -> str: # The initial version mapping approach to make falling back # from '-std=c++14' to '-std=c++1y' was too brittle. For instance, # Apple's Clang uses a different versioning scheme to upstream LLVM, @@ -154,11 +169,13 @@ class CPPCompiler(CLikeCompiler, Compiler): class ClangCPPCompiler(ClangCompiler, CPPCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, - defines: T.Optional[T.List[str]] = None, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + defines: T.Optional[T.Dict[str, str]] = None, + full_version: T.Optional[str] = None): CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, - info, exe_wrapper, **kwargs) + info, exe_wrapper, linker=linker, full_version=full_version) ClangCompiler.__init__(self, defines) default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'] self.warn_args = {'0': [], @@ -166,7 +183,7 @@ class ClangCPPCompiler(ClangCompiler, CPPCompiler): '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = CPPCompiler.get_options(self) opts.update({ 'eh': coredata.UserComboOption( @@ -191,7 +208,7 @@ class ClangCPPCompiler(ClangCompiler, CPPCompiler): }) return opts - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] std = options['std'] if std.value != 'none': @@ -204,31 +221,39 @@ class ClangCPPCompiler(ClangCompiler, CPPCompiler): return args - def get_option_link_args(self, options): + def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: if self.info.is_windows() or self.info.is_cygwin(): - return options['winlibs'].value[:] + # without a typedict mypy can't understand this. + libs = options['winlibs'].value.copy() + assert isinstance(libs, list) + for l in libs: + assert isinstance(l, str) + return libs return [] - def language_stdlib_only_link_flags(self): + def language_stdlib_only_link_flags(self) -> T.List[str]: return ['-lstdc++'] class AppleClangCPPCompiler(ClangCPPCompiler): - def language_stdlib_only_link_flags(self): + def language_stdlib_only_link_flags(self) -> T.List[str]: return ['-lc++'] class EmscriptenCPPCompiler(EmscriptenMixin, LinkerEnvVarsMixin, ClangCPPCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross: bool, info: 'MachineInfo', exe_wrapper=None, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + defines: T.Optional[T.Dict[str, str]] = None, + full_version: T.Optional[str] = None): if not is_cross: raise MesonException('Emscripten compiler can only be used for cross compilation.') - ClangCPPCompiler.__init__(self, exelist=exelist, version=version, - for_machine=for_machine, is_cross=is_cross, - info=info, exe_wrapper=exe_wrapper, **kwargs) + ClangCPPCompiler.__init__(self, exelist, version, for_machine, is_cross, + info, exe_wrapper=exe_wrapper, linker=linker, + defines=defines, full_version=full_version) self.id = 'emscripten' - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] std = options['std'] if std.value != 'none': @@ -237,11 +262,12 @@ class EmscriptenCPPCompiler(EmscriptenMixin, LinkerEnvVarsMixin, ClangCPPCompile class ArmclangCPPCompiler(ArmclangCompiler, CPPCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): - CPPCompiler.__init__(self, exelist=exelist, version=version, - for_machine=for_machine, is_cross=is_cross, - info=info, exe_wrapper=exe_wrapper, **kwargs) + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): + CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, + info, exe_wrapper, linker=linker, full_version=full_version) ArmclangCompiler.__init__(self) default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'] self.warn_args = {'0': [], @@ -249,7 +275,7 @@ class ArmclangCPPCompiler(ArmclangCompiler, CPPCompiler): '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = CPPCompiler.get_options(self) opts.update({ 'eh': coredata.UserComboOption( @@ -268,7 +294,7 @@ class ArmclangCPPCompiler(ArmclangCompiler, CPPCompiler): }) return opts - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] std = options['std'] if std.value != 'none': @@ -278,14 +304,18 @@ class ArmclangCPPCompiler(ArmclangCompiler, CPPCompiler): return args - def get_option_link_args(self, options): + def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: return [] class GnuCPPCompiler(GnuCompiler, CPPCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrap, defines, **kwargs): - CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrap, **kwargs) + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + defines: T.Optional[T.Dict[str, str]] = None, + full_version: T.Optional[str] = None): + CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, + info, exe_wrapper, linker=linker, full_version=full_version) GnuCompiler.__init__(self, defines) default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'] self.warn_args = {'0': [], @@ -293,7 +323,7 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler): '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = CPPCompiler.get_options(self) opts.update({ 'eh': coredata.UserComboOption( @@ -322,7 +352,7 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler): }) return opts - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] std = options['std'] if std.value != 'none': @@ -337,44 +367,57 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler): args.append('-D_GLIBCXX_DEBUG=1') return args - def get_option_link_args(self, options): + def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: if self.info.is_windows() or self.info.is_cygwin(): - return options['winlibs'].value[:] + # without a typedict mypy can't understand this. + libs = options['winlibs'].value.copy() + assert isinstance(libs, list) + for l in libs: + assert isinstance(l, str) + return libs return [] - def get_pch_use_args(self, pch_dir, header): + def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: return ['-fpch-preprocess', '-include', os.path.basename(header)] - def language_stdlib_only_link_flags(self): + def language_stdlib_only_link_flags(self) -> T.List[str]: return ['-lstdc++'] class PGICPPCompiler(PGICompiler, CPPCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): - CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): + CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, + info, exe_wrapper, linker=linker, full_version=full_version) PGICompiler.__init__(self) class NvidiaHPC_CPPCompiler(PGICompiler, CPPCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): - CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): + CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, + info, exe_wrapper, linker=linker, full_version=full_version) PGICompiler.__init__(self) self.id = 'nvidia_hpc' class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, - defines=None, **kwargs): - GnuCPPCompiler.__init__(self, exelist, version, for_machine, - is_cross, info, exe_wrapper, defines, - **kwargs) + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + defines: T.Optional[T.Dict[str, str]] = None, + full_version: T.Optional[str] = None): + GnuCPPCompiler.__init__(self, exelist, version, for_machine, is_cross, + info, exe_wrapper, linker=linker, + full_version=full_version, defines=defines) ElbrusCompiler.__init__(self) - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = CPPCompiler.get_options(self) cpp_stds = [ @@ -408,7 +451,9 @@ class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler): # Elbrus C++ compiler does not have lchmod, but there is only linker warning, not compiler error. # So we should explicitly fail at this case. - def has_function(self, funcname, prefix, env, *, extra_args=None, dependencies=None): + def has_function(self, funcname: str, prefix: str, env: 'Environment', *, + extra_args: T.Optional[T.List[str]] = None, + dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: if funcname == 'lchmod': return False, False else: @@ -417,7 +462,7 @@ class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler): dependencies=dependencies) # Elbrus C++ compiler does not support RTTI, so don't check for it. - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] std = options['std'] if std.value != 'none': @@ -431,10 +476,12 @@ class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler): class IntelCPPCompiler(IntelGnuLikeCompiler, CPPCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrap, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, - info, exe_wrap, **kwargs) + info, exe_wrapper, linker=linker, full_version=full_version) IntelGnuLikeCompiler.__init__(self) self.lang_header = 'c++-header' default_warn_args = ['-Wall', '-w3', '-diag-disable:remark', @@ -444,7 +491,7 @@ class IntelCPPCompiler(IntelGnuLikeCompiler, CPPCompiler): '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra']} - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = CPPCompiler.get_options(self) # Every Unix compiler under the sun seems to accept -std=c++03, # with the exception of ICC. Instead of preventing the user from @@ -474,7 +521,7 @@ class IntelCPPCompiler(IntelGnuLikeCompiler, CPPCompiler): }) return opts - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] std = options['std'] if std.value != 'none': @@ -491,11 +538,11 @@ class IntelCPPCompiler(IntelGnuLikeCompiler, CPPCompiler): args.append('-D_GLIBCXX_DEBUG=1') return args - def get_option_link_args(self, options): + def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: return [] -class VisualStudioLikeCPPCompilerMixin: +class VisualStudioLikeCPPCompilerMixin(CompilerMixinBase): """Mixin for C++ specific method overrides in MSVC-like compilers.""" @@ -511,10 +558,11 @@ class VisualStudioLikeCPPCompilerMixin: 'c++latest': (False, "latest"), } - def get_option_link_args(self, options): - return options['winlibs'].value[:] + def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: + # need a typeddict for this + return T.cast(T.List[str], options['winlibs'].value[:]) - def _get_options_impl(self, opts, cpp_stds: T.List[str]): + def _get_options_impl(self, opts: 'OptionDictType', cpp_stds: T.List[str]) -> 'OptionDictType': opts.update({ 'eh': coredata.UserComboOption( 'C++ exception handling type.', @@ -534,7 +582,7 @@ class VisualStudioLikeCPPCompilerMixin: }) return opts - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] eh = options['eh'] @@ -558,19 +606,19 @@ class VisualStudioLikeCPPCompilerMixin: return args - def get_compiler_check_args(self): + def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: # XXX: this is a hack because so much GnuLike stuff is in the base CPPCompiler class. - return CLikeCompiler.get_compiler_check_args(self) + return Compiler.get_compiler_check_args(self, mode) -class CPP11AsCPP14Mixin: +class CPP11AsCPP14Mixin(CompilerMixinBase): """Mixin class for VisualStudio and ClangCl to replace C++11 std with C++14. This is a limitation of Clang and MSVC that ICL doesn't share. """ - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: # Note: there is no explicit flag for supporting C++11; we attempt to do the best we can # which means setting the C++ standard version to C++14, in compilers that support it # (i.e., after VS2015U3) @@ -590,14 +638,18 @@ class CPP11AsCPP14Mixin: class VisualStudioCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixin, MSVCCompiler, CPPCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross: bool, info: 'MachineInfo', exe_wrap, target, **kwargs): - CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrap, **kwargs) + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, + is_cross: bool, info: 'MachineInfo', target: str, + exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): + CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, + info, exe_wrapper, linker=linker, full_version=full_version) MSVCCompiler.__init__(self, target) self.base_options = ['b_pch', 'b_vscrt', 'b_ndebug'] # FIXME add lto, pgo and the like self.id = 'msvc' - def get_options(self): + def get_options(self) -> 'OptionDictType': cpp_stds = ['none', 'c++11', 'vc++11'] # Visual Studio 2015 and later if version_compare(self.version, '>=19'): @@ -607,7 +659,7 @@ class VisualStudioCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixi cpp_stds.extend(['vc++14', 'c++17', 'vc++17']) return self._get_options_impl(super().get_options(), cpp_stds) - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: if options['std'].value != 'none' and version_compare(self.version, '<19.00.24210'): mlog.warning('This version of MSVC does not support cpp_std arguments') options = copy.copy(options) @@ -624,40 +676,52 @@ class VisualStudioCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixi return args class ClangClCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixin, ClangClCompiler, CPPCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrap, target, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, + is_cross: bool, info: 'MachineInfo', target: str, + exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, - info, exe_wrap, **kwargs) + info, exe_wrapper, linker=linker, full_version=full_version) ClangClCompiler.__init__(self, target) self.id = 'clang-cl' - def get_options(self): + def get_options(self) -> 'OptionDictType': cpp_stds = ['none', 'c++11', 'vc++11', 'c++14', 'vc++14', 'c++17', 'vc++17', 'c++latest'] return self._get_options_impl(super().get_options(), cpp_stds) class IntelClCPPCompiler(VisualStudioLikeCPPCompilerMixin, IntelVisualStudioLikeCompiler, CPPCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrap, target, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, + is_cross: bool, info: 'MachineInfo', target: str, + exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, - info, exe_wrap, **kwargs) + info, exe_wrapper, linker=linker, full_version=full_version) IntelVisualStudioLikeCompiler.__init__(self, target) - def get_options(self): + def get_options(self) -> 'OptionDictType': # This has only been tested with version 19.0, cpp_stds = ['none', 'c++11', 'vc++11', 'c++14', 'vc++14', 'c++17', 'vc++17', 'c++latest'] return self._get_options_impl(super().get_options(), cpp_stds) + def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: + # XXX: this is a hack because so much GnuLike stuff is in the base CPPCompiler class. + return IntelVisualStudioLikeCompiler.get_compiler_check_args(self, mode) + class ArmCPPCompiler(ArmCompiler, CPPCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrap=None, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, - info, exe_wrap, **kwargs) + info, exe_wrapper, linker=linker, full_version=full_version) ArmCompiler.__init__(self) - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = CPPCompiler.get_options(self) opts.update({ 'std': coredata.UserComboOption( @@ -668,7 +732,7 @@ class ArmCPPCompiler(ArmCompiler, CPPCompiler): }) return opts - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] std = options['std'] if std.value == 'c++11': @@ -677,67 +741,71 @@ class ArmCPPCompiler(ArmCompiler, CPPCompiler): args.append('--cpp') return args - def get_option_link_args(self, options): + def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: return [] - def get_compiler_check_args(self): + def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: return [] class CcrxCPPCompiler(CcrxCompiler, CPPCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrap=None, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, - info, exe_wrap, **kwargs) + info, exe_wrapper, linker=linker, full_version=full_version) CcrxCompiler.__init__(self) # Override CCompiler.get_always_args - def get_always_args(self): + def get_always_args(self) -> T.List[str]: return ['-nologo', '-lang=cpp'] - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: return [] - def get_compile_only_args(self): + def get_compile_only_args(self) -> T.List[str]: return [] - def get_output_args(self, target): + def get_output_args(self, target: str) -> T.List[str]: return ['-output=obj=%s' % target] - def get_option_link_args(self, options): + def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: return [] - def get_compiler_check_args(self): + def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: return [] class C2000CPPCompiler(C2000Compiler, CPPCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrap=None, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, - info, exe_wrap, **kwargs) + info, exe_wrapper, linker=linker, full_version=full_version) C2000Compiler.__init__(self) - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = CPPCompiler.get_options(self) opts.update({'cpp_std': coredata.UserComboOption('C++ language standard to use', ['none', 'c++03'], 'none')}) return opts - def get_always_args(self): + def get_always_args(self) -> T.List[str]: return ['-nologo', '-lang=cpp'] - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: return [] - def get_compile_only_args(self): + def get_compile_only_args(self) -> T.List[str]: return [] - def get_output_args(self, target): + def get_output_args(self, target: str) -> T.List[str]: return ['-output=obj=%s' % target] - def get_option_link_args(self, options): + def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: return [] - def get_compiler_check_args(self): + def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: return [] diff --git a/mesonbuild/compilers/cs.py b/mesonbuild/compilers/cs.py index b269aecf9..ba65d0746 100644 --- a/mesonbuild/compilers/cs.py +++ b/mesonbuild/compilers/cs.py @@ -13,6 +13,7 @@ # limitations under the License. import os.path, subprocess +import textwrap import typing as T from ..mesonlib import EnvironmentException @@ -22,6 +23,7 @@ from .mixins.islinker import BasicLinkerIsCompilerMixin if T.TYPE_CHECKING: from ..envconfig import MachineInfo + from ..environment import Environment cs_optimization_args = {'0': [], 'g': [], @@ -29,63 +31,43 @@ cs_optimization_args = {'0': [], '2': ['-optimize+'], '3': ['-optimize+'], 's': ['-optimize+'], - } + } # type: T.Dict[str, T.List[str]] class CsCompiler(BasicLinkerIsCompilerMixin, Compiler): language = 'cs' - def __init__(self, exelist, version, for_machine: MachineChoice, - info: 'MachineInfo', comp_id, runner=None): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, + info: 'MachineInfo', comp_id: str, runner: T.Optional[str] = None): super().__init__(exelist, version, for_machine, info) self.id = comp_id self.runner = runner @classmethod - def get_display_language(cls): + def get_display_language(cls) -> str: return 'C sharp' - def get_always_args(self): + def get_always_args(self) -> T.List[str]: return ['/nologo'] - def get_linker_always_args(self): + def get_linker_always_args(self) -> T.List[str]: return ['/nologo'] - def get_output_args(self, fname): + def get_output_args(self, fname: str) -> T.List[str]: return ['-out:' + fname] - def get_link_args(self, fname): + def get_link_args(self, fname: str) -> T.List[str]: return ['-r:' + fname] - def get_werror_args(self): + def get_werror_args(self) -> T.List[str]: return ['-warnaserror'] - def split_shlib_to_parts(self, fname): - return None, fname - - def get_dependency_gen_args(self, outtarget, outfile): - return [] - - def get_linker_exelist(self): - return self.exelist[:] - - def get_compile_only_args(self): - return [] - - def get_coverage_args(self): - return [] - - def get_std_exe_link_args(self): - return [] - - def get_include_args(self, path): - return [] - - def get_pic_args(self): + def get_pic_args(self) -> T.List[str]: return [] - def compute_parameters_with_absolute_paths(self, parameter_list, build_dir): + def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], + build_dir: str) -> T.List[str]: for idx, i in enumerate(parameter_list): if i[:2] == '-L': parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:])) @@ -94,26 +76,27 @@ class CsCompiler(BasicLinkerIsCompilerMixin, Compiler): return parameter_list - def get_pch_use_args(self, pch_dir, header): + def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: return [] - def get_pch_name(self, header_name): + def get_pch_name(self, header_name: str) -> str: return '' - def sanity_check(self, work_dir, environment): + def sanity_check(self, work_dir: str, environment: 'Environment') -> None: src = 'sanity.cs' obj = 'sanity.exe' source_name = os.path.join(work_dir, src) with open(source_name, 'w') as ofile: - ofile.write('''public class Sanity { - static public void Main () { - } -} -''') + ofile.write(textwrap.dedent(''' + public class Sanity { + static public void Main () { + } + } + ''')) pc = subprocess.Popen(self.exelist + self.get_always_args() + [src], cwd=work_dir) pc.wait() if pc.returncode != 0: - raise EnvironmentException('Mono compiler %s can not compile programs.' % self.name_string()) + raise EnvironmentException('C# compiler %s can not compile programs.' % self.name_string()) if self.runner: cmdlist = [self.runner, obj] else: @@ -123,32 +106,32 @@ class CsCompiler(BasicLinkerIsCompilerMixin, Compiler): if pe.returncode != 0: raise EnvironmentException('Executables created by Mono compiler %s are not runnable.' % self.name_string()) - def needs_static_linker(self): + def needs_static_linker(self) -> bool: return False - def get_buildtype_args(self, buildtype): + def get_buildtype_args(self, buildtype: str) -> T.List[str]: return mono_buildtype_args[buildtype] - def get_debug_args(self, is_debug): + def get_debug_args(self, is_debug: bool) -> T.List[str]: return ['-debug'] if is_debug else [] - def get_optimization_args(self, optimization_level): + def get_optimization_args(self, optimization_level: str) -> T.List[str]: return cs_optimization_args[optimization_level] class MonoCompiler(CsCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, info: 'MachineInfo'): super().__init__(exelist, version, for_machine, info, 'mono', runner='mono') class VisualStudioCsCompiler(CsCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, info: 'MachineInfo'): super().__init__(exelist, version, for_machine, info, 'csc') - def get_buildtype_args(self, buildtype): + def get_buildtype_args(self, buildtype: str) -> T.List[str]: res = mono_buildtype_args[buildtype] if not self.info.is_windows(): tmp = [] diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py index 482d504bc..bf46a7d4d 100644 --- a/mesonbuild/compilers/cuda.py +++ b/mesonbuild/compilers/cuda.py @@ -12,9 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +import enum import os.path import typing as T -from functools import partial from .. import coredata from .. import mlog @@ -23,8 +23,18 @@ from .compilers import (Compiler, cuda_buildtype_args, cuda_optimization_args, cuda_debug_args) if T.TYPE_CHECKING: + from ..build import BuildTarget + from ..coredata import OptionDictType + from ..dependencies import Dependency, ExternalProgram from ..environment import Environment # noqa: F401 from ..envconfig import MachineInfo + from ..linkers import DynamicLinker + + +class _Phase(enum.Enum): + + COMPILER = 'compiler' + LINKER = 'linker' class CudaCompiler(Compiler): @@ -32,12 +42,14 @@ class CudaCompiler(Compiler): LINKER_PREFIX = '-Xlinker=' language = 'cuda' - _universal_flags = {'compiler': ['-I', '-D', '-U', '-E'], 'linker': ['-l', '-L']} + _universal_flags = {_Phase.COMPILER: ['-I', '-D', '-U', '-E'], _Phase.LINKER: ['-l', '-L']} # type: T.Dict[_Phase, T.List[str]] - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, exe_wrapper, host_compiler, info: 'MachineInfo', **kwargs): - super().__init__(exelist, version, for_machine, info, **kwargs) - self.is_cross = is_cross + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, + is_cross: bool, exe_wrapper: T.Optional['ExternalProgram'], + host_compiler: Compiler, info: 'MachineInfo', + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): + super().__init__(exelist, version, for_machine, info, linker=linker, full_version=full_version, is_cross=is_cross) self.exe_wrapper = exe_wrapper self.host_compiler = host_compiler self.base_options = host_compiler.base_options @@ -45,29 +57,23 @@ class CudaCompiler(Compiler): self.warn_args = {level: self._to_host_flags(flags) for level, flags in host_compiler.warn_args.items()} @classmethod - def _to_host_flags(cls, flags, phase='compiler'): - return list(map(partial(cls._to_host_flag, phase=phase), flags)) + def _to_host_flags(cls, flags: T.List[str], phase: _Phase = _Phase.COMPILER) -> T.List[str]: + return [cls._to_host_flag(f, phase=phase) for f in flags] @classmethod - def _to_host_flag(cls, flag, phase): + def _to_host_flag(cls, flag: str, phase: _Phase) -> str: if not flag[0] in ['-', '/'] or flag[:2] in cls._universal_flags[phase]: return flag - return '-X{}={}'.format(phase, flag) + return '-X{}={}'.format(phase.value, flag) - def needs_static_linker(self): + def needs_static_linker(self) -> bool: return False - def get_always_args(self): - return [] - - def get_no_stdinc_args(self): - return [] - - def thread_link_flags(self, environment): + def thread_link_flags(self, environment: 'Environment') -> T.List[str]: return self._to_host_flags(self.host_compiler.thread_link_flags(environment)) - def sanity_check(self, work_dir, environment): + def sanity_check(self, work_dir: str, environment: 'Environment') -> None: mlog.debug('Sanity testing ' + self.get_display_language() + ' compiler:', ' '.join(self.exelist)) mlog.debug('Is cross compiler: %s.' % str(self.is_cross)) @@ -138,7 +144,7 @@ class CudaCompiler(Compiler): if self.exe_wrapper is None: return else: - cmdlist = self.exe_wrapper + [binary_name] + cmdlist = self.exe_wrapper.get_command() + [binary_name] else: cmdlist = self.exelist + ['--run', '"' + binary_name + '"'] mlog.debug('Sanity check run command line: ', ' '.join(cmdlist)) @@ -160,7 +166,10 @@ class CudaCompiler(Compiler): else: mlog.debug('cudaGetDeviceCount() returned ' + stde) - def has_header_symbol(self, hname, symbol, prefix, env, extra_args=None, dependencies=None): + def has_header_symbol(self, hname: str, symbol: str, prefix: str, + env: 'Environment', *, + extra_args: T.Optional[T.List[str]] = None, + dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: result, cached = super().has_header_symbol(hname, symbol, prefix, env, extra_args=extra_args, dependencies=dependencies) if result: return True, cached @@ -173,18 +182,18 @@ class CudaCompiler(Compiler): int main(void) {{ return 0; }}''' return self.compiles(t.format(**fargs), env, extra_args=extra_args, dependencies=dependencies) - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = super().get_options() opts.update({'cuda_std': coredata.UserComboOption('C++ language standard to use', ['none', 'c++03', 'c++11', 'c++14'], 'none')}) return opts - def _to_host_compiler_options(self, options): - overrides = {name: opt.value for name, opt in options.copy().items()} + def _to_host_compiler_options(self, options: 'OptionDictType') -> 'OptionDictType': + overrides = {name: opt.value for name, opt in options.items()} return OptionOverrideProxy(overrides, self.host_compiler.get_options()) - def get_option_compile_args(self, options): + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] # On Windows, the version of the C++ standard used by nvcc is dictated by # the combination of CUDA version and MSVC version; the --std= is thus ignored @@ -205,62 +214,61 @@ class CudaCompiler(Compiler): arg = arg.replace('-Wl,', '', 1) arg = arg.replace(' ', '\\') # espace whitespace cooked.append(arg) - return cls._to_host_flags(cooked, 'linker') + return cls._to_host_flags(cooked, _Phase.LINKER) - def get_option_link_args(self, options): + def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: return self._cook_link_args(self.host_compiler.get_option_link_args(self._to_host_compiler_options(options))) - def get_soname_args(self, *args): - return self._cook_link_args(self.host_compiler.get_soname_args(*args)) + def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, + suffix: str, soversion: str, + darwin_versions: T.Tuple[str, str], + is_shared_module: bool) -> T.List[str]: + return self._cook_link_args(self.host_compiler.get_soname_args( + env, prefix, shlib_name, suffix, soversion, darwin_versions, + is_shared_module)) - def get_dependency_gen_args(self, outtarget, outfile): - return [] - - def get_compile_only_args(self): + def get_compile_only_args(self) -> T.List[str]: return ['-c'] - def get_no_optimization_args(self): + def get_no_optimization_args(self) -> T.List[str]: return ['-O0'] - def get_optimization_args(self, optimization_level): + def get_optimization_args(self, optimization_level: str) -> T.List[str]: # alternatively, consider simply redirecting this to the host compiler, which would # give us more control over options like "optimize for space" (which nvcc doesn't support): # return self._to_host_flags(self.host_compiler.get_optimization_args(optimization_level)) return cuda_optimization_args[optimization_level] - def get_debug_args(self, is_debug): + def get_debug_args(self, is_debug: bool) -> T.List[str]: return cuda_debug_args[is_debug] - def get_werror_args(self): + def get_werror_args(self) -> T.List[str]: return ['-Werror=cross-execution-space-call,deprecated-declarations,reorder'] - def get_warn_args(self, level): + def get_warn_args(self, level: str) -> T.List[str]: return self.warn_args[level] - def get_buildtype_args(self, buildtype): + def get_buildtype_args(self, buildtype: str) -> T.List[str]: # nvcc doesn't support msvc's "Edit and Continue" PDB format; "downgrade" to # a regular PDB to avoid cl's warning to that effect (D9025 : overriding '/ZI' with '/Zi') host_args = ['/Zi' if arg == '/ZI' else arg for arg in self.host_compiler.get_buildtype_args(buildtype)] return cuda_buildtype_args[buildtype] + self._to_host_flags(host_args) - def get_include_args(self, path, is_system): + def get_include_args(self, path: str, is_system: bool) -> T.List[str]: if path == '': path = '.' return ['-I' + path] - def get_compile_debugfile_args(self, rel_obj, **kwargs): - return self._to_host_flags(self.host_compiler.get_compile_debugfile_args(rel_obj, **kwargs)) + def get_compile_debugfile_args(self, rel_obj: str, pch: bool = False) -> T.List[str]: + return self._to_host_flags(self.host_compiler.get_compile_debugfile_args(rel_obj, pch)) - def get_link_debugfile_args(self, targetfile): + def get_link_debugfile_args(self, targetfile: str) -> T.List[str]: return self._cook_link_args(self.host_compiler.get_link_debugfile_args(targetfile)) - def depfile_for_object(self, objfile): - return objfile + '.' + self.get_depfile_suffix() - - def get_depfile_suffix(self): + def get_depfile_suffix(self) -> str: return 'd' - def get_buildtype_linker_args(self, buildtype): + def get_buildtype_linker_args(self, buildtype: str) -> T.List[str]: return self._cook_link_args(self.host_compiler.get_buildtype_linker_args(buildtype)) def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, @@ -270,13 +278,14 @@ class CudaCompiler(Compiler): env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath) return (self._cook_link_args(rpath_args), rpath_dirs_to_remove) - def linker_to_compiler_args(self, args): + def linker_to_compiler_args(self, args: T.List[str]) -> T.List[str]: return args - def get_pic_args(self): + def get_pic_args(self) -> T.List[str]: return self._to_host_flags(self.host_compiler.get_pic_args()) - def compute_parameters_with_absolute_paths(self, parameter_list, build_dir): + def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], + build_dir: str) -> T.List[str]: return [] def get_output_args(self, target: str) -> T.List[str]: @@ -285,13 +294,14 @@ class CudaCompiler(Compiler): def get_std_exe_link_args(self) -> T.List[str]: return self._cook_link_args(self.host_compiler.get_std_exe_link_args()) - def find_library(self, libname, env, extra_dirs, libtype: LibType = LibType.PREFER_SHARED): + def find_library(self, libname: str, env: 'Environment', extra_dirs: T.List[str], + libtype: LibType = LibType.PREFER_SHARED) -> T.Optional[T.List[str]]: return ['-l' + libname] # FIXME - def get_crt_compile_args(self, crt_val, buildtype): + def get_crt_compile_args(self, crt_val: str, buildtype: str) -> T.List[str]: return self._to_host_flags(self.host_compiler.get_crt_compile_args(crt_val, buildtype)) - def get_crt_link_args(self, crt_val, buildtype): + def get_crt_link_args(self, crt_val: str, buildtype: str) -> T.List[str]: # nvcc defaults to static, release version of msvc runtime and provides no # native option to override it; override it with /NODEFAULTLIB host_link_arg_overrides = [] @@ -300,11 +310,11 @@ class CudaCompiler(Compiler): host_link_arg_overrides += ['/NODEFAULTLIB:LIBCMT.lib'] return self._cook_link_args(host_link_arg_overrides + self.host_compiler.get_crt_link_args(crt_val, buildtype)) - def get_target_link_args(self, target): + def get_target_link_args(self, target: 'BuildTarget') -> T.List[str]: return self._cook_link_args(super().get_target_link_args(target)) - def get_dependency_compile_args(self, dep): + def get_dependency_compile_args(self, dep: 'Dependency') -> T.List[str]: return self._to_host_flags(super().get_dependency_compile_args(dep)) - def get_dependency_link_args(self, dep): + def get_dependency_link_args(self, dep: 'Dependency') -> T.List[str]: return self._cook_link_args(super().get_dependency_link_args(dep)) diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index ca7f80dcb..630291af8 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -30,8 +30,13 @@ from .compilers import ( from .mixins.gnu import GnuCompiler if T.TYPE_CHECKING: - from ..dependencies import ExternalProgram + from .compilers import Compiler as CompilerMixinBase + from ..dependencies import Dependency, ExternalProgram from ..envconfig import MachineInfo + from ..environment import Environment + from ..linkers import DynamicLinker +else: + CompilerMixinBase = object d_feature_args = {'gcc': {'unittest': '-funittest', 'debug': '-fdebug', @@ -48,7 +53,7 @@ d_feature_args = {'gcc': {'unittest': '-funittest', 'version': '-version', 'import_dir': '-J' } - } + } # type: T.Dict[str, T.Dict[str, str]] ldc_optimization_args = {'0': [], 'g': [], @@ -56,7 +61,7 @@ ldc_optimization_args = {'0': [], '2': ['-O2'], '3': ['-O3'], 's': ['-Os'], - } + } # type: T.Dict[str, T.List[str]] dmd_optimization_args = {'0': [], 'g': [], @@ -64,23 +69,35 @@ dmd_optimization_args = {'0': [], '2': ['-O'], '3': ['-O'], 's': ['-O'], - } + } # type: T.Dict[str, T.List[str]] -class DmdLikeCompilerMixin: +class DmdLikeCompilerMixin(CompilerMixinBase): + + """Mixin class for DMD and LDC. + + LDC has a number of DMD like arguments, and this class allows for code + sharing between them as makes sense. + """ + + if T.TYPE_CHECKING: + mscrt_args = {} # type: T.Dict[str, T.List[str]] + + def _get_target_arch_args(self) -> T.List[str]: ... LINKER_PREFIX = '-L=' - def get_output_args(self, target): - return ['-of=' + target] + def get_output_args(self, outputname: str) -> T.List[str]: + return ['-of=' + outputname] - def get_linker_output_args(self, target): - return ['-of=' + target] + def get_linker_output_args(self, outputname: str) -> T.List[str]: + return ['-of=' + outputname] - def get_include_args(self, path, is_system): + def get_include_args(self, path: str, is_system: bool) -> T.List[str]: return ['-I=' + path] - def compute_parameters_with_absolute_paths(self, parameter_list, build_dir): + def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], + build_dir: str) -> T.List[str]: for idx, i in enumerate(parameter_list): if i[:3] == '-I=': parameter_list[idx] = i[:3] + os.path.normpath(os.path.join(build_dir, i[3:])) @@ -93,40 +110,34 @@ class DmdLikeCompilerMixin: return parameter_list - def get_warn_args(self, level): + def get_warn_args(self, level: str) -> T.List[str]: return ['-wi'] - def get_werror_args(self): + def get_werror_args(self) -> T.List[str]: return ['-w'] - def get_dependency_gen_args(self, outtarget, outfile): - # DMD and LDC does not currently return Makefile-compatible dependency info. - return [] - - def get_coverage_args(self): + def get_coverage_args(self) -> T.List[str]: return ['-cov'] - def get_coverage_link_args(self): + def get_coverage_link_args(self) -> T.List[str]: return [] - def get_preprocess_only_args(self): + def get_preprocess_only_args(self) -> T.List[str]: return ['-E'] - def get_compile_only_args(self): + def get_compile_only_args(self) -> T.List[str]: return ['-c'] - def depfile_for_object(self, objfile): - return objfile + '.' + self.get_depfile_suffix() - - def get_depfile_suffix(self): + def get_depfile_suffix(self) -> str: return 'deps' - def get_pic_args(self): + def get_pic_args(self) -> T.List[str]: if self.info.is_windows(): return [] return ['-fPIC'] - def get_feature_args(self, kwargs, build_to_src): + def get_feature_args(self, kwargs: T.Dict[str, T.Any], build_to_src: str) -> T.List[str]: + # TODO: using a TypeDict here would improve this res = [] if 'unittest' in kwargs: unittest = kwargs.pop('unittest') @@ -208,18 +219,17 @@ class DmdLikeCompilerMixin: return res - def get_buildtype_linker_args(self, buildtype): + def get_buildtype_linker_args(self, buildtype: str) -> T.List[str]: if buildtype != 'plain': - return self.get_target_arch_args() - return [] - - def get_std_exe_link_args(self): + return self._get_target_arch_args() return [] - def gen_import_library_args(self, implibname): + def gen_import_library_args(self, implibname: str) -> T.List[str]: return self.linker.import_library_args(implibname) - def build_rpath_args(self, env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath): + def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, + rpath_paths: str, build_rpath: str, + install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: if self.info.is_windows(): return ([], set()) @@ -243,7 +253,7 @@ class DmdLikeCompilerMixin: return super().build_rpath_args( env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath) - def translate_args_to_nongnu(self, args): + def _translate_args_to_nongnu(self, args: T.List[str]) -> T.List[str]: dcargs = [] # Translate common arguments to flags the LDC/DMD compilers # can understand. @@ -251,11 +261,11 @@ class DmdLikeCompilerMixin: # and are therefore out of the user's control. for arg in args: # Translate OS specific arguments first. - osargs = [] + osargs = [] # type: T.List[str] if self.info.is_windows(): osargs = self.translate_arg_to_windows(arg) elif self.info.is_darwin(): - osargs = self.translate_arg_to_osx(arg) + osargs = self._translate_arg_to_osx(arg) if osargs: dcargs.extend(osargs) continue @@ -334,7 +344,7 @@ class DmdLikeCompilerMixin: return dcargs @classmethod - def translate_arg_to_windows(cls, arg): + def translate_arg_to_windows(cls, arg: str) -> T.List[str]: args = [] if arg.startswith('-Wl,'): # Translate linker arguments here. @@ -360,20 +370,20 @@ class DmdLikeCompilerMixin: return args @classmethod - def translate_arg_to_osx(cls, arg): + def _translate_arg_to_osx(cls, arg: str) -> T.List[str]: args = [] if arg.startswith('-install_name'): args.append('-L=' + arg) return args - def get_debug_args(self, is_debug): + def get_debug_args(self, is_debug: bool) -> T.List[str]: ddebug_args = [] if is_debug: ddebug_args = [d_feature_args[self.id]['debug']] return clike_debug_args[is_debug] + ddebug_args - def get_crt_args(self, crt_val, buildtype): + def _get_crt_args(self, crt_val: str, buildtype: str) -> T.List[str]: if not self.info.is_windows(): return [] @@ -396,26 +406,32 @@ class DmdLikeCompilerMixin: assert(buildtype == 'custom') raise EnvironmentException('Requested C runtime based on buildtype, but buildtype is "custom".') - def get_soname_args(self, *args, **kwargs) -> T.List[str]: + def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, + suffix: str, soversion: str, + darwin_versions: T.Tuple[str, str], + is_shared_module: bool) -> T.List[str]: + sargs = super().get_soname_args(env, prefix, shlib_name, suffix, + soversion, darwin_versions, is_shared_module) + # LDC and DMD actually do use a linker, but they proxy all of that with # their own arguments if self.linker.id.startswith('ld.'): soargs = [] - for arg in super().get_soname_args(*args, **kwargs): + for arg in sargs: a, b = arg.split(',', maxsplit=1) soargs.append(a) soargs.append(self.LINKER_PREFIX + b) return soargs elif self.linker.id.startswith('ld64'): soargs = [] - for arg in super().get_soname_args(*args, **kwargs): + for arg in sargs: if not arg.startswith(self.LINKER_PREFIX): soargs.append(self.LINKER_PREFIX + arg) else: soargs.append(arg) return soargs else: - return super().get_soname_args(*args, **kwargs) + return sargs def get_allow_undefined_link_args(self) -> T.List[str]: args = self.linker.get_allow_undefined_args() @@ -428,9 +444,11 @@ class DmdLikeCompilerMixin: args = [a.replace('-L=', '-Xcc=-Wl,') for a in args] return args + class DCompilerArgs(CompilerArgs): prepend_prefixes = ('-I', '-L') - dedup2_prefixes = ('-I') + dedup2_prefixes = ('-I', ) + class DCompiler(Compiler): mscrt_args = { @@ -444,19 +462,22 @@ class DCompiler(Compiler): language = 'd' def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, - info: 'MachineInfo', arch: str, exe_wrapper: T.Optional['ExternalProgram'] = None, - **kwargs): - super().__init__(exelist, version, for_machine, info, **kwargs) - self.id = 'unknown' + info: 'MachineInfo', arch: str, *, + exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None, + is_cross: bool = False): + super().__init__(exelist, version, for_machine, info, linker=linker, + full_version=full_version, is_cross=is_cross) self.arch = arch self.exe_wrapper = exe_wrapper - def sanity_check(self, work_dir, environment): + def sanity_check(self, work_dir: str, environment: 'Environment') -> None: source_name = os.path.join(work_dir, 'sanity.d') output_name = os.path.join(work_dir, 'dtest') with open(source_name, 'w') as ofile: ofile.write('''void main() { }''') - pc = subprocess.Popen(self.exelist + self.get_output_args(output_name) + self.get_target_arch_args() + [source_name], cwd=work_dir) + pc = subprocess.Popen(self.exelist + self.get_output_args(output_name) + self._get_target_arch_args() + [source_name], cwd=work_dir) pc.wait() if pc.returncode != 0: raise EnvironmentException('D compiler %s can not compile programs.' % self.name_string()) @@ -470,21 +491,19 @@ class DCompiler(Compiler): if subprocess.call(cmdlist) != 0: raise EnvironmentException('Executables created by D compiler %s are not runnable.' % self.name_string()) - def needs_static_linker(self): + def needs_static_linker(self) -> bool: return True - def depfile_for_object(self, objfile): - return objfile + '.' + self.get_depfile_suffix() - - def get_depfile_suffix(self): + def get_depfile_suffix(self) -> str: return 'deps' - def get_pic_args(self): + def get_pic_args(self) -> T.List[str]: if self.info.is_windows(): return [] return ['-fPIC'] - def get_feature_args(self, kwargs, build_to_src): + def get_feature_args(self, kwargs: T.Dict[str, T.Any], build_to_src: str) -> T.List[str]: + # TODO: using a TypeDict here would improve this res = [] if 'unittest' in kwargs: unittest = kwargs.pop('unittest') @@ -566,57 +585,18 @@ class DCompiler(Compiler): return res - def get_buildtype_linker_args(self, buildtype): + def get_buildtype_linker_args(self, buildtype: str) -> T.List[str]: if buildtype != 'plain': - return self.get_target_arch_args() - return [] - - def get_std_exe_link_args(self): + return self._get_target_arch_args() return [] - def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'): - if callable(extra_args): - extra_args = extra_args(mode) - if extra_args is None: - extra_args = [] - elif isinstance(extra_args, str): - extra_args = [extra_args] - if dependencies is None: - dependencies = [] - elif not isinstance(dependencies, list): - dependencies = [dependencies] - # Collect compiler arguments - args = self.compiler_args() - for d in dependencies: - # Add compile flags needed by dependencies - args += d.get_compile_args() - if mode == 'link': - # Add link flags needed to find dependencies - args += d.get_link_args() - - if mode == 'compile': - # Add DFLAGS from the env - args += env.coredata.get_external_args(self.for_machine, self.language) - elif mode == 'link': - # Add LDFLAGS from the env - args += env.coredata.get_external_link_args(self.for_machine, self.language) - # extra_args must override all other arguments, so we add them last - args += extra_args - return args - def compiler_args(self, args: T.Optional[T.Iterable[str]] = None) -> DCompilerArgs: return DCompilerArgs(self, args) - def compiles(self, code, env, *, extra_args=None, dependencies=None, mode='compile'): - args = self._get_compiler_check_args(env, extra_args, dependencies, mode) - - with self.cached_compile(code, env.coredata, extra_args=args, mode=mode) as p: - return p.returncode == 0, p.cached - - def has_multi_arguments(self, args, env): + def has_multi_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]: return self.compiles('int i;\n', env, extra_args=args) - def get_target_arch_args(self): + def _get_target_arch_args(self) -> T.List[str]: # LDC2 on Windows targets to current OS architecture, but # it should follow the target specified by the MSVC toolchain. if self.info.is_windows(): @@ -625,15 +605,12 @@ class DCompiler(Compiler): return ['-m32'] return [] - def get_crt_compile_args(self, crt_val, buildtype): + def get_crt_compile_args(self, crt_val: str, buildtype: str) -> T.List[str]: return [] - def get_crt_link_args(self, crt_val, buildtype): + def get_crt_link_args(self, crt_val: str, buildtype: str) -> T.List[str]: return [] - def thread_link_flags(self, env): - return self.linker.thread_flags(env) - class GnuDCompiler(GnuCompiler, DCompiler): @@ -641,9 +618,14 @@ class GnuDCompiler(GnuCompiler, DCompiler): LINKER_PREFIX = GnuCompiler.LINKER_PREFIX def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, - info: 'MachineInfo', arch: str, *, exe_wrapper: T.Optional['ExternalProgram'] = None, - **kwargs): - DCompiler.__init__(self, exelist, version, for_machine, info, arch, exe_wrapper=exe_wrapper, **kwargs) + info: 'MachineInfo', arch: str, *, + exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None, + is_cross: bool = False): + DCompiler.__init__(self, exelist, version, for_machine, info, arch, + exe_wrapper=exe_wrapper, linker=linker, + full_version=full_version, is_cross=is_cross) GnuCompiler.__init__(self, {}) self.id = 'gcc' default_warn_args = ['-Wall', '-Wdeprecated'] @@ -659,23 +641,24 @@ class GnuDCompiler(GnuCompiler, DCompiler): # (and some backported versions) self._has_deps_support = version_compare(self.version, '>=7.1') - def get_colorout_args(self, colortype): + def get_colorout_args(self, colortype: str) -> T.List[str]: if self._has_color_support: super().get_colorout_args(colortype) return [] - def get_dependency_gen_args(self, outtarget, outfile): + def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: if self._has_deps_support: return super().get_dependency_gen_args(outtarget, outfile) return [] - def get_warn_args(self, level): + def get_warn_args(self, level: str) -> T.List[str]: return self.warn_args[level] - def get_buildtype_args(self, buildtype): + def get_buildtype_args(self, buildtype: str) -> T.List[str]: return d_gdc_buildtype_args[buildtype] - def compute_parameters_with_absolute_paths(self, parameter_list, build_dir): + def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], + build_dir: str) -> T.List[str]: for idx, i in enumerate(parameter_list): if i[:2] == '-I' or i[:2] == '-L': parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:])) @@ -691,46 +674,51 @@ class GnuDCompiler(GnuCompiler, DCompiler): return args return args + ['-shared-libphobos'] - def get_disable_assert_args(self): + def get_disable_assert_args(self) -> T.List[str]: return ['-frelease'] class LLVMDCompiler(DmdLikeCompilerMixin, DCompiler): def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, - info: 'MachineInfo', arch: str, **kwargs): - DCompiler.__init__(self, exelist, version, for_machine, info, arch, **kwargs) + info: 'MachineInfo', arch: str, *, + exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None, + is_cross: bool = False): + DCompiler.__init__(self, exelist, version, for_machine, info, arch, + exe_wrapper=exe_wrapper, linker=linker, + full_version=full_version, is_cross=is_cross) self.id = 'llvm' self.base_options = ['b_coverage', 'b_colorout', 'b_vscrt', 'b_ndebug'] - def get_colorout_args(self, colortype): + def get_colorout_args(self, colortype: str) -> T.List[str]: if colortype == 'always': return ['-enable-color'] return [] - def get_warn_args(self, level): - if level == '2' or level == '3': + def get_warn_args(self, level: str) -> T.List[str]: + if level in {'2', '3'}: return ['-wi', '-dw'] elif level == '1': return ['-wi'] - else: - return [] + return [] - def get_buildtype_args(self, buildtype): + def get_buildtype_args(self, buildtype: str) -> T.List[str]: if buildtype != 'plain': - return self.get_target_arch_args() + d_ldc_buildtype_args[buildtype] + return self._get_target_arch_args() + d_ldc_buildtype_args[buildtype] return d_ldc_buildtype_args[buildtype] - def get_pic_args(self): + def get_pic_args(self) -> T.List[str]: return ['-relocation-model=pic'] - def get_crt_link_args(self, crt_val, buildtype): - return self.get_crt_args(crt_val, buildtype) + def get_crt_link_args(self, crt_val: str, buildtype: str) -> T.List[str]: + return self._get_crt_args(crt_val, buildtype) - def unix_args_to_native(self, args): - return self.translate_args_to_nongnu(args) + def unix_args_to_native(self, args: T.List[str]) -> T.List[str]: + return self._translate_args_to_nongnu(args) - def get_optimization_args(self, optimization_level): + def get_optimization_args(self, optimization_level: str) -> T.List[str]: return ldc_optimization_args[optimization_level] @classmethod @@ -750,22 +738,28 @@ class LLVMDCompiler(DmdLikeCompilerMixin, DCompiler): class DmdDCompiler(DmdLikeCompilerMixin, DCompiler): def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, - info: 'MachineInfo', arch: str, **kwargs): - DCompiler.__init__(self, exelist, version, for_machine, info, arch, **kwargs) + info: 'MachineInfo', arch: str, *, + exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None, + is_cross: bool = False): + DCompiler.__init__(self, exelist, version, for_machine, info, arch, + exe_wrapper=exe_wrapper, linker=linker, + full_version=full_version, is_cross=is_cross) self.id = 'dmd' self.base_options = ['b_coverage', 'b_colorout', 'b_vscrt', 'b_ndebug'] - def get_colorout_args(self, colortype): + def get_colorout_args(self, colortype: str) -> T.List[str]: if colortype == 'always': return ['-color=on'] return [] - def get_buildtype_args(self, buildtype): + def get_buildtype_args(self, buildtype: str) -> T.List[str]: if buildtype != 'plain': - return self.get_target_arch_args() + d_dmd_buildtype_args[buildtype] + return self._get_target_arch_args() + d_dmd_buildtype_args[buildtype] return d_dmd_buildtype_args[buildtype] - def get_std_exe_link_args(self): + def get_std_exe_link_args(self) -> T.List[str]: if self.info.is_windows(): # DMD links against D runtime only when main symbol is found, # so these needs to be inserted when linking static D libraries. @@ -776,7 +770,7 @@ class DmdDCompiler(DmdLikeCompilerMixin, DCompiler): return ['phobos.lib'] return [] - def get_std_shared_lib_link_args(self): + def get_std_shared_lib_link_args(self) -> T.List[str]: libname = 'libphobos2.so' if self.info.is_windows(): if self.arch == 'x86_64': @@ -787,7 +781,7 @@ class DmdDCompiler(DmdLikeCompilerMixin, DCompiler): libname = 'phobos.lib' return ['-shared', '-defaultlib=' + libname] - def get_target_arch_args(self): + def _get_target_arch_args(self) -> T.List[str]: # DMD32 and DMD64 on 64-bit Windows defaults to 32-bit (OMF). # Force the target to 64-bit in order to stay consistent # across the different platforms. @@ -799,13 +793,13 @@ class DmdDCompiler(DmdLikeCompilerMixin, DCompiler): return ['-m32'] return [] - def get_crt_compile_args(self, crt_val, buildtype): - return self.get_crt_args(crt_val, buildtype) + def get_crt_compile_args(self, crt_val: str, buildtype: str) -> T.List[str]: + return self._get_crt_args(crt_val, buildtype) - def unix_args_to_native(self, args): - return self.translate_args_to_nongnu(args) + def unix_args_to_native(self, args: T.List[str]) -> T.List[str]: + return self._translate_args_to_nongnu(args) - def get_optimization_args(self, optimization_level): + def get_optimization_args(self, optimization_level: str) -> T.List[str]: return dmd_optimization_args[optimization_level] def can_linker_accept_rsp(self) -> bool: diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index 9c2f5bfdf..9f2f10672 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -29,38 +29,41 @@ from .mixins.intel import IntelGnuLikeCompiler, IntelVisualStudioLikeCompiler from .mixins.clang import ClangCompiler from .mixins.elbrus import ElbrusCompiler from .mixins.pgi import PGICompiler -from .. import mlog from mesonbuild.mesonlib import ( version_compare, EnvironmentException, MesonException, MachineChoice, LibType ) if T.TYPE_CHECKING: + from ..coredata import OptionDictType + from ..dependencies import Dependency, ExternalProgram from ..envconfig import MachineInfo + from ..environment import Environment + from ..linkers import DynamicLinker class FortranCompiler(CLikeCompiler, Compiler): language = 'fortran' - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross: bool, info: 'MachineInfo', exe_wrapper=None, **kwargs): - Compiler.__init__(self, exelist, version, for_machine, info, is_cross=is_cross, **kwargs) + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): + Compiler.__init__(self, exelist, version, for_machine, info, + is_cross=is_cross, full_version=full_version, linker=linker) CLikeCompiler.__init__(self, exe_wrapper) - self.id = 'unknown' - def has_function(self, funcname, prefix, env, *, extra_args=None, dependencies=None): + def has_function(self, funcname: str, prefix: str, env: 'Environment', *, + extra_args: T.Optional[T.List[str]] = None, + dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: raise MesonException('Fortran does not have "has_function" capability.\n' 'It is better to test if a Fortran capability is working like:\n\n' "meson.get_compiler('fortran').links('block; end block; end program')\n\n" 'that example is to see if the compiler has Fortran 2008 Block element.') - def sanity_check(self, work_dir: Path, environment): - """ - Check to be sure a minimal program can compile and execute - with this compiler & platform. - """ - work_dir = Path(work_dir) + def sanity_check(self, work_dir_: str, environment: 'Environment') -> None: + work_dir = Path(work_dir_) source_name = work_dir / 'sanitycheckf.f90' binary_name = work_dir / 'sanitycheckf' if binary_name.is_file(): @@ -85,7 +88,7 @@ class FortranCompiler(CLikeCompiler, Compiler): if self.exe_wrapper is None: # Can't check if the binaries run so we have to assume they do return - cmdlist = self.exe_wrapper + [str(binary_name)] + cmdlist = self.exe_wrapper.get_command() + [str(binary_name)] else: cmdlist = [str(binary_name)] # %% Run the test executable @@ -96,31 +99,26 @@ class FortranCompiler(CLikeCompiler, Compiler): except OSError: raise EnvironmentException('Executables created by Fortran compiler %s are not runnable.' % self.name_string()) - def get_std_warn_args(self, level): - return FortranCompiler.std_warn_args - - def get_buildtype_args(self, buildtype): + def get_buildtype_args(self, buildtype: str) -> T.List[str]: return gnulike_buildtype_args[buildtype] - def get_optimization_args(self, optimization_level): + def get_optimization_args(self, optimization_level: str) -> T.List[str]: return gnu_optimization_args[optimization_level] - def get_debug_args(self, is_debug): + def get_debug_args(self, is_debug: bool) -> T.List[str]: return clike_debug_args[is_debug] - def get_dependency_gen_args(self, outtarget, outfile): - return [] - - def get_preprocess_only_args(self): + def get_preprocess_only_args(self) -> T.List[str]: return ['-cpp'] + super().get_preprocess_only_args() - def get_module_incdir_args(self): + def get_module_incdir_args(self) -> T.Tuple[str, ...]: return ('-I', ) - def get_module_outdir_args(self, path): + def get_module_outdir_args(self, path: str) -> T.List[str]: return ['-module', path] - def compute_parameters_with_absolute_paths(self, parameter_list, build_dir): + def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], + build_dir: str) -> T.List[str]: for idx, i in enumerate(parameter_list): if i[:2] == '-I' or i[:2] == '-L': parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:])) @@ -141,37 +139,28 @@ class FortranCompiler(CLikeCompiler, Compiler): return filename - def find_library(self, libname, env, extra_dirs, libtype: LibType = LibType.PREFER_SHARED): + def find_library(self, libname: str, env: 'Environment', extra_dirs: T.List[str], + libtype: LibType = LibType.PREFER_SHARED) -> T.Optional[T.List[str]]: code = 'stop; end program' return self._find_library_impl(libname, env, extra_dirs, code, libtype) - def has_multi_arguments(self, args: T.Sequence[str], env): - for arg in args[:]: - # some compilers, e.g. GCC, don't warn for unsupported warning-disable - # flags, so when we are testing a flag like "-Wno-forgotten-towel", also - # check the equivalent enable flag too "-Wforgotten-towel" - # GCC does error for "-fno-foobar" - if arg.startswith('-Wno-'): - args.append('-W' + arg[5:]) - if arg.startswith('-Wl,'): - mlog.warning('{} looks like a linker argument, ' - 'but has_argument and other similar methods only ' - 'support checking compiler arguments. Using them ' - 'to check linker arguments are never supported, ' - 'and results are likely to be wrong regardless of ' - 'the compiler you are using. has_link_argument or ' - 'other similar method can be used instead.' - .format(arg)) - code = 'stop; end program' - return self.has_arguments(args, env, code, mode='compile') + def has_multi_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]: + return self._has_multi_arguments(args, env, 'stop; end program') + + def has_multi_link_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]: + return self._has_multi_link_arguments(args, env, 'stop; end program') class GnuFortranCompiler(GnuCompiler, FortranCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, - defines=None, **kwargs): + + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + defines: T.Optional[T.Dict[str, str]] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): FortranCompiler.__init__(self, exelist, version, for_machine, - is_cross, info, exe_wrapper, **kwargs) + is_cross, info, exe_wrapper, linker=linker, + full_version=full_version) GnuCompiler.__init__(self, defines) default_warn_args = ['-Wall'] self.warn_args = {'0': [], @@ -179,7 +168,7 @@ class GnuFortranCompiler(GnuCompiler, FortranCompiler): '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic', '-fimplicit-none']} - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = FortranCompiler.get_options(self) fortran_stds = ['legacy', 'f95', 'f2003'] if version_compare(self.version, '>=4.4.0'): @@ -195,14 +184,14 @@ class GnuFortranCompiler(GnuCompiler, FortranCompiler): }) return opts - def get_option_compile_args(self, options) -> T.List[str]: + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] std = options['std'] if std.value != 'none': args.append('-std=' + std.value) return args - def get_dependency_gen_args(self, outtarget, outfile) -> T.List[str]: + def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: # Disabled until this is fixed: # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=62162 # return ['-cpp', '-MD', '-MQ', outtarget] @@ -214,7 +203,10 @@ class GnuFortranCompiler(GnuCompiler, FortranCompiler): def language_stdlib_only_link_flags(self) -> T.List[str]: return ['-lgfortran', '-lm'] - def has_header(self, hname, prefix, env, *, extra_args=None, dependencies=None, disable_cache=False): + def has_header(self, hname: str, prefix: str, env: 'Environment', *, + extra_args: T.Optional[T.List[str]] = None, + dependencies: T.Optional[T.List['Dependency']] = None, + disable_cache: bool = False) -> T.Tuple[bool, bool]: ''' Derived from mixins/clike.py:has_header, but without C-style usage of __has_include which breaks with GCC-Fortran 10: @@ -227,22 +219,27 @@ class GnuFortranCompiler(GnuCompiler, FortranCompiler): class ElbrusFortranCompiler(GnuFortranCompiler, ElbrusCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, - defines=None, **kwargs): - GnuFortranCompiler.__init__(self, exelist, version, for_machine, - is_cross, info, exe_wrapper, defines, - **kwargs) + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + defines: T.Optional[T.Dict[str, str]] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): + GnuFortranCompiler.__init__(self, exelist, version, for_machine, is_cross, + info, exe_wrapper, defines=defines, + linker=linker, full_version=full_version) ElbrusCompiler.__init__(self) class G95FortranCompiler(FortranCompiler): LINKER_PREFIX = '-Wl,' - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): FortranCompiler.__init__(self, exelist, version, for_machine, - is_cross, info, exe_wrapper, **kwargs) + is_cross, info, exe_wrapper, linker=linker, + full_version=full_version) self.id = 'g95' default_warn_args = ['-Wall'] self.warn_args = {'0': [], @@ -253,7 +250,7 @@ class G95FortranCompiler(FortranCompiler): def get_module_outdir_args(self, path: str) -> T.List[str]: return ['-fmod=' + path] - def get_no_warn_args(self): + def get_no_warn_args(self) -> T.List[str]: # FIXME: Confirm that there's no compiler option to disable all warnings return [] @@ -262,22 +259,25 @@ class SunFortranCompiler(FortranCompiler): LINKER_PREFIX = '-Wl,' - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, - **kwargs): - FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): + FortranCompiler.__init__(self, exelist, version, for_machine, + is_cross, info, exe_wrapper, linker=linker, + full_version=full_version) self.id = 'sun' - def get_dependency_gen_args(self, outtarget, outfile) -> T.List[str]: + def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: return ['-fpp'] - def get_always_args(self): + def get_always_args(self) -> T.List[str]: return [] - def get_warn_args(self, level): + def get_warn_args(self, level: str) -> T.List[str]: return [] - def get_module_incdir_args(self): + def get_module_incdir_args(self) -> T.Tuple[str, ...]: return ('-M', ) def get_module_outdir_args(self, path: str) -> T.List[str]: @@ -289,12 +289,15 @@ class SunFortranCompiler(FortranCompiler): class IntelFortranCompiler(IntelGnuLikeCompiler, FortranCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, - **kwargs): - self.file_suffixes = ('f90', 'f', 'for', 'ftn', 'fpp') + file_suffixes = ('f90', 'f', 'for', 'ftn', 'fpp', ) + + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): FortranCompiler.__init__(self, exelist, version, for_machine, - is_cross, info, exe_wrapper, **kwargs) + is_cross, info, exe_wrapper, linker=linker, + full_version=full_version) # FIXME: Add support for OS X and Windows in detect_fortran_compiler so # we are sent the type of compiler IntelGnuLikeCompiler.__init__(self) @@ -305,7 +308,7 @@ class IntelFortranCompiler(IntelGnuLikeCompiler, FortranCompiler): '2': default_warn_args + ['-warn', 'unused'], '3': ['-warn', 'all']} - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = FortranCompiler.get_options(self) fortran_stds = ['legacy', 'f95', 'f2003', 'f2008', 'f2018'] opts.update({ @@ -317,7 +320,7 @@ class IntelFortranCompiler(IntelGnuLikeCompiler, FortranCompiler): }) return opts - def get_option_compile_args(self, options) -> T.List[str]: + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] std = options['std'] stds = {'legacy': 'none', 'f95': 'f95', 'f2003': 'f03', 'f2008': 'f08', 'f2018': 'f18'} @@ -328,7 +331,7 @@ class IntelFortranCompiler(IntelGnuLikeCompiler, FortranCompiler): def get_preprocess_only_args(self) -> T.List[str]: return ['-cpp', '-EP'] - def get_always_args(self): + def get_always_args(self) -> T.List[str]: """Ifort doesn't have -pipe.""" val = super().get_always_args() val.remove('-pipe') @@ -343,14 +346,17 @@ class IntelFortranCompiler(IntelGnuLikeCompiler, FortranCompiler): class IntelClFortranCompiler(IntelVisualStudioLikeCompiler, FortranCompiler): - file_suffixes = ['f90', 'f', 'for', 'ftn', 'fpp'] + file_suffixes = ('f90', 'f', 'for', 'ftn', 'fpp', ) always_args = ['/nologo'] - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, target: str, info: 'MachineInfo', exe_wrapper=None, - **kwargs): + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, + is_cross: bool, info: 'MachineInfo', target: str, + exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): FortranCompiler.__init__(self, exelist, version, for_machine, - is_cross, info, exe_wrapper, **kwargs) + is_cross, info, exe_wrapper, linker=linker, + full_version=full_version) IntelVisualStudioLikeCompiler.__init__(self, target) default_warn_args = ['/warn:general', '/warn:truncated_source'] @@ -359,7 +365,7 @@ class IntelClFortranCompiler(IntelVisualStudioLikeCompiler, FortranCompiler): '2': default_warn_args + ['/warn:unused'], '3': ['/warn:all']} - def get_options(self): + def get_options(self) -> 'OptionDictType': opts = FortranCompiler.get_options(self) fortran_stds = ['legacy', 'f95', 'f2003', 'f2008', 'f2018'] opts.update({ @@ -371,7 +377,7 @@ class IntelClFortranCompiler(IntelVisualStudioLikeCompiler, FortranCompiler): }) return opts - def get_option_compile_args(self, options) -> T.List[str]: + def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: args = [] std = options['std'] stds = {'legacy': 'none', 'f95': 'f95', 'f2003': 'f03', 'f2008': 'f08', 'f2018': 'f18'} @@ -379,16 +385,19 @@ class IntelClFortranCompiler(IntelVisualStudioLikeCompiler, FortranCompiler): args.append('/stand:' + stds[std.value]) return args - def get_module_outdir_args(self, path) -> T.List[str]: + def get_module_outdir_args(self, path: str) -> T.List[str]: return ['/module:' + path] class PathScaleFortranCompiler(FortranCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, - **kwargs): + + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): FortranCompiler.__init__(self, exelist, version, for_machine, - is_cross, info, exe_wrapper, **kwargs) + is_cross, info, exe_wrapper, linker=linker, + full_version=full_version) self.id = 'pathscale' default_warn_args = ['-fullwarn'] self.warn_args = {'0': [], @@ -401,11 +410,14 @@ class PathScaleFortranCompiler(FortranCompiler): class PGIFortranCompiler(PGICompiler, FortranCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, - **kwargs): + + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): FortranCompiler.__init__(self, exelist, version, for_machine, - is_cross, info, exe_wrapper, **kwargs) + is_cross, info, exe_wrapper, linker=linker, + full_version=full_version) PGICompiler.__init__(self) default_warn_args = ['-Minform=inform'] @@ -420,11 +432,14 @@ class PGIFortranCompiler(PGICompiler, FortranCompiler): class NvidiaHPC_FortranCompiler(PGICompiler, FortranCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, - **kwargs): + + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): FortranCompiler.__init__(self, exelist, version, for_machine, - is_cross, info, exe_wrapper, **kwargs) + is_cross, info, exe_wrapper, linker=linker, + full_version=full_version) PGICompiler.__init__(self) self.id = 'nvidia_hpc' @@ -436,12 +451,15 @@ class NvidiaHPC_FortranCompiler(PGICompiler, FortranCompiler): class FlangFortranCompiler(ClangCompiler, FortranCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, - **kwargs): + + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): FortranCompiler.__init__(self, exelist, version, for_machine, - is_cross, info, exe_wrapper, **kwargs) - ClangCompiler.__init__(self, []) + is_cross, info, exe_wrapper, linker=linker, + full_version=full_version) + ClangCompiler.__init__(self, {}) self.id = 'flang' default_warn_args = ['-Minform=inform'] self.warn_args = {'0': [], @@ -453,11 +471,14 @@ class FlangFortranCompiler(ClangCompiler, FortranCompiler): return ['-lflang', '-lpgmath'] class Open64FortranCompiler(FortranCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, - **kwargs): + + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): FortranCompiler.__init__(self, exelist, version, for_machine, - is_cross, info, exe_wrapper, **kwargs) + is_cross, info, exe_wrapper, linker=linker, + full_version=full_version) self.id = 'open64' default_warn_args = ['-fullwarn'] self.warn_args = {'0': [], @@ -470,17 +491,20 @@ class Open64FortranCompiler(FortranCompiler): class NAGFortranCompiler(FortranCompiler): - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross, info: 'MachineInfo', exe_wrapper=None, - **kwargs): + + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, + info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None, + linker: T.Optional['DynamicLinker'] = None, + full_version: T.Optional[str] = None): FortranCompiler.__init__(self, exelist, version, for_machine, - is_cross, info, exe_wrapper, **kwargs) + is_cross, info, exe_wrapper, linker=linker, + full_version=full_version) self.id = 'nagfor' - def get_warn_args(self, level): + def get_warn_args(self, level: str) -> T.List[str]: return [] - def get_module_outdir_args(self, path) -> T.List[str]: + def get_module_outdir_args(self, path: str) -> T.List[str]: return ['-mdir', path] def openmp_flags(self) -> T.List[str]: diff --git a/mesonbuild/compilers/java.py b/mesonbuild/compilers/java.py index 8405b431f..77e1a9b6f 100644 --- a/mesonbuild/compilers/java.py +++ b/mesonbuild/compilers/java.py @@ -15,6 +15,7 @@ import os.path import shutil import subprocess +import textwrap import typing as T from ..mesonlib import EnvironmentException, MachineChoice @@ -23,56 +24,40 @@ from .mixins.islinker import BasicLinkerIsCompilerMixin if T.TYPE_CHECKING: from ..envconfig import MachineInfo + from ..environment import Environment class JavaCompiler(BasicLinkerIsCompilerMixin, Compiler): language = 'java' - def __init__(self, exelist, version, for_machine: MachineChoice, - info: 'MachineInfo'): - super().__init__(exelist, version, for_machine, info) + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, + info: 'MachineInfo', full_version: T.Optional[str] = None): + super().__init__(exelist, version, for_machine, info, full_version=full_version) self.id = 'unknown' self.javarunner = 'java' - def get_werror_args(self): + def get_werror_args(self) -> T.List[str]: return ['-Werror'] - def split_shlib_to_parts(self, fname): - return None, fname - - def get_dependency_gen_args(self, outtarget, outfile): - return [] - - def get_compile_only_args(self): - return [] - - def get_output_args(self, subdir): + def get_output_args(self, subdir: str) -> T.List[str]: if subdir == '': subdir = './' return ['-d', subdir, '-s', subdir] - def get_coverage_args(self): - return [] - - def get_std_exe_link_args(self): + def get_pic_args(self) -> T.List[str]: return [] - def get_include_args(self, path): + def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: return [] - def get_pic_args(self): - return [] - - def get_pch_use_args(self, pch_dir, header): - return [] - - def get_pch_name(self, header_name): + def get_pch_name(self, name: str) -> str: return '' - def get_buildtype_args(self, buildtype): + def get_buildtype_args(self, buildtype: str) -> T.List[str]: return java_buildtype_args[buildtype] - def compute_parameters_with_absolute_paths(self, parameter_list, build_dir): + def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], + build_dir: str) -> T.List[str]: for idx, i in enumerate(parameter_list): if i in ['-cp', '-classpath', '-sourcepath'] and idx + 1 < len(parameter_list): path_list = parameter_list[idx + 1].split(os.pathsep) @@ -81,17 +66,18 @@ class JavaCompiler(BasicLinkerIsCompilerMixin, Compiler): return parameter_list - def sanity_check(self, work_dir, environment): + def sanity_check(self, work_dir: str, environment: 'Environment') -> None: src = 'SanityCheck.java' obj = 'SanityCheck' source_name = os.path.join(work_dir, src) with open(source_name, 'w') as ofile: - ofile.write('''class SanityCheck { - public static void main(String[] args) { - int i; - } -} -''') + ofile.write(textwrap.dedent( + '''class SanityCheck { + public static void main(String[] args) { + int i; + } + } + ''')) pc = subprocess.Popen(self.exelist + [src], cwd=work_dir) pc.wait() if pc.returncode != 0: @@ -111,5 +97,8 @@ class JavaCompiler(BasicLinkerIsCompilerMixin, Compiler): "all about it." raise EnvironmentException(m) - def needs_static_linker(self): + def needs_static_linker(self) -> bool: return False + + def get_optimization_args(self, optimization_level: str) -> T.List[str]: + return [] diff --git a/mesonbuild/compilers/mixins/arm.py b/mesonbuild/compilers/mixins/arm.py index 25fb545c5..ee7d33753 100644 --- a/mesonbuild/compilers/mixins/arm.py +++ b/mesonbuild/compilers/mixins/arm.py @@ -81,7 +81,7 @@ class ArmCompiler(Compiler): self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + [], - '3': default_warn_args + []} + '3': default_warn_args + []} # type: T.Dict[str, T.List[str]] # Assembly self.can_compile_suffixes.add('s') @@ -96,7 +96,6 @@ class ArmCompiler(Compiler): def get_always_args(self) -> T.List[str]: return [] - # Override CCompiler.get_dependency_gen_args def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: return ['--depend_target', outtarget, '--depend', outfile, '--depend_single_line'] @@ -171,7 +170,6 @@ class ArmclangCompiler(Compiler): # so it might change semantics at any time. return ['-include-pch', os.path.join(pch_dir, self.get_pch_name(header))] - # Override CCompiler.get_dependency_gen_args def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: return ['-MD', '-MT', outtarget, '-MF', outfile] diff --git a/mesonbuild/compilers/mixins/c2000.py b/mesonbuild/compilers/mixins/c2000.py index aca1ee8ef..287aaa89e 100644 --- a/mesonbuild/compilers/mixins/c2000.py +++ b/mesonbuild/compilers/mixins/c2000.py @@ -65,7 +65,7 @@ class C2000Compiler(Compiler): self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + [], - '3': default_warn_args + []} + '3': default_warn_args + []} # type: T.Dict[str, T.List[str]] def get_pic_args(self) -> T.List[str]: # PIC support is not enabled by default for c2000, @@ -81,10 +81,6 @@ class C2000Compiler(Compiler): def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: return [] - # Override CCompiler.get_dependency_gen_args - def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: - return [] - def thread_flags(self, env: 'Environment') -> T.List[str]: return [] diff --git a/mesonbuild/compilers/mixins/ccrx.py b/mesonbuild/compilers/mixins/ccrx.py index fb8279791..eba4c455f 100644 --- a/mesonbuild/compilers/mixins/ccrx.py +++ b/mesonbuild/compilers/mixins/ccrx.py @@ -69,7 +69,7 @@ class CcrxCompiler(Compiler): self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + [], - '3': default_warn_args + []} + '3': default_warn_args + []} # type: T.Dict[str, T.List[str]] def get_pic_args(self) -> T.List[str]: # PIC support is not enabled by default for CCRX, @@ -85,10 +85,6 @@ class CcrxCompiler(Compiler): def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: return [] - # Override CCompiler.get_dependency_gen_args - def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: - return [] - def thread_flags(self, env: 'Environment') -> T.List[str]: return [] diff --git a/mesonbuild/compilers/mixins/clang.py b/mesonbuild/compilers/mixins/clang.py index 8c8594454..acdb3526e 100644 --- a/mesonbuild/compilers/mixins/clang.py +++ b/mesonbuild/compilers/mixins/clang.py @@ -20,6 +20,7 @@ import typing as T from ... import mesonlib from ...linkers import AppleDynamicLinker +from ..compilers import CompileCheckMode from .gnu import GnuLikeCompiler if T.TYPE_CHECKING: @@ -76,11 +77,13 @@ class ClangCompiler(GnuLikeCompiler): # so it might change semantics at any time. return ['-include-pch', os.path.join(pch_dir, self.get_pch_name(header))] - def has_multi_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]: - myargs = ['-Werror=unknown-warning-option', '-Werror=unused-command-line-argument'] - if mesonlib.version_compare(self.version, '>=3.6.0'): - myargs.append('-Werror=ignored-optimization-argument') - return super().has_multi_arguments(myargs + args, env) + def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: + myargs = [] # type: T.List[str] + if mode is CompileCheckMode.COMPILE: + myargs.extend(['-Werror=unknown-warning-option', '-Werror=unused-command-line-argument']) + if mesonlib.version_compare(self.version, '>=3.6.0'): + myargs.append('-Werror=ignored-optimization-argument') + return super().get_compiler_check_args(mode) + myargs def has_function(self, funcname: str, prefix: str, env: 'Environment', *, extra_args: T.Optional[T.List[str]] = None, diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index e146f5f62..dca09ea78 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -20,7 +20,6 @@ of this is to have mixin's, which are classes that are designed *not* to be standalone, they only work through inheritance. """ -import contextlib import collections import functools import glob @@ -37,6 +36,7 @@ from ... import mlog from ...linkers import GnuLikeDynamicLinkerMixin, SolarisDynamicLinker, CompCertDynamicLinker from ...mesonlib import LibType from .. import compilers +from ..compilers import CompileCheckMode from .visualstudio import VisualStudioLikeCompiler if T.TYPE_CHECKING: @@ -140,7 +140,7 @@ class CLikeCompiler(Compiler): if not exe_wrapper or not exe_wrapper.found() or not exe_wrapper.get_command(): self.exe_wrapper = None else: - self.exe_wrapper = exe_wrapper.get_command() + self.exe_wrapper = exe_wrapper def compiler_args(self, args: T.Optional[T.Iterable[str]] = None) -> CLikeCompilerArgs: # This is correct, mypy just doesn't understand co-operative inheritance @@ -169,12 +169,6 @@ class CLikeCompiler(Compiler): # Almost every compiler uses this for disabling warnings return ['-w'] - def split_shlib_to_parts(self, fname: str) -> T.Tuple[T.Optional[str], str]: - return None, fname - - def depfile_for_object(self, objfile: str) -> str: - return objfile + '.' + self.get_depfile_suffix() - def get_depfile_suffix(self) -> str: return 'd' @@ -190,23 +184,12 @@ class CLikeCompiler(Compiler): def get_no_optimization_args(self) -> T.List[str]: return ['-O0'] - def get_compiler_check_args(self) -> T.List[str]: - ''' - Get arguments useful for compiler checks such as being permissive in - the code quality and not doing any optimization. - ''' - return self.get_no_optimization_args() - def get_output_args(self, target: str) -> T.List[str]: return ['-o', target] def get_werror_args(self) -> T.List[str]: return ['-Werror'] - def get_std_exe_link_args(self) -> T.List[str]: - # TODO: is this a linker property? - return [] - def get_include_args(self, path: str, is_system: bool) -> T.List[str]: if path == '': path = '.' @@ -306,7 +289,7 @@ class CLikeCompiler(Compiler): source_name = os.path.join(work_dir, sname) binname = sname.rsplit('.', 1)[0] - mode = 'link' + mode = CompileCheckMode.LINK if self.is_cross: binname += '_cross' if self.exe_wrapper is None: @@ -315,7 +298,7 @@ class CLikeCompiler(Compiler): # on OSX the compiler binary is the same but you need # a ton of compiler flags to differentiate between # arm and x86_64. So just compile. - mode = 'compile' + mode = CompileCheckMode.COMPILE cargs, largs = self._get_basic_compiler_args(environment, mode) extra_flags = cargs + self.linker_to_compiler_args(largs) @@ -343,7 +326,7 @@ class CLikeCompiler(Compiler): if self.exe_wrapper is None: # Can't check if the binaries run so we have to assume they do return - cmdlist = self.exe_wrapper + [binary_name] + cmdlist = self.exe_wrapper.get_command() + [binary_name] else: cmdlist = [binary_name] mlog.debug('Running test binary command: ' + ' '.join(cmdlist)) @@ -401,10 +384,10 @@ class CLikeCompiler(Compiler): return self.compiles(t.format(**fargs), env, extra_args=extra_args, dependencies=dependencies) - def _get_basic_compiler_args(self, env: 'Environment', mode: str) -> T.Tuple[T.List[str], T.List[str]]: + def _get_basic_compiler_args(self, env: 'Environment', mode: CompileCheckMode) -> T.Tuple[T.List[str], T.List[str]]: cargs = [] # type: T.List[str] largs = [] # type: T.List[str] - if mode == 'link': + if mode is CompileCheckMode.LINK: # Sometimes we need to manually select the CRT to use with MSVC. # One example is when trying to do a compiler check that involves # linking with static libraries since MSVC won't select a CRT for @@ -425,7 +408,7 @@ class CLikeCompiler(Compiler): cleaned_sys_args = self.remove_linkerlike_args(sys_args) cargs += cleaned_sys_args - if mode == 'link': + if mode is CompileCheckMode.LINK: ld_value = env.lookup_binary_entry(self.for_machine, self.language + '_ld') if ld_value is not None: largs += self.use_linker_args(ld_value[0]) @@ -439,17 +422,17 @@ class CLikeCompiler(Compiler): cargs += self.get_compiler_args_for_mode(mode) return cargs, largs - def _get_compiler_check_args(self, env: 'Environment', - extra_args: T.Union[None, arglist.CompilerArgs, T.List[str]], - dependencies: T.Optional[T.List['Dependency']], - mode: str = 'compile') -> arglist.CompilerArgs: + def build_wrapper_args(self, env: 'Environment', + extra_args: T.Union[None, arglist.CompilerArgs, T.List[str]], + dependencies: T.Optional[T.List['Dependency']], + mode: CompileCheckMode = CompileCheckMode.COMPILE) -> arglist.CompilerArgs: # TODO: the caller should handle the listfing of these arguments if extra_args is None: extra_args = [] else: # TODO: we want to do this in the caller extra_args = mesonlib.listify(extra_args) - extra_args = mesonlib.listify([e(mode) if callable(e) else e for e in extra_args]) + extra_args = mesonlib.listify([e(mode.value) if callable(e) else e for e in extra_args]) if dependencies is None: dependencies = [] @@ -462,7 +445,7 @@ class CLikeCompiler(Compiler): for d in dependencies: # Add compile flags needed by dependencies cargs += d.get_compile_args() - if mode == 'link': + if mode is CompileCheckMode.LINK: # Add link flags needed to find dependencies largs += d.get_link_args() @@ -470,7 +453,7 @@ class CLikeCompiler(Compiler): cargs += ca largs += la - cargs += self.get_compiler_check_args() + cargs += self.get_compiler_check_args(mode) # on MSVC compiler and linker flags must be separated by the "/link" argument # at this point, the '/link' argument may already be part of extra_args, otherwise, it is added here @@ -480,37 +463,6 @@ class CLikeCompiler(Compiler): args = cargs + extra_args + largs return args - def compiles(self, code: str, env: 'Environment', *, - extra_args: T.Union[None, T.List[str], arglist.CompilerArgs] = None, - dependencies: T.Optional[T.List['Dependency']] = None, - mode: str = 'compile', - disable_cache: bool = False) -> T.Tuple[bool, bool]: - with self._build_wrapper(code, env, extra_args, dependencies, mode, disable_cache=disable_cache) as p: - return p.returncode == 0, p.cached - - @contextlib.contextmanager - def _build_wrapper(self, code: str, env: 'Environment', - extra_args: T.Union[None, arglist.CompilerArgs, T.List[str]] = None, - dependencies: T.Optional[T.List['Dependency']] = None, - mode: str = 'compile', want_output: bool = False, - disable_cache: bool = False, - temp_dir: str = None) -> T.Iterator[T.Optional[compilers.CompileResult]]: - args = self._get_compiler_check_args(env, extra_args, dependencies, mode) - if disable_cache or want_output: - with self.compile(code, extra_args=args, mode=mode, want_output=want_output, temp_dir=env.scratch_dir) as r: - yield r - else: - with self.cached_compile(code, env.coredata, extra_args=args, mode=mode, temp_dir=env.scratch_dir) as r: - yield r - - def links(self, code: str, env: 'Environment', *, - extra_args: T.Union[None, T.List[str], arglist.CompilerArgs] = None, - dependencies: T.Optional[T.List['Dependency']] = None, - mode: str = 'compile', - disable_cache: bool = False) -> T.Tuple[bool, bool]: - return self.compiles(code, env, extra_args=extra_args, - dependencies=dependencies, mode='link', disable_cache=disable_cache) - def run(self, code: str, env: 'Environment', *, extra_args: T.Optional[T.List[str]] = None, dependencies: T.Optional[T.List['Dependency']] = None) -> compilers.RunResult: @@ -524,7 +476,7 @@ class CLikeCompiler(Compiler): p.returncode)) return compilers.RunResult(False) if need_exe_wrapper: - cmdlist = self.exe_wrapper + [p.output_name] + cmdlist = self.exe_wrapper.get_command() + [p.output_name] else: cmdlist = [p.output_name] try: @@ -729,8 +681,8 @@ class CLikeCompiler(Compiler): # define {define} #endif {delim}\n{define}''' - args = self._get_compiler_check_args(env, extra_args, dependencies, - mode='preprocess').to_native() + args = self.build_wrapper_args(env, extra_args, dependencies, + mode=CompileCheckMode.PREPROCESS).to_native() func = functools.partial(self.cached_compile, code.format(**fargs), env.coredata, extra_args=args, mode='preprocess') if disable_cache: func = functools.partial(self.compile, code.format(**fargs), extra_args=args, mode='preprocess', temp_dir=env.scratch_dir) @@ -976,7 +928,7 @@ class CLikeCompiler(Compiler): } #endif ''' - args = self.get_compiler_check_args() + args = self.get_compiler_check_args(CompileCheckMode.COMPILE) n = 'symbols_have_underscore_prefix' with self._build_wrapper(code, env, extra_args=args, mode='compile', want_output=True, temp_dir=env.scratch_dir) as p: if p.returncode != 0: @@ -1263,9 +1215,6 @@ class CLikeCompiler(Compiler): return [] return ['-pthread'] - def thread_link_flags(self, env: 'Environment') -> T.List[str]: - return self.linker.thread_flags(env) - def linker_to_compiler_args(self, args: T.List[str]) -> T.List[str]: return args.copy() @@ -1273,7 +1222,7 @@ class CLikeCompiler(Compiler): mode: str) -> T.Tuple[bool, bool]: return self.compiles(code, env, extra_args=args, mode=mode) - def has_multi_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]: + def _has_multi_arguments(self, args: T.List[str], env: 'Environment', code: str) -> T.Tuple[bool, bool]: new_args = [] # type: T.List[str] for arg in args: # some compilers, e.g. GCC, don't warn for unsupported warning-disable @@ -1291,18 +1240,22 @@ class CLikeCompiler(Compiler): 'other similar method can be used instead.' .format(arg)) new_args.append(arg) - code = 'extern int i;\nint i;\n' return self.has_arguments(new_args, env, code, mode='compile') - def has_multi_link_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]: + def has_multi_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]: + return self._has_multi_arguments(args, env, 'extern int i;\nint i;\n') + + def _has_multi_link_arguments(self, args: T.List[str], env: 'Environment', code: str) -> T.Tuple[bool, bool]: # First time we check for link flags we need to first check if we have # --fatal-warnings, otherwise some linker checks could give some # false positive. args = self.linker.fatal_warnings() + args args = self.linker_to_compiler_args(args) - code = 'int main(void) { return 0; }\n' return self.has_arguments(args, env, code, mode='link') + def has_multi_link_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]: + return self._has_multi_link_arguments(args, env, 'int main(void) { return 0; }\n') + @staticmethod def _concatenate_string_literals(s: str) -> str: pattern = re.compile(r'(?P
.*([^\\]")|^")(?P([^\\"]|\\.)*)"\s+"(?P ([^\\"]|\\.)*)(?P ".*)') diff --git a/mesonbuild/compilers/mixins/compcert.py b/mesonbuild/compilers/mixins/compcert.py index 0f816a819..3211f6af2 100644 --- a/mesonbuild/compilers/mixins/compcert.py +++ b/mesonbuild/compilers/mixins/compcert.py @@ -68,7 +68,7 @@ class CompCertCompiler(Compiler): self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + [], - '3': default_warn_args + []} + '3': default_warn_args + []} # type: T.Dict[str, T.List[str]] def get_always_args(self) -> T.List[str]: return [] @@ -99,10 +99,6 @@ class CompCertCompiler(Compiler): patched_args.append(arg) return patched_args - # Override CCompiler.get_dependency_gen_args - def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: - return [] - def thread_flags(self, env: 'Environment') -> T.List[str]: return [] diff --git a/mesonbuild/compilers/mixins/gnu.py b/mesonbuild/compilers/mixins/gnu.py index 9c60fcbd9..41afadd1e 100644 --- a/mesonbuild/compilers/mixins/gnu.py +++ b/mesonbuild/compilers/mixins/gnu.py @@ -27,7 +27,7 @@ from ... import mlog if T.TYPE_CHECKING: from ...environment import Environment - from .clike import CLikeCompiler as Compiler + from ..compilers import Compiler else: # This is a bit clever, for mypy we pretend that these mixins descend from # Compiler, so we get all of the methods and attributes defined for us, but diff --git a/mesonbuild/compilers/mixins/intel.py b/mesonbuild/compilers/mixins/intel.py index 5bb55ffa1..442e8c752 100644 --- a/mesonbuild/compilers/mixins/intel.py +++ b/mesonbuild/compilers/mixins/intel.py @@ -24,6 +24,7 @@ import os import typing as T from ... import mesonlib +from ..compilers import CompileCheckMode from .gnu import GnuLikeCompiler from .visualstudio import VisualStudioLikeCompiler @@ -99,13 +100,8 @@ class IntelGnuLikeCompiler(GnuLikeCompiler): else: return ['-openmp'] - def compiles(self, code: str, env: 'Environment', *, - extra_args: T.Union[None, T.List[str], 'CompilerArgs'] = None, - dependencies: T.Optional[T.List['Dependency']] = None, - mode: str = 'compile', - disable_cache: bool = False) -> T.Tuple[bool, bool]: - extra_args = extra_args.copy() if extra_args is not None else [] - extra_args += [ + def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: + extra_args = [ '-diag-error', '10006', # ignoring unknown option '-diag-error', '10148', # Option not supported '-diag-error', '10155', # ignoring argument required @@ -113,7 +109,7 @@ class IntelGnuLikeCompiler(GnuLikeCompiler): '-diag-error', '10157', # Ignoring argument of the wrong type '-diag-error', '10158', # Argument must be separate. Can be hit by trying an option like -foo-bar=foo when -foo=bar is a valid option but -foo-bar isn't ] - return super().compiles(code, env, extra_args=extra_args, dependencies=dependencies, mode=mode, disable_cache=disable_cache) + return super().get_compiler_check_args(mode) + extra_args def get_profile_generate_args(self) -> T.List[str]: return ['-prof-gen=threadsafe'] @@ -157,15 +153,10 @@ class IntelVisualStudioLikeCompiler(VisualStudioLikeCompiler): super().__init__(target) self.id = 'intel-cl' - def compiles(self, code: str, env: 'Environment', *, - extra_args: T.Union[None, T.List[str], 'CompilerArgs'] = None, - dependencies: T.Optional[T.List['Dependency']] = None, - mode: str = 'compile', - disable_cache: bool = False) -> T.Tuple[bool, bool]: - # This covers a case that .get('foo', []) doesn't, that extra_args is - if mode != 'link': - extra_args = extra_args.copy() if extra_args is not None else [] - extra_args.extend([ + def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: + args = super().get_compiler_check_args(mode) + if mode is not CompileCheckMode.LINK: + args.extend([ '/Qdiag-error:10006', # ignoring unknown option '/Qdiag-error:10148', # Option not supported '/Qdiag-error:10155', # ignoring argument required @@ -173,7 +164,7 @@ class IntelVisualStudioLikeCompiler(VisualStudioLikeCompiler): '/Qdiag-error:10157', # Ignoring argument of the wrong type '/Qdiag-error:10158', # Argument must be separate. Can be hit by trying an option like -foo-bar=foo when -foo=bar is a valid option but -foo-bar isn't ]) - return super().compiles(code, env, extra_args=extra_args, dependencies=dependencies, mode=mode, disable_cache=disable_cache) + return args def get_toolset_version(self) -> T.Optional[str]: # Avoid circular dependencies.... @@ -195,3 +186,6 @@ class IntelVisualStudioLikeCompiler(VisualStudioLikeCompiler): def get_optimization_args(self, optimization_level: str) -> T.List[str]: return self.OPTIM_ARGS[optimization_level] + + def get_pch_base_name(self, header: str) -> str: + return os.path.basename(header) \ No newline at end of file diff --git a/mesonbuild/compilers/mixins/islinker.py b/mesonbuild/compilers/mixins/islinker.py index ce7a8af47..2445eecb7 100644 --- a/mesonbuild/compilers/mixins/islinker.py +++ b/mesonbuild/compilers/mixins/islinker.py @@ -97,8 +97,7 @@ class BasicLinkerIsCompilerMixin(Compiler): return [] def get_coverage_link_args(self) -> T.List[str]: - m = "Linker {} doesn't implement coverage data generation.".format(self.id) - raise mesonlib.EnvironmentException(m) + return [] def no_undefined_link_args(self) -> T.List[str]: return [] diff --git a/mesonbuild/compilers/mixins/pgi.py b/mesonbuild/compilers/mixins/pgi.py index f6ad279f9..61dee8d5a 100644 --- a/mesonbuild/compilers/mixins/pgi.py +++ b/mesonbuild/compilers/mixins/pgi.py @@ -50,7 +50,8 @@ class PGICompiler(Compiler): self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args, - '3': default_warn_args} + '3': default_warn_args + } # type: T.Dict[str, T.List[str]] def get_module_incdir_args(self) -> T.Tuple[str]: return ('-module', ) @@ -85,9 +86,6 @@ class PGICompiler(Compiler): parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:])) return parameter_list - def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: - return [] - def get_always_args(self) -> T.List[str]: return [] diff --git a/mesonbuild/compilers/mixins/visualstudio.py b/mesonbuild/compilers/mixins/visualstudio.py index 77f8dfc13..3494beefe 100644 --- a/mesonbuild/compilers/mixins/visualstudio.py +++ b/mesonbuild/compilers/mixins/visualstudio.py @@ -194,9 +194,6 @@ class VisualStudioLikeCompiler(Compiler, metaclass=abc.ABCMeta): args = [arg for arg in args if arg != '/Gw'] return args - def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: - return [] - def linker_to_compiler_args(self, args: T.List[str]) -> T.List[str]: return ['/link'] + args diff --git a/mesonbuild/compilers/mixins/xc16.py b/mesonbuild/compilers/mixins/xc16.py index edc5f2ca1..77c4690ff 100644 --- a/mesonbuild/compilers/mixins/xc16.py +++ b/mesonbuild/compilers/mixins/xc16.py @@ -65,7 +65,7 @@ class Xc16Compiler(Compiler): self.warn_args = {'0': [], '1': default_warn_args, '2': default_warn_args + [], - '3': default_warn_args + []} + '3': default_warn_args + []} # type: T.Dict[str, T.List[str]] def get_always_args(self) -> T.List[str]: return [] @@ -84,10 +84,6 @@ class Xc16Compiler(Compiler): def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: return [] - # Override CCompiler.get_dependency_gen_args - def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: - return [] - def thread_flags(self, env: 'Environment') -> T.List[str]: return [] diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py index baa727278..02bc79124 100644 --- a/mesonbuild/compilers/rust.py +++ b/mesonbuild/compilers/rust.py @@ -13,51 +13,63 @@ # limitations under the License. import subprocess, os.path +import textwrap import typing as T from ..mesonlib import EnvironmentException, MachineChoice, Popen_safe from .compilers import Compiler, rust_buildtype_args, clike_debug_args if T.TYPE_CHECKING: + from ..dependencies import ExternalProgram from ..envconfig import MachineInfo from ..environment import Environment # noqa: F401 + from ..linkers import DynamicLinker -rust_optimization_args = {'0': [], - 'g': ['-C', 'opt-level=0'], - '1': ['-C', 'opt-level=1'], - '2': ['-C', 'opt-level=2'], - '3': ['-C', 'opt-level=3'], - 's': ['-C', 'opt-level=s'], - } +rust_optimization_args = { + '0': [], + 'g': ['-C', 'opt-level=0'], + '1': ['-C', 'opt-level=1'], + '2': ['-C', 'opt-level=2'], + '3': ['-C', 'opt-level=3'], + 's': ['-C', 'opt-level=s'], +} # type: T.Dict[str, T.List[str]] class RustCompiler(Compiler): # rustc doesn't invoke the compiler itself, it doesn't need a LINKER_PREFIX language = 'rust' - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross: bool, info: 'MachineInfo', exe_wrapper=None, **kwargs): - super().__init__(exelist, version, for_machine, info, is_cross=is_cross, **kwargs) + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, + is_cross: bool, info: 'MachineInfo', + exe_wrapper: T.Optional['ExternalProgram'] = None, + full_version: T.Optional[str] = None, + linker: T.Optional['DynamicLinker'] = None): + super().__init__(exelist, version, for_machine, info, + is_cross=is_cross, full_version=full_version, + linker=linker) self.exe_wrapper = exe_wrapper self.id = 'rustc' - def needs_static_linker(self): + def needs_static_linker(self) -> bool: return False - def sanity_check(self, work_dir, environment): + def sanity_check(self, work_dir: str, environment: 'Environment') -> None: source_name = os.path.join(work_dir, 'sanity.rs') output_name = os.path.join(work_dir, 'rusttest') with open(source_name, 'w') as ofile: - ofile.write('''fn main() { -} -''') + ofile.write(textwrap.dedent( + '''fn main() { + } + ''')) pc = subprocess.Popen(self.exelist + ['-o', output_name, source_name], stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=work_dir) - stdo, stde = pc.communicate() - stdo = stdo.decode('utf-8', errors='replace') - stde = stde.decode('utf-8', errors='replace') + _stdo, _stde = pc.communicate() + assert isinstance(_stdo, bytes) + assert isinstance(_stde, bytes) + stdo = _stdo.decode('utf-8', errors='replace') + stde = _stde.decode('utf-8', errors='replace') if pc.returncode != 0: raise EnvironmentException('Rust compiler %s can not compile programs.\n%s\n%s' % ( self.name_string(), @@ -67,7 +79,7 @@ class RustCompiler(Compiler): if self.exe_wrapper is None: # Can't check if the binaries run so we have to assume they do return - cmdlist = self.exe_wrapper + [output_name] + cmdlist = self.exe_wrapper.get_command() + [output_name] else: cmdlist = [output_name] pe = subprocess.Popen(cmdlist, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) @@ -75,24 +87,25 @@ class RustCompiler(Compiler): if pe.returncode != 0: raise EnvironmentException('Executables created by Rust compiler %s are not runnable.' % self.name_string()) - def get_dependency_gen_args(self, outfile): + def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: return ['--dep-info', outfile] - def get_buildtype_args(self, buildtype): + def get_buildtype_args(self, buildtype: str) -> T.List[str]: return rust_buildtype_args[buildtype] - def get_sysroot(self): + def get_sysroot(self) -> str: cmd = self.exelist + ['--print', 'sysroot'] p, stdo, stde = Popen_safe(cmd) return stdo.split('\n')[0] - def get_debug_args(self, is_debug): + def get_debug_args(self, is_debug: bool) -> T.List[str]: return clike_debug_args[is_debug] - def get_optimization_args(self, optimization_level): + def get_optimization_args(self, optimization_level: str) -> T.List[str]: return rust_optimization_args[optimization_level] - def compute_parameters_with_absolute_paths(self, parameter_list, build_dir): + def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], + build_dir: str) -> T.List[str]: for idx, i in enumerate(parameter_list): if i[:2] == '-L': for j in ['dependency', 'crate', 'native', 'framework', 'all']: @@ -103,9 +116,6 @@ class RustCompiler(Compiler): return parameter_list - def get_std_exe_link_args(self): - return [] - def get_output_args(self, outputname: str) -> T.List[str]: return ['-o', outputname] diff --git a/mesonbuild/compilers/swift.py b/mesonbuild/compilers/swift.py index 55f27618c..8682e54a9 100644 --- a/mesonbuild/compilers/swift.py +++ b/mesonbuild/compilers/swift.py @@ -21,76 +21,83 @@ from .compilers import Compiler, swift_buildtype_args, clike_debug_args if T.TYPE_CHECKING: from ..envconfig import MachineInfo - -swift_optimization_args = {'0': [], - 'g': [], - '1': ['-O'], - '2': ['-O'], - '3': ['-O'], - 's': ['-O'], - } + from ..environment import Environment + from ..linkers import DynamicLinker + +swift_optimization_args = { + '0': [], + 'g': [], + '1': ['-O'], + '2': ['-O'], + '3': ['-O'], + 's': ['-O'], +} # type: T.Dict[str, T.List[str]] class SwiftCompiler(Compiler): LINKER_PREFIX = ['-Xlinker'] language = 'swift' - def __init__(self, exelist, version, for_machine: MachineChoice, - is_cross: bool, info: 'MachineInfo', **kwargs): - super().__init__(exelist, version, for_machine, info, is_cross=is_cross, **kwargs) + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, + is_cross: bool, info: 'MachineInfo', full_version: T.Optional[str] = None, + linker: T.Optional['DynamicLinker'] = None): + super().__init__(exelist, version, for_machine, info, + is_cross=is_cross, full_version=full_version, + linker=linker) self.version = version self.id = 'llvm' - def needs_static_linker(self): + def needs_static_linker(self) -> bool: return True - def get_werror_args(self): + def get_werror_args(self) -> T.List[str]: return ['--fatal-warnings'] - def get_dependency_gen_args(self, outtarget, outfile): + def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: return ['-emit-dependencies'] - def depfile_for_object(self, objfile): + def depfile_for_object(self, objfile: str) -> str: return os.path.splitext(objfile)[0] + '.' + self.get_depfile_suffix() - def get_depfile_suffix(self): + def get_depfile_suffix(self) -> str: return 'd' - def get_output_args(self, target): + def get_output_args(self, target: str) -> T.List[str]: return ['-o', target] - def get_header_import_args(self, headername): + def get_header_import_args(self, headername: str) -> T.List[str]: return ['-import-objc-header', headername] - def get_warn_args(self, level): + def get_warn_args(self, level: str) -> T.List[str]: return [] - def get_buildtype_args(self, buildtype): + def get_buildtype_args(self, buildtype: str) -> T.List[str]: return swift_buildtype_args[buildtype] - def get_std_exe_link_args(self): + def get_std_exe_link_args(self) -> T.List[str]: return ['-emit-executable'] - def get_module_args(self, modname): + def get_module_args(self, modname: str) -> T.List[str]: return ['-module-name', modname] - def get_mod_gen_args(self): + def get_mod_gen_args(self) -> T.List[str]: return ['-emit-module'] - def get_include_args(self, dirname): - return ['-I' + dirname] + def get_include_args(self, path: str, is_system: bool) -> T.List[str]: + return ['-I' + path] - def get_compile_only_args(self): + def get_compile_only_args(self) -> T.List[str]: return ['-c'] - def compute_parameters_with_absolute_paths(self, parameter_list, build_dir): + def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], + build_dir: str) -> T.List[str]: for idx, i in enumerate(parameter_list): if i[:2] == '-I' or i[:2] == '-L': parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:])) return parameter_list - def sanity_check(self, work_dir, environment): + def sanity_check(self, work_dir: str, environment: 'Environment') -> None: src = 'swifttest.swift' source_name = os.path.join(work_dir, src) output_name = os.path.join(work_dir, 'swifttest') @@ -113,8 +120,8 @@ class SwiftCompiler(Compiler): if subprocess.call(output_name) != 0: raise EnvironmentException('Executables created by Swift compiler %s are not runnable.' % self.name_string()) - def get_debug_args(self, is_debug): + def get_debug_args(self, is_debug: bool) -> T.List[str]: return clike_debug_args[is_debug] - def get_optimization_args(self, optimization_level): + def get_optimization_args(self, optimization_level: str) -> T.List[str]: return swift_optimization_args[optimization_level] diff --git a/mesonbuild/compilers/vala.py b/mesonbuild/compilers/vala.py index f31a29413..af800c247 100644 --- a/mesonbuild/compilers/vala.py +++ b/mesonbuild/compilers/vala.py @@ -18,64 +18,66 @@ import typing as T from .. import mlog from ..mesonlib import EnvironmentException, MachineChoice, version_compare -from .compilers import Compiler +from .compilers import Compiler, LibType if T.TYPE_CHECKING: from ..envconfig import MachineInfo + from ..environment import Environment class ValaCompiler(Compiler): language = 'vala' - def __init__(self, exelist, version, for_machine: MachineChoice, + def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo'): super().__init__(exelist, version, for_machine, info, is_cross=is_cross) self.version = version self.id = 'valac' self.base_options = ['b_colorout'] - def needs_static_linker(self): + def needs_static_linker(self) -> bool: return False # Because compiles into C. - def get_optimization_args(self, optimization_level): + def get_optimization_args(self, optimization_level: str) -> T.List[str]: return [] - def get_debug_args(self, is_debug): + def get_debug_args(self, is_debug: bool) -> T.List[str]: return ['--debug'] if is_debug else [] - def get_output_args(self, target): + def get_output_args(self, target: str) -> T.List[str]: return [] # Because compiles into C. - def get_compile_only_args(self): + def get_compile_only_args(self) -> T.List[str]: return [] # Because compiles into C. - def get_pic_args(self): + def get_pic_args(self) -> T.List[str]: return [] - def get_pie_args(self): + def get_pie_args(self) -> T.List[str]: return [] - def get_pie_link_args(self): + def get_pie_link_args(self) -> T.List[str]: return [] - def get_always_args(self): + def get_always_args(self) -> T.List[str]: return ['-C'] - def get_warn_args(self, warning_level): + def get_warn_args(self, warning_level: str) -> T.List[str]: return [] - def get_no_warn_args(self): + def get_no_warn_args(self) -> T.List[str]: return ['--disable-warnings'] - def get_werror_args(self): + def get_werror_args(self) -> T.List[str]: return ['--fatal-warnings'] - def get_colorout_args(self, colortype): + def get_colorout_args(self, colortype: str) -> T.List[str]: if version_compare(self.version, '>=0.37.1'): return ['--color=' + colortype] return [] - def compute_parameters_with_absolute_paths(self, parameter_list, build_dir): + def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], + build_dir: str) -> T.List[str]: for idx, i in enumerate(parameter_list): if i[:9] == '--girdir=': parameter_list[idx] = i[:9] + os.path.normpath(os.path.join(build_dir, i[9:])) @@ -88,7 +90,7 @@ class ValaCompiler(Compiler): return parameter_list - def sanity_check(self, work_dir, environment): + def sanity_check(self, work_dir: str, environment: 'Environment') -> None: code = 'class MesonSanityCheck : Object { }' extra_flags = [] extra_flags += environment.coredata.get_external_args(self.for_machine, self.language) @@ -98,16 +100,16 @@ class ValaCompiler(Compiler): extra_flags += environment.coredata.get_external_link_args(self.for_machine, self.language) with self.cached_compile(code, environment.coredata, extra_args=extra_flags, mode='compile') as p: if p.returncode != 0: - msg = 'Vala compiler {!r} can not compile programs' \ - ''.format(self.name_string()) + msg = 'Vala compiler {!r} can not compile programs'.format(self.name_string()) raise EnvironmentException(msg) - def get_buildtype_args(self, buildtype): - if buildtype == 'debug' or buildtype == 'debugoptimized' or buildtype == 'minsize': + def get_buildtype_args(self, buildtype: str) -> T.List[str]: + if buildtype in {'debug', 'debugoptimized', 'minsize'}: return ['--debug'] return [] - def find_library(self, libname, env, extra_dirs, *args): + def find_library(self, libname: str, env: 'Environment', extra_dirs: T.List[str], + libtype: LibType = LibType.PREFER_SHARED) -> T.Optional[T.List[str]]: if extra_dirs and isinstance(extra_dirs, str): extra_dirs = [extra_dirs] # Valac always looks in the default vapi dir, so only search there if @@ -129,8 +131,8 @@ class ValaCompiler(Compiler): mlog.debug('Searched {!r} and {!r} wasn\'t found'.format(extra_dirs, libname)) return None - def thread_flags(self, env): + def thread_flags(self, env: 'Environment') -> T.List[str]: return [] - def thread_link_flags(self, env): + def thread_link_flags(self, env: 'Environment') -> T.List[str]: return [] diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index a6cfd5bf2..9d7cb4958 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -34,8 +34,9 @@ if T.TYPE_CHECKING: from . import dependencies from .compilers.compilers import Compiler, CompileResult # noqa: F401 from .environment import Environment + from .mesonlib import OptionOverrideProxy - OptionDictType = T.Dict[str, 'UserOption[T.Any]'] + OptionDictType = T.Union[T.Dict[str, 'UserOption[T.Any]'], OptionOverrideProxy] CompilerCheckCacheKey = T.Tuple[T.Tuple[str, ...], str, str, T.Tuple[str, ...], str] version = '0.55.999' diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 513a03c46..b9505b668 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -1205,7 +1205,7 @@ class Environment: return cls( ccache + compiler, version, for_machine, is_cross, - info, exe_wrap, defines, full_version=full_version, + info, exe_wrap, defines=defines, full_version=full_version, linker=linker) if 'Emscripten' in out: @@ -1264,8 +1264,8 @@ class Environment: cls = ClangClCCompiler if lang == 'c' else ClangClCPPCompiler linker = self._guess_win_linker(['lld-link'], cls, for_machine) return cls( - compiler, version, for_machine, is_cross, info, exe_wrap, - target, linker=linker) + compiler, version, for_machine, is_cross, info, target, + exe_wrap, linker=linker) if 'clang' in out or 'Clang' in out: linker = None @@ -1291,7 +1291,7 @@ class Environment: return cls( ccache + compiler, version, for_machine, is_cross, info, - exe_wrap, defines, full_version=full_version, linker=linker) + exe_wrap, defines=defines, full_version=full_version, linker=linker) if 'Intel(R) C++ Intel(R)' in err: version = search_version(err) @@ -1300,8 +1300,8 @@ class Environment: self.coredata.add_lang_args(cls.language, cls, for_machine, self) linker = XilinkDynamicLinker(for_machine, [], version=version) return cls( - compiler, version, for_machine, is_cross, info=info, - exe_wrap=exe_wrap, target=target, linker=linker) + compiler, version, for_machine, is_cross, info, target, + exe_wrap, linker=linker) if 'Microsoft' in out or 'Microsoft' in err: # Latest versions of Visual Studio print version # number to stderr but earlier ones print version @@ -1324,8 +1324,8 @@ class Environment: cls = VisualStudioCCompiler if lang == 'c' else VisualStudioCPPCompiler linker = self._guess_win_linker(['link'], cls, for_machine) return cls( - compiler, version, for_machine, is_cross, info, exe_wrap, - target, full_version=cl_signature, linker=linker) + compiler, version, for_machine, is_cross, info, target, + exe_wrap, full_version=cl_signature, linker=linker) if 'PGI Compilers' in out: cls = PGICCompiler if lang == 'c' else PGICPPCompiler self.coredata.add_lang_args(cls.language, cls, for_machine, self) @@ -1495,8 +1495,8 @@ class Environment: self.coredata.add_lang_args(cls.language, cls, for_machine, self) linker = XilinkDynamicLinker(for_machine, [], version=version) return cls( - compiler, version, for_machine, is_cross, target, - info, exe_wrap, linker=linker) + compiler, version, for_machine, is_cross, info, + target, exe_wrap, linker=linker) if 'ifort (IFORT)' in out: linker = self._guess_nix_linker(compiler, IntelFortranCompiler, for_machine) diff --git a/mesonbuild/linkers.py b/mesonbuild/linkers.py index ed28fa3cf..ad5a4f592 100644 --- a/mesonbuild/linkers.py +++ b/mesonbuild/linkers.py @@ -1171,8 +1171,11 @@ class XilinkDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): id = 'xilink' - def __init__(self, for_machine: mesonlib.MachineChoice, always_args: T.List[str], - *, version: str = 'unknown version'): + def __init__(self, for_machine: mesonlib.MachineChoice, always_args: T.List[str], *, + exelist: T.Optional[T.List[str]] = None, + prefix: T.Union[str, T.List[str]] = '', + machine: str = 'x86', version: str = 'unknown version', + direct: bool = True): super().__init__(['xilink.exe'], for_machine, '', always_args, version=version) diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index 17d2733df..f2977717e 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -1696,7 +1696,7 @@ class OptionProxy(T.Generic[_T]): self.value = value -class OptionOverrideProxy: +class OptionOverrideProxy(collections.abc.MutableMapping): '''Mimic an option list but transparently override selected option values. @@ -1706,23 +1706,30 @@ class OptionOverrideProxy: # python 3.8 or typing_extensions def __init__(self, overrides: T.Dict[str, T.Any], *options: 'OptionDictType'): - self.overrides = overrides - self.options = options - - def __getitem__(self, option_name: str) -> T.Any: - for opts in self.options: - if option_name in opts: - return self._get_override(option_name, opts[option_name]) - raise KeyError('Option not found', option_name) - - def _get_override(self, option_name: str, base_opt: 'UserOption[T.Any]') -> T.Union[OptionProxy[T.Any], 'UserOption[T.Any]']: - if option_name in self.overrides: - return OptionProxy(base_opt.validate_value(self.overrides[option_name])) - return base_opt - - def copy(self) -> T.Dict[str, T.Any]: - result = {} # type: T.Dict[str, T.Any] - for opts in self.options: - for option_name in opts: - result[option_name] = self._get_override(option_name, opts[option_name]) - return result + self.overrides = overrides.copy() + self.options = {} # type: T.Dict[str, UserOption] + for o in options: + self.options.update(o) + + def __getitem__(self, key: str) -> T.Union['UserOption', OptionProxy]: + if key in self.options: + opt = self.options[key] + if key in self.overrides: + return OptionProxy(opt.validate_value(self.overrides[key])) + return opt + raise KeyError('Option not found', key) + + def __setitem__(self, key: str, value: T.Union['UserOption', OptionProxy]) -> None: + self.overrides[key] = value.value + + def __delitem__(self, key: str) -> None: + del self.overrides[key] + + def __iter__(self) -> T.Iterator[str]: + return iter(self.options) + + def __len__(self) -> int: + return len(self.options) + + def copy(self) -> 'OptionOverrideProxy': + return OptionOverrideProxy(self.overrides.copy(), self.options.copy()) diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index 66bbe2ab8..f7cbf8007 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -220,7 +220,7 @@ def list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[s sub_core_options[sub + ':' + k] = o core_options.update(sub_core_options) - def add_keys(options: T.Dict[str, cdata.UserOption], section: str, machine: str = 'any') -> None: + def add_keys(options: 'cdata.OptionDictType', section: str, machine: str = 'any') -> None: for key in sorted(options.keys()): opt = options[key] optdict = {'name': key, 'value': opt.value, 'section': section, 'machine': machine} diff --git a/run_mypy.py b/run_mypy.py index 04f563ae9..db578be74 100755 --- a/run_mypy.py +++ b/run_mypy.py @@ -10,16 +10,12 @@ modules = [ # fully typed submodules 'mesonbuild/ast', 'mesonbuild/cmake', - 'mesonbuild/compilers/mixins', + 'mesonbuild/compilers', 'mesonbuild/scripts', 'mesonbuild/wrap', # specific files 'mesonbuild/arglist.py', - 'mesonbuild/compilers/compilers.py', - 'mesonbuild/compilers/c_function_attributes.py', - 'mesonbuild/compilers/objc.py', - 'mesonbuild/compilers/objcpp.py', # 'mesonbuild/coredata.py', 'mesonbuild/dependencies/boost.py', 'mesonbuild/dependencies/hdf5.py', diff --git a/run_unittests.py b/run_unittests.py index db61ca6b1..7ddf17dee 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -360,7 +360,7 @@ class InternalTests(unittest.TestCase): stat.S_IRGRP | stat.S_IXGRP) def test_compiler_args_class_none_flush(self): - cc = mesonbuild.compilers.CCompiler([], 'fake', False, MachineChoice.HOST, mock.Mock()) + cc = mesonbuild.compilers.ClangCCompiler([], 'fake', MachineChoice.HOST, False, mock.Mock()) a = cc.compiler_args(['-I.']) #first we are checking if the tree construction deduplicates the correct -I argument a += ['-I..'] @@ -383,8 +383,8 @@ class InternalTests(unittest.TestCase): a += ['-Ifirst'] self.assertEqual(a, ['-Ifirst', '-Isecond', '-Ithird']) - def test_compiler_args_class(self): - cc = mesonbuild.compilers.CCompiler([], 'fake', False, MachineChoice.HOST, mock.Mock()) + def test_compiler_args_class_clike(self): + cc = mesonbuild.compilers.ClangCCompiler([], 'fake', MachineChoice.HOST, False, mock.Mock()) # Test that empty initialization works a = cc.compiler_args() self.assertEqual(a, [])