From 682d22129c32edc64c610478368e1bc1f1dbc921 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Mon, 21 Sep 2020 12:48:51 -0700 Subject: [PATCH] compilers: Tell mypy that the compiler mixins are just that We do this by making the mixins inherit the Compiler class only when mypy is examining the code (using some clever inheritance shenanigans). This caught a bunch of issues, and also lets us delete a ton of code. --- mesonbuild/compilers/compilers.py | 23 ++++----- mesonbuild/compilers/mixins/arm.py | 24 ++++----- mesonbuild/compilers/mixins/c2000.py | 13 +++-- mesonbuild/compilers/mixins/ccrx.py | 9 +++- mesonbuild/compilers/mixins/clang.py | 18 ++----- mesonbuild/compilers/mixins/clike.py | 57 ++++++--------------- mesonbuild/compilers/mixins/compcert.py | 12 +++-- mesonbuild/compilers/mixins/elbrus.py | 3 -- mesonbuild/compilers/mixins/emscripten.py | 18 +++---- mesonbuild/compilers/mixins/gnu.py | 34 ++++-------- mesonbuild/compilers/mixins/intel.py | 8 +-- mesonbuild/compilers/mixins/islinker.py | 17 +++--- mesonbuild/compilers/mixins/pgi.py | 14 ++--- mesonbuild/compilers/mixins/visualstudio.py | 36 +++++-------- mesonbuild/compilers/mixins/xc16.py | 13 +++-- mesonbuild/linkers.py | 1 + 16 files changed, 122 insertions(+), 178 deletions(-) diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index b1a572fb3..12643b0a5 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -440,10 +440,10 @@ class CompileResult: class Compiler(metaclass=abc.ABCMeta): # Libraries to ignore in find_library() since they are provided by the # compiler or the C library. Currently only used for MSVC. - ignore_libs = () # type: T.Tuple[str, ...] + ignore_libs = [] # type: T.List[str] # Libraries that are internal compiler implementations, and must not be # manually searched. - internal_libs = () # type: T.Tuple[str, ...] + internal_libs = [] # type: T.List[str] LINKER_PREFIX = None # type: T.Union[None, str, T.List[str]] INVOKES_LINKER = True @@ -518,18 +518,18 @@ class Compiler(metaclass=abc.ABCMeta): raise EnvironmentException('%s does not support get_define ' % self.get_id()) def compute_int(self, expression: str, low: T.Optional[int], high: T.Optional[int], - guess: T.Optional[int], prefix: str, env: 'Environment', - extra_args: T.List[str], dependencies: T.List['Dependency']) -> int: + guess: T.Optional[int], prefix: str, env: 'Environment', *, + extra_args: T.Optional[T.List[str]], dependencies: T.Optional[T.List['Dependency']]) -> int: raise EnvironmentException('%s does not support compute_int ' % self.get_id()) def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], build_dir: str) -> T.List[str]: raise EnvironmentException('%s does not support compute_parameters_with_absolute_paths ' % self.get_id()) - def has_members(self, typename: str, membernames: T.Iterable[str], + def has_members(self, typename: str, membernames: T.List[str], prefix: str, env: 'Environment', *, - extra_args: T.Optional[T.Iterable[str]] = None, - dependencies: T.Optional[T.Iterable['Dependency']] = None) -> T.Tuple[bool, bool]: + extra_args: T.Optional[T.List[str]] = None, + dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: raise EnvironmentException('%s does not support has_member(s) ' % self.get_id()) def has_type(self, typename: str, prefix: str, env: 'Environment', @@ -662,8 +662,8 @@ class Compiler(metaclass=abc.ABCMeta): raise EnvironmentException('Language %s does not support alignment checks.' % self.get_display_language()) def has_function(self, funcname: str, prefix: str, env: 'Environment', *, - extra_args: T.Optional[T.Iterable[str]] = None, - dependencies: T.Optional[T.Iterable['Dependency']] = None) -> T.Tuple[bool, bool]: + extra_args: T.Optional[T.List[str]] = None, + dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: """See if a function exists. Returns a two item tuple of bools. The first bool is whether the @@ -672,8 +672,7 @@ class Compiler(metaclass=abc.ABCMeta): """ raise EnvironmentException('Language %s does not support function checks.' % self.get_display_language()) - @classmethod - def unix_args_to_native(cls, args: T.List[str]) -> T.List[str]: + def unix_args_to_native(self, args: T.List[str]) -> T.List[str]: "Always returns a copy that can be independently mutated" return args.copy() @@ -878,7 +877,7 @@ class Compiler(metaclass=abc.ABCMeta): def get_gui_app_args(self, value: bool) -> T.List[str]: return [] - def has_func_attribute(self, name: str, env: 'Environment') -> T.List[str]: + def has_func_attribute(self, name: str, env: 'Environment') -> T.Tuple[bool, bool]: raise EnvironmentException( 'Language {} does not support function attributes.'.format(self.get_display_language())) diff --git a/mesonbuild/compilers/mixins/arm.py b/mesonbuild/compilers/mixins/arm.py index 142e692b1..25fb545c5 100644 --- a/mesonbuild/compilers/mixins/arm.py +++ b/mesonbuild/compilers/mixins/arm.py @@ -23,8 +23,14 @@ from ..compilers import clike_debug_args from .clang import clang_color_args if T.TYPE_CHECKING: - from ...envconfig import MachineChoice from ...environment import Environment + from ...compilers.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 + # for runtime we make them descend from object (which all classes normally + # do). This gives up DRYer type checking, with no runtime impact + Compiler = object arm_buildtype_args = { 'plain': [], @@ -63,14 +69,10 @@ armclang_optimization_args = { } # type: T.Dict[str, T.List[str]] -class ArmCompiler: +class ArmCompiler(Compiler): """Functionality that is common to all ARM family compilers.""" - if T.TYPE_CHECKING: - is_cross = True - can_compile_suffixes = set() # type: T.Set[str] - def __init__(self) -> None: if not self.is_cross: raise mesonlib.EnvironmentException('armcc supports only cross-compilation.') @@ -133,15 +135,7 @@ class ArmCompiler: return parameter_list -class ArmclangCompiler: - - if T.TYPE_CHECKING: - can_compile_suffixes = set() # type: T.Set[str] - is_cross = True - version = '0' - linker = ArmClangDynamicLinker(MachineChoice.HOST, version='1.2.3') - - def get_pch_name(self, name: str) -> str: ... +class ArmclangCompiler(Compiler): def __init__(self) -> None: if not self.is_cross: diff --git a/mesonbuild/compilers/mixins/c2000.py b/mesonbuild/compilers/mixins/c2000.py index eb66003aa..aca1ee8ef 100644 --- a/mesonbuild/compilers/mixins/c2000.py +++ b/mesonbuild/compilers/mixins/c2000.py @@ -21,6 +21,13 @@ from ...mesonlib import EnvironmentException if T.TYPE_CHECKING: from ...environment import Environment + from ...compilers.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 + # for runtime we make them descend from object (which all classes normally + # do). This gives up DRYer type checking, with no runtime impact + Compiler = object c2000_buildtype_args = { 'plain': [], @@ -46,11 +53,7 @@ c2000_debug_args = { } # type: T.Dict[bool, T.List[str]] -class C2000Compiler: - - if T.TYPE_CHECKING: - is_cross = True - can_compile_suffixes = set() # type: T.Set[str] +class C2000Compiler(Compiler): def __init__(self) -> None: if not self.is_cross: diff --git a/mesonbuild/compilers/mixins/ccrx.py b/mesonbuild/compilers/mixins/ccrx.py index 4ac815a9d..fb8279791 100644 --- a/mesonbuild/compilers/mixins/ccrx.py +++ b/mesonbuild/compilers/mixins/ccrx.py @@ -21,6 +21,13 @@ from ...mesonlib import EnvironmentException if T.TYPE_CHECKING: from ...environment import Environment + from ...compilers.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 + # for runtime we make them descend from object (which all classes normally + # do). This gives up DRYer type checking, with no runtime impact + Compiler = object ccrx_buildtype_args = { 'plain': [], @@ -46,7 +53,7 @@ ccrx_debug_args = { } # type: T.Dict[bool, T.List[str]] -class CcrxCompiler: +class CcrxCompiler(Compiler): if T.TYPE_CHECKING: is_cross = True diff --git a/mesonbuild/compilers/mixins/clang.py b/mesonbuild/compilers/mixins/clang.py index 8d80751fb..8c8594454 100644 --- a/mesonbuild/compilers/mixins/clang.py +++ b/mesonbuild/compilers/mixins/clang.py @@ -23,10 +23,8 @@ from ...linkers import AppleDynamicLinker from .gnu import GnuLikeCompiler if T.TYPE_CHECKING: - from ...envconfig import MachineChoice from ...environment import Environment from ...dependencies import Dependency # noqa: F401 - from ...linkers import AppleDynamicLinker clang_color_args = { 'auto': ['-Xclang', '-fcolor-diagnostics'], @@ -45,11 +43,6 @@ clang_optimization_args = { class ClangCompiler(GnuLikeCompiler): - if T.TYPE_CHECKING: - linker = AppleDynamicLinker([], MachineChoice.HOST, '', []) - - def get_pch_name(self, name: str) -> str: ... - def __init__(self, defines: T.Optional[T.Dict[str, str]]): super().__init__() self.id = 'clang' @@ -83,14 +76,11 @@ 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.List[str]: + 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') - # Mypy doesn't understand co-coperative inheritance - return super().has_multi_arguments( # type: ignore - myargs + args, - env) + return super().has_multi_arguments(myargs + args, env) def has_function(self, funcname: str, prefix: str, env: 'Environment', *, extra_args: T.Optional[T.List[str]] = None, @@ -104,10 +94,8 @@ class ClangCompiler(GnuLikeCompiler): # TODO: this really should be communicated by the linker if isinstance(self.linker, AppleDynamicLinker) and mesonlib.version_compare(self.version, '>=8.0'): extra_args.append('-Wl,-no_weak_imports') - # Mypy doesn't understand co-coperative inheritance - ret = super().has_function(funcname, prefix, env, extra_args=extra_args, # type: ignore + return super().has_function(funcname, prefix, env, extra_args=extra_args, dependencies=dependencies) - return T.cast(T.Tuple[bool, bool], ret) def openmp_flags(self) -> T.List[str]: if mesonlib.version_compare(self.version, '>=3.8.0'): diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index 3baef50cc..e146f5f62 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -40,10 +40,15 @@ from .. import compilers from .visualstudio import VisualStudioLikeCompiler if T.TYPE_CHECKING: - from ...coredata import CoreData from ...dependencies import Dependency, ExternalProgram from ...environment import Environment - from ...linkers import DynamicLinker + from ...compilers.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 + # for runtime we make them descend from object (which all classes normally + # do). This gives up DRYer type checking, with no runtime impact + Compiler = object GROUP_FLAGS = re.compile(r'''\.so (?:\.[0-9]+)? (?:\.[0-9]+)? (?:\.[0-9]+)?$ | ^(?:-Wl,)?-l | @@ -115,46 +120,13 @@ class CLikeCompilerArgs(arglist.CompilerArgs): return 'CLikeCompilerArgs({!r}, {!r})'.format(self.compiler, self._container) -class CLikeCompiler: +class CLikeCompiler(Compiler): """Shared bits for the C and CPP Compilers.""" if T.TYPE_CHECKING: - can_compile_suffixes = set() # type: T.Set[str] - exelist = [] # type: T.List[str] - for_machine = mesonlib.MachineChoice.HOST - id = '' - ignore_libs = () # type: T.Tuple[str, ...] - language = '' - linker = SolarisDynamicLinker([], mesonlib.MachineChoice.HOST, [], []) # type: DynamicLinker warn_args = {} # type: T.Dict[str, T.List[str]] - @staticmethod - def attribute_check_func(name: str) -> str:... - def get_allow_undefined_link_args(self) -> T.List[str]: ... - def get_compiler_args_for_mode(self, mode: str) -> T.List[str]: ... - def get_display_language(self) -> str: ... - def get_largefile_args(self) -> T.List[str]: ... - def get_linker_always_args(self) -> T.List[str]: ... - def get_pch_suffix(self) -> str: ... - def get_id(self) -> str: ... - def name_string(self) -> str: ... - def remove_linkerlike_args(self, args: T.List[str]) -> T.List[str]: ... - @classmethod - def use_linker_args(cls, linker: str) -> T.List[str]: ... - - @contextlib.contextmanager - def compile(self, code: 'mesonlib.FileOrString', - extra_args: T.Union[None, arglist.CompilerArgs, T.List[str]] = None, - *, mode: str = 'link', want_output: bool = False, - temp_dir: T.Optional[str] = None) -> T.Iterator[T.Optional[compilers.CompileResult]]: ... - - @contextlib.contextmanager - def cached_compile(self, code: str, cdata: 'CoreData', *, - extra_args: T.Union[None, arglist.CompilerArgs, T.List[str]] = None, - mode: str = 'link', - temp_dir: T.Optional[str] = None) -> T.Iterator[T.Optional[compilers.CompileResult]]: ... - # TODO: Replace this manual cache with functools.lru_cache find_library_cache = {} # type: T.Dict[T.Tuple[T.Tuple[str, ...], str, T.Tuple[str, ...], str, LibType], T.Optional[T.List[str]]] find_framework_cache = {} # type: T.Dict[T.Tuple[T.Tuple[str, ...], str, T.Tuple[str, ...], bool], T.Optional[T.List[str]]] @@ -170,9 +142,9 @@ class CLikeCompiler: else: self.exe_wrapper = exe_wrapper.get_command() - def compiler_args(self, args: T.Optional[T.List[str]] = None) -> CLikeCompilerArgs: + def compiler_args(self, args: T.Optional[T.Iterable[str]] = None) -> CLikeCompilerArgs: # This is correct, mypy just doesn't understand co-operative inheritance - return CLikeCompilerArgs(self, args) # type: ignore + return CLikeCompilerArgs(self, args) def needs_static_linker(self) -> bool: return True # When compiling static libraries, so yes. @@ -296,13 +268,16 @@ class CLikeCompiler: return self._get_library_dirs(env, elf_class).copy() @functools.lru_cache() - def get_program_dirs(self, env: 'Environment') -> T.List[str]: + def _get_program_dirs(self, env: 'Environment') -> T.List[str]: ''' Programs used by the compiler. Also where toolchain DLLs such as libstdc++-6.dll are found with MinGW. ''' return self.get_compiler_dirs(env, 'programs') + def get_program_dirs(self, env: 'Environment') -> T.List[str]: + return self._get_program_dirs(env).copy() + def get_pic_args(self) -> T.List[str]: return ['-fPIC'] @@ -506,7 +481,7 @@ class CLikeCompiler: return args def compiles(self, code: str, env: 'Environment', *, - extra_args: T.Optional[T.List[str]] = None, + 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]: @@ -529,7 +504,7 @@ class CLikeCompiler: yield r def links(self, code: str, env: 'Environment', *, - extra_args: T.Optional[T.List[str]] = None, + 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]: diff --git a/mesonbuild/compilers/mixins/compcert.py b/mesonbuild/compilers/mixins/compcert.py index fd144bea8..0f816a819 100644 --- a/mesonbuild/compilers/mixins/compcert.py +++ b/mesonbuild/compilers/mixins/compcert.py @@ -20,6 +20,13 @@ import typing as T if T.TYPE_CHECKING: from ...environment import Environment + from ...compilers.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 + # for runtime we make them descend from object (which all classes normally + # do). This gives up DRYer type checking, with no runtime impact + Compiler = object ccomp_buildtype_args = { 'plain': [''], @@ -51,10 +58,7 @@ ccomp_args_to_wul = [ r"^-r$" ] # type: T.List[str] -class CompCertCompiler: - - if T.TYPE_CHECKING: - can_compile_suffixes = set() # type: T.Set[str] +class CompCertCompiler(Compiler): def __init__(self) -> None: self.id = 'ccomp' diff --git a/mesonbuild/compilers/mixins/elbrus.py b/mesonbuild/compilers/mixins/elbrus.py index 3a7437ce4..2ea359950 100644 --- a/mesonbuild/compilers/mixins/elbrus.py +++ b/mesonbuild/compilers/mixins/elbrus.py @@ -31,9 +31,6 @@ class ElbrusCompiler(GnuLikeCompiler): # Elbrus compiler is nearly like GCC, but does not support # PCH, LTO, sanitizers and color output as of version 1.21.x. - if T.TYPE_CHECKING: - exelist = [] # type: T.List[str] - def __init__(self) -> None: super().__init__() self.id = 'lcc' diff --git a/mesonbuild/compilers/mixins/emscripten.py b/mesonbuild/compilers/mixins/emscripten.py index f15db40bf..87bc40c87 100644 --- a/mesonbuild/compilers/mixins/emscripten.py +++ b/mesonbuild/compilers/mixins/emscripten.py @@ -20,15 +20,17 @@ import typing as T from ... import coredata if T.TYPE_CHECKING: - from ...envconfig import MachineChoice from ...environment import Environment + from ...compilers.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 + # for runtime we make them descend from object (which all classes normally + # do). This gives up DRYer type checking, with no runtime impact + Compiler = object -class EmscriptenMixin: - - if T.TYPE_CHECKING: - for_machine = MachineChoice.HOST - language = '' +class EmscriptenMixin(Compiler): def _get_compile_output(self, dirname: str, mode: str) -> str: # In pre-processor mode, the output is sent to stdout and discarded @@ -54,9 +56,7 @@ class EmscriptenMixin: return args def get_options(self) -> 'coredata.OptionDictType': - # Mypy and co-operative inheritance - _opts = super().get_options() # type: ignore - opts = T.cast('coredata.OptionDictType', _opts) + opts = super().get_options() opts.update({ '{}_thread_count'.format(self.language): coredata.UserIntegerOption( 'Number of threads to use in web assembly, set to 0 to disable', diff --git a/mesonbuild/compilers/mixins/gnu.py b/mesonbuild/compilers/mixins/gnu.py index f7b24c8c2..9c60fcbd9 100644 --- a/mesonbuild/compilers/mixins/gnu.py +++ b/mesonbuild/compilers/mixins/gnu.py @@ -26,14 +26,14 @@ from ... import mesonlib from ... import mlog if T.TYPE_CHECKING: - import contextlib - - from .. import compilers - from ... import arglist - from ...coredata import UserOption # noqa: F401 - from ...dependency import Dependency - from ...envconfig import MachineInfo from ...environment import Environment + from .clike import CLikeCompiler as 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 + # for runtime we make them descend from object (which all classes normally + # do). This gives up DRYer type checking, with no runtime impact + Compiler = object # XXX: prevent circular references. # FIXME: this really is a posix interface not a c-like interface @@ -135,7 +135,7 @@ def gnulike_default_include_dirs(compiler: T.Tuple[str], lang: str) -> T.List[st return paths -class GnuLikeCompiler(metaclass=abc.ABCMeta): +class GnuLikeCompiler(Compiler, metaclass=abc.ABCMeta): """ GnuLikeCompiler is a common interface to all compilers implementing the GNU-style commandline interface. This includes GCC, Clang @@ -143,21 +143,6 @@ class GnuLikeCompiler(metaclass=abc.ABCMeta): that the actual concrete subclass define their own implementation. """ - if T.TYPE_CHECKING: - can_compile_suffixes = set() # type: T.Set[str] - exelist = [] # type: T.List[str] - info = MachineInfo('', '', '', '') - language = '' - version = '' - - @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]]: ... - LINKER_PREFIX = '-Wl,' def __init__(self) -> None: @@ -354,8 +339,7 @@ class GnuCompiler(GnuLikeCompiler): def get_warn_args(self, level: str) -> T.List[str]: # Mypy doesn't understand cooperative inheritance - _args = super().get_warn_args(level) # type: ignore - args = T.cast(T.List[str], _args) + args = super().get_warn_args(level) if mesonlib.version_compare(self.version, '<4.8.0') and '-Wpedantic' in args: # -Wpedantic was added in 4.8.0 # https://gcc.gnu.org/gcc-4.8/changes.html diff --git a/mesonbuild/compilers/mixins/intel.py b/mesonbuild/compilers/mixins/intel.py index cbbfc7a73..b83e5c484 100644 --- a/mesonbuild/compilers/mixins/intel.py +++ b/mesonbuild/compilers/mixins/intel.py @@ -28,8 +28,6 @@ from .gnu import GnuLikeCompiler from .visualstudio import VisualStudioLikeCompiler if T.TYPE_CHECKING: - import subprocess # noqa: F401 - from ...arglist import CompilerArgs from ...dependencies import Dependency from ...environment import Environment @@ -115,8 +113,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 ] - ret = super().compiles(code, env, extra_args=extra_args, dependencies=dependencies, mode=mode, disable_cache=disable_cache) # type: ignore - return T.cast(T.Tuple[bool, bool], ret) + return super().compiles(code, env, extra_args=extra_args, dependencies=dependencies, mode=mode, disable_cache=disable_cache) def get_profile_generate_args(self) -> T.List[str]: return ['-prof-gen=threadsafe'] @@ -176,8 +173,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 ]) - ret = super().compiles(code, env, extra_args=extra_args, dependencies=dependencies, mode=mode, disable_cache=disable_cache) # type: ignore - return T.cast(T.Tuple[bool, bool], ret) + return super().compiles(code, env, extra_args=extra_args, dependencies=dependencies, mode=mode, disable_cache=disable_cache) def get_toolset_version(self) -> T.Optional[str]: # Avoid circular dependencies.... diff --git a/mesonbuild/compilers/mixins/islinker.py b/mesonbuild/compilers/mixins/islinker.py index 6fc8c4eb7..ce7a8af47 100644 --- a/mesonbuild/compilers/mixins/islinker.py +++ b/mesonbuild/compilers/mixins/islinker.py @@ -27,9 +27,16 @@ from ... import mesonlib if T.TYPE_CHECKING: from ...coredata import OptionDictType from ...environment import Environment + from ...compilers.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 + # for runtime we make them descend from object (which all classes normally + # do). This gives up DRYer type checking, with no runtime impact + Compiler = object -class BasicLinkerIsCompilerMixin: +class BasicLinkerIsCompilerMixin(Compiler): """Provides a baseline of methods that a linker would implement. @@ -38,10 +45,6 @@ class BasicLinkerIsCompilerMixin: functionality itself. """ - if T.TYPE_CHECKING: - exelist = [] # type: T.List[str] - id = '' - def sanitizer_link_args(self, value: str) -> T.List[str]: return [] @@ -103,8 +106,8 @@ class BasicLinkerIsCompilerMixin: def bitcode_args(self) -> T.List[str]: raise mesonlib.MesonException("This linker doesn't support bitcode bundles") - def get_soname_args(self, for_machine: 'mesonlib.MachineChoice', - prefix: str, shlib_name: str, suffix: str, soversion: 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]: raise mesonlib.MesonException("This linker doesn't support soname args") diff --git a/mesonbuild/compilers/mixins/pgi.py b/mesonbuild/compilers/mixins/pgi.py index d69abdad9..f6ad279f9 100644 --- a/mesonbuild/compilers/mixins/pgi.py +++ b/mesonbuild/compilers/mixins/pgi.py @@ -21,8 +21,14 @@ from pathlib import Path from ..compilers import clike_debug_args, clike_optimization_args if T.TYPE_CHECKING: - from ...envconfig import MachineInfo from ...environment import Environment + from ...compilers.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 + # for runtime we make them descend from object (which all classes normally + # do). This gives up DRYer type checking, with no runtime impact + Compiler = object pgi_buildtype_args = { 'plain': [], @@ -34,11 +40,7 @@ pgi_buildtype_args = { } # type: T.Dict[str, T.List[str]] -class PGICompiler: - - if T.TYPE_CHECKING: - info = MachineInfo('', '', '', '') - language = '' +class PGICompiler(Compiler): def __init__(self) -> None: self.base_options = ['b_pch'] diff --git a/mesonbuild/compilers/mixins/visualstudio.py b/mesonbuild/compilers/mixins/visualstudio.py index 06866783f..d9abb9540 100644 --- a/mesonbuild/compilers/mixins/visualstudio.py +++ b/mesonbuild/compilers/mixins/visualstudio.py @@ -20,18 +20,19 @@ import abc import os import typing as T +from ... import arglist from ... import mesonlib from ... import mlog if T.TYPE_CHECKING: - from contextlib import contextmanager - - from ...arglist import CompilerArgs - from ...compilers.compilers import CompileResult - from ...dependencies import Dependency - from ...envconfig import MachineChoice from ...environment import Environment - from ...linkers import MSVCDynamicLinker + from .clike import CLikeCompiler as 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 + # for runtime we make them descend from object (which all classes normally + # do). This gives up DRYer type checking, with no runtime impact + Compiler = object vs32_instruction_set_args = { 'mmx': ['/arch:SSE'], # There does not seem to be a flag just for MMX @@ -92,7 +93,7 @@ msvc_debug_args = { } # type: T.Dict[bool, T.List[str]] -class VisualStudioLikeCompiler(metaclass=abc.ABCMeta): +class VisualStudioLikeCompiler(Compiler, metaclass=abc.ABCMeta): """A common interface for all compilers implementing an MSVC-style interface. @@ -102,24 +103,10 @@ class VisualStudioLikeCompiler(metaclass=abc.ABCMeta): This class implements as much common logic as possible. """ - if T.TYPE_CHECKING: - linker = MSVCDynamicLinker(MachineChoice.HOST, []) - version = '' - - @contextmanager # yes, yes, it's a half truth. - 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]]: ... - std_warn_args = ['/W3'] std_opt_args = ['/O2'] - # XXX: this is copied in this patch only to avoid circular dependencies - #ignore_libs = unixy_compiler_internal_libs - ignore_libs = ('m', 'c', 'pthread', 'dl', 'rt', 'execinfo') - internal_libs = () + ignore_libs = arglist.UNIXY_COMPILER_INTERNAL_LIBS + ['execinfo'] + internal_libs = [] # type: T.List[str] crt_args = { 'none': [], @@ -156,6 +143,7 @@ class VisualStudioLikeCompiler(metaclass=abc.ABCMeta): self.machine = 'arm' else: self.machine = target + assert self.linker is not None self.linker.machine = self.machine # Override CCompiler.get_always_args diff --git a/mesonbuild/compilers/mixins/xc16.py b/mesonbuild/compilers/mixins/xc16.py index ed9be1502..edc5f2ca1 100644 --- a/mesonbuild/compilers/mixins/xc16.py +++ b/mesonbuild/compilers/mixins/xc16.py @@ -21,6 +21,13 @@ from ...mesonlib import EnvironmentException if T.TYPE_CHECKING: from ...environment import Environment + from ...compilers.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 + # for runtime we make them descend from object (which all classes normally + # do). This gives up DRYer type checking, with no runtime impact + Compiler = object xc16_buildtype_args = { 'plain': [], @@ -46,11 +53,7 @@ xc16_debug_args = { } # type: T.Dict[bool, T.List[str]] -class Xc16Compiler: - - if T.TYPE_CHECKING: - can_compile_suffixes = set() # type: T.Set[str] - is_cross = True +class Xc16Compiler(Compiler): def __init__(self) -> None: if not self.is_cross: diff --git a/mesonbuild/linkers.py b/mesonbuild/linkers.py index d85c88e79..ed28fa3cf 100644 --- a/mesonbuild/linkers.py +++ b/mesonbuild/linkers.py @@ -351,6 +351,7 @@ class DynamicLinker(LinkerEnvVarsMixin, metaclass=abc.ABCMeta): self.version = version self.prefix_arg = prefix_arg self.always_args = always_args + self.machine = None # type: T.Optional[str] def __repr__(self) -> str: return '<{}: v{} `{}`>'.format(type(self).__name__, self.version, ' '.join(self.exelist))