diff options
author | Dylan Baker <dylan@pnwbakers.com> | 2020-12-02 16:02:03 -0800 |
---|---|---|
committer | Dylan Baker <dylan@pnwbakers.com> | 2021-01-04 12:20:39 -0800 |
commit | fe973d9fc45581f20fefc41fc0b8eb0066c0129d (patch) | |
tree | cbf7f5bd779ddae1655c9644ef96c4df66e67ee3 | |
parent | bdca05e2e66abbd872c17b8226641a2b8d018112 (diff) | |
download | meson-fe973d9fc45581f20fefc41fc0b8eb0066c0129d.zip meson-fe973d9fc45581f20fefc41fc0b8eb0066c0129d.tar.gz meson-fe973d9fc45581f20fefc41fc0b8eb0066c0129d.tar.bz2 |
use OptionKey for compiler_options
26 files changed, 382 insertions, 317 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index b9f175a..4c35253 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -36,6 +36,8 @@ from ..mesonlib import ( ) if T.TYPE_CHECKING: + from ..arglist import CompilerArgs + from ..compilers import Compiler from ..interpreter import Interpreter, Test @@ -214,13 +216,10 @@ class Backend: self.environment.coredata.builtins, self.environment.coredata.base_options) - def get_compiler_options_for_target(self, target): - comp_reg = self.environment.coredata.compiler_options[target.for_machine] + def get_compiler_options_for_target(self, target: build.BuildTarget) -> OptionOverrideProxy: + comp_reg = self.environment.coredata.compiler_options comp_override = target.option_overrides_compiler - return { - lang: OptionOverrideProxy(comp_override[lang], comp_reg[lang]) - for lang in set(comp_reg.keys()) | set(comp_override.keys()) - } + return OptionOverrideProxy(comp_override, comp_reg) def get_option_for_target(self, option_name, target): if option_name in target.option_overrides_base: @@ -672,13 +671,13 @@ class Backend: return extra_args - def generate_basic_compiler_args(self, target, compiler, no_warn_args=False): + def generate_basic_compiler_args(self, target: build.BuildTarget, compiler: 'Compiler', no_warn_args: bool = False) -> 'CompilerArgs': # Create an empty commands list, and start adding arguments from # various sources in the order in which they must override each other # starting from hard-coded defaults followed by build options and so on. commands = compiler.compiler_args() - copt_proxy = self.get_compiler_options_for_target(target)[compiler.language] + copt_proxy = self.get_compiler_options_for_target(target) # First, the trivial ones that are impossible to override. # # Add -nostdinc/-nostdinc++ if needed; can't be overridden diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 836cd5b..39e0645 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -49,6 +49,9 @@ from ..build import InvalidArguments from ..interpreter import Interpreter from ..coredata import OptionKey +if T.TYPE_CHECKING: + from ..linkers import StaticLinker + FORTRAN_INCLUDE_PAT = r"^\s*#?include\s*['\"](\w+\.\w+)['\"]" FORTRAN_MODULE_PAT = r"^\s*\bmodule\b\s+(\w+)\s*(?:!+.*)*$" FORTRAN_SUBMOD_PAT = r"^\s*\bsubmodule\b\s*\((\w+:?\w+)\)\s*(\w+)" @@ -891,7 +894,7 @@ int dummy; cpp = target.compilers['cpp'] if cpp.get_id() != 'msvc': return False - if self.environment.coredata.compiler_options[target.for_machine]['cpp']['std'] != 'c++latest': + if self.environment.coredata.compiler_options[OptionKey('std', machine=target.for_machine, lang='cpp')] != 'latest': return False if not mesonlib.current_vs_supports_modules(): return False @@ -1614,7 +1617,7 @@ int dummy; for a in rustc.linker.get_always_args(): args += ['-C', 'link-arg={}'.format(a)] - opt_proxy = self.get_compiler_options_for_target(target)[rustc.language] + opt_proxy = self.get_compiler_options_for_target(target) args += ['--crate-name', target.name] args += rustc.get_buildtype_args(self.get_option_for_target('buildtype', target)) @@ -2832,7 +2835,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) self.add_build(elem) return [prelink_name] - def generate_link(self, target, outname, obj_list, linker, extra_args=None, stdlib_args=None): + def generate_link(self, target: build.BuildTarget, outname, obj_list, linker: T.Union['Compiler', 'StaticLinker'], extra_args=None, stdlib_args=None): extra_args = extra_args if extra_args is not None else [] stdlib_args = stdlib_args if stdlib_args is not None else [] implicit_outs = [] @@ -2929,14 +2932,14 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) # to be after all internal and external libraries so that unresolved # symbols from those can be found here. This is needed when the # *_winlibs that we want to link to are static mingw64 libraries. - if hasattr(linker, 'get_language'): + if isinstance(linker, Compiler): # The static linker doesn't know what language it is building, so we # don't know what option. Fortunately, it doesn't care to see the # language-specific options either. # # We shouldn't check whether we are making a static library, because # in the LTO case we do use a real compiler here. - commands += linker.get_option_link_args(self.environment.coredata.compiler_options[target.for_machine][linker.get_language()]) + commands += linker.get_option_link_args(self.environment.coredata.compiler_options) dep_targets = [] dep_targets.extend(self.guess_external_link_dependencies(linker, target, commands, internal)) diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index 59a5ed4..f893e8f 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -879,7 +879,7 @@ class Vs2010Backend(backends.Backend): # Exception handling has to be set in the xml in addition to the "AdditionalOptions" because otherwise # cl will give warning D9025: overriding '/Ehs' with cpp_eh value if 'cpp' in target.compilers: - eh = self.environment.coredata.compiler_options[target.for_machine]['cpp']['eh'] + eh = self.environment.coredata.compiler_options[OptionKey('eh', machine=target.for_machine, lang='cpp')] if eh.value == 'a': ET.SubElement(clconf, 'ExceptionHandling').text = 'Async' elif eh.value == 's': @@ -927,7 +927,7 @@ class Vs2010Backend(backends.Backend): file_args[l] += compilers.get_base_compile_args( self.get_base_options_for_target(target), comp) file_args[l] += comp.get_option_compile_args( - self.environment.coredata.compiler_options[target.for_machine][comp.language]) + self.environment.coredata.compiler_options) # Add compile args added using add_project_arguments() for l, args in self.build.projects_args[target.for_machine].get(target.subproject, {}).items(): @@ -941,10 +941,8 @@ class Vs2010Backend(backends.Backend): # Compile args added from the env or cross file: CFLAGS/CXXFLAGS, etc. We want these # to override all the defaults, but not the per-target compile args. for l in file_args.keys(): - opts = self.environment.coredata.compiler_options[target.for_machine][l] - k = 'args' - if k in opts: - file_args[l] += opts[k].value + opts = self.environment.coredata.compiler_options[OptionKey('args', machine=target.for_machine, lang=l)] + file_args[l] += opts.value for args in file_args.values(): # This is where Visual Studio will insert target_args, target_defines, # etc, which are added later from external deps (see below). diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 091bfc8..3b7e10d 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -36,8 +36,10 @@ from .compilers import ( ) from .linkers import StaticLinker from .interpreterbase import FeatureNew +from .coredata import OptionKey if T.TYPE_CHECKING: + from .coredata import KeyedOptionDictType, OptionDictType from .interpreter import Test from .mesonlib import FileMode, FileOrString @@ -415,8 +417,8 @@ a hard error in the future.'''.format(name)) self.for_machine = for_machine self.install = False self.build_always_stale = False - self.option_overrides_base = {} - self.option_overrides_compiler = defaultdict(dict) + self.option_overrides_base: 'OptionDictType' = {} + self.option_overrides_compiler: 'KeyedOptionDictType' = {} self.extra_files = [] # type: T.List[File] if not hasattr(self, 'typename'): raise RuntimeError('Target type is not set for target class "{}". This is a bug'.format(type(self).__name__)) @@ -511,9 +513,9 @@ a hard error in the future.'''.format(name)) for k, v in option_overrides.items(): if '_' in k: - lang, k2 = k.split('_', 1) - if lang in all_languages: - self.option_overrides_compiler[lang][k2] = v + key = OptionKey.from_string(k) + if key.lang: + self.option_overrides_compiler[key.evolve(machine=self.for_machine)] = v continue self.option_overrides_base[k] = v diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py index d4f7fba..6125f15 100644 --- a/mesonbuild/cmake/interpreter.py +++ b/mesonbuild/cmake/interpreter.py @@ -31,6 +31,7 @@ from pathlib import Path import typing as T import re from os import environ +from ..coredata import OptionKey from ..mparser import ( Token, @@ -577,10 +578,10 @@ class ConverterTarget: @lru_cache(maxsize=None) def _all_lang_stds(self, lang: str) -> T.List[str]: - lang_opts = self.env.coredata.compiler_options.build.get(lang, None) - if not lang_opts or 'std' not in lang_opts: + try: + res = self.env.coredata.compiler_options[OptionKey('std', machine=MachineChoice.BUILD, lang=lang)].choices # type: ignore + except KeyError: return [] - res = lang_opts['std'].choices # TODO: Get rid of this once we have propper typing for options assert isinstance(res, list) diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 7340896..fe5f465 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -37,9 +37,10 @@ from .compilers import ( msvc_winlibs, Compiler, ) +from ..coredata import OptionKey if T.TYPE_CHECKING: - from ..coredata import OptionDictType + from ..coredata import KeyedOptionDictType from ..dependencies import Dependency, ExternalProgram from ..envconfig import MachineInfo from ..environment import Environment @@ -95,10 +96,10 @@ class CCompiler(CLikeCompiler, Compiler): return self.compiles(t.format(**fargs), env, extra_args=extra_args, dependencies=dependencies) - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = super().get_options() opts.update({ - 'std': coredata.UserComboOption( + OptionKey('std', machine=self.for_machine, lang=self.language): coredata.UserComboOption( 'C langauge standard to use', ['none'], 'none', @@ -119,7 +120,7 @@ class _ClangCStds(CompilerMixinBase): _C18_VERSION = '>=8.0.0' _C2X_VERSION = '>=9.0.0' - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = super().get_options() c_stds = ['c89', 'c99', 'c11'] g_stds = ['gnu89', 'gnu99', 'gnu11'] @@ -134,7 +135,7 @@ class _ClangCStds(CompilerMixinBase): if version_compare(self.version, self._C2X_VERSION): c_stds += ['c2x'] g_stds += ['gnu2x'] - opts['std'].choices = ['none'] + c_stds + g_stds + opts[OptionKey('std', machine=self.for_machine, lang=self.language)].choices = ['none'] + c_stds + g_stds return opts @@ -153,28 +154,28 @@ class ClangCCompiler(_ClangCStds, ClangCompiler, CCompiler): '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = super().get_options() if self.info.is_windows() or self.info.is_cygwin(): opts.update({ - 'winlibs': coredata.UserArrayOption( + OptionKey('winlibs', machine=self.for_machine, lang=self.language): coredata.UserArrayOption( 'Standard Win libraries to link against', gnu_winlibs, ), }) return opts - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - std = options['std'] + std = options[OptionKey('std', machine=self.for_machine, lang=self.language)] if std.value != 'none': args.append('-std=' + std.value) return args - def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: if self.info.is_windows() or self.info.is_cygwin(): # without a typedict mypy can't understand this. - libs = options['winlibs'].value.copy() + libs = options[OptionKey('winlibs', machine=self.for_machine, lang=self.language)].value.copy() assert isinstance(libs, list) for l in libs: assert isinstance(l, str) @@ -223,19 +224,20 @@ class ArmclangCCompiler(ArmclangCompiler, CCompiler): '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = CCompiler.get_options(self) - opts['std'].choices = ['none', 'c90', 'c99', 'c11', 'gnu90', 'gnu99', 'gnu11'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + opts[key].choices = ['none', 'c90', 'c99', 'c11', 'gnu90', 'gnu99', 'gnu11'] return opts - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - std = options['std'] + std = options[OptionKey('std', machine=self.for_machine, lang=self.language)] if std.value != 'none': args.append('-std=' + std.value) return args - def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return [] @@ -257,7 +259,7 @@ class GnuCCompiler(GnuCompiler, CCompiler): '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = CCompiler.get_options(self) c_stds = ['c89', 'c99', 'c11'] g_stds = ['gnu89', 'gnu99', 'gnu11'] @@ -267,27 +269,28 @@ class GnuCCompiler(GnuCompiler, CCompiler): if version_compare(self.version, self._C2X_VERSION): c_stds += ['c2x'] g_stds += ['gnu2x'] - opts['std'].choices = ['none'] + c_stds + g_stds + key = OptionKey('std', machine=self.for_machine, lang=self.language) + opts[key].choices = ['none'] + c_stds + g_stds if self.info.is_windows() or self.info.is_cygwin(): opts.update({ - 'winlibs': coredata.UserArrayOption( + key.evolve('winlibs'): coredata.UserArrayOption( 'Standard Win libraries to link against', gnu_winlibs, ), }) return opts - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - std = options['std'] + std = options[OptionKey('std', lang=self.language, machine=self.for_machine)] if std.value != 'none': args.append('-std=' + std.value) return args - def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: if self.info.is_windows() or self.info.is_cygwin(): # without a typeddict mypy can't figure this out - libs = options['winlibs'].value.copy() + libs: T.List[str] = options[OptionKey('winlibs', lang=self.language, machine=self.for_machine)].value.copy() assert isinstance(libs, list) for l in libs: assert isinstance(l, str) @@ -331,9 +334,9 @@ class ElbrusCCompiler(GnuCCompiler, ElbrusCompiler): 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) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = CCompiler.get_options(self) - opts['std'].choices = [ + opts[OptionKey('std', machine=self.for_machine, lang=self.language)].choices = [ 'none', 'c89', 'c90', 'c9x', 'c99', 'c1x', 'c11', 'gnu89', 'gnu90', 'gnu9x', 'gnu99', 'gnu1x', 'gnu11', 'iso9899:2011', 'iso9899:1990', 'iso9899:199409', 'iso9899:1999', @@ -368,18 +371,18 @@ class IntelCCompiler(IntelGnuLikeCompiler, CCompiler): '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra']} - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = CCompiler.get_options(self) c_stds = ['c89', 'c99'] g_stds = ['gnu89', 'gnu99'] if version_compare(self.version, '>=16.0.0'): c_stds += ['c11'] - opts['std'].choices = ['none'] + c_stds + g_stds + opts[OptionKey('std', machine=self.for_machine, lang=self.language)].choices = ['none'] + c_stds + g_stds return opts - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - std = options['std'] + std = options[OptionKey('std', machine=self.for_machine, lang=self.language)] if std.value != 'none': args.append('-std=' + std.value) return args @@ -389,19 +392,20 @@ class VisualStudioLikeCCompilerMixin(CompilerMixinBase): """Shared methods that apply to MSVC-like C compilers.""" - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = super().get_options() opts.update({ - 'winlibs': coredata.UserArrayOption( + OptionKey('winlibs', machine=self.for_machine, lang=self.language): coredata.UserArrayOption( 'Windows libs to link against.', msvc_winlibs, ), }) return opts - def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: # need a TypeDict to make this work - libs = options['winlibs'].value.copy() + key = OptionKey('winlibs', machine=self.for_machine, lang=self.language) + libs = options[key].value.copy() assert isinstance(libs, list) for l in libs: assert isinstance(l, str) @@ -423,7 +427,7 @@ class VisualStudioCCompiler(MSVCCompiler, VisualStudioLikeCCompilerMixin, CCompi full_version=full_version) MSVCCompiler.__init__(self, target) - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = super().get_options() c_stds = ['c89', 'c99'] # Need to have these to be compatible with projects @@ -436,12 +440,13 @@ class VisualStudioCCompiler(MSVCCompiler, VisualStudioLikeCCompilerMixin, CCompi if version_compare(self.version, self._C17_VERSION): c_stds += ['c17', 'c18'] g_stds += ['gnu17', 'gnu18'] - opts['std'].choices = ['none'] + c_stds + g_stds + key = OptionKey('std', machine=self.for_machine, lang=self.language) + opts[key].choices = ['none'] + c_stds + g_stds return opts - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - std = options['std'] + std = options[OptionKey('std', machine=self.for_machine, lang=self.language)] if std.value.startswith('gnu'): mlog.log_once( 'cl.exe does not actually support gnu standards, and meson ' @@ -466,8 +471,9 @@ class ClangClCCompiler(_ClangCStds, ClangClCompiler, VisualStudioLikeCCompilerMi full_version=full_version) ClangClCompiler.__init__(self, target) - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: - std = options['std'].value + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: + key = OptionKey('std', machine=self.for_machine, lang=self.language) + std = options[key].value if std != "none": return ['/clang:-std={}'.format(std)] return [] @@ -487,14 +493,16 @@ class IntelClCCompiler(IntelVisualStudioLikeCompiler, VisualStudioLikeCCompilerM full_version=full_version) IntelVisualStudioLikeCompiler.__init__(self, target) - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = super().get_options() - opts['std'].choices = ['none', 'c89', 'c99', 'c11'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + opts[key].choices = ['none', 'c89', 'c99', 'c11'] return opts - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - std = options['std'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + std = options[key] if std.value == 'c89': mlog.log_once("ICL doesn't explicitly implement c89, setting the standard to 'none', which is close.") elif std.value != 'none': @@ -513,14 +521,16 @@ class ArmCCompiler(ArmCompiler, CCompiler): full_version=full_version) ArmCompiler.__init__(self) - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = CCompiler.get_options(self) - opts['std'].choices = ['none', 'c89', 'c99', 'c11'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + opts[key].choices = ['none', 'c89', 'c99', 'c11'] return opts - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - std = options['std'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + std = options[key] if std.value != 'none': args.append('--' + std.value) return args @@ -540,17 +550,19 @@ class CcrxCCompiler(CcrxCompiler, CCompiler): def get_always_args(self) -> T.List[str]: return ['-nologo'] - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = CCompiler.get_options(self) - opts['std'].choices = ['none', 'c89', 'c99'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + opts[key].choices = ['none', 'c89', 'c99'] return opts def get_no_stdinc_args(self) -> T.List[str]: return [] - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - std = options['std'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + std = options[key] if std.value == 'c89': args.append('-lang=c') elif std.value == 'c99': @@ -585,17 +597,19 @@ class Xc16CCompiler(Xc16Compiler, CCompiler): info, exe_wrapper, linker=linker, full_version=full_version) Xc16Compiler.__init__(self) - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = CCompiler.get_options(self) - opts['std'].choices = ['none', 'c89', 'c99', 'gnu89', 'gnu99'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + opts[key].choices = ['none', 'c89', 'c99', 'gnu89', 'gnu99'] return opts def get_no_stdinc_args(self) -> T.List[str]: return [] - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - std = options['c_std'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + std = options[key] if std.value != 'none': args.append('-ansi') args.append('-std=' + std.value) @@ -628,12 +642,13 @@ class CompCertCCompiler(CompCertCompiler, CCompiler): info, exe_wrapper, linker=linker, full_version=full_version) CompCertCompiler.__init__(self) - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = CCompiler.get_options(self) - opts['std'].choices = ['none', 'c89', 'c99'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + opts[key].choices = ['none', 'c89', 'c99'] return opts - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return [] def get_no_optimization_args(self) -> T.List[str]: @@ -664,17 +679,19 @@ class C2000CCompiler(C2000Compiler, CCompiler): def get_always_args(self) -> T.List[str]: return [] - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = CCompiler.get_options(self) - opts['std'].choices = ['none', 'c89', 'c99', 'c11'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + opts[key].choices = ['none', 'c89', 'c99', 'c11'] return opts def get_no_stdinc_args(self) -> T.List[str]: return [] - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - std = options['c_std'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + std = options[key] if std.value != 'none': args.append('--' + std.value) return args diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 0bd2b4c..acf3823 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -32,10 +32,11 @@ from ..envconfig import ( ) from ..arglist import CompilerArgs +from ..coredata import OptionKey if T.TYPE_CHECKING: from ..build import BuildTarget - from ..coredata import OptionDictType + from ..coredata import OptionDictType, KeyedOptionDictType from ..envconfig import MachineInfo from ..environment import Environment from ..linkers import DynamicLinker # noqa: F401 @@ -596,13 +597,13 @@ class Compiler(metaclass=abc.ABCMeta): is_cross: bool) -> T.List[str]: return self.linker.get_args_from_envvars(for_machine, is_cross) - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': return {} - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return [] - def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return self.linker.get_option_args(options) def check_header(self, hname: str, prefix: str, env: 'Environment', *, @@ -826,7 +827,7 @@ class Compiler(metaclass=abc.ABCMeta): def get_std_shared_lib_link_args(self) -> T.List[str]: return self.linker.get_std_shared_lib_args() - def get_std_shared_module_link_args(self, options: 'OptionDictType') -> T.List[str]: + def get_std_shared_module_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return self.linker.get_std_shared_module_args(options) def get_link_whole_for(self, args: T.List[str]) -> T.List[str]: @@ -1243,14 +1244,16 @@ def get_args_from_envvars(lang: str, def get_global_options(lang: str, comp: T.Type[Compiler], for_machine: MachineChoice, - is_cross: bool) -> 'OptionDictType': + is_cross: bool) -> 'KeyedOptionDictType': """Retreive options that apply to all compilers for a given language.""" description = 'Extra arguments passed to the {}'.format(lang) + argkey = OptionKey('args', lang=lang, machine=for_machine) + largkey = argkey.evolve('link_args') opts = { - 'args': coredata.UserArrayOption( + argkey: coredata.UserArrayOption( description + ' compiler', [], split_args=True, user_input=True, allow_dups=True), - 'link_args': coredata.UserArrayOption( + largkey: coredata.UserArrayOption( description + ' linker', [], split_args=True, user_input=True, allow_dups=True), } # type: OptionDictType @@ -1262,10 +1265,7 @@ def get_global_options(lang: str, is_cross, comp.INVOKES_LINKER) - for k, o in opts.items(): - if k == 'args': - o.set_value(compile_args) - elif k == 'link_args': - o.set_value(link_args) + opts[argkey].set_value(compile_args) + opts[largkey].set_value(link_args) return opts diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index 7577a54..578e362 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -41,8 +41,10 @@ from .mixins.elbrus import ElbrusCompiler from .mixins.pgi import PGICompiler from .mixins.emscripten import EmscriptenMixin +from ..coredata import OptionKey + if T.TYPE_CHECKING: - from ..coredata import OptionDictType + from ..coredata import KeyedOptionDictType from ..dependencies import Dependency, ExternalProgram from ..envconfig import MachineInfo from ..environment import Environment @@ -169,10 +171,11 @@ class CPPCompiler(CLikeCompiler, Compiler): raise MesonException('C++ Compiler does not support -std={}'.format(cpp_std)) - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = super().get_options() + key = OptionKey('std', machine=self.for_machine, lang=self.language) opts.update({ - 'std': coredata.UserComboOption( + key: coredata.UserComboOption( 'C++ language standard to use', ['none'], 'none', @@ -196,47 +199,50 @@ class ClangCPPCompiler(ClangCompiler, CPPCompiler): '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = CPPCompiler.get_options(self) + key = OptionKey('key', machine=self.for_machine, lang=self.language) opts.update({ - 'eh': coredata.UserComboOption( + key.evolve('eh'): coredata.UserComboOption( 'C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default', ), - 'rtti': coredata.UserBooleanOption('Enable RTTI', True), + key.evolve('rtti'): coredata.UserBooleanOption('Enable RTTI', True), }) - opts['std'].choices = [ + opts[key.evolve('std')].choices = [ 'none', 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'c++1z', 'c++2a', 'c++20', 'gnu++11', 'gnu++14', 'gnu++17', 'gnu++1z', 'gnu++2a', 'gnu++20', ] if self.info.is_windows() or self.info.is_cygwin(): opts.update({ - 'winlibs': coredata.UserArrayOption( + key.evolve('winlibs'): coredata.UserArrayOption( 'Standard Win libraries to link against', gnu_winlibs, ), }) return opts - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - std = options['std'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + std = options[key] if std.value != 'none': args.append(self._find_best_cpp_std(std.value)) - non_msvc_eh_options(options['eh'].value, args) + non_msvc_eh_options(options[key.evolve('eh')].value, args) - if not options['rtti'].value: + if not options[key.evolve('rtti')].value: args.append('-fno-rtti') return args - def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: if self.info.is_windows() or self.info.is_cygwin(): # without a typedict mypy can't understand this. - libs = options['winlibs'].value.copy() + key = OptionKey('winlibs', machine=self.for_machine, lang=self.language) + libs = options[key].value.copy() assert isinstance(libs, list) for l in libs: assert isinstance(l, str) @@ -265,9 +271,10 @@ class EmscriptenCPPCompiler(EmscriptenMixin, LinkerEnvVarsMixin, ClangCPPCompile defines=defines, full_version=full_version) self.id = 'emscripten' - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - std = options['std'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + std = options[key] if std.value != 'none': args.append(self._find_best_cpp_std(std.value)) return args @@ -287,32 +294,34 @@ class ArmclangCPPCompiler(ArmclangCompiler, CPPCompiler): '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = CPPCompiler.get_options(self) + key = OptionKey('std', machine=self.for_machine, lang=self.language) opts.update({ - 'eh': coredata.UserComboOption( + key.evolve('eh'): coredata.UserComboOption( 'C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default', ), }) - opts['std'].choices = [ + opts[key].choices = [ 'none', 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'gnu++98', 'gnu++03', 'gnu++11', 'gnu++14', 'gnu++17', ] return opts - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - std = options['std'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + std = options[key] if std.value != 'none': args.append('-std=' + std.value) - non_msvc_eh_options(options['eh'].value, args) + non_msvc_eh_options(options[key.evolve('eh')].value, args) return args - def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return [] @@ -331,53 +340,56 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler): '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': + key = OptionKey('std', machine=self.for_machine, lang=self.language) opts = CPPCompiler.get_options(self) opts.update({ - 'eh': coredata.UserComboOption( + key.evolve('eh'): coredata.UserComboOption( 'C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default', ), - 'rtti': coredata.UserBooleanOption('Enable RTTI', True), - 'debugstl': coredata.UserBooleanOption( + key.evolve('rtti'): coredata.UserBooleanOption('Enable RTTI', True), + key.evolve('debugstl'): coredata.UserBooleanOption( 'STL debug mode', False, ) }) - opts['std'].choices = [ + opts[key].choices = [ 'none', 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'c++1z', 'c++2a', 'c++20', 'gnu++03', 'gnu++11', 'gnu++14', 'gnu++17', 'gnu++1z', 'gnu++2a', 'gnu++20', ] if self.info.is_windows() or self.info.is_cygwin(): opts.update({ - 'winlibs': coredata.UserArrayOption( + key.evolve('winlibs'): coredata.UserArrayOption( 'Standard Win libraries to link against', gnu_winlibs, ), }) return opts - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - std = options['std'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + std = options[key] if std.value != 'none': args.append(self._find_best_cpp_std(std.value)) - non_msvc_eh_options(options['eh'].value, args) + non_msvc_eh_options(options[key.evolve('eh')].value, args) - if not options['rtti'].value: + if not options[key.evolve('rtti')].value: args.append('-fno-rtti') - if options['debugstl'].value: + if options[key.evolve('debugstl')].value: args.append('-D_GLIBCXX_DEBUG=1') return args - def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: if self.info.is_windows() or self.info.is_cygwin(): # without a typedict mypy can't understand this. - libs = options['winlibs'].value.copy() + key = OptionKey('winlibs', machine=self.for_machine, lang=self.language) + libs = options[key].value.copy() assert isinstance(libs, list) for l in libs: assert isinstance(l, str) @@ -424,7 +436,7 @@ class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler): full_version=full_version, defines=defines) ElbrusCompiler.__init__(self) - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = CPPCompiler.get_options(self) cpp_stds = [ @@ -438,18 +450,19 @@ class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler): if version_compare(self.version, '>=1.25.00'): cpp_stds += [ 'c++2a', 'gnu++2a' ] + key = OptionKey('std', machine=self.for_machine, lang=self.language) opts.update({ - 'eh': coredata.UserComboOption( + key.evolve('eh'): coredata.UserComboOption( 'C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default', ), - 'debugstl': coredata.UserBooleanOption( + key.evolve('debugstl'): coredata.UserBooleanOption( 'STL debug mode', False, ), }) - opts['std'].choices = cpp_stds + opts[key].choices = cpp_stds return opts # Elbrus C++ compiler does not have lchmod, but there is only linker warning, not compiler error. @@ -465,15 +478,16 @@ 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: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - std = options['std'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + std = options[key] if std.value != 'none': args.append(self._find_best_cpp_std(std.value)) - non_msvc_eh_options(options['eh'].value, args) + non_msvc_eh_options(options[key.evolve('eh')].value, args) - if options['debugstl'].value: + if options[key.evolve('debugstl')].value: args.append('-D_GLIBCXX_DEBUG=1') return args @@ -494,7 +508,7 @@ class IntelCPPCompiler(IntelGnuLikeCompiler, CPPCompiler): '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra']} - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': 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 @@ -511,36 +525,40 @@ class IntelCPPCompiler(IntelGnuLikeCompiler, CPPCompiler): if version_compare(self.version, '>=19.1.0'): c_stds += ['c++2a'] g_stds += ['gnu++2a'] + + + key = OptionKey('std', machine=self.for_machine, lang=self.language) opts.update({ - 'eh': coredata.UserComboOption( + key.evolve('eh'): coredata.UserComboOption( 'C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default', ), - 'rtti': coredata.UserBooleanOption('Enable RTTI', True), - 'debugstl': coredata.UserBooleanOption('STL debug mode', False), + key.evolve('rtti'): coredata.UserBooleanOption('Enable RTTI', True), + key.evolve('debugstl'): coredata.UserBooleanOption('STL debug mode', False), }) - opts['std'].choices = ['none'] + c_stds + g_stds + opts[key].choices = ['none'] + c_stds + g_stds return opts - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - std = options['std'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + std = options[key] if std.value != 'none': remap_cpp03 = { 'c++03': 'c++98', 'gnu++03': 'gnu++98' } args.append('-std=' + remap_cpp03.get(std.value, std.value)) - if options['eh'].value == 'none': + if options[key.evolve('eh')].value == 'none': args.append('-fno-exceptions') - if not options['rtti'].value: + if not options[key.evolve('rtti')].value: args.append('-fno-rtti') - if options['debugstl'].value: + if options[key.evolve('debugstl')].value: args.append('-D_GLIBCXX_DEBUG=1') return args - def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return [] @@ -560,30 +578,33 @@ class VisualStudioLikeCPPCompilerMixin(CompilerMixinBase): 'c++latest': (False, "latest"), } - def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: # need a typeddict for this - return T.cast(T.List[str], options['winlibs'].value[:]) + key = OptionKey('winlibs', machine=self.for_machine, lang=self.language) + return T.cast(T.List[str], options[key].value[:]) - def _get_options_impl(self, opts: 'OptionDictType', cpp_stds: T.List[str]) -> 'OptionDictType': + def _get_options_impl(self, opts: 'KeyedOptionDictType', cpp_stds: T.List[str]) -> 'KeyedOptionDictType': + key = OptionKey('std', machine=self.for_machine, lang=self.language) opts.update({ - 'eh': coredata.UserComboOption( + key.evolve('eh'): coredata.UserComboOption( 'C++ exception handling type.', ['none', 'default', 'a', 's', 'sc'], 'default', ), - 'rtti': coredata.UserBooleanOption('Enable RTTI', True), - 'winlibs': coredata.UserArrayOption( + key.evolve('rtti'): coredata.UserBooleanOption('Enable RTTI', True), + key.evolve('winlibs'): coredata.UserArrayOption( 'Windows libs to link against.', msvc_winlibs, ), }) - opts['std'].choices = cpp_stds + opts[key.evolve('std')].choices = cpp_stds return opts - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] + key = OptionKey('std', machine=self.for_machine, lang=self.language) - eh = options['eh'] + eh = options[key.evolve('eh')] if eh.value == 'default': args.append('/EHsc') elif eh.value == 'none': @@ -591,10 +612,10 @@ class VisualStudioLikeCPPCompilerMixin(CompilerMixinBase): else: args.append('/EH' + eh.value) - if not options['rtti'].value: + if not options[key.evolve('rtti')].value: args.append('/GR-') - permissive, ver = self.VC_VERSION_MAP[options['std'].value] + permissive, ver = self.VC_VERSION_MAP[options[key].value] if ver is not None: args.append('/std:c++{}'.format(ver)) @@ -616,22 +637,23 @@ class CPP11AsCPP14Mixin(CompilerMixinBase): This is a limitation of Clang and MSVC that ICL doesn't share. """ - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> 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) # if one is using anything before that point, one cannot set the standard. - if options['std'].value in {'vc++11', 'c++11'}: + key = OptionKey('std', machine=self.for_machine, lang=self.language) + if options[key].value in {'vc++11', 'c++11'}: mlog.warning(self.id, 'does not support C++11;', 'attempting best effort; setting the standard to C++14', once=True) # Don't mutate anything we're going to change, we need to use # deepcopy since we're messing with members, and we can't simply # copy the members because the option proxy doesn't support it. options = copy.deepcopy(options) - if options['std'].value == 'vc++11': - options['std'].value = 'vc++14' + if options[key].value == 'vc++11': + options[key].value = 'vc++14' else: - options['std'].value = 'c++14' + options[key].value = 'c++14' return super().get_option_compile_args(options) @@ -647,7 +669,7 @@ class VisualStudioCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixi self.base_options = ['b_pch', 'b_vscrt', 'b_ndebug'] # FIXME add lto, pgo and the like self.id = 'msvc' - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': cpp_stds = ['none', 'c++11', 'vc++11'] # Visual Studio 2015 and later if version_compare(self.version, '>=19'): @@ -657,11 +679,12 @@ 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: 'OptionDictType') -> T.List[str]: - if options['std'].value != 'none' and version_compare(self.version, '<19.00.24210'): + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: + key = OptionKey('std', machine=self.for_machine, lang=self.language) + if options[key].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) - options['std'].value = 'none' + options[key].value = 'none' args = super().get_option_compile_args(options) @@ -684,7 +707,7 @@ class ClangClCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixin, Cl ClangClCompiler.__init__(self, target) self.id = 'clang-cl' - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': 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) @@ -700,7 +723,7 @@ class IntelClCPPCompiler(VisualStudioLikeCPPCompilerMixin, IntelVisualStudioLike info, exe_wrapper, linker=linker, full_version=full_version) IntelVisualStudioLikeCompiler.__init__(self, target) - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': # 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) @@ -719,21 +742,23 @@ class ArmCPPCompiler(ArmCompiler, CPPCompiler): info, exe_wrapper, linker=linker, full_version=full_version) ArmCompiler.__init__(self) - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = CPPCompiler.get_options(self) - opts['std'].choices = ['none', 'c++03', 'c++11'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + opts[key].choices = ['none', 'c++03', 'c++11'] return opts - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - std = options['std'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + std = options[key] if std.value == 'c++11': args.append('--cpp11') elif std.value == 'c++03': args.append('--cpp') return args - def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return [] def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: @@ -753,7 +778,7 @@ class CcrxCPPCompiler(CcrxCompiler, CPPCompiler): def get_always_args(self) -> T.List[str]: return ['-nologo', '-lang=cpp'] - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return [] def get_compile_only_args(self) -> T.List[str]: @@ -762,7 +787,7 @@ class CcrxCPPCompiler(CcrxCompiler, CPPCompiler): def get_output_args(self, target: str) -> T.List[str]: return ['-output=obj=%s' % target] - def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return [] def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: @@ -777,15 +802,16 @@ class C2000CPPCompiler(C2000Compiler, CPPCompiler): info, exe_wrapper, linker=linker, full_version=full_version) C2000Compiler.__init__(self) - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = CPPCompiler.get_options(self) - opts['std'].choices = ['none', 'c++03'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + opts[key].choices = ['none', 'c++03'] return opts def get_always_args(self) -> T.List[str]: return ['-nologo', '-lang=cpp'] - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return [] def get_compile_only_args(self) -> T.List[str]: @@ -794,7 +820,7 @@ class C2000CPPCompiler(C2000Compiler, CPPCompiler): def get_output_args(self, target: str) -> T.List[str]: return ['-output=obj=%s' % target] - def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return [] def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py index 89fcf40..da1e002 100644 --- a/mesonbuild/compilers/cuda.py +++ b/mesonbuild/compilers/cuda.py @@ -17,6 +17,7 @@ import os.path import typing as T from .. import coredata +from ..coredata import OptionKey from .. import mlog from ..mesonlib import EnvironmentException, MachineChoice, Popen_safe, OptionOverrideProxy, is_windows, LibType from .compilers import (Compiler, cuda_buildtype_args, cuda_optimization_args, @@ -24,7 +25,7 @@ from .compilers import (Compiler, cuda_buildtype_args, cuda_optimization_args, if T.TYPE_CHECKING: from ..build import BuildTarget - from ..coredata import OptionDictType + from ..coredata import KeyedOptionDictType from ..dependencies import Dependency, ExternalProgram from ..environment import Environment # noqa: F401 from ..envconfig import MachineInfo @@ -195,24 +196,26 @@ class CudaCompiler(Compiler): }}''' return self.compiles(t.format_map(fargs), env, extra_args=extra_args, dependencies=dependencies) - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = super().get_options() - opts.update({'std': coredata.UserComboOption('C++ language standard to use with cuda', + key = OptionKey('std', machine=self.for_machine, lang=self.language) + opts.update({key: coredata.UserComboOption('C++ language standard to use with cuda', ['none', 'c++03', 'c++11', 'c++14'], 'none')}) return opts - def _to_host_compiler_options(self, options: 'OptionDictType') -> 'OptionDictType': + def _to_host_compiler_options(self, options: 'KeyedOptionDictType') -> 'KeyedOptionDictType': 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: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> 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 # and attempting to use it will result in a warning: https://stackoverflow.com/a/51272091/741027 if not is_windows(): - std = options['std'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + std = options[key] if std.value != 'none': args.append('--std=' + std.value) @@ -229,7 +232,7 @@ class CudaCompiler(Compiler): cooked.append(arg) return cls._to_host_flags(cooked, _Phase.LINKER) - def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_link_args(self, options: 'KeyedOptionDictType') -> 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, env: 'Environment', prefix: str, shlib_name: str, diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index e17be17..edd7911 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -17,6 +17,7 @@ import typing as T import subprocess, os from .. import coredata +from ..coredata import OptionKey from .compilers import ( clike_debug_args, Compiler, @@ -35,7 +36,7 @@ from mesonbuild.mesonlib import ( ) if T.TYPE_CHECKING: - from ..coredata import OptionDictType + from ..coredata import KeyedOptionDictType from ..dependencies import Dependency, ExternalProgram from ..envconfig import MachineInfo from ..environment import Environment @@ -71,7 +72,7 @@ class FortranCompiler(CLikeCompiler, Compiler): source_name.write_text('print *, "Fortran compilation is working."; end') - extra_flags = [] + extra_flags: T.List[str] = [] extra_flags += environment.coredata.get_external_args(self.for_machine, self.language) extra_flags += environment.coredata.get_external_link_args(self.for_machine, self.language) extra_flags += self.get_always_args() @@ -150,10 +151,11 @@ class FortranCompiler(CLikeCompiler, Compiler): 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') - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = super().get_options() + key = OptionKey('std', machine=self.for_machine, lang=self.language) opts.update({ - 'std': coredata.UserComboOption( + key: coredata.UserComboOption( 'Fortran language standard to use', ['none'], 'none', @@ -179,19 +181,21 @@ class GnuFortranCompiler(GnuCompiler, FortranCompiler): '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic', '-fimplicit-none']} - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = FortranCompiler.get_options(self) fortran_stds = ['legacy', 'f95', 'f2003'] if version_compare(self.version, '>=4.4.0'): fortran_stds += ['f2008'] if version_compare(self.version, '>=8.0.0'): fortran_stds += ['f2018'] - opts['std'].choices = ['none'] + fortran_stds + key = OptionKey('std', machine=self.for_machine, lang=self.language) + opts[key].choices = ['none'] + fortran_stds return opts - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - std = options['std'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + std = options[key] if std.value != 'none': args.append('-std=' + std.value) return args @@ -313,14 +317,16 @@ class IntelFortranCompiler(IntelGnuLikeCompiler, FortranCompiler): '2': default_warn_args + ['-warn', 'unused'], '3': ['-warn', 'all']} - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = FortranCompiler.get_options(self) - opts['std'].choices = ['none', 'legacy', 'f95', 'f2003', 'f2008', 'f2018'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + opts[key].choices = ['none', 'legacy', 'f95', 'f2003', 'f2008', 'f2018'] return opts - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - std = options['std'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + std = options[key] stds = {'legacy': 'none', 'f95': 'f95', 'f2003': 'f03', 'f2008': 'f08', 'f2018': 'f18'} if std.value != 'none': args.append('-stand=' + stds[std.value]) @@ -363,14 +369,16 @@ class IntelClFortranCompiler(IntelVisualStudioLikeCompiler, FortranCompiler): '2': default_warn_args + ['/warn:unused'], '3': ['/warn:all']} - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': opts = FortranCompiler.get_options(self) - opts['std'].choices = ['none', 'legacy', 'f95', 'f2003', 'f2008', 'f2018'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + opts[key].choices = ['none', 'legacy', 'f95', 'f2003', 'f2008', 'f2018'] return opts - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - std = options['std'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + std = options[key] stds = {'legacy': 'none', 'f95': 'f95', 'f2003': 'f03', 'f2008': 'f08', 'f2018': 'f18'} if std.value != 'none': args.append('/stand:' + stds[std.value]) diff --git a/mesonbuild/compilers/mixins/emscripten.py b/mesonbuild/compilers/mixins/emscripten.py index cd18b35..aacea15 100644 --- a/mesonbuild/compilers/mixins/emscripten.py +++ b/mesonbuild/compilers/mixins/emscripten.py @@ -50,15 +50,16 @@ class EmscriptenMixin(Compiler): def thread_link_flags(self, env: 'Environment') -> T.List[str]: args = ['-s', 'USE_PTHREADS=1'] - count = env.coredata.compiler_options[self.for_machine][self.language]['thread_count'].value # type: int + count: int = env.coredata.compiler_options[coredata.OptionKey('thread_count', lang=self.language, machine=self.for_machine)].value # type: ignore if count: args.extend(['-s', 'PTHREAD_POOL_SIZE={}'.format(count)]) return args - def get_options(self) -> 'coredata.OptionDictType': + def get_options(self) -> 'coredata.KeyedOptionDictType': opts = super().get_options() + key = coredata.OptionKey('thread_count', machine=self.for_machine, lang=self.language) opts.update({ - 'thread_count': coredata.UserIntegerOption( + key: coredata.UserIntegerOption( 'Number of threads to use in web assembly, set to 0 to disable', (0, None, 4), # Default was picked at random ), diff --git a/mesonbuild/compilers/mixins/islinker.py b/mesonbuild/compilers/mixins/islinker.py index 2445eec..3fe3382 100644 --- a/mesonbuild/compilers/mixins/islinker.py +++ b/mesonbuild/compilers/mixins/islinker.py @@ -25,7 +25,7 @@ import typing as T from ... import mesonlib if T.TYPE_CHECKING: - from ...coredata import OptionDictType + from ...coredata import KeyedOptionDictType from ...environment import Environment from ...compilers.compilers import Compiler else: @@ -66,7 +66,7 @@ class BasicLinkerIsCompilerMixin(Compiler): def get_linker_lib_prefix(self) -> str: return '' - def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return [] def has_multi_link_args(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]: @@ -78,7 +78,7 @@ class BasicLinkerIsCompilerMixin(Compiler): def get_std_shared_lib_link_args(self) -> T.List[str]: return [] - def get_std_shared_module_args(self, options: 'OptionDictType') -> T.List[str]: + def get_std_shared_module_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return self.get_std_shared_lib_link_args() def get_link_whole_for(self, args: T.List[str]) -> T.List[str]: diff --git a/mesonbuild/compilers/objc.py b/mesonbuild/compilers/objc.py index 1b280eb..e47bf2f 100644 --- a/mesonbuild/compilers/objc.py +++ b/mesonbuild/compilers/objc.py @@ -51,7 +51,7 @@ class ObjCCompiler(CLikeCompiler, Compiler): # TODO try to use sanity_check_impl instead of duplicated code source_name = os.path.join(work_dir, 'sanitycheckobjc.m') binary_name = os.path.join(work_dir, 'sanitycheckobjc') - extra_flags = [] + extra_flags: T.List[str] = [] extra_flags += environment.coredata.get_external_args(self.for_machine, self.language) if self.is_cross: extra_flags += self.get_compile_only_args() diff --git a/mesonbuild/compilers/objcpp.py b/mesonbuild/compilers/objcpp.py index 16ba77e..c0f93d7 100644 --- a/mesonbuild/compilers/objcpp.py +++ b/mesonbuild/compilers/objcpp.py @@ -50,7 +50,7 @@ class ObjCPPCompiler(CLikeCompiler, Compiler): # TODO try to use sanity_check_impl instead of duplicated code source_name = os.path.join(work_dir, 'sanitycheckobjcpp.mm') binary_name = os.path.join(work_dir, 'sanitycheckobjcpp') - extra_flags = [] + extra_flags: T.List[str] = [] extra_flags += environment.coredata.get_external_args(self.for_machine, self.language) if self.is_cross: extra_flags += self.get_compile_only_args() diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py index 312b3b6..cf1af0a 100644 --- a/mesonbuild/compilers/rust.py +++ b/mesonbuild/compilers/rust.py @@ -17,11 +17,12 @@ import textwrap import typing as T from .. import coredata +from ..coredata import OptionKey from ..mesonlib import EnvironmentException, MachineChoice, MesonException, Popen_safe from .compilers import Compiler, rust_buildtype_args, clike_debug_args if T.TYPE_CHECKING: - from ..coredata import OptionDictType + from ..coredata import KeyedOptionDictType from ..dependencies import ExternalProgram from ..envconfig import MachineInfo from ..environment import Environment # noqa: F401 @@ -133,18 +134,20 @@ class RustCompiler(Compiler): # C compiler for dynamic linking, as such we invoke the C compiler's # use_linker_args method instead. - def get_options(self) -> 'OptionDictType': + def get_options(self) -> 'KeyedOptionDictType': + key = OptionKey('std', machine=self.for_machine, lang=self.language) return { - 'std': coredata.UserComboOption( + key: coredata.UserComboOption( 'Rust Eddition to use', ['none', '2015', '2018'], 'none', ), } - def get_option_compile_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] - std = options['std'] + key = OptionKey('std', machine=self.for_machine, lang=self.language) + std = options[key] if std.value != 'none': args.append('--edition=' + std.value) return args diff --git a/mesonbuild/compilers/swift.py b/mesonbuild/compilers/swift.py index 8682e54..7b18591 100644 --- a/mesonbuild/compilers/swift.py +++ b/mesonbuild/compilers/swift.py @@ -101,7 +101,7 @@ class SwiftCompiler(Compiler): src = 'swifttest.swift' source_name = os.path.join(work_dir, src) output_name = os.path.join(work_dir, 'swifttest') - extra_flags = [] + extra_flags: T.List[str] = [] extra_flags += environment.coredata.get_external_args(self.for_machine, self.language) if self.is_cross: extra_flags += self.get_compile_only_args() diff --git a/mesonbuild/compilers/vala.py b/mesonbuild/compilers/vala.py index af800c2..14971d4 100644 --- a/mesonbuild/compilers/vala.py +++ b/mesonbuild/compilers/vala.py @@ -92,7 +92,7 @@ class ValaCompiler(Compiler): def sanity_check(self, work_dir: str, environment: 'Environment') -> None: code = 'class MesonSanityCheck : Object { }' - extra_flags = [] + extra_flags: T.List[str] = [] extra_flags += environment.coredata.get_external_args(self.for_machine, self.language) if self.is_cross: extra_flags += self.get_compile_only_args() @@ -116,7 +116,7 @@ class ValaCompiler(Compiler): # no extra dirs are specified. if not extra_dirs: code = 'class MesonFindLibrary : Object { }' - args = [] + args: T.List[str] = [] args += env.coredata.get_external_args(self.for_machine, self.language) vapi_args = ['--pkg', libname] args += vapi_args diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index eae986d..97f5fff 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -67,16 +67,17 @@ def classify_argument(key: 'OptionKey') -> OptionType: all_builtins = set(BUILTIN_OPTIONS) | set(BUILTIN_OPTIONS_PER_MACHINE) | set(builtin_dir_noprefix_options) if key.name in base_options: - assert key.machine is MachineChoice.HOST + assert key.machine is MachineChoice.HOST, str(key) return OptionType.BASE elif key.lang is not None: return OptionType.COMPILER elif key.name in all_builtins: return OptionType.BUILTIN elif key.name.startswith('backend_'): + assert key.machine is MachineChoice.HOST, str(key) return OptionType.BACKEND else: - assert key.machine is MachineChoice.HOST + assert key.machine is MachineChoice.HOST, str(key) return OptionType.PROJECT @@ -168,23 +169,24 @@ class OptionKey: This takes strings like `mysubproject:build.myoption` and Creates an OptionKey out of them. """ - from .compilers import all_languages - if any(raw.startswith(f'{l}_') for l in all_languages): - lang, raw2 = raw.split('_', 1) - else: - lang, raw2 = None, raw try: - subproject, raw3 = raw2.split(':') + subproject, raw2 = raw.split(':') except ValueError: - subproject, raw3 = '', raw2 + subproject, raw2 = '', raw - if raw3.startswith('build.'): - opt = raw3.lstrip('build.') + if raw2.startswith('build.'): + raw3 = raw2.lstrip('build.') for_machine = MachineChoice.BUILD else: - opt = raw3 + raw3 = raw2 for_machine = MachineChoice.HOST + + from .compilers import all_languages + if any(raw3.startswith(f'{l}_') for l in all_languages): + lang, opt = raw3.split('_', 1) + else: + lang, opt = None, raw3 assert ':' not in opt assert 'build.' not in opt @@ -580,10 +582,7 @@ class CoreData: self.builtins_per_machine: PerMachine['OptionDictType'] = PerMachine({}, {}) self.backend_options: 'KeyedOptionDictType' = {} self.user_options: 'KeyedOptionDictType' = {} - self.compiler_options = PerMachine( - defaultdict(dict), - defaultdict(dict), - ) # type: PerMachine[T.defaultdict[str, OptionDictType]] + self.compiler_options: 'KeyedOptionDictType' = {} self.base_options = {} # type: OptionDictType self.cross_files = self.__load_config_files(options, scratch_dir, 'cross') self.compilers = PerMachine(OrderedDict(), OrderedDict()) # type: PerMachine[T.Dict[str, Compiler]] @@ -860,7 +859,7 @@ class CoreData: def _get_all_nonbuiltin_options(self) -> T.Iterable[T.Dict[str, UserOption]]: yield {str(k): v for k, v in self.backend_options.items()} yield {str(k): v for k, v in self.user_options.items()} - yield dict(self.flatten_lang_iterator(self.get_prefixed_options_per_machine(self.compiler_options))) + yield {str(k): v for k, v in self.compiler_options.items()} yield self.base_options def _get_all_builtin_options(self) -> T.Iterable[T.Dict[str, UserOption]]: @@ -882,11 +881,11 @@ 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): - return self.compiler_options[for_machine][lang]['args'].value + def get_external_args(self, for_machine: MachineChoice, lang: str) -> T.Union[str, T.List[str]]: + return self.compiler_options[OptionKey('args', machine=for_machine, lang=lang)].value - def get_external_link_args(self, for_machine: MachineChoice, lang): - return self.compiler_options[for_machine][lang]['link_args'].value + def get_external_link_args(self, for_machine: MachineChoice, lang: str) -> T.Union[str, T.List[str]]: + return self.compiler_options[OptionKey('link_args', machine=for_machine, lang=lang)].value def merge_user_options(self, options: T.Dict[str, UserOption[T.Any]]) -> None: for name, value in options.items(): @@ -914,14 +913,17 @@ class CoreData: return len(self.cross_files) > 0 def copy_build_options_from_regular_ones(self): - assert(not self.is_cross_build()) + assert not self.is_cross_build() for k, o in self.builtins_per_machine.host.items(): self.builtins_per_machine.build[k].set_value(o.value) - for lang, host_opts in self.compiler_options.host.items(): - build_opts = self.compiler_options.build[lang] - for k, o in host_opts.items(): - if k in build_opts: - build_opts[k].set_value(o.value) + for bk, bv in self.compiler_options.items(): + if bk.machine is MachineChoice.BUILD: + hk = bk.as_host() + try: + hv = self.compiler_options[hk] + bv.set_value(hv.value) + except KeyError: + continue def set_options(self, options: T.Dict[OptionKey, T.Any], subproject: str = '', warn_unknown: bool = True) -> None: if not self.is_cross_build(): @@ -989,14 +991,13 @@ class CoreData: self.set_options(options, subproject=subproject) - def add_compiler_options(self, options: 'OptionDictType', lang: str, for_machine: MachineChoice, + def add_compiler_options(self, options: 'KeyedOptionDictType', lang: str, for_machine: MachineChoice, env: 'Environment') -> None: for k, o in options.items(): - key = OptionKey(k, lang=lang, machine=for_machine) - value = env.options.get(key) + value = env.options.get(k) if value is not None: o.set_value(value) - self.compiler_options[for_machine][lang].setdefault(k, o) + self.compiler_options.setdefault(k, o) def add_lang_args(self, lang: str, comp: T.Type['Compiler'], for_machine: MachineChoice, env: 'Environment') -> None: diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index d2a118f..3120279 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -629,7 +629,9 @@ class Environment: machines.target = MachineInfo.from_literal(config['target_machine']) # Keep only per machine options from the native file. The cross # file takes precedence over all other options. - self.keep_per_machine_options() + for key, value in list(self.options.items()): + if self.coredata.is_per_machine_option(key): + self.options[key.as_build()] = value self.load_machine_file_options(config, properties.host, MachineChoice.HOST) else: # IF we aren't cross compiling, but we hav ea native file, the @@ -736,15 +738,15 @@ class Environment: subproject, section = section.split(':') else: subproject = '' - if section in ['project options', 'built-in options']: + if section == 'built-in options': for k, v in values.items(): key = coredata.OptionKey.from_string(k).evolve(subproject=subproject, machine=machine) self.options[key] = v - - def keep_per_machine_options(self) -> None: - for key, value in self.options.items(): - if self.coredata.is_per_machine_option(key): - self.options[key.as_build()] = value + elif section == 'project options': + for k, v in values.items(): + # Project options are always for the machine machine + key = coredata.OptionKey.from_string(k).evolve(subproject=subproject) + self.options[key] = v def set_default_options_from_env(self) -> None: for for_machine in MachineChoice: @@ -936,7 +938,7 @@ class Environment: elif isinstance(comp_class.LINKER_PREFIX, list): check_args = comp_class.LINKER_PREFIX + ['/logo'] + comp_class.LINKER_PREFIX + ['--version'] - check_args += self.coredata.compiler_options[for_machine][comp_class.language]['args'].value + check_args += self.coredata.compiler_options[coredata.OptionKey('args', lang=comp_class.language, machine=for_machine)].value override = [] # type: T.List[str] value = self.lookup_binary_entry(for_machine, comp_class.language + '_ld') @@ -1002,7 +1004,7 @@ class Environment: """ self.coredata.add_lang_args(comp_class.language, comp_class, for_machine, self) extra_args = extra_args or [] - extra_args += self.coredata.compiler_options[for_machine][comp_class.language]['args'].value + extra_args += self.coredata.compiler_options[coredata.OptionKey('args', lang=comp_class.language, machine=for_machine)].value if isinstance(comp_class.LINKER_PREFIX, str): check_args = [comp_class.LINKER_PREFIX + '--version'] + extra_args diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index e6936e4..6aba3e7 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -52,6 +52,7 @@ import typing as T import importlib if T.TYPE_CHECKING: + from .compilers import Compiler from .envconfig import MachineInfo from .environment import Environment from .modules import ExtensionModule @@ -1058,7 +1059,7 @@ find_library_permitted_kwargs = set([ find_library_permitted_kwargs |= set(['header_' + k for k in header_permitted_kwargs]) class CompilerHolder(InterpreterObject): - def __init__(self, compiler, env, subproject): + def __init__(self, compiler: 'Compiler', env: 'Environment', subproject: str): InterpreterObject.__init__(self) self.compiler = compiler self.environment = env @@ -1143,7 +1144,7 @@ class CompilerHolder(InterpreterObject): args += self.compiler.get_include_args(idir, False) if not nobuiltins: for_machine = Interpreter.machine_from_native_kwarg(kwargs) - opts = self.environment.coredata.compiler_options[for_machine][self.compiler.language] + opts = self.environment.coredata.compiler_options args += self.compiler.get_option_compile_args(opts) if mode == 'link': args += self.compiler.get_option_link_args(opts) @@ -3059,8 +3060,6 @@ 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))), ]: v = opts.get(optname) if v is None or v.yielding: @@ -3068,8 +3067,15 @@ external dependencies (including libraries) must go to "dependencies".''') if v is not None: return v + key = coredata.OptionKey.from_string(optname) + for opts in [self.coredata.compiler_options]: + v = opts.get(key) + if v is None or v.yielding: + v = opts.get(key.as_root()) + if v is not None: + return v + try: - key = coredata.OptionKey.from_string(optname) opt = self.coredata.user_options[key] if opt.yielding and key.subproject and key.as_root() in self.coredata.user_options: popt = self.coredata.user_options[key.as_root()] diff --git a/mesonbuild/linkers.py b/mesonbuild/linkers.py index 0f05fef..141c8fd 100644 --- a/mesonbuild/linkers.py +++ b/mesonbuild/linkers.py @@ -21,7 +21,7 @@ from .arglist import CompilerArgs from .envconfig import get_env_var if T.TYPE_CHECKING: - from .coredata import OptionDictType + from .coredata import KeyedOptionDictType from .envconfig import MachineChoice from .environment import Environment @@ -40,7 +40,7 @@ class StaticLinker: """ return mesonlib.is_windows() - def get_base_link_args(self, options: 'OptionDictType') -> T.List[str]: + def get_base_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: """Like compilers.get_base_link_args, but for the static linker.""" return [] @@ -70,7 +70,7 @@ class StaticLinker: def openmp_flags(self) -> T.List[str]: return [] - def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return [] @classmethod @@ -378,7 +378,7 @@ class DynamicLinker(LinkerEnvVarsMixin, metaclass=abc.ABCMeta): # XXX: is use_ldflags a compiler or a linker attribute? - def get_option_args(self, options: 'OptionDictType') -> T.List[str]: + def get_option_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return [] def has_multi_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]: @@ -401,7 +401,7 @@ class DynamicLinker(LinkerEnvVarsMixin, metaclass=abc.ABCMeta): def get_std_shared_lib_args(self) -> T.List[str]: return [] - def get_std_shared_module_args(self, options: 'OptionDictType') -> T.List[str]: + def get_std_shared_module_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return self.get_std_shared_lib_args() def get_pie_args(self) -> T.List[str]: @@ -693,7 +693,7 @@ class AppleDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): def get_allow_undefined_args(self) -> T.List[str]: return self._apply_prefix('-undefined,dynamic_lookup') - def get_std_shared_module_args(self, options: 'OptionDictType') -> T.List[str]: + def get_std_shared_module_args(self, options: 'KeyedOptionDictType') -> T.List[str]: return ['-bundle'] + self._apply_prefix('-undefined,dynamic_lookup') def get_pie_args(self) -> T.List[str]: diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index 20e6d26..c14d701 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -17,6 +17,8 @@ from . import coredata, environment, mesonlib, build, mintro, mlog from .ast import AstIDGenerator import typing as T +from .mesonlib import MachineChoice + if T.TYPE_CHECKING: import argparse from .coredata import OptionKey, UserOption @@ -217,13 +219,8 @@ class Conf: core_options = {k: o for k, o in self.coredata.builtins.items() if k in core_option_names} core_options = self.split_options_per_subproject(core_options) - host_compiler_options = self.split_options_per_subproject( - dict(self.coredata.flatten_lang_iterator( - self.coredata.compiler_options.host.items()))) - build_compiler_options = self.split_options_per_subproject( - dict(self.coredata.flatten_lang_iterator( - (insert_build_prefix(k), o) - for k, o in self.coredata.compiler_options.build.items()))) + host_compiler_options = self.split_options_per_subproject2({k: v for k, v in self.coredata.compiler_options.items() if k.machine is MachineChoice.HOST}) + build_compiler_options = self.split_options_per_subproject2({k: v for k, v in self.coredata.compiler_options.items() if k.machine is MachineChoice.BUILD}) project_options = self.split_options_per_subproject2(self.coredata.user_options) show_build_options = self.default_values_only or self.build.environment.is_cross_build() diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index e252e82..7b2560f 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -33,6 +33,8 @@ import typing as T import os import argparse +from .mesonlib import MachineChoice + def get_meson_info_file(info_dir: str) -> str: return os.path.join(info_dir, 'meson-info.json') @@ -260,13 +262,12 @@ def list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[s add_keys({str(k): v for k, v in coredata.backend_options.items()}, 'backend') add_keys(coredata.base_options, 'base') add_keys( - dict(coredata.flatten_lang_iterator(coredata.compiler_options.host.items())), + {str(k): v for k, v in coredata.compiler_options.items() if k.machine is MachineChoice.HOST}, 'compiler', machine='host', ) - tmp_dict = dict(coredata.flatten_lang_iterator(coredata.compiler_options.build.items())) # type: T.Dict[str, cdata.UserOption] add_keys( - {'build.' + k: o for k, o in tmp_dict.items()}, + {str(k): v for k, v in coredata.compiler_options.items() if k.machine is MachineChoice.BUILD}, 'compiler', machine='build', ) diff --git a/mesonbuild/rewriter.py b/mesonbuild/rewriter.py index dcc5040..776a39a 100644 --- a/mesonbuild/rewriter.py +++ b/mesonbuild/rewriter.py @@ -469,8 +469,7 @@ class Rewriter: **{'build.' + k: o for k, o in cdata.builtins_per_machine.build.items()}, **{str(k): v for k, v in cdata.backend_options.items()}, **cdata.base_options, - **(dict(cdata.flatten_lang_iterator(cdata.compiler_options.host.items()))), - **{'build.' + k: o for k, o in cdata.flatten_lang_iterator(cdata.compiler_options.build.items())}, + **{str(k): v for k, v in cdata.compiler_options.items()}, **{str(k): v for k, v in cdata.user_options.items()}, } diff --git a/run_tests.py b/run_tests.py index 0f02636..15e643a 100755 --- a/run_tests.py +++ b/run_tests.py @@ -34,7 +34,7 @@ from mesonbuild import mesonmain from mesonbuild import mtest from mesonbuild import mlog from mesonbuild.environment import Environment, detect_ninja -from mesonbuild.coredata import backendlist, version as meson_version +from mesonbuild.coredata import backendlist, version as meson_version, OptionKey NINJA_1_9_OR_NEWER = False NINJA_CMD = None @@ -127,7 +127,7 @@ def get_fake_env(sdir='', bdir=None, prefix='', opts=None): if opts is None: opts = get_fake_options(prefix) env = Environment(sdir, bdir, opts) - env.coredata.compiler_options.host['c']['args'] = FakeCompilerOptions() + env.coredata.compiler_options[OptionKey('args', lang='c')] = FakeCompilerOptions() env.machines.host.cpu_family = 'x86_64' # Used on macOS inside find_library return env diff --git a/run_unittests.py b/run_unittests.py index 1a7a0c4..0236909 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -30,8 +30,6 @@ import functools import io import operator import threading -import urllib.error -import urllib.request import zipfile import hashlib from itertools import chain @@ -66,6 +64,7 @@ from mesonbuild.dependencies import PkgConfigDependency, ExternalProgram import mesonbuild.dependencies.base from mesonbuild.build import Target, ConfigurationData import mesonbuild.modules.pkgconfig +from mesonbuild.coredata import OptionKey from mesonbuild.mtest import TAPParser, TestResult @@ -874,7 +873,7 @@ class InternalTests(unittest.TestCase): env = get_fake_env() compiler = env.detect_c_compiler(MachineChoice.HOST) env.coredata.compilers.host = {'c': compiler} - env.coredata.compiler_options.host['c']['link_args'] = FakeCompilerOptions() + env.coredata.compiler_options[OptionKey('link_args', lang='c')] = FakeCompilerOptions() p1 = Path(tmpdir) / '1' p2 = Path(tmpdir) / '2' p1.mkdir() @@ -1336,10 +1335,10 @@ class DataTests(unittest.TestCase): cc = env.detect_c_compiler(MachineChoice.HOST) cpp = env.detect_cpp_compiler(MachineChoice.HOST) for comp in (cc, cpp): - for opt in comp.get_options().keys(): - self.assertIn(opt, md) + for opt in comp.get_options(): + self.assertIn(str(opt), md) for opt in comp.base_options: - self.assertIn(opt, md) + self.assertIn(str(opt), md) self.assertNotIn('b_unknown', md) @staticmethod @@ -3681,7 +3680,7 @@ class AllPlatformTests(BasePlatformTests): def test_command_line(self): testdir = os.path.join(self.unit_test_dir, '34 command line') - K = mesonbuild.coredata.OptionKey + K = OptionKey # Verify default values when passing no args that affect the # configuration, and as a bonus, test that --profile-self works. @@ -3782,11 +3781,11 @@ class AllPlatformTests(BasePlatformTests): # c_args value should be parsed with split_args self.init(testdir, extra_args=['-Dc_args=-Dfoo -Dbar "-Dthird=one two"', '--fatal-meson-warnings']) obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.compiler_options.host['c']['args'].value, ['-Dfoo', '-Dbar', '-Dthird=one two']) + self.assertEqual(obj.compiler_options[OptionKey('args', lang='c')].value, ['-Dfoo', '-Dbar', '-Dthird=one two']) self.setconf('-Dc_args="foo bar" one two') obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.compiler_options.host['c']['args'].value, ['foo bar', 'one', 'two']) + self.assertEqual(obj.compiler_options[OptionKey('args', lang='c')].value, ['foo bar', 'one', 'two']) self.wipe() self.init(testdir, extra_args=['-Dset_percent_opt=myoption%', '--fatal-meson-warnings']) @@ -3805,7 +3804,7 @@ class AllPlatformTests(BasePlatformTests): self.assertEqual(obj.builtins['bindir'].value, 'bar') self.assertEqual(obj.builtins['buildtype'].value, 'release') self.assertEqual(obj.base_options['b_sanitize'].value, 'thread') - self.assertEqual(obj.compiler_options.host['c']['args'].value, ['-Dbar']) + self.assertEqual(obj.compiler_options[OptionKey('args', lang='c')].value, ['-Dbar']) self.setconf(['--bindir=bar', '--bindir=foo', '-Dbuildtype=release', '-Dbuildtype=plain', '-Db_sanitize=thread', '-Db_sanitize=address', @@ -3814,7 +3813,7 @@ class AllPlatformTests(BasePlatformTests): self.assertEqual(obj.builtins['bindir'].value, 'foo') self.assertEqual(obj.builtins['buildtype'].value, 'plain') self.assertEqual(obj.base_options['b_sanitize'].value, 'address') - self.assertEqual(obj.compiler_options.host['c']['args'].value, ['-Dfoo']) + self.assertEqual(obj.compiler_options[OptionKey('args', lang='c')].value, ['-Dfoo']) self.wipe() except KeyError: # Ignore KeyError, it happens on CI for compilers that does not @@ -6300,7 +6299,7 @@ class LinuxlikeTests(BasePlatformTests): Oargs = [arg for arg in cmd if arg.startswith('-O')] self.assertEqual(Oargs, [Oflag, '-O0']) - def _test_stds_impl(self, testdir, compiler: 'Compiler', p: str) -> None: + def _test_stds_impl(self, testdir: str, compiler: 'Compiler') -> None: has_cpp17 = (compiler.get_id() not in {'clang', 'gcc'} or compiler.get_id() == 'clang' and _clang_at_least(compiler, '>=5.0.0', '>=9.1') or compiler.get_id() == 'gcc' and version_compare(compiler.version, '>=5.0.0')) @@ -6316,8 +6315,8 @@ class LinuxlikeTests(BasePlatformTests): # Check that all the listed -std=xxx options for this compiler work just fine when used # https://en.wikipedia.org/wiki/Xcode#Latest_versions # https://www.gnu.org/software/gcc/projects/cxx-status.html - for v in compiler.get_options()['std'].choices: - lang_std = p + '_std' + key = OptionKey('std', lang=compiler.language) + for v in compiler.get_options()[key].choices: # we do it like this to handle gnu++17,c++17 and gnu17,c17 cleanly # thus, C++ first if '++17' in v and not has_cpp17: @@ -6331,8 +6330,7 @@ class LinuxlikeTests(BasePlatformTests): continue elif '18' in v and not has_c18: continue - std_opt = '{}={}'.format(lang_std, v) - self.init(testdir, extra_args=['-D' + std_opt]) + self.init(testdir, extra_args=[f'-D{key!s}={v}']) cmd = self.get_compdb()[0]['command'] # c++03 and gnu++03 are not understood by ICC, don't try to look for them skiplist = frozenset([ @@ -6344,15 +6342,15 @@ class LinuxlikeTests(BasePlatformTests): try: self.build() except Exception: - print('{} was {!r}'.format(lang_std, v)) + print(f'{key!s} was {v!r}') raise self.wipe() # Check that an invalid std option in CFLAGS/CPPFLAGS fails # Needed because by default ICC ignores invalid options cmd_std = '-std=FAIL' - if p == 'c': + if compiler.language == 'c': env_flag_name = 'CFLAGS' - elif p == 'cpp': + elif compiler.language == 'cpp': env_flag_name = 'CXXFLAGS' else: raise NotImplementedError('Language {} not defined.'.format(p)) @@ -6373,7 +6371,7 @@ class LinuxlikeTests(BasePlatformTests): testdir = os.path.join(self.common_test_dir, '1 trivial') env = get_fake_env(testdir, self.builddir, self.prefix) cc = env.detect_c_compiler(MachineChoice.HOST) - self._test_stds_impl(testdir, cc, 'c') + self._test_stds_impl(testdir, cc) def test_compiler_cpp_stds(self): ''' @@ -6383,7 +6381,7 @@ class LinuxlikeTests(BasePlatformTests): testdir = os.path.join(self.common_test_dir, '2 cpp') env = get_fake_env(testdir, self.builddir, self.prefix) cpp = env.detect_cpp_compiler(MachineChoice.HOST) - self._test_stds_impl(testdir, cpp, 'cpp') + self._test_stds_impl(testdir, cpp) def test_unity_subproj(self): testdir = os.path.join(self.common_test_dir, '43 subproject') @@ -6905,7 +6903,7 @@ class LinuxlikeTests(BasePlatformTests): self.assertTrue(os.path.exists(os.path.join(pkg_dir, 'librelativepath.pc'))) env = get_fake_env(testdir, self.builddir, self.prefix) - env.coredata.set_options({mesonbuild.coredata.OptionKey('pkg_config_path'): pkg_dir}, subproject='') + env.coredata.set_options({OptionKey('pkg_config_path'): pkg_dir}, subproject='') kwargs = {'required': True, 'silent': True} relative_path_dep = PkgConfigDependency('librelativepath', env, kwargs) self.assertTrue(relative_path_dep.found()) @@ -9318,7 +9316,7 @@ class SubprojectsCommandTests(BasePlatformTests): out = self._subprojects_cmd(['foreach', '--types', 'git'] + dummy_cmd) self.assertEqual(ran_in(out), ['subprojects/sub_git']) -def _clang_at_least(compiler, minver: str, apple_minver: T.Optional[str]) -> bool: +def _clang_at_least(compiler: 'Compiler', minver: str, apple_minver: T.Optional[str]) -> bool: """ check that Clang compiler is at least a specified version, whether AppleClang or regular Clang |