compilers: move get_compile_check_args() to Compiler

This is groundwork to put _build_wrapper in the base Compiler, which is
needed to make the D compilers truly type safe.
This commit is contained in:
Dylan Baker 2020-09-28 12:53:15 -07:00
parent e039727e63
commit 8291e947f5
3 changed files with 47 additions and 26 deletions

View File

@ -14,6 +14,7 @@
import abc import abc
import contextlib, os.path, re, tempfile import contextlib, os.path, re, tempfile
import enum
import itertools import itertools
import typing as T import typing as T
from functools import lru_cache from functools import lru_cache
@ -165,6 +166,14 @@ def is_known_suffix(fname: 'mesonlib.FileOrString') -> bool:
return suffix in all_suffixes return suffix in all_suffixes
class CompileCheckMode(enum.Enum):
PREPROCESS = 'preprocess'
COMPILE = 'compile'
LINK = 'link'
cuda_buildtype_args = {'plain': [], cuda_buildtype_args = {'plain': [],
'debug': [], 'debug': [],
'debugoptimized': [], 'debugoptimized': [],
@ -716,14 +725,16 @@ class Compiler(metaclass=abc.ABCMeta):
suffix = 'obj' suffix = 'obj'
return os.path.join(dirname, 'output.' + suffix) 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 # TODO: mode should really be an enum
args = [] # type: T.List[str] args = [] # type: T.List[str]
args += self.get_always_args() args += self.get_always_args()
if mode == 'compile': if mode is CompileCheckMode.COMPILE:
args += self.get_compile_only_args() args += self.get_compile_only_args()
if mode == 'preprocess': elif mode is CompileCheckMode.PREPROCESS:
args += self.get_preprocess_only_args() args += self.get_preprocess_only_args()
else:
assert mode is CompileCheckMode.LINK
return args return args
def compiler_args(self, args: T.Optional[T.Iterable[str]] = None) -> CompilerArgs: def compiler_args(self, args: T.Optional[T.Iterable[str]] = None) -> CompilerArgs:
@ -761,7 +772,7 @@ class Compiler(metaclass=abc.ABCMeta):
if mode != 'preprocess': if mode != 'preprocess':
output = self._get_compile_output(tmpdirname, mode) output = self._get_compile_output(tmpdirname, mode)
commands += self.get_output_args(output) 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 # extra_args must be last because it could contain '/link' to
# pass args to VisualStudio's linker. In that case everything # pass args to VisualStudio's linker. In that case everything
# in the command line after '/link' is given to the linker. # in the command line after '/link' is given to the linker.
@ -1106,6 +1117,21 @@ class Compiler(metaclass=abc.ABCMeta):
def module_name_to_filename(self, module_name: str) -> str: def module_name_to_filename(self, module_name: str) -> str:
raise EnvironmentError('{} does not implement module_name_to_filename'.format(self.id)) 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 get_args_from_envvars(lang: str, def get_args_from_envvars(lang: str,
for_machine: MachineChoice, for_machine: MachineChoice,

View File

@ -26,6 +26,7 @@ from .compilers import (
gnu_winlibs, gnu_winlibs,
msvc_winlibs, msvc_winlibs,
Compiler, Compiler,
CompileCheckMode,
) )
from .c_function_attributes import CXX_FUNC_ATTRIBUTES, C_FUNC_ATTRIBUTES from .c_function_attributes import CXX_FUNC_ATTRIBUTES, C_FUNC_ATTRIBUTES
from .mixins.clike import CLikeCompiler from .mixins.clike import CLikeCompiler
@ -90,11 +91,11 @@ class CPPCompiler(CLikeCompiler, Compiler):
code = 'class breakCCompiler;int main(void) { return 0; }\n' code = 'class breakCCompiler;int main(void) { return 0; }\n'
return self._sanity_check_impl(work_dir, environment, 'sanitycheckcpp.cc', code) return self._sanity_check_impl(work_dir, environment, 'sanitycheckcpp.cc', code)
def get_compiler_check_args(self) -> T.List[str]: def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]:
# -fpermissive allows non-conforming code to compile which is necessary # -fpermissive allows non-conforming code to compile which is necessary
# for many C++ checks. Particularly, the has_header_symbol check is # for many C++ checks. Particularly, the has_header_symbol check is
# too strict without this and always fails. # 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: str, symbol: str, prefix: str, def has_header_symbol(self, hname: str, symbol: str, prefix: str,
env: 'Environment', *, env: 'Environment', *,
@ -605,9 +606,9 @@ class VisualStudioLikeCPPCompilerMixin(CompilerMixinBase):
return args return args
def get_compiler_check_args(self) -> T.List[str]: 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. # 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(CompilerMixinBase): class CPP11AsCPP14Mixin(CompilerMixinBase):
@ -739,7 +740,7 @@ class ArmCPPCompiler(ArmCompiler, CPPCompiler):
def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]:
return [] return []
def get_compiler_check_args(self) -> T.List[str]: def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]:
return [] return []
@ -768,7 +769,7 @@ class CcrxCPPCompiler(CcrxCompiler, CPPCompiler):
def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]:
return [] return []
def get_compiler_check_args(self) -> T.List[str]: def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]:
return [] return []
class C2000CPPCompiler(C2000Compiler, CPPCompiler): class C2000CPPCompiler(C2000Compiler, CPPCompiler):
@ -802,5 +803,5 @@ class C2000CPPCompiler(C2000Compiler, CPPCompiler):
def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]:
return [] return []
def get_compiler_check_args(self) -> T.List[str]: def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]:
return [] return []

View File

@ -37,6 +37,7 @@ from ... import mlog
from ...linkers import GnuLikeDynamicLinkerMixin, SolarisDynamicLinker, CompCertDynamicLinker from ...linkers import GnuLikeDynamicLinkerMixin, SolarisDynamicLinker, CompCertDynamicLinker
from ...mesonlib import LibType from ...mesonlib import LibType
from .. import compilers from .. import compilers
from ..compilers import CompileCheckMode
from .visualstudio import VisualStudioLikeCompiler from .visualstudio import VisualStudioLikeCompiler
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
@ -184,13 +185,6 @@ class CLikeCompiler(Compiler):
def get_no_optimization_args(self) -> T.List[str]: def get_no_optimization_args(self) -> T.List[str]:
return ['-O0'] 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]: def get_output_args(self, target: str) -> T.List[str]:
return ['-o', target] return ['-o', target]
@ -296,7 +290,7 @@ class CLikeCompiler(Compiler):
source_name = os.path.join(work_dir, sname) source_name = os.path.join(work_dir, sname)
binname = sname.rsplit('.', 1)[0] binname = sname.rsplit('.', 1)[0]
mode = 'link' mode = CompileCheckMode.LINK
if self.is_cross: if self.is_cross:
binname += '_cross' binname += '_cross'
if self.exe_wrapper is None: if self.exe_wrapper is None:
@ -305,7 +299,7 @@ class CLikeCompiler(Compiler):
# on OSX the compiler binary is the same but you need # on OSX the compiler binary is the same but you need
# a ton of compiler flags to differentiate between # a ton of compiler flags to differentiate between
# arm and x86_64. So just compile. # arm and x86_64. So just compile.
mode = 'compile' mode = CompileCheckMode.COMPILE
cargs, largs = self._get_basic_compiler_args(environment, mode) cargs, largs = self._get_basic_compiler_args(environment, mode)
extra_flags = cargs + self.linker_to_compiler_args(largs) extra_flags = cargs + self.linker_to_compiler_args(largs)
@ -432,7 +426,7 @@ class CLikeCompiler(Compiler):
def _get_compiler_check_args(self, env: 'Environment', def _get_compiler_check_args(self, env: 'Environment',
extra_args: T.Union[None, arglist.CompilerArgs, T.List[str]], extra_args: T.Union[None, arglist.CompilerArgs, T.List[str]],
dependencies: T.Optional[T.List['Dependency']], dependencies: T.Optional[T.List['Dependency']],
mode: str = 'compile') -> arglist.CompilerArgs: mode: CompileCheckMode = CompileCheckMode.COMPILE) -> arglist.CompilerArgs:
# TODO: the caller should handle the listfing of these arguments # TODO: the caller should handle the listfing of these arguments
if extra_args is None: if extra_args is None:
extra_args = [] extra_args = []
@ -460,7 +454,7 @@ class CLikeCompiler(Compiler):
cargs += ca cargs += ca
largs += la 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 # 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 # at this point, the '/link' argument may already be part of extra_args, otherwise, it is added here
@ -482,10 +476,10 @@ class CLikeCompiler(Compiler):
def _build_wrapper(self, code: str, env: 'Environment', def _build_wrapper(self, code: str, env: 'Environment',
extra_args: T.Union[None, arglist.CompilerArgs, T.List[str]] = None, extra_args: T.Union[None, arglist.CompilerArgs, T.List[str]] = None,
dependencies: T.Optional[T.List['Dependency']] = None, dependencies: T.Optional[T.List['Dependency']] = None,
mode: str = 'compile', want_output: bool = False, mode: str = CompileCheckMode.COMPILE, want_output: bool = False,
disable_cache: bool = False, disable_cache: bool = False,
temp_dir: str = None) -> T.Iterator[T.Optional[compilers.CompileResult]]: temp_dir: str = None) -> T.Iterator[T.Optional[compilers.CompileResult]]:
args = self._get_compiler_check_args(env, extra_args, dependencies, mode) args = self._get_compiler_check_args(env, extra_args, dependencies, CompileCheckMode(mode))
if disable_cache or want_output: 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: with self.compile(code, extra_args=args, mode=mode, want_output=want_output, temp_dir=env.scratch_dir) as r:
yield r yield r
@ -720,7 +714,7 @@ class CLikeCompiler(Compiler):
#endif #endif
{delim}\n{define}''' {delim}\n{define}'''
args = self._get_compiler_check_args(env, extra_args, dependencies, args = self._get_compiler_check_args(env, extra_args, dependencies,
mode='preprocess').to_native() mode=CompileCheckMode.PREPROCESS).to_native()
func = functools.partial(self.cached_compile, code.format(**fargs), env.coredata, extra_args=args, mode='preprocess') func = functools.partial(self.cached_compile, code.format(**fargs), env.coredata, extra_args=args, mode='preprocess')
if disable_cache: if disable_cache:
func = functools.partial(self.compile, code.format(**fargs), extra_args=args, mode='preprocess', temp_dir=env.scratch_dir) func = functools.partial(self.compile, code.format(**fargs), extra_args=args, mode='preprocess', temp_dir=env.scratch_dir)
@ -966,7 +960,7 @@ class CLikeCompiler(Compiler):
} }
#endif #endif
''' '''
args = self.get_compiler_check_args() args = self.get_compiler_check_args(CompileCheckMode.COMPILE)
n = 'symbols_have_underscore_prefix' 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: 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: if p.returncode != 0: