From ed6bf2b4017b42d7a3ee0a74fabaa6097c9404dd Mon Sep 17 00:00:00 2001 From: John Ericson Date: Tue, 21 Apr 2020 01:22:37 -0400 Subject: [PATCH] WIP: Create enum to use instead of strings for language --- mesonbuild/backend/ninjabackend.py | 10 ++-- mesonbuild/cmake/executor.py | 4 +- mesonbuild/compilers/c.py | 4 +- mesonbuild/compilers/compilers.py | 81 ++++++++++++++++------------ mesonbuild/compilers/cpp.py | 4 +- mesonbuild/compilers/cs.py | 4 +- mesonbuild/compilers/cuda.py | 13 +++-- mesonbuild/compilers/d.py | 4 +- mesonbuild/compilers/fortran.py | 4 +- mesonbuild/compilers/java.py | 4 +- mesonbuild/compilers/mixins/clike.py | 2 +- mesonbuild/compilers/mixins/gnu.py | 2 +- mesonbuild/compilers/mixins/pgi.py | 3 +- mesonbuild/compilers/objc.py | 4 +- mesonbuild/compilers/objcpp.py | 4 +- mesonbuild/compilers/rust.py | 4 +- mesonbuild/compilers/swift.py | 4 +- mesonbuild/compilers/vala.py | 4 +- mesonbuild/coredata.py | 40 +++++++++----- mesonbuild/envconfig.py | 4 +- mesonbuild/environment.py | 12 ++--- mesonbuild/interpreter.py | 3 +- mesonbuild/mconf.py | 6 +-- mesonbuild/mesonlib.py | 60 +++++++++++++++++++++ mesonbuild/optinterpreter.py | 2 +- run_unittests.py | 2 +- 26 files changed, 190 insertions(+), 98 deletions(-) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index e76546680..22fe8f403 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -32,7 +32,7 @@ from ..compilers import (Compiler, CompilerArgs, CCompiler, FortranCompiler, PGICCompiler, VisualStudioLikeCompiler) from ..linkers import ArLinker from ..mesonlib import ( - File, LibType, MachineChoice, MesonException, OrderedSet, PerMachine, + File, LibType, Language, MachineChoice, MesonException, OrderedSet, PerMachine, ProgressBar, quote_arg, unholder, ) from ..mesonlib import get_compiler_for_source, has_path_sep @@ -1376,12 +1376,12 @@ int dummy; return PerMachine('_FOR_BUILD', '')[for_machine] @classmethod - def get_compiler_rule_name(cls, lang: str, for_machine: MachineChoice) -> str: - return '%s_COMPILER%s' % (lang, cls.get_rule_suffix(for_machine)) + def get_compiler_rule_name(cls, lang: Language, for_machine: MachineChoice) -> str: + return '%s_COMPILER%s' % (lang.get_lower_case_name(), cls.get_rule_suffix(for_machine)) @classmethod - def get_pch_rule_name(cls, lang: str, for_machine: MachineChoice) -> str: - return '%s_PCH%s' % (lang, cls.get_rule_suffix(for_machine)) + def get_pch_rule_name(cls, lang: Language, for_machine: MachineChoice) -> str: + return '%s_PCH%s' % (lang.get_lower_case_name(), cls.get_rule_suffix(for_machine)) @classmethod def compiler_to_rule_name(cls, compiler: Compiler) -> str: diff --git a/mesonbuild/cmake/executor.py b/mesonbuild/cmake/executor.py index a41b293b4..ddf2a6d70 100644 --- a/mesonbuild/cmake/executor.py +++ b/mesonbuild/cmake/executor.py @@ -250,7 +250,7 @@ class CMakeExecutor: fallback = os.path.realpath(__file__) # A file used as a fallback wehen everything else fails compilers = self.environment.coredata.compilers[MachineChoice.BUILD] - def make_abs(exe: str, lang: str) -> str: + def make_abs(exe: str, lang: Language) -> str: if os.path.isabs(exe): return exe @@ -260,7 +260,7 @@ class CMakeExecutor: p = fallback return p - def choose_compiler(lang: str) -> T.Tuple[str, str]: + def choose_compiler(lang: Language) -> T.Tuple[str, str]: exe_list = [] if lang in compilers: exe_list = compilers[lang].get_exelist() diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 1bc9e8499..52a51571c 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -16,7 +16,7 @@ import os.path import typing as T from .. import coredata -from ..mesonlib import MachineChoice, MesonException, mlog, version_compare +from ..mesonlib import Language, MachineChoice, MesonException, mlog, version_compare from ..linkers import LinkerEnvVarsMixin from .c_function_attributes import C_FUNC_ATTRIBUTES from .mixins.clike import CLikeCompiler @@ -50,7 +50,7 @@ class CCompiler(CLikeCompiler, Compiler): except KeyError: raise MesonException('Unknown function attribute "{}"'.format(name)) - language = 'c' + language = Language.C def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional[str] = None, **kwargs): diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 3d3a503cd..ffd8d0619 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -26,7 +26,7 @@ from .. import coredata from .. import mlog from .. import mesonlib from ..mesonlib import ( - EnvironmentException, MachineChoice, MesonException, + EnvironmentException, Language, MachineChoice, MesonException, Popen_safe, split_args ) from ..envconfig import ( @@ -51,52 +51,67 @@ lib_suffixes = ('a', 'lib', 'dll', 'dll.a', 'dylib', 'so') # Mapping of language to suffixes of files that should always be in that language # This means we can't include .h headers here since they could be C, C++, ObjC, etc. lang_suffixes = { - 'c': ('c',), - 'cpp': ('cpp', 'cc', 'cxx', 'c++', 'hh', 'hpp', 'ipp', 'hxx'), - 'cuda': ('cu',), + Language.C: ('c',), + Language.CPP: ('cpp', 'cc', 'cxx', 'c++', 'hh', 'hpp', 'ipp', 'hxx'), + Language.CUDA: ('cu',), # f90, f95, f03, f08 are for free-form fortran ('f90' recommended) # f, for, ftn, fpp are for fixed-form fortran ('f' or 'for' recommended) - 'fortran': ('f90', 'f95', 'f03', 'f08', 'f', 'for', 'ftn', 'fpp'), - 'd': ('d', 'di'), - 'objc': ('m',), - 'objcpp': ('mm',), - 'rust': ('rs',), - 'vala': ('vala', 'vapi', 'gs'), - 'cs': ('cs',), - 'swift': ('swift',), - 'java': ('java',), + Language.FORTRAN: ('f90', 'f95', 'f03', 'f08', 'f', 'for', 'ftn', 'fpp'), + Language.D: ('d', 'di'), + Language.OBJC: ('m',), + Language.OBJCPP: ('mm',), + Language.RUST: ('rs',), + Language.VALA: ('vala', 'vapi', 'gs'), + Language.CS: ('cs',), + Language.SWIFT: ('swift',), + Language.JAVA: ('java',), } all_languages = lang_suffixes.keys() -cpp_suffixes = lang_suffixes['cpp'] + ('h',) -c_suffixes = lang_suffixes['c'] + ('h',) +cpp_suffixes = lang_suffixes[Language.CPP] + ('h',) +c_suffixes = lang_suffixes[Language.C] + ('h',) # List of languages that by default consume and output libraries following the # C ABI; these can generally be used interchangebly -clib_langs = ('objcpp', 'cpp', 'objc', 'c', 'fortran',) +clib_langs = (Language.OBJCPP, Language.CPP, Language.OBJC, Language.C, Language.FORTRAN,) # List of languages that can be linked with C code directly by the linker # used in build.py:process_compilers() and build.py:get_dynamic_linker() -clink_langs = ('d', 'cuda') + clib_langs +clink_langs = (Language.D, Language.CUDA) + clib_langs clink_suffixes = () -for _l in clink_langs + ('vala',): +for _l in clink_langs + (Language.VALA,): clink_suffixes += lang_suffixes[_l] clink_suffixes += ('h', 'll', 's') all_suffixes = set(itertools.chain(*lang_suffixes.values(), clink_suffixes)) # Languages that should use LDFLAGS arguments when linking. -languages_using_ldflags = {'objcpp', 'cpp', 'objc', 'c', 'fortran', 'd', 'cuda'} +languages_using_ldflags = { + Language.OBJCPP, + Language.CPP, + Language.OBJC, + Language.C, + Language.FORTRAN, + Language.D, + Language.CUDA +} # Languages that should use CPPFLAGS arguments when linking. -languages_using_cppflags = {'c', 'cpp', 'objc', 'objcpp'} +languages_using_cppflags = { + Language.C, + Language.CPP, + Language.OBJC, + Language.OBJCPP, +} soregex = re.compile(r'.*\.so(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?$') # Environment variables that each lang uses. -cflags_mapping = {'c': 'CFLAGS', - 'cpp': 'CXXFLAGS', - 'cuda': 'CUFLAGS', - 'objc': 'OBJCFLAGS', - 'objcpp': 'OBJCXXFLAGS', - 'fortran': 'FFLAGS', - 'd': 'DFLAGS', - 'vala': 'VALAFLAGS', - 'rust': 'RUSTFLAGS'} +cflags_mapping = { + Language.C: 'CFLAGS', + Language.CPP: 'CXXFLAGS', + Language.CUDA: 'CUFLAGS', + Language.OBJC: 'OBJCFLAGS', + Language.OBJCPP: 'OBJCXXFLAGS', + Language.FORTRAN: 'FFLAGS', + Language.D: 'DFLAGS', + Language.VALA: 'VALAFLAGS', + Language.RUST: 'RUSTFLAGS', +} unixy_compiler_internal_libs = ('m', 'c', 'pthread', 'dl', 'rt') # execinfo is a compiler lib on FreeBSD and NetBSD @@ -569,7 +584,7 @@ class CompilerArgs(collections.abc.MutableSequence): return False def need_to_split_linker_args(self): - return isinstance(self.compiler, Compiler) and self.compiler.get_language() == 'd' + return isinstance(self.compiler, Compiler) and self.compiler.get_language() == Language.D def to_native(self, copy: bool = False) -> T.List[str]: # Check if we need to add --start/end-group for circular dependencies @@ -1227,7 +1242,7 @@ def get_largefile_args(compiler): return [] -def get_args_from_envvars(lang: str, +def get_args_from_envvars(lang: Language, for_machine: MachineChoice, is_cross: bool, use_linker_args: bool) -> T.Tuple[T.List[str], T.List[str]]: @@ -1264,7 +1279,7 @@ def get_args_from_envvars(lang: str, return compile_flags, link_flags -def get_global_options(lang: str, +def get_global_options(lang: Language, comp: T.Type[Compiler], for_machine: MachineChoice, is_cross: bool, @@ -1288,7 +1303,7 @@ def get_global_options(lang: str, comp.INVOKES_LINKER) for k, o in opts.items(): - user_k = lang + '_' + k + user_k = lang.get_lower_case_name() + '_' + k if user_k in properties: # Get from configuration files. o.set_value(properties[user_k]) diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index d30017f27..c4c7da50d 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -19,7 +19,7 @@ import typing as T from .. import coredata from .. import mlog -from ..mesonlib import MesonException, MachineChoice, version_compare +from ..mesonlib import Language, MesonException, MachineChoice, version_compare from ..linkers import LinkerEnvVarsMixin from .compilers import ( @@ -60,7 +60,7 @@ class CPPCompiler(CLikeCompiler, Compiler): except KeyError: raise MesonException('Unknown function attribute "{}"'.format(name)) - language = 'cpp' + language = Language.CPP def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrap: T.Optional[str] = None, **kwargs): diff --git a/mesonbuild/compilers/cs.py b/mesonbuild/compilers/cs.py index 843348e76..bc917cb2b 100644 --- a/mesonbuild/compilers/cs.py +++ b/mesonbuild/compilers/cs.py @@ -15,7 +15,7 @@ import os.path, subprocess import typing as T -from ..mesonlib import EnvironmentException +from ..mesonlib import Language, EnvironmentException from .compilers import Compiler, MachineChoice, mono_buildtype_args from .mixins.islinker import BasicLinkerIsCompilerMixin @@ -34,7 +34,7 @@ cs_optimization_args = {'0': [], class CsCompiler(BasicLinkerIsCompilerMixin, Compiler): - language = 'cs' + language = Language.CS def __init__(self, exelist, version, for_machine: MachineChoice, info: 'MachineInfo', comp_id, runner=None): diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py index e839f532f..00233b069 100644 --- a/mesonbuild/compilers/cuda.py +++ b/mesonbuild/compilers/cuda.py @@ -18,9 +18,14 @@ from functools import partial from .. import coredata from .. import mlog -from ..mesonlib import EnvironmentException, MachineChoice, Popen_safe, OptionOverrideProxy, is_windows, LibType -from .compilers import (Compiler, cuda_buildtype_args, cuda_optimization_args, - cuda_debug_args) +from ..mesonlib import ( + EnvironmentException, Language, LibType, MachineChoice, OptionOverrideProxy, + Popen_safe, is_windows +) +from .compilers import ( + Compiler, cuda_buildtype_args, cuda_optimization_args, + cuda_debug_args +) if T.TYPE_CHECKING: from ..environment import Environment # noqa: F401 @@ -30,7 +35,7 @@ if T.TYPE_CHECKING: class CudaCompiler(Compiler): LINKER_PREFIX = '-Xlinker=' - language = 'cuda' + language = Language.CUDA _universal_flags = {'compiler': ['-I', '-D', '-U', '-E'], 'linker': ['-l', '-L']} diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index a83e22116..caa8e44f6 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -16,7 +16,7 @@ import os.path, subprocess import typing as T from ..mesonlib import ( - EnvironmentException, MachineChoice, version_compare, + EnvironmentException, Language, MachineChoice, version_compare, ) from .compilers import ( @@ -436,7 +436,7 @@ class DCompiler(Compiler): 'mtd': ['-mscrtlib=libcmtd'], } - language = 'd' + language = Language.D def __init__(self, exelist, version, for_machine: MachineChoice, info: 'MachineInfo', arch, is_cross, exe_wrapper, **kwargs): diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index 01283a1de..2b20aa4ab 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -32,7 +32,7 @@ from .mixins.pgi import PGICompiler from .. import mlog from mesonbuild.mesonlib import ( - version_compare, EnvironmentException, MesonException, MachineChoice, LibType + version_compare, EnvironmentException, Language, MesonException, MachineChoice, LibType ) if T.TYPE_CHECKING: @@ -41,7 +41,7 @@ if T.TYPE_CHECKING: class FortranCompiler(CLikeCompiler, Compiler): - language = 'fortran' + language = Language.FORTRAN def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): diff --git a/mesonbuild/compilers/java.py b/mesonbuild/compilers/java.py index 5aeb2508c..c9a7af990 100644 --- a/mesonbuild/compilers/java.py +++ b/mesonbuild/compilers/java.py @@ -17,7 +17,7 @@ import shutil import subprocess import typing as T -from ..mesonlib import EnvironmentException, MachineChoice +from ..mesonlib import EnvironmentException, Language, MachineChoice from .compilers import Compiler, java_buildtype_args from .mixins.islinker import BasicLinkerIsCompilerMixin @@ -26,7 +26,7 @@ if T.TYPE_CHECKING: class JavaCompiler(BasicLinkerIsCompilerMixin, Compiler): - language = 'java' + language = Language.JAVA def __init__(self, exelist, version, for_machine: MachineChoice, info: 'MachineInfo'): diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index 24f4796fd..260342e15 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -304,7 +304,7 @@ class CLikeCompiler: cargs += cleaned_sys_args if mode == 'link': - ld_value = env.lookup_binary_entry(self.for_machine, self.language + '_ld') + ld_value = env.lookup_binary_entry(self.for_machine, self.language.get_lower_case_name() + '_ld') if ld_value is not None: largs += self.use_linker_args(ld_value[0]) diff --git a/mesonbuild/compilers/mixins/gnu.py b/mesonbuild/compilers/mixins/gnu.py index 3526a91d4..a1541bdd2 100644 --- a/mesonbuild/compilers/mixins/gnu.py +++ b/mesonbuild/compilers/mixins/gnu.py @@ -84,7 +84,7 @@ gnu_color_args = { @functools.lru_cache(maxsize=None) -def gnulike_default_include_dirs(compiler: T.Tuple[str], lang: str) -> T.List[str]: +def gnulike_default_include_dirs(compiler: T.Tuple[str], lang: mesonlib.Language) -> T.List[str]: lang_map = { 'c': 'c', 'cpp': 'c++', diff --git a/mesonbuild/compilers/mixins/pgi.py b/mesonbuild/compilers/mixins/pgi.py index 77a7a28c5..e5df38ec2 100644 --- a/mesonbuild/compilers/mixins/pgi.py +++ b/mesonbuild/compilers/mixins/pgi.py @@ -18,6 +18,7 @@ import typing as T import os from pathlib import Path +from ...mesonlib import Language from ..compilers import clike_debug_args, clike_optimization_args pgi_buildtype_args = { @@ -87,7 +88,7 @@ class PGICompiler: def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: # PGI supports PCH for C++ only. hdr = Path(pch_dir).resolve().parent / header - if self.language == 'cpp': + if self.language == Language.CPP: return ['--pch', '--pch_dir', str(hdr.parent), '-I{}'.format(hdr.parent)] diff --git a/mesonbuild/compilers/objc.py b/mesonbuild/compilers/objc.py index 52d258dcd..b042bc50c 100644 --- a/mesonbuild/compilers/objc.py +++ b/mesonbuild/compilers/objc.py @@ -15,7 +15,7 @@ import os.path, subprocess import typing as T -from ..mesonlib import EnvironmentException, MachineChoice +from ..mesonlib import EnvironmentException, Language, MachineChoice from .compilers import Compiler from .mixins.clike import CLikeCompiler @@ -28,7 +28,7 @@ if T.TYPE_CHECKING: class ObjCCompiler(CLikeCompiler, Compiler): - language = 'objc' + language = Language.OBJC def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', diff --git a/mesonbuild/compilers/objcpp.py b/mesonbuild/compilers/objcpp.py index c8b422b35..4cfb1ab7f 100644 --- a/mesonbuild/compilers/objcpp.py +++ b/mesonbuild/compilers/objcpp.py @@ -15,7 +15,7 @@ import os.path, subprocess import typing as T -from ..mesonlib import EnvironmentException, MachineChoice +from ..mesonlib import EnvironmentException, Language, MachineChoice from .mixins.clike import CLikeCompiler from .compilers import Compiler @@ -27,7 +27,7 @@ if T.TYPE_CHECKING: class ObjCPPCompiler(CLikeCompiler, Compiler): - language = 'objcpp' + language = Language.OBJCPP def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py index c2e21c4ab..46832c5d5 100644 --- a/mesonbuild/compilers/rust.py +++ b/mesonbuild/compilers/rust.py @@ -15,7 +15,7 @@ import subprocess, os.path import typing as T -from ..mesonlib import EnvironmentException, MachineChoice, Popen_safe +from ..mesonlib import EnvironmentException, Language, MachineChoice, Popen_safe from .compilers import Compiler, rust_buildtype_args, clike_debug_args if T.TYPE_CHECKING: @@ -33,7 +33,7 @@ rust_optimization_args = {'0': [], class RustCompiler(Compiler): # rustc doesn't invoke the compiler itself, it doesn't need a LINKER_PREFIX - language = 'rust' + language = Language.RUST def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): diff --git a/mesonbuild/compilers/swift.py b/mesonbuild/compilers/swift.py index 1942120c7..c7d00412c 100644 --- a/mesonbuild/compilers/swift.py +++ b/mesonbuild/compilers/swift.py @@ -15,7 +15,7 @@ import subprocess, os.path import typing as T -from ..mesonlib import EnvironmentException, MachineChoice +from ..mesonlib import EnvironmentException, Language, MachineChoice from .compilers import Compiler, swift_buildtype_args, clike_debug_args @@ -33,7 +33,7 @@ swift_optimization_args = {'0': [], class SwiftCompiler(Compiler): LINKER_PREFIX = ['-Xlinker'] - language = 'swift' + language = Language.SWIFT def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', **kwargs): diff --git a/mesonbuild/compilers/vala.py b/mesonbuild/compilers/vala.py index a5d49b6ac..635cce39d 100644 --- a/mesonbuild/compilers/vala.py +++ b/mesonbuild/compilers/vala.py @@ -16,7 +16,7 @@ import os.path import typing as T from .. import mlog -from ..mesonlib import EnvironmentException, MachineChoice, version_compare +from ..mesonlib import EnvironmentException, Language, MachineChoice, version_compare from .compilers import Compiler @@ -25,7 +25,7 @@ if T.TYPE_CHECKING: class ValaCompiler(Compiler): - language = 'vala' + language = Language.VALA def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo'): diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 0b790849f..8d043aa00 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -19,7 +19,7 @@ from itertools import chain from pathlib import PurePath from collections import OrderedDict, defaultdict from .mesonlib import ( - MesonException, MachineChoice, PerMachine, OrderedSet, + Language, MesonException, MachineChoice, PerMachine, OrderedSet, default_libdir, default_libexecdir, default_prefix, split_args ) from .envconfig import get_env_var_pair @@ -373,7 +373,7 @@ class CoreData: self.compiler_options = PerMachine( defaultdict(dict), defaultdict(dict), - ) # : PerMachine[T.defaultdict[str, OptionDictType]] + ) # : PerMachine[T.defaultdict[Language, OptionDictType]] self.base_options = {} # : OptionDictType self.cross_files = self.__load_config_files(options, scratch_dir, 'cross') self.compilers = PerMachine(OrderedDict(), OrderedDict()) @@ -623,29 +623,41 @@ class CoreData: options_per_machine # : PerMachine[T.Dict[str, _V]]] ) -> T.Iterable[T.Tuple[str, _V]]: return cls._flatten_pair_iterator( - (for_machine.get_prefix(), options_per_machine[for_machine]) + (for_machine.get_prefix(), options_per_machine[for_machine].items()) for for_machine in iter(MachineChoice) ) @classmethod def flatten_lang_iterator( cls, - outer # : T.Iterable[T.Tuple[str, T.Dict[str, _V]]] + outer # : T.Iterable[T.Tuple[Language, T.Dict[str, V]]] ) -> T.Iterable[T.Tuple[str, _V]]: - return cls._flatten_pair_iterator((lang + '_', opts) for lang, opts in outer) + return cls._flatten_pair_iterator( + (lang.get_lower_case_name() + '_', inner.items()) + for lang, inner in outer + ) + + @classmethod + def flatten_lang_iterator_per_machine( + cls, + outer # : PerMachine[Dict[Language, T.Dict[str, V]]] + ) -> T.Iterable[T.Tuple[str, _V]]: + self.get_prefixed_options_per_machine( + self.compiler_options.map(lambda opts_per_lang: + self.flatten_lang_iterator(opts_per_lang))) @staticmethod def _flatten_pair_iterator( - outer # : T.Iterable[T.Tuple[str, T.Dict[str, _V]]] + outer # : T.Iterable[T.Tuple[str, T.Iterable[T.Tuple[str, _V]]]] ) -> T.Iterable[T.Tuple[str, _V]]: for k0, v0 in outer: - for k1, v1 in v0.items(): + for k1, v1 in v0: yield (k0 + k1, v1) def _get_all_nonbuiltin_options(self) -> T.Iterable[T.Dict[str, UserOption]]: yield self.backend_options yield self.user_options - yield dict(self.flatten_lang_iterator(self.get_prefixed_options_per_machine(self.compiler_options))) + yield dict(flatten_lang_iterator_per_machine(self.compiler_options)) yield self.base_options def _get_all_builtin_options(self) -> T.Iterable[T.Dict[str, UserOption]]: @@ -667,10 +679,10 @@ class CoreData: .with_traceback(sys.exc_info()[2]) raise MesonException('Tried to validate unknown option %s.' % option_name) - def get_external_args(self, for_machine: MachineChoice, lang): + def get_external_args(self, for_machine: MachineChoice, lang: Language): return self.compiler_options[for_machine][lang]['args'].value - def get_external_link_args(self, for_machine: MachineChoice, lang): + def get_external_link_args(self, for_machine: MachineChoice, lang: Language): return self.compiler_options[for_machine][lang]['link_args'].value def merge_user_options(self, options): @@ -821,7 +833,7 @@ class CoreData: self.set_options(options, subproject=subproject) - def add_lang_args(self, lang: str, comp: T.Type['Compiler'], + def add_lang_args(self, lang: Language, comp: T.Type['Compiler'], for_machine: MachineChoice, env: 'Environment') -> None: """Add global language arguments that are needed before compiler/linker detection.""" from .compilers import compilers @@ -834,12 +846,12 @@ class CoreData: env.properties[for_machine]).items(): # prefixed compiler options affect just this machine opt_prefix = for_machine.get_prefix() - user_k = opt_prefix + lang + '_' + k + user_k = opt_prefix + lang.get_lower_case_name() + '_' + k if user_k in env.cmd_line_options: o.set_value(env.cmd_line_options[user_k]) self.compiler_options[for_machine][lang].setdefault(k, o) - def process_new_compiler(self, lang: str, comp: T.Type['Compiler'], env: 'Environment') -> None: + def process_new_compiler(self, lang: Language, comp: T.Type['Compiler'], env: 'Environment') -> None: from . import compilers self.compilers[comp.for_machine][lang] = comp @@ -848,7 +860,7 @@ class CoreData: for k, o in comp.get_options().items(): # prefixed compiler options affect just this machine opt_prefix = comp.for_machine.get_prefix() - user_k = opt_prefix + lang + '_' + k + user_k = opt_prefix + lang.get_lower_case_name() + '_' + k if user_k in env.cmd_line_options: o.set_value(env.cmd_line_options[user_k]) self.compiler_options[comp.for_machine][lang].setdefault(k, o) diff --git a/mesonbuild/envconfig.py b/mesonbuild/envconfig.py index 25b3c7ffa..327d3fab4 100644 --- a/mesonbuild/envconfig.py +++ b/mesonbuild/envconfig.py @@ -152,13 +152,13 @@ class Properties: self.properties = properties or {} # type: T.Dict[str, T.Union[str, T.List[str]]] def has_stdlib(self, language: str) -> bool: - return language + '_stdlib' in self.properties + return language.get_lower_case_name() + '_stdlib' in self.properties # Some of get_stdlib, get_root, get_sys_root are wider than is actually # true, but without heterogenious dict annotations it's not practical to # narrow them def get_stdlib(self, language: str) -> T.Union[str, T.List[str]]: - return self.properties[language + '_stdlib'] + return self.properties[language.get_lower_case_name() + '_stdlib'] def get_root(self) -> T.Optional[T.Union[str, T.List[str]]]: return self.properties.get('root', None) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 64efda62e..18b777338 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -21,7 +21,7 @@ from . import coredata from .linkers import ArLinker, ArmarLinker, VisualStudioLinker, DLinker, CcrxLinker, Xc16Linker, C2000Linker, IntelVisualStudioLinker from . import mesonlib from .mesonlib import ( - MesonException, EnvironmentException, MachineChoice, Popen_safe, + MesonException, EnvironmentException, Language, MachineChoice, Popen_safe, PerMachineDefaultable, PerThreeMachineDefaultable, split_args, quote_arg ) from . import mlog @@ -774,7 +774,7 @@ class Environment: check_args += self.coredata.compiler_options[for_machine][comp_class.language]['args'].value override = [] # type: T.List[str] - value = self.lookup_binary_entry(for_machine, comp_class.language + '_ld') + value = self.lookup_binary_entry(for_machine, comp_class.language.get_lower_case_name() + '_ld') if value is not None: override = comp_class.use_linker_args(value[0]) check_args += override @@ -841,7 +841,7 @@ class Environment: check_args = comp_class.LINKER_PREFIX + ['--version'] + extra_args override = [] # type: T.List[str] - value = self.lookup_binary_entry(for_machine, comp_class.language + '_ld') + value = self.lookup_binary_entry(for_machine, comp_class.language.get_lower_case_name() + '_ld') if value is not None: override = comp_class.use_linker_args(value[0]) check_args += override @@ -896,7 +896,7 @@ class Environment: raise EnvironmentException('Unable to determine dynamic linker') return linker - def _detect_c_or_cpp_compiler(self, lang: str, for_machine: MachineChoice) -> Compiler: + def _detect_c_or_cpp_compiler(self, lang: Language, for_machine: MachineChoice) -> Compiler: popen_exceptions = {} compilers, ccache, exe_wrap = self._get_compilers(lang, for_machine) is_cross = not self.machines.matches_build_machine(for_machine) @@ -1623,7 +1623,7 @@ class Environment: raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') - def compiler_from_language(self, lang: str, for_machine: MachineChoice): + def compiler_from_language(self, lang: Language, for_machine: MachineChoice): if lang == 'c': comp = self.detect_c_compiler(for_machine) elif lang == 'cpp': @@ -1652,7 +1652,7 @@ class Environment: comp = None return comp - def detect_compiler_for(self, lang: str, for_machine: MachineChoice): + def detect_compiler_for(self, lang: Language, for_machine: MachineChoice): comp = self.compiler_from_language(lang, for_machine) if comp is not None: assert comp.for_machine == for_machine diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 48b6bd6e9..fb606ca4d 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -2802,8 +2802,7 @@ external dependencies (including libraries) must go to "dependencies".''') for opts in [ self.coredata.base_options, compilers.base_options, self.coredata.builtins, dict(self.coredata.get_prefixed_options_per_machine(self.coredata.builtins_per_machine)), - dict(self.coredata.flatten_lang_iterator( - self.coredata.get_prefixed_options_per_machine(self.coredata.compiler_options))), + dict(self.coredata.flatten_lang_iterator_per_machine(self.coredata.compiler_options)), ]: v = opts.get(optname) if v is None or v.yielding: diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index 05e9518ff..6c450daef 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -216,9 +216,9 @@ class Conf: self.coredata.flatten_lang_iterator( self.coredata.compiler_options.host.items())) build_compiler_options = self.split_options_per_subproject( - self.coredata.flatten_lang_iterator( - (insert_build_prefix(k), o) - for k, o in self.coredata.compiler_options.build.items())) + (insert_build_prefix(k), o) + for k, o in self.coredata.flatten_lang_iterator( + self.coredata.compiler_options.build.items())) project_options = self.split_options_per_subproject(self.coredata.user_options.items()) show_build_options = self.default_values_only or self.build.environment.is_cross_build() diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index 6c1e4668b..0ce3df1c9 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -14,6 +14,7 @@ """A library of random helper functionality.""" from pathlib import Path +import copy import sys import stat import time @@ -373,6 +374,12 @@ class PerMachine(T.Generic[_T]): def __setitem__(self, machine: MachineChoice, val: _T) -> None: setattr(self, machine.get_lower_case_name(), val) + def map(self, fun): + return PerMachine( + fun(self.build), + fun(self.host), + ) + def miss_defaulting(self) -> "PerMachineDefaultable[T.Optional[_T]]": """Unset definition duplicated from their previous to None @@ -459,6 +466,59 @@ class PerThreeMachineDefaultable(PerMachineDefaultable, PerThreeMachine[T.Option return freeze +class Language(Enum): + + """Enum class representing the languages Meson supports. + """ + + # Alphabetized for now, but order comparisons explicitly disallowed so it + # shouldn't matter. + C = 0 + CPP = 1 + CS = 2 + CUDA = 3 + D = 4 + FORTRAN = 5 + JAVA = 6 + OBJC = 7 + OBJCPP = 8 + RUST = 9 + SWIFT = 10 + VALA = 11 + + def get_lower_case_name(self) -> str: + return { + Language.C: 'c', + Language.CPP: 'cpp', + Language.CS: 'cs', + Language.CUDA: 'cuda', + Language.D: 'd', + Language.FORTRAN: 'fortran', + Language.JAVA: 'java', + Language.OBJC: 'objc', + Language.OBJCPP: 'objcpp', + Language.RUST: 'rust', + Language.SWIFT: 'swift', + Language.VALA: 'vala', + }[self] + + @staticmethod + def from_lower_case_name(lang_name: str) -> Language: + return { + 'c': Language.C, + 'cpp': Language.CPP, + 'cs': Language.CS, + 'cuda': Language.CUDA, + 'd': Language.D, + 'fortran': Language.FORTRAN, + 'java': Language.JAVA, + 'objc': Language.OBJC, + 'objcpp': Language.OBJCPP, + 'rust': Language.RUST, + 'swift': Language.SWIFT, + 'vala': Language.VALA, + }[lang_name] + def is_sunos() -> bool: return platform.system().lower() == 'sunos' diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py index c13cc5da3..c3cf1d89d 100644 --- a/mesonbuild/optinterpreter.py +++ b/mesonbuild/optinterpreter.py @@ -22,7 +22,7 @@ from . import mesonlib from . import compilers forbidden_option_names = set(coredata.builtin_options.keys()) -forbidden_prefixes = [lang + '_' for lang in compilers.all_languages] + ['b_', 'backend_'] +forbidden_prefixes = [lang.get_lower_case_name() + '_' for lang in compilers.all_languages] + ['b_', 'backend_'] reserved_prefixes = ['cross_'] def is_invalid_name(name: str, *, log: bool = True) -> bool: diff --git a/run_unittests.py b/run_unittests.py index 831e53fdc..e427ee969 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -53,7 +53,7 @@ import mesonbuild.modules.gnome from mesonbuild.interpreter import Interpreter, ObjectHolder from mesonbuild.ast import AstInterpreter from mesonbuild.mesonlib import ( - BuildDirLock, LibType, MachineChoice, PerMachine, Version, is_windows, + BuildDirLock, Language, LibType, MachineChoice, PerMachine, Version, is_windows, is_osx, is_cygwin, is_dragonflybsd, is_openbsd, is_haiku, is_sunos, windows_proof_rmtree, python_command, version_compare, split_args, quote_arg, relpath