diff options
Diffstat (limited to 'mesonbuild')
38 files changed, 407 insertions, 318 deletions
diff --git a/mesonbuild/ast/introspection.py b/mesonbuild/ast/introspection.py index c7dcf73..1197510 100644 --- a/mesonbuild/ast/introspection.py +++ b/mesonbuild/ast/introspection.py @@ -182,7 +182,7 @@ class IntrospectionInterpreter(AstInterpreter): if self.subproject: options = {} for k in comp.get_options(): - v = copy.copy(self.coredata.options[k]) + v = copy.copy(self.coredata.optstore.get_value_object(k)) k = k.evolve(subproject=self.subproject) options[k] = v self.coredata.add_compiler_options(options, lang, for_machine, self.environment, self.subproject) diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 740f349..c1a72f1 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -962,7 +962,7 @@ class Backend: def target_uses_pch(self, target: build.BuildTarget) -> bool: try: return T.cast('bool', target.get_option(OptionKey('b_pch'))) - except KeyError: + except (KeyError, AttributeError): return False @staticmethod diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 9d43c5e..3052967 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -623,7 +623,7 @@ class NinjaBackend(backends.Backend): outfile.write('# Do not edit by hand.\n\n') outfile.write('ninja_required_version = 1.8.2\n\n') - num_pools = self.environment.coredata.options[OptionKey('backend_max_links')].value + num_pools = self.environment.coredata.optstore.get_value('backend_max_links') if num_pools > 0: outfile.write(f'''pool link_pool depth = {num_pools} @@ -656,8 +656,8 @@ class NinjaBackend(backends.Backend): self.generate_dist() mlog.log_timestamp("Dist generated") key = OptionKey('b_coverage') - if (key in self.environment.coredata.options and - self.environment.coredata.options[key].value): + if (key in self.environment.coredata.optstore and + self.environment.coredata.optstore.get_value(key)): gcovr_exe, gcovr_version, lcov_exe, lcov_version, genhtml_exe, llvm_cov_exe = environment.find_coverage_tools(self.environment.coredata) mlog.debug(f'Using {gcovr_exe} ({gcovr_version}), {lcov_exe} and {llvm_cov_exe} for code coverage') if gcovr_exe or (lcov_exe and genhtml_exe): @@ -1991,7 +1991,7 @@ class NinjaBackend(backends.Backend): buildtype = target.get_option(OptionKey('buildtype')) crt = target.get_option(OptionKey('b_vscrt')) args += rustc.get_crt_link_args(crt, buildtype) - except KeyError: + except (KeyError, AttributeError): pass if mesonlib.version_compare(rustc.version, '>= 1.67.0'): @@ -2295,7 +2295,7 @@ class NinjaBackend(backends.Backend): return options def generate_static_link_rules(self): - num_pools = self.environment.coredata.options[OptionKey('backend_max_links')].value + num_pools = self.environment.coredata.optstore.get_value('backend_max_links') if 'java' in self.environment.coredata.compilers.host: self.generate_java_link() for for_machine in MachineChoice: @@ -2343,7 +2343,7 @@ class NinjaBackend(backends.Backend): self.add_rule(NinjaRule(rule, cmdlist, args, description, **options, extra=pool)) def generate_dynamic_link_rules(self): - num_pools = self.environment.coredata.options[OptionKey('backend_max_links')].value + num_pools = self.environment.coredata.optstore.get_value('backend_max_links') for for_machine in MachineChoice: complist = self.environment.coredata.compilers[for_machine] for langname, compiler in complist.items(): @@ -3605,7 +3605,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) def get_user_option_args(self): cmds = [] - for (k, v) in self.environment.coredata.options.items(): + for k, v in self.environment.coredata.optstore.items(): if k.is_project(): cmds.append('-D' + str(k) + '=' + (v.value if isinstance(v.value, str) else str(v.value).lower())) # The order of these arguments must be the same between runs of Meson @@ -3734,8 +3734,8 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) if ctlist: elem.add_dep(self.generate_custom_target_clean(ctlist)) - if OptionKey('b_coverage') in self.environment.coredata.options and \ - self.environment.coredata.options[OptionKey('b_coverage')].value: + if OptionKey('b_coverage') in self.environment.coredata.optstore and \ + self.environment.coredata.optstore.get_value('b_coverage'): self.generate_gcov_clean() elem.add_dep('clean-gcda') elem.add_dep('clean-gcno') diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index 91275c7..793b678 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -532,7 +532,7 @@ class Vs2010Backend(backends.Backend): replace_if_different(sln_filename, sln_filename_tmp) def generate_projects(self, vslite_ctx: dict = None) -> T.List[Project]: - startup_project = self.environment.coredata.options[OptionKey('backend_startup_project')].value + startup_project = self.environment.coredata.optstore.get_value('backend_startup_project') projlist: T.List[Project] = [] startup_idx = 0 for (i, (name, target)) in enumerate(self.build.targets.items()): diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 313f73e..071dbdf 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -533,7 +533,7 @@ class Target(HoldableObject, metaclass=abc.ABCMeta): for k, v in overrides.items()} else: ovr = {} - self.options = coredata.OptionsView(self.environment.coredata.options, self.subproject, ovr) + self.options = coredata.OptionsView(self.environment.coredata.optstore, self.subproject, ovr) # XXX: this should happen in the interpreter if has_path_sep(self.name): # Fix failing test 53 when this becomes an error. @@ -664,7 +664,7 @@ class Target(HoldableObject, metaclass=abc.ABCMeta): def get_option(self, key: 'OptionKey') -> T.Union[str, int, bool]: # TODO: if it's possible to annotate get_option or validate_option_value # in the future we might be able to remove the cast here - return T.cast('T.Union[str, int, bool]', self.options[key].value) + return T.cast('T.Union[str, int, bool]', self.options.get_value(key)) @staticmethod def parse_overrides(kwargs: T.Dict[str, T.Any]) -> T.Dict[OptionKey, str]: @@ -1242,8 +1242,8 @@ class BuildTarget(Target): k = OptionKey(option) if kwargs.get(arg) is not None: val = T.cast('bool', kwargs[arg]) - elif k in self.environment.coredata.options: - val = self.environment.coredata.options[k].value + elif k in self.environment.coredata.optstore: + val = self.environment.coredata.optstore.get_value(k) else: val = False @@ -1930,8 +1930,8 @@ class Executable(BuildTarget): compilers: T.Dict[str, 'Compiler'], kwargs): key = OptionKey('b_pie') - if 'pie' not in kwargs and key in environment.coredata.options: - kwargs['pie'] = environment.coredata.options[key].value + if 'pie' not in kwargs and key in environment.coredata.optstore: + kwargs['pie'] = environment.coredata.optstore.get_value(key) super().__init__(name, subdir, subproject, for_machine, sources, structured_sources, objects, environment, compilers, kwargs) self.win_subsystem = kwargs.get('win_subsystem') or 'console' diff --git a/mesonbuild/cargo/interpreter.py b/mesonbuild/cargo/interpreter.py index 57f2bed..1d06474 100644 --- a/mesonbuild/cargo/interpreter.py +++ b/mesonbuild/cargo/interpreter.py @@ -27,11 +27,11 @@ from .. import coredata, options if T.TYPE_CHECKING: from types import ModuleType + from typing import Any from . import manifest from .. import mparser from ..environment import Environment - from ..coredata import KeyedOptionDictType # tomllib is present in python 3.11, before that it is a pypi module called tomli, # we try to import tomllib, then tomli, @@ -700,7 +700,7 @@ def _create_lib(cargo: Manifest, build: builder.Builder, crate_type: manifest.CR ] -def interpret(subp_name: str, subdir: str, env: Environment) -> T.Tuple[mparser.CodeBlockNode, KeyedOptionDictType]: +def interpret(subp_name: str, subdir: str, env: Environment) -> T.Tuple[mparser.CodeBlockNode, dict[OptionKey, options.UserOption[Any]]]: # subp_name should be in the form "foo-0.1-rs" package_name = subp_name.rsplit('-', 2)[0] manifests = _load_manifests(os.path.join(env.source_dir, subdir)) diff --git a/mesonbuild/cmake/common.py b/mesonbuild/cmake/common.py index f117a9f..ad4ec6b 100644 --- a/mesonbuild/cmake/common.py +++ b/mesonbuild/cmake/common.py @@ -51,9 +51,9 @@ blacklist_cmake_defs = [ ] def cmake_is_debug(env: 'Environment') -> bool: - if OptionKey('b_vscrt') in env.coredata.options: + if OptionKey('b_vscrt') in env.coredata.optstore: is_debug = env.coredata.get_option(OptionKey('buildtype')) == 'debug' - if env.coredata.options[OptionKey('b_vscrt')].value in {'mdd', 'mtd'}: + if env.coredata.optstore.get_value('b_vscrt') in {'mdd', 'mtd'}: is_debug = True return is_debug else: diff --git a/mesonbuild/cmake/executor.py b/mesonbuild/cmake/executor.py index dd43cc0..392063d 100644 --- a/mesonbuild/cmake/executor.py +++ b/mesonbuild/cmake/executor.py @@ -51,7 +51,7 @@ class CMakeExecutor: self.cmakebin = None return - self.prefix_paths = self.environment.coredata.options[OptionKey('cmake_prefix_path', machine=self.for_machine)].value + self.prefix_paths = self.environment.coredata.optstore.get_value(OptionKey('cmake_prefix_path', machine=self.for_machine)) if self.prefix_paths: self.extra_cmake_args += ['-DCMAKE_PREFIX_PATH={}'.format(';'.join(self.prefix_paths))] diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py index 4c42dbb..f67591f 100644 --- a/mesonbuild/cmake/interpreter.py +++ b/mesonbuild/cmake/interpreter.py @@ -532,7 +532,7 @@ class ConverterTarget: @lru_cache(maxsize=None) def _all_lang_stds(self, lang: str) -> 'ImmutableListProtocol[str]': try: - res = self.env.coredata.options[OptionKey('std', machine=MachineChoice.BUILD, lang=lang)].choices + res = self.env.coredata.optstore.get_value_object(OptionKey('std', machine=MachineChoice.BUILD, lang=lang)).choices except KeyError: return [] diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 7f2efc9..8fda3a5 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -165,16 +165,16 @@ class ClangCCompiler(_ClangCStds, ClangCompiler, CCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] key = self.form_langopt_key('std') - std = options[key] - if std.value != 'none': - args.append('-std=' + std.value) + std = options.get_value(key) + if std != 'none': + args.append('-std=' + std) return args 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. key = self.form_langopt_key('winlibs') - libs = options[key].value.copy() + libs = options.get_value(key).copy() assert isinstance(libs, list) for l in libs: assert isinstance(l, str) @@ -258,9 +258,9 @@ class ArmclangCCompiler(ArmclangCompiler, CCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] key = self.form_langopt_key('std') - std = options[key] - if std.value != 'none': - args.append('-std=' + std.value) + std = options.get_value(key) + if std != 'none': + args.append('-std=' + std) return args def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: @@ -318,16 +318,16 @@ class GnuCCompiler(GnuCompiler, CCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] key = self.form_langopt_key('std') - std = options[key] - if std.value != 'none': - args.append('-std=' + std.value) + std = options.get_value(key) + if std != 'none': + args.append('-std=' + std) return args 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 key = self.form_langopt_key('winlibs') - libs: T.List[str] = options[key].value.copy() + libs: T.List[str] = options.get_value(key).copy() assert isinstance(libs, list) for l in libs: assert isinstance(l, str) @@ -432,9 +432,9 @@ class IntelCCompiler(IntelGnuLikeCompiler, CCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] key = self.form_langopt_key('std') - std = options[key] - if std.value != 'none': - args.append('-std=' + std.value) + std = options.get_value(key) + if std != 'none': + args.append('-std=' + std) return args @@ -461,7 +461,7 @@ class VisualStudioLikeCCompilerMixin(CompilerMixinBase): def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: # need a TypeDict to make this work key = self.form_langopt_key('winlibs') - libs = options[key].value.copy() + libs = options.get_value(key).copy() assert isinstance(libs, list) for l in libs: assert isinstance(l, str) @@ -498,11 +498,11 @@ class VisualStudioCCompiler(MSVCCompiler, VisualStudioLikeCCompilerMixin, CCompi def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] key = self.form_langopt_key('std') - std = options[key] + std = options.get_value(key) # As of MVSC 16.8, /std:c11 and /std:c17 are the only valid C standard options. - if std.value in {'c11'}: + if std == 'c11': args.append('/std:c11') - elif std.value in {'c17', 'c18'}: + elif std in {'c17', 'c18'}: args.append('/std:c17') return args @@ -519,7 +519,7 @@ class ClangClCCompiler(_ClangCStds, ClangClCompiler, VisualStudioLikeCCompilerMi def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: key = self.form_langopt_key('std') - std = options[key].value + std = options.get_value(key) if std != "none": return [f'/clang:-std={std}'] return [] @@ -541,7 +541,10 @@ class IntelClCCompiler(IntelVisualStudioLikeCompiler, VisualStudioLikeCCompilerM def get_options(self) -> 'MutableKeyedOptionDictType': opts = super().get_options() key = self.form_langopt_key('std') - std_opt = opts[key] + # To shut up mypy. + if isinstance(opts, dict): + raise RuntimeError('This is a transitory issue that should not happen. Please report with full backtrace.') + std_opt = opts.get_value_object(key) assert isinstance(std_opt, options.UserStdOption), 'for mypy' std_opt.set_versions(['c89', 'c99', 'c11']) return opts @@ -549,11 +552,11 @@ class IntelClCCompiler(IntelVisualStudioLikeCompiler, VisualStudioLikeCCompilerM def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] key = self.form_langopt_key('std') - std = options[key] - if std.value == 'c89': + std = options.get_value(key) + if std == 'c89': mlog.log("ICL doesn't explicitly implement c89, setting the standard to 'none', which is close.", once=True) - elif std.value != 'none': - args.append('/Qstd:' + std.value) + elif std != 'none': + args.append('/Qstd:' + std) return args @@ -583,9 +586,9 @@ class ArmCCompiler(ArmCompiler, CCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] key = self.form_langopt_key('std') - std = options[key] - if std.value != 'none': - args.append('--' + std.value) + std = options.get_value(key) + if std != 'none': + args.append('--' + std) return args @@ -616,10 +619,10 @@ class CcrxCCompiler(CcrxCompiler, CCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] key = self.form_langopt_key('std') - std = options[key] - if std.value == 'c89': + std = options.get_value(key) + if std == 'c89': args.append('-lang=c') - elif std.value == 'c99': + elif std == 'c99': args.append('-lang=c99') return args @@ -664,10 +667,10 @@ class Xc16CCompiler(Xc16Compiler, CCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] key = self.form_langopt_key('std') - std = options[key] - if std.value != 'none': + std = options.get_value(key) + if std != 'none': args.append('-ansi') - args.append('-std=' + std.value) + args.append('-std=' + std) return args def get_compile_only_args(self) -> T.List[str]: @@ -748,9 +751,9 @@ class TICCompiler(TICompiler, CCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] key = self.form_langopt_key('std') - std = options[key] - if std.value != 'none': - args.append('--' + std.value) + std = options.get_value(key) + if std != 'none': + args.append('--' + std) return args class C2000CCompiler(TICCompiler): @@ -784,10 +787,10 @@ class MetrowerksCCompilerARM(MetrowerksCompiler, CCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] key = self.form_langopt_key('std') - std = options[key] - if std.value != 'none': + std = options.get_value(key) + if std != 'none': args.append('-lang') - args.append(std.value) + args.append(std) return args class MetrowerksCCompilerEmbeddedPowerPC(MetrowerksCompiler, CCompiler): @@ -814,7 +817,7 @@ class MetrowerksCCompilerEmbeddedPowerPC(MetrowerksCompiler, CCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] key = self.form_langopt_key('std') - std = options[key] - if std.value != 'none': - args.append('-lang ' + std.value) + std = options.get_value(key) + if std != 'none': + args.append('-lang ' + std) return args diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index ef0ea70..4a1fd98 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -25,6 +25,7 @@ from ..mesonlib import ( from ..arglist import CompilerArgs if T.TYPE_CHECKING: + from typing import Any from ..build import BuildTarget, DFeatures from ..coredata import MutableKeyedOptionDictType, KeyedOptionDictType from ..envconfig import MachineInfo @@ -247,14 +248,14 @@ BASE_OPTIONS: T.Mapping[OptionKey, BaseOption] = { choices=MSCRT_VALS + ['from_buildtype', 'static_from_buildtype']), } -base_options: KeyedOptionDictType = {key: base_opt.init_option(key) for key, base_opt in BASE_OPTIONS.items()} +base_options = {key: base_opt.init_option(key) for key, base_opt in BASE_OPTIONS.items()} def option_enabled(boptions: T.Set[OptionKey], options: 'KeyedOptionDictType', option: OptionKey) -> bool: try: if option not in boptions: return False - ret = options[option].value + ret = options.get_value(option) assert isinstance(ret, bool), 'must return bool' # could also be str return ret except KeyError: @@ -264,8 +265,8 @@ def option_enabled(boptions: T.Set[OptionKey], options: 'KeyedOptionDictType', def get_option_value(options: 'KeyedOptionDictType', opt: OptionKey, fallback: '_T') -> '_T': """Get the value of an option, or the fallback value.""" try: - v: '_T' = options[opt].value - except KeyError: + v: '_T' = options.get_value(opt) + except (KeyError, AttributeError): return fallback assert isinstance(v, type(fallback)), f'Should have {type(fallback)!r} but was {type(v)!r}' @@ -279,52 +280,52 @@ def are_asserts_disabled(options: KeyedOptionDictType) -> bool: :param options: OptionDictionary :return: whether to disable assertions or not """ - return (options[OptionKey('b_ndebug')].value == 'true' or - (options[OptionKey('b_ndebug')].value == 'if-release' and - options[OptionKey('buildtype')].value in {'release', 'plain'})) + return (options.get_value('b_ndebug') == 'true' or + (options.get_value('b_ndebug') == 'if-release' and + options.get_value('buildtype') in {'release', 'plain'})) def get_base_compile_args(options: 'KeyedOptionDictType', compiler: 'Compiler', env: 'Environment') -> T.List[str]: args: T.List[str] = [] try: - if options[OptionKey('b_lto')].value: + if options.get_value(OptionKey('b_lto')): args.extend(compiler.get_lto_compile_args( threads=get_option_value(options, OptionKey('b_lto_threads'), 0), mode=get_option_value(options, OptionKey('b_lto_mode'), 'default'))) - except KeyError: + except (KeyError, AttributeError): pass try: - args += compiler.get_colorout_args(options[OptionKey('b_colorout')].value) - except KeyError: + args += compiler.get_colorout_args(options.get_value(OptionKey('b_colorout'))) + except (KeyError, AttributeError): pass try: - args += compiler.sanitizer_compile_args(options[OptionKey('b_sanitize')].value) - except KeyError: + args += compiler.sanitizer_compile_args(options.get_value(OptionKey('b_sanitize'))) + except (KeyError, AttributeError): pass try: - pgo_val = options[OptionKey('b_pgo')].value + pgo_val = options.get_value(OptionKey('b_pgo')) if pgo_val == 'generate': args.extend(compiler.get_profile_generate_args()) elif pgo_val == 'use': args.extend(compiler.get_profile_use_args()) - except KeyError: + except (KeyError, AttributeError): pass try: - if options[OptionKey('b_coverage')].value: + if options.get_value(OptionKey('b_coverage')): args += compiler.get_coverage_args() - except KeyError: + except (KeyError, AttributeError): pass try: args += compiler.get_assert_args(are_asserts_disabled(options), env) - except KeyError: + except (KeyError, AttributeError): pass # This does not need a try...except if option_enabled(compiler.base_options, options, OptionKey('b_bitcode')): args.append('-fembed-bitcode') try: - crt_val = options[OptionKey('b_vscrt')].value - buildtype = options[OptionKey('buildtype')].value try: + crt_val = options.get_value(OptionKey('b_vscrt')) + buildtype = options.get_value(OptionKey('buildtype')) args += compiler.get_crt_compile_args(crt_val, buildtype) except AttributeError: pass @@ -336,8 +337,8 @@ def get_base_link_args(options: 'KeyedOptionDictType', linker: 'Compiler', is_shared_module: bool, build_dir: str) -> T.List[str]: args: T.List[str] = [] try: - if options[OptionKey('b_lto')].value: - if options[OptionKey('werror')].value: + if options.get_value('b_lto'): + if options.get_value('werror'): args.extend(linker.get_werror_args()) thinlto_cache_dir = None @@ -349,24 +350,24 @@ def get_base_link_args(options: 'KeyedOptionDictType', linker: 'Compiler', threads=get_option_value(options, OptionKey('b_lto_threads'), 0), mode=get_option_value(options, OptionKey('b_lto_mode'), 'default'), thinlto_cache_dir=thinlto_cache_dir)) - except KeyError: + except (KeyError, AttributeError): pass try: - args += linker.sanitizer_link_args(options[OptionKey('b_sanitize')].value) - except KeyError: + args += linker.sanitizer_link_args(options.get_value('b_sanitize')) + except (KeyError, AttributeError): pass try: - pgo_val = options[OptionKey('b_pgo')].value + pgo_val = options.get_value('b_pgo') if pgo_val == 'generate': args.extend(linker.get_profile_generate_args()) elif pgo_val == 'use': args.extend(linker.get_profile_use_args()) - except KeyError: + except (KeyError, AttributeError): pass try: - if options[OptionKey('b_coverage')].value: + if options.get_value('b_coverage'): args += linker.get_coverage_link_args() - except KeyError: + except (KeyError, AttributeError): pass as_needed = option_enabled(linker.base_options, options, OptionKey('b_asneeded')) @@ -390,9 +391,9 @@ def get_base_link_args(options: 'KeyedOptionDictType', linker: 'Compiler', args.extend(linker.get_allow_undefined_link_args()) try: - crt_val = options[OptionKey('b_vscrt')].value - buildtype = options[OptionKey('buildtype')].value try: + crt_val = options.get_value(OptionKey('b_vscrt')) + buildtype = options.get_value(OptionKey('buildtype')) args += linker.get_crt_link_args(crt_val, buildtype) except AttributeError: pass @@ -1357,7 +1358,7 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta): def get_global_options(lang: str, comp: T.Type[Compiler], for_machine: MachineChoice, - env: 'Environment') -> 'KeyedOptionDictType': + env: 'Environment') -> 'dict[OptionKey, options.UserOption[Any]]': """Retrieve options that apply to all compilers for a given language.""" description = f'Extra arguments passed to the {lang}' argkey = OptionKey('args', lang=lang, machine=for_machine) @@ -1387,6 +1388,6 @@ def get_global_options(lang: str, # autotools compatibility. largs.extend_value(comp_options) - opts: 'KeyedOptionDictType' = {argkey: cargs, largkey: largs} + opts: 'dict[OptionKey, options.UserOption[Any]]' = {argkey: cargs, largkey: largs} return opts diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index 12d7201..df2f905 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -278,15 +278,15 @@ class ClangCPPCompiler(_StdCPPLibMixin, ClangCompiler, CPPCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = self.form_langopt_key('std') - std = options[key] - if std.value != 'none': - args.append(self._find_best_cpp_std(std.value)) + std = options.get_value(key) + if std != 'none': + args.append(self._find_best_cpp_std(std)) key = self.form_langopt_key('eh') - non_msvc_eh_options(options[key].value, args) + non_msvc_eh_options(options.get_value(key), args) key = self.form_langopt_key('debugstl') - if options[key].value: + if options.get_value(key): args.append('-D_GLIBCXX_DEBUG=1') # We can't do _LIBCPP_DEBUG because it's unreliable unless libc++ was built with it too: @@ -296,7 +296,7 @@ class ClangCPPCompiler(_StdCPPLibMixin, ClangCompiler, CPPCompiler): args.append('-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG') key = self.form_langopt_key('rtti') - if not options[key].value: + if not options.get_value(key): args.append('-fno-rtti') return args @@ -305,7 +305,7 @@ class ClangCPPCompiler(_StdCPPLibMixin, ClangCompiler, CPPCompiler): if self.info.is_windows() or self.info.is_cygwin(): # without a typedict mypy can't understand this. key = self.form_langopt_key('winlibs') - libs = options[key].value.copy() + libs = options.get_value(key).copy() assert isinstance(libs, list) for l in libs: assert isinstance(l, str) @@ -365,9 +365,9 @@ class EmscriptenCPPCompiler(EmscriptenMixin, ClangCPPCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = self.form_langopt_key('std') - std = options[key] - if std.value != 'none': - args.append(self._find_best_cpp_std(std.value)) + std = options.get_value(key) + if std != 'none': + args.append(self._find_best_cpp_std(std)) return args @@ -409,12 +409,12 @@ class ArmclangCPPCompiler(ArmclangCompiler, CPPCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = self.form_langopt_key('std') - std = options[key] - if std.value != 'none': - args.append('-std=' + std.value) + std = options.get_value(key) + if std != 'none': + args.append('-std=' + std) key = self.form_langopt_key('eh') - non_msvc_eh_options(options[key].value, args) + non_msvc_eh_options(options.get_value(key), args) return args @@ -483,16 +483,16 @@ class GnuCPPCompiler(_StdCPPLibMixin, GnuCompiler, CPPCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = self.form_langopt_key('std') - std = options[key] - if std.value != 'none': - args.append(self._find_best_cpp_std(std.value)) + std = options.get_value(key) + if std != 'none': + args.append(self._find_best_cpp_std(std)) - non_msvc_eh_options(options[key.evolve('eh')].value, args) + non_msvc_eh_options(options.get_value(key.evolve('eh')), args) - if not options[key.evolve('rtti')].value: + if not options.get_value(key.evolve('rtti')): args.append('-fno-rtti') - if options[key.evolve('debugstl')].value: + if options.get_value(key.evolve('debugstl')): args.append('-D_GLIBCXX_DEBUG=1') return args @@ -500,7 +500,7 @@ class GnuCPPCompiler(_StdCPPLibMixin, GnuCompiler, CPPCompiler): if self.info.is_windows() or self.info.is_cygwin(): # without a typedict mypy can't understand this. key = self.form_langopt_key('winlibs') - libs = options[key].value.copy() + libs = options.get_value(key).copy() assert isinstance(libs, list) for l in libs: assert isinstance(l, str) @@ -616,15 +616,15 @@ class ElbrusCPPCompiler(ElbrusCompiler, CPPCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = self.form_langopt_key('std') - std = options[key] + std = options.get_value(key) if std.value != 'none': args.append(self._find_best_cpp_std(std.value)) key = self.form_langopt_key('eh') - non_msvc_eh_options(options[key].value, args) + non_msvc_eh_options(options.get_value(key), args) key = self.form_langopt_key('debugstl') - if options[key].value: + if options.get_value(key): args.append('-D_GLIBCXX_DEBUG=1') return args @@ -688,18 +688,18 @@ class IntelCPPCompiler(IntelGnuLikeCompiler, CPPCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = self.form_langopt_key('std') - std = options[key] - if std.value != 'none': + std = options.get_value(key) + if std != 'none': remap_cpp03 = { 'c++03': 'c++98', 'gnu++03': 'gnu++98' } - args.append('-std=' + remap_cpp03.get(std.value, std.value)) - if options[key.evolve('eh')].value == 'none': + args.append('-std=' + remap_cpp03.get(std.value, std)) + if options.get_value(key.evolve('eh')) == 'none': args.append('-fno-exceptions') - if not options[key.evolve('rtti')].value: + if not options.get_value(key.evolve('rtti')): args.append('-fno-rtti') - if options[key.evolve('debugstl')].value: + if options.get_value(key.evolve('debugstl')): args.append('-D_GLIBCXX_DEBUG=1') return args @@ -733,7 +733,7 @@ class VisualStudioLikeCPPCompilerMixin(CompilerMixinBase): def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: # need a typeddict for this key = self.form_langopt_key('winlibs') - return T.cast('T.List[str]', options[key].value[:]) + return T.cast('T.List[str]', options.get_value(key)[:]) def _get_options_impl(self, opts: 'MutableKeyedOptionDictType', cpp_stds: T.List[str]) -> 'MutableKeyedOptionDictType': key = self.form_langopt_key('std') @@ -762,18 +762,18 @@ class VisualStudioLikeCPPCompilerMixin(CompilerMixinBase): args: T.List[str] = [] key = self.form_langopt_key('std') - eh = options[self.form_langopt_key('eh')] - if eh.value == 'default': + eh = options.get_value(self.form_langopt_key('eh')) + if eh == 'default': args.append('/EHsc') - elif eh.value == 'none': + elif eh == 'none': args.append('/EHs-c-') else: - args.append('/EH' + eh.value) + args.append('/EH' + eh) - if not options[self.form_langopt_key('rtti')].value: + if not options.get_value(self.form_langopt_key('rtti')): args.append('/GR-') - permissive, ver = self.VC_VERSION_MAP[options[key].value] + permissive, ver = self.VC_VERSION_MAP[options.get_value(key)] if ver is not None: args.append(f'/std:c++{ver}') @@ -801,7 +801,7 @@ class CPP11AsCPP14Mixin(CompilerMixinBase): # (i.e., after VS2015U3) # if one is using anything before that point, one cannot set the standard. key = self.form_langopt_key('std') - if options[key].value in {'vc++11', 'c++11'}: + if options.get_value(key) 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, fatal=False) @@ -809,10 +809,10 @@ class CPP11AsCPP14Mixin(CompilerMixinBase): # 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[key].value == 'vc++11': - options[key].value = 'vc++14' + if options.get_value(key) == 'vc++11': + options.set_value(key, 'vc++14') else: - options[key].value = 'c++14' + options.set_value(key, 'c++14') return super().get_option_compile_args(options) @@ -848,10 +848,10 @@ class VisualStudioCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixi def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: key = self.form_langopt_key('std') - if options[key].value != 'none' and version_compare(self.version, '<19.00.24210'): + if options.get_value(key) != 'none' and version_compare(self.version, '<19.00.24210'): mlog.warning('This version of MSVC does not support cpp_std arguments', fatal=False) options = copy.copy(options) - options[key].value = 'none' + options.set_value(key, 'none') args = super().get_option_compile_args(options) @@ -924,10 +924,10 @@ class ArmCPPCompiler(ArmCompiler, CPPCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = self.form_langopt_key('std') - std = options[key] - if std.value == 'c++11': + std = options.get_value(key) + if std == 'c++11': args.append('--cpp11') - elif std.value == 'c++03': + elif std == 'c++03': args.append('--cpp') return args @@ -986,9 +986,9 @@ class TICPPCompiler(TICompiler, CPPCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = self.form_langopt_key('std') - std = options[key] - if std.value != 'none': - args.append('--' + std.value) + std = options.get_value(key) + if std != 'none': + args.append('--' + std) return args def get_always_args(self) -> T.List[str]: @@ -1027,10 +1027,10 @@ class MetrowerksCPPCompilerARM(MetrowerksCompiler, CPPCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = self.form_langopt_key('std') - std = options[key] - if std.value != 'none': + std = options.get_value(key) + if std != 'none': args.append('-lang') - args.append(std.value) + args.append(std) return args class MetrowerksCPPCompilerEmbeddedPowerPC(MetrowerksCompiler, CPPCompiler): @@ -1056,7 +1056,7 @@ class MetrowerksCPPCompilerEmbeddedPowerPC(MetrowerksCompiler, CPPCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = self.form_langopt_key('std') - std = options[key] - if std.value != 'none': - args.append('-lang ' + std.value) + std = options.get_value(key) + if std != 'none': + args.append('-lang ' + std) return args diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py index 954040e..dc9cf8a 100644 --- a/mesonbuild/compilers/cuda.py +++ b/mesonbuild/compilers/cuda.py @@ -13,7 +13,7 @@ from .. import options from .. import mlog from ..mesonlib import ( EnvironmentException, Popen_safe, - is_windows, LibType, version_compare, + is_windows, LibType, version_compare, OptionKey ) from .compilers import Compiler @@ -549,7 +549,7 @@ class CudaCompiler(Compiler): # Use the -ccbin option, if available, even during sanity checking. # Otherwise, on systems where CUDA does not support the default compiler, # NVCC becomes unusable. - flags += self.get_ccbin_args(env.coredata.options) + flags += self.get_ccbin_args(env.coredata.optstore) # If cross-compiling, we can't run the sanity check, only compile it. if env.need_exe_wrapper(self.for_machine) and not env.has_exe_wrapper(): @@ -655,16 +655,17 @@ class CudaCompiler(Compiler): ''), ) - def _to_host_compiler_options(self, options: 'KeyedOptionDictType') -> 'KeyedOptionDictType': + def _to_host_compiler_options(self, master_options: 'KeyedOptionDictType') -> 'KeyedOptionDictType': """ Convert an NVCC Option set to a host compiler's option set. """ # We must strip the -std option from the host compiler option set, as NVCC has # its own -std flag that may not agree with the host compiler's. - host_options = {key: options.get(key, opt) for key, opt in self.host_compiler.get_options().items()} - std_key = self.form_langopt_key('std') + host_options = {key: master_options.get(key, opt) for key, opt in self.host_compiler.get_options().items()} + std_key = OptionKey('std', machine=self.for_machine, lang=self.host_compiler.language) overrides = {std_key: 'none'} + # To shut up mypy. return coredata.OptionsView(host_options, overrides=overrides) def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: @@ -674,9 +675,9 @@ class CudaCompiler(Compiler): # and attempting to use it will result in a warning: https://stackoverflow.com/a/51272091/741027 if not is_windows(): key = self.form_langopt_key('std') - std = options[key] - if std.value != 'none': - args.append('--std=' + std.value) + std = options.get_value(key) + if std != 'none': + args.append('--std=' + std) return args + self._to_host_flags(self.host_compiler.get_option_compile_args(self._to_host_compiler_options(options))) @@ -792,9 +793,9 @@ class CudaCompiler(Compiler): def get_dependency_link_args(self, dep: 'Dependency') -> T.List[str]: return self._to_host_flags(super().get_dependency_link_args(dep), _Phase.LINKER) - def get_ccbin_args(self, options: 'KeyedOptionDictType') -> T.List[str]: + def get_ccbin_args(self, ccoptions: 'KeyedOptionDictType') -> T.List[str]: key = self.form_langopt_key('ccbindir') - ccbindir = options[key].value + ccbindir = ccoptions.get_value(key) if isinstance(ccbindir, str) and ccbindir != '': return [self._shield_nvcc_list_arg('-ccbin='+ccbindir, False)] else: diff --git a/mesonbuild/compilers/cython.py b/mesonbuild/compilers/cython.py index 76e66c0..7c11286 100644 --- a/mesonbuild/compilers/cython.py +++ b/mesonbuild/compilers/cython.py @@ -84,10 +84,10 @@ class CythonCompiler(Compiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = self.form_langopt_key('version') - version = options[key] - args.append(f'-{version.value}') + version = options.get_value(key) + args.append(f'-{version}') key = self.form_langopt_key('language') - lang = options[key] - if lang.value == 'cpp': + lang = options.get_value(key) + if lang == 'cpp': args.append('--cplus') return args diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index 66fb466..9b288e9 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -154,9 +154,9 @@ class GnuFortranCompiler(GnuCompiler, FortranCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = self.form_langopt_key('std') - std = options[key] - if std.value != 'none': - args.append('-std=' + std.value) + std = options.get_value(key) + if std != 'none': + args.append('-std=' + std) return args def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: @@ -291,10 +291,10 @@ class IntelFortranCompiler(IntelGnuLikeCompiler, FortranCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = self.form_langopt_key('std') - std = options[key] + std = options.get_value(key) stds = {'legacy': 'none', 'f95': 'f95', 'f2003': 'f03', 'f2008': 'f08', 'f2018': 'f18'} - if std.value != 'none': - args.append('-stand=' + stds[std.value]) + if std != 'none': + args.append('-stand=' + stds[std]) return args def get_preprocess_only_args(self) -> T.List[str]: @@ -346,10 +346,10 @@ class IntelClFortranCompiler(IntelVisualStudioLikeCompiler, FortranCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] key = self.form_langopt_key('std') - std = options[key] + std = options.get_value(key) stds = {'legacy': 'none', 'f95': 'f95', 'f2003': 'f03', 'f2008': 'f08', 'f2018': 'f18'} - if std.value != 'none': - args.append('/stand:' + stds[std.value]) + if std != 'none': + args.append('/stand:' + stds[std]) return args def get_werror_args(self) -> T.List[str]: diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index d273015..70e81a4 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -26,7 +26,7 @@ from ... import arglist from ... import mesonlib from ... import mlog from ...linkers.linkers import GnuLikeDynamicLinkerMixin, SolarisDynamicLinker, CompCertDynamicLinker -from ...mesonlib import LibType, OptionKey +from ...mesonlib import LibType from .. import compilers from ..compilers import CompileCheckMode from .visualstudio import VisualStudioLikeCompiler @@ -376,8 +376,8 @@ class CLikeCompiler(Compiler): # linking with static libraries since MSVC won't select a CRT for # us in that case and will error out asking us to pick one. try: - crt_val = env.coredata.options[OptionKey('b_vscrt')].value - buildtype = env.coredata.options[OptionKey('buildtype')].value + crt_val = env.coredata.optstore.get_value('b_vscrt') + buildtype = env.coredata.optstore.get_value('buildtype') cargs += self.get_crt_compile_args(crt_val, buildtype) except (KeyError, AttributeError): pass diff --git a/mesonbuild/compilers/mixins/elbrus.py b/mesonbuild/compilers/mixins/elbrus.py index 27cba80..10df3de 100644 --- a/mesonbuild/compilers/mixins/elbrus.py +++ b/mesonbuild/compilers/mixins/elbrus.py @@ -84,9 +84,9 @@ class ElbrusCompiler(GnuLikeCompiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] - std = options[OptionKey('std', lang=self.language, machine=self.for_machine)] - if std.value != 'none': - args.append('-std=' + std.value) + std = options.get_value(OptionKey('std', lang=self.language, machine=self.for_machine)) + if std != 'none': + args.append('-std=' + std) return args def openmp_flags(self) -> T.List[str]: diff --git a/mesonbuild/compilers/mixins/emscripten.py b/mesonbuild/compilers/mixins/emscripten.py index 110dbc6..6b7f087 100644 --- a/mesonbuild/compilers/mixins/emscripten.py +++ b/mesonbuild/compilers/mixins/emscripten.py @@ -51,7 +51,7 @@ class EmscriptenMixin(Compiler): def thread_link_flags(self, env: 'Environment') -> T.List[str]: args = ['-pthread'] - count: int = env.coredata.options[OptionKey('thread_count', lang=self.language, machine=self.for_machine)].value + count: int = env.coredata.optstore.get_value(OptionKey('thread_count', lang=self.language, machine=self.for_machine)) if count: args.append(f'-sPTHREAD_POOL_SIZE={count}') return args diff --git a/mesonbuild/compilers/objc.py b/mesonbuild/compilers/objc.py index 4d33ec8..c63f288 100644 --- a/mesonbuild/compilers/objc.py +++ b/mesonbuild/compilers/objc.py @@ -90,9 +90,9 @@ class ClangObjCCompiler(ClangCompiler, ObjCCompiler): def get_option_compile_args(self, options: 'coredata.KeyedOptionDictType') -> T.List[str]: args = [] - std = options[OptionKey('std', machine=self.for_machine, lang='c')] - if std.value != 'none': - args.append('-std=' + std.value) + std = options.get_value(OptionKey('std', machine=self.for_machine, lang='c')) + if std != 'none': + args.append('-std=' + std) return args class AppleClangObjCCompiler(ClangObjCCompiler): diff --git a/mesonbuild/compilers/objcpp.py b/mesonbuild/compilers/objcpp.py index e28e3ed..e24406c 100644 --- a/mesonbuild/compilers/objcpp.py +++ b/mesonbuild/compilers/objcpp.py @@ -92,9 +92,9 @@ class ClangObjCPPCompiler(ClangCompiler, ObjCPPCompiler): def get_option_compile_args(self, options: 'coredata.KeyedOptionDictType') -> T.List[str]: args = [] - std = options[OptionKey('std', machine=self.for_machine, lang='cpp')] - if std.value != 'none': - args.append('-std=' + std.value) + std = options.get_value(OptionKey('std', machine=self.for_machine, lang='cpp')) + if std != 'none': + args.append('-std=' + std) return args diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py index 346a3dd..b130c58 100644 --- a/mesonbuild/compilers/rust.py +++ b/mesonbuild/compilers/rust.py @@ -173,9 +173,9 @@ class RustCompiler(Compiler): def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args = [] key = self.form_langopt_key('std') - std = options[key] - if std.value != 'none': - args.append('--edition=' + std.value) + std = options.get_value(key) + if std != 'none': + args.append('--edition=' + std) return args def get_crt_compile_args(self, crt_val: str, buildtype: str) -> T.List[str]: diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 782e770..36191d9 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -32,6 +32,7 @@ import typing as T if T.TYPE_CHECKING: from typing_extensions import Protocol + from typing import Any from . import dependencies from .compilers.compilers import Compiler, CompileResult, RunResult, CompileCheckMode @@ -40,6 +41,7 @@ if T.TYPE_CHECKING: from .mesonlib import FileOrString from .cmake.traceparser import CMakeCacheEntry from .interpreterbase import SubProject + from .options import UserOption class SharedCMDOptions(Protocol): @@ -58,7 +60,7 @@ if T.TYPE_CHECKING: OptionDictType = T.Union[T.Dict[str, 'options.UserOption[T.Any]'], 'OptionsView'] MutableKeyedOptionDictType = T.Dict['OptionKey', 'options.UserOption[T.Any]'] - KeyedOptionDictType = T.Union[MutableKeyedOptionDictType, 'OptionsView'] + KeyedOptionDictType = T.Union['options.OptionStore', 'OptionsView'] CompilerCheckCacheKey = T.Tuple[T.Tuple[str, ...], str, FileOrString, T.Tuple[str, ...], CompileCheckMode] # code, args RunCheckCacheKey = T.Tuple[str, T.Tuple[str, ...]] @@ -150,8 +152,8 @@ class DependencyCache: def __calculate_subkey(self, type_: DependencyCacheType) -> T.Tuple[str, ...]: data: T.Dict[DependencyCacheType, T.List[str]] = { - DependencyCacheType.PKG_CONFIG: stringlistify(self.__builtins[self.__pkg_conf_key].value), - DependencyCacheType.CMAKE: stringlistify(self.__builtins[self.__cmake_key].value), + DependencyCacheType.PKG_CONFIG: stringlistify(self.__builtins.get_value(self.__pkg_conf_key)), + DependencyCacheType.CMAKE: stringlistify(self.__builtins.get_value(self.__cmake_key)), DependencyCacheType.OTHER: [], } assert type_ in data, 'Someone forgot to update subkey calculations for a new type' @@ -241,7 +243,7 @@ _V = T.TypeVar('_V') class CoreData: - def __init__(self, options: SharedCMDOptions, scratch_dir: str, meson_command: T.List[str]): + def __init__(self, cmd_options: SharedCMDOptions, scratch_dir: str, meson_command: T.List[str]): self.lang_guids = { 'default': '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942', 'c': '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942', @@ -255,8 +257,8 @@ class CoreData: self.meson_command = meson_command self.target_guids = {} self.version = version - self.options: 'MutableKeyedOptionDictType' = {} - self.cross_files = self.__load_config_files(options, scratch_dir, 'cross') + self.optstore = options.OptionStore() + self.cross_files = self.__load_config_files(cmd_options, scratch_dir, 'cross') self.compilers: PerMachine[T.Dict[str, Compiler]] = PerMachine(OrderedDict(), OrderedDict()) # Stores the (name, hash) of the options file, The name will be either @@ -272,8 +274,8 @@ class CoreData: # For host == build configurations these caches should be the same. self.deps: PerMachine[DependencyCache] = PerMachineDefaultable.default( self.is_cross_build(), - DependencyCache(self.options, MachineChoice.BUILD), - DependencyCache(self.options, MachineChoice.HOST)) + DependencyCache(self.optstore, MachineChoice.BUILD), + DependencyCache(self.optstore, MachineChoice.HOST)) self.compiler_check_cache: T.Dict['CompilerCheckCacheKey', 'CompileResult'] = OrderedDict() self.run_check_cache: T.Dict['RunCheckCacheKey', 'RunResult'] = OrderedDict() @@ -282,18 +284,18 @@ class CoreData: self.cmake_cache: PerMachine[CMakeStateCache] = PerMachine(CMakeStateCache(), CMakeStateCache()) # Only to print a warning if it changes between Meson invocations. - self.config_files = self.__load_config_files(options, scratch_dir, 'native') + self.config_files = self.__load_config_files(cmd_options, scratch_dir, 'native') self.builtin_options_libdir_cross_fixup() self.init_builtins('') @staticmethod - def __load_config_files(options: SharedCMDOptions, scratch_dir: str, ftype: str) -> T.List[str]: + def __load_config_files(cmd_options: SharedCMDOptions, scratch_dir: str, ftype: str) -> T.List[str]: # Need to try and make the passed filenames absolute because when the # files are parsed later we'll have chdir()d. if ftype == 'cross': - filenames = options.cross_file + filenames = cmd_options.cross_file else: - filenames = options.native_file + filenames = cmd_options.native_file if not filenames: return [] @@ -403,10 +405,10 @@ class CoreData: def init_builtins(self, subproject: str) -> None: # Create builtin options with default values for key, opt in options.BUILTIN_OPTIONS.items(): - self.add_builtin_option(self.options, key.evolve(subproject=subproject), opt) + self.add_builtin_option(self.optstore, key.evolve(subproject=subproject), opt) for for_machine in iter(MachineChoice): for key, opt in options.BUILTIN_OPTIONS_PER_MACHINE.items(): - self.add_builtin_option(self.options, key.evolve(subproject=subproject, machine=for_machine), opt) + self.add_builtin_option(self.optstore, key.evolve(subproject=subproject, machine=for_machine), opt) @staticmethod def add_builtin_option(opts_map: 'MutableKeyedOptionDictType', key: OptionKey, @@ -415,33 +417,33 @@ class CoreData: if opt.yielding: # This option is global and not per-subproject return - value = opts_map[key.as_root()].value + value = opts_map.get_value(key.as_root()) else: value = None - opts_map[key] = opt.init_option(key, value, options.default_prefix()) + opts_map.add_system_option(key, opt.init_option(key, value, options.default_prefix())) def init_backend_options(self, backend_name: str) -> None: if backend_name == 'ninja': - self.options[OptionKey('backend_max_links')] = options.UserIntegerOption( + self.optstore.add_system_option('backend_max_links', options.UserIntegerOption( 'backend_max_links', 'Maximum number of linker processes to run or 0 for no ' 'limit', - (0, None, 0)) + (0, None, 0))) elif backend_name.startswith('vs'): - self.options[OptionKey('backend_startup_project')] = options.UserStringOption( + self.optstore.add_system_option('backend_startup_project', options.UserStringOption( 'backend_startup_project', 'Default project to execute in Visual Studio', - '') + '')) def get_option(self, key: OptionKey) -> T.Union[T.List[str], str, int, bool]: try: - v = self.options[key].value + v = self.optstore.get_value(key) return v except KeyError: pass try: - v = self.options[key.as_root()] + v = self.optstore.get_value_object(key.as_root()) if v.yielding: return v.value except KeyError: @@ -455,11 +457,11 @@ class CoreData: if key.name == 'prefix': value = self.sanitize_prefix(value) else: - prefix = self.options[OptionKey('prefix')].value + prefix = self.optstore.get_value('prefix') value = self.sanitize_dir_option_value(prefix, key, value) try: - opt = self.options[key] + opt = self.optstore.get_value_object(key) except KeyError: raise MesonException(f'Tried to set unknown builtin option {str(key)}') @@ -510,7 +512,7 @@ class CoreData: def get_nondefault_buildtype_args(self) -> T.List[T.Union[T.Tuple[str, str, str], T.Tuple[str, bool, bool]]]: result: T.List[T.Union[T.Tuple[str, str, str], T.Tuple[str, bool, bool]]] = [] - value = self.options[OptionKey('buildtype')].value + value = self.optstore.get_value('buildtype') if value == 'plain': opt = 'plain' debug = False @@ -529,8 +531,8 @@ class CoreData: else: assert value == 'custom' return [] - actual_opt = self.options[OptionKey('optimization')].value - actual_debug = self.options[OptionKey('debug')].value + actual_opt = self.optstore.get_value('optimization') + actual_debug = self.optstore.get_value('debug') if actual_opt != opt: result.append(('optimization', actual_opt, opt)) if actual_debug != debug: @@ -559,8 +561,8 @@ class CoreData: assert value == 'custom' return False - dirty |= self.options[OptionKey('optimization')].set_value(opt) - dirty |= self.options[OptionKey('debug')].set_value(debug) + dirty |= self.optstore.set_value('optimization', opt) + dirty |= self.optstore.set_value('debug', debug) return dirty @@ -572,30 +574,32 @@ class CoreData: def get_external_args(self, for_machine: MachineChoice, lang: str) -> T.List[str]: # mypy cannot analyze type of OptionKey - return T.cast('T.List[str]', self.options[OptionKey('args', machine=for_machine, lang=lang)].value) + key = OptionKey('args', machine=for_machine, lang=lang) + return T.cast('T.List[str]', self.optstore.get_value(key)) def get_external_link_args(self, for_machine: MachineChoice, lang: str) -> T.List[str]: # mypy cannot analyze type of OptionKey - return T.cast('T.List[str]', self.options[OptionKey('link_args', machine=for_machine, lang=lang)].value) + key = OptionKey('link_args', machine=for_machine, lang=lang) + return T.cast('T.List[str]', self.optstore.get_value(key)) - def update_project_options(self, options: 'MutableKeyedOptionDictType', subproject: SubProject) -> None: - for key, value in options.items(): + def update_project_options(self, project_options: 'MutableKeyedOptionDictType', subproject: SubProject) -> None: + for key, value in project_options.items(): if not key.is_project(): continue - if key not in self.options: - self.options[key] = value + if key not in self.optstore: + self.optstore.add_project_option(key, value) continue if key.subproject != subproject: raise MesonBugException(f'Tried to set an option for subproject {key.subproject} from {subproject}!') - oldval = self.options[key] + oldval = self.optstore.get_value_object(key) if type(oldval) is not type(value): - self.options[key] = value + self.optstore.set_value(key, value.value) elif oldval.choices != value.choices: # If the choices have changed, use the new value, but attempt # to keep the old options. If they are not valid keep the new # defaults but warn. - self.options[key] = value + self.optstore.set_value_object(key, value) try: value.set_value(oldval.value) except MesonException: @@ -603,9 +607,9 @@ class CoreData: fatal=False) # Find any extranious keys for this project and remove them - for key in self.options.keys() - options.keys(): + for key in self.optstore.keys() - project_options.keys(): if key.is_project() and key.subproject == subproject: - del self.options[key] + self.optstore.remove(key) def is_cross_build(self, when_building_for: MachineChoice = MachineChoice.HOST) -> bool: if when_building_for == MachineChoice.BUILD: @@ -616,13 +620,13 @@ class CoreData: dirty = False assert not self.is_cross_build() for k in options.BUILTIN_OPTIONS_PER_MACHINE: - o = self.options[k] - dirty |= self.options[k.as_build()].set_value(o.value) - for bk, bv in self.options.items(): + o = self.optstore.get_value_object(k) + dirty |= self.optstore.set_value(k.as_build(), o.value) + for bk, bv in self.optstore.items(): if bk.machine is MachineChoice.BUILD: hk = bk.as_host() try: - hv = self.options[hk] + hv = self.optstore.get_value_object(hk) dirty |= bv.set_value(hv.value) except KeyError: continue @@ -637,16 +641,16 @@ class CoreData: pfk = OptionKey('prefix') if pfk in opts_to_set: prefix = self.sanitize_prefix(opts_to_set[pfk]) - dirty |= self.options[OptionKey('prefix')].set_value(prefix) + dirty |= self.optstore.set_value('prefix', prefix) for key in options.BUILTIN_DIR_NOPREFIX_OPTIONS: if key not in opts_to_set: - dirty |= self.options[key].set_value(options.BUILTIN_OPTIONS[key].prefixed_default(key, prefix)) + dirty |= self.optstore.set_value(key, options.BUILTIN_OPTIONS[key].prefixed_default(key, prefix)) unknown_options: T.List[OptionKey] = [] for k, v in opts_to_set.items(): if k == pfk: continue - elif k in self.options: + elif k in self.optstore: dirty |= self.set_option(k, v, first_invocation) elif k.machine != MachineChoice.BUILD and k.type != OptionType.COMPILER: unknown_options.append(k) @@ -690,7 +694,7 @@ class CoreData: # Always test this using the HOST machine, as many builtin options # are not valid for the BUILD machine, but the yielding value does # not differ between them even when they are valid for both. - if subproject and k.is_builtin() and self.options[k.evolve(subproject='', machine=MachineChoice.HOST)].yielding: + if subproject and k.is_builtin() and self.optstore.get_value_object(k.evolve(subproject='', machine=MachineChoice.HOST)).yielding: continue # Skip base, compiler, and backend options, they are handled when # adding languages and setting backend. @@ -703,23 +707,23 @@ class CoreData: self.set_options(options, subproject=subproject, first_invocation=env.first_invocation) - def add_compiler_options(self, options: MutableKeyedOptionDictType, lang: str, for_machine: MachineChoice, + def add_compiler_options(self, c_options: MutableKeyedOptionDictType, lang: str, for_machine: MachineChoice, env: Environment, subproject: str) -> None: - for k, o in options.items(): + for k, o in c_options.items(): value = env.options.get(k) if value is not None: o.set_value(value) if not subproject: - self.options[k] = o # override compiler option on reconfigure - self.options.setdefault(k, o) + self.optstore.set_value_object(k, o) # override compiler option on reconfigure + self.optstore.setdefault(k, o) if subproject: sk = k.evolve(subproject=subproject) value = env.options.get(sk) or value if value is not None: o.set_value(value) - self.options[sk] = o # override compiler option on reconfigure - self.options.setdefault(sk, o) + self.optstore.set_value_object(sk, o) # override compiler option on reconfigure + self.optstore.setdefault(sk, o) def add_lang_args(self, lang: str, comp: T.Type['Compiler'], for_machine: MachineChoice, env: 'Environment') -> None: @@ -727,8 +731,8 @@ class CoreData: from .compilers import compilers # These options are all new at this point, because the compiler is # responsible for adding its own options, thus calling - # `self.options.update()`` is perfectly safe. - self.options.update(compilers.get_global_options(lang, comp, for_machine, env)) + # `self.optstore.update()`` is perfectly safe. + self.optstore.update(compilers.get_global_options(lang, comp, for_machine, env)) def process_compiler_options(self, lang: str, comp: Compiler, env: Environment, subproject: str) -> None: from . import compilers @@ -741,20 +745,20 @@ class CoreData: skey = key.evolve(subproject=subproject) else: skey = key - if skey not in self.options: - self.options[skey] = copy.deepcopy(compilers.base_options[key]) + if skey not in self.optstore: + self.optstore.add_system_option(skey, copy.deepcopy(compilers.base_options[key])) if skey in env.options: - self.options[skey].set_value(env.options[skey]) + self.optstore.set_value(skey, env.options[skey]) enabled_opts.append(skey) elif subproject and key in env.options: - self.options[skey].set_value(env.options[key]) + self.optstore.set_value(skey, env.options[key]) enabled_opts.append(skey) - if subproject and key not in self.options: - self.options[key] = copy.deepcopy(self.options[skey]) + if subproject and key not in self.optstore: + self.optstore.add_system_option(key, copy.deepcopy(self.optstore.get_value_object(skey))) elif skey in env.options: - self.options[skey].set_value(env.options[skey]) + self.optstore.set_value(skey, env.options[skey]) elif subproject and key in env.options: - self.options[skey].set_value(env.options[key]) + self.optstore.set_value(skey, env.options[key]) self.emit_base_options_warnings(enabled_opts) def emit_base_options_warnings(self, enabled_opts: T.List[OptionKey]) -> None: @@ -894,7 +898,7 @@ class OptionsView(abc.Mapping): # TODO: the typing here could be made more explicit using a TypeDict from # python 3.8 or typing_extensions - original_options: KeyedOptionDictType + original_options: T.Union[KeyedOptionDictType, 'dict[OptionKey, UserOption[Any]]'] subproject: T.Optional[str] = None overrides: T.Optional[T.Mapping[OptionKey, T.Union[str, int, bool, T.List[str]]]] = None @@ -905,7 +909,15 @@ class OptionsView(abc.Mapping): if not key.is_project(): opt = self.original_options.get(key) if opt is None or opt.yielding: - opt = self.original_options[key.as_root()] + key2 = key.as_root() + # This hack goes away once wi start using OptionStore + # to hold overrides. + if isinstance(self.original_options, options.OptionStore): + if key2 not in self.original_options: + raise KeyError + opt = self.original_options.get_value_object(key2) + else: + opt = self.original_options[key2] else: opt = self.original_options[key] if opt.yielding: @@ -917,6 +929,16 @@ class OptionsView(abc.Mapping): opt.set_value(override_value) return opt + def get_value(self, key: T.Union[str, OptionKey]): + if isinstance(key, str): + key = OptionKey(key) + return self[key].value + + def set_value(self, key: T.Union[str, OptionKey], value: T.Union[str, int, bool, T.List[str]]): + if isinstance(key, str): + key = OptionKey(key) + self.overrides[key] = value + def __iter__(self) -> T.Iterator[OptionKey]: return iter(self.original_options) diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py index cccc0c3..02aa1ea 100644 --- a/mesonbuild/dependencies/boost.py +++ b/mesonbuild/dependencies/boost.py @@ -580,8 +580,8 @@ class BoostDependency(SystemDependency): # MSVC is very picky with the library tags vscrt = '' try: - crt_val = self.env.coredata.options[mesonlib.OptionKey('b_vscrt')].value - buildtype = self.env.coredata.options[mesonlib.OptionKey('buildtype')].value + crt_val = self.env.coredata.optstore.get_value('b_vscrt') + buildtype = self.env.coredata.optstore.get_value('buildtype') vscrt = self.clib_compiler.get_crt_compile_args(crt_val, buildtype)[0] except (KeyError, IndexError, AttributeError): pass diff --git a/mesonbuild/dependencies/pkgconfig.py b/mesonbuild/dependencies/pkgconfig.py index 30e3d28..a87f413 100644 --- a/mesonbuild/dependencies/pkgconfig.py +++ b/mesonbuild/dependencies/pkgconfig.py @@ -238,7 +238,7 @@ class PkgConfigCLI(PkgConfigInterface): def _get_env(self, uninstalled: bool = False) -> EnvironmentVariables: env = EnvironmentVariables() key = OptionKey('pkg_config_path', machine=self.for_machine) - extra_paths: T.List[str] = self.env.coredata.options[key].value[:] + extra_paths: T.List[str] = self.env.coredata.optstore.get_value(key)[:] if uninstalled: uninstalled_path = Path(self.env.get_build_dir(), 'meson-uninstalled').as_posix() if uninstalled_path not in extra_paths: @@ -397,7 +397,7 @@ class PkgConfigDependency(ExternalDependency): # # Only prefix_libpaths are reordered here because there should not be # too many system_libpaths to cause library version issues. - pkg_config_path: T.List[str] = self.env.coredata.options[OptionKey('pkg_config_path', machine=self.for_machine)].value + pkg_config_path: T.List[str] = self.env.coredata.optstore.get_value(OptionKey('pkg_config_path', machine=self.for_machine)) pkg_config_path = self._convert_mingw_paths(pkg_config_path) prefix_libpaths = OrderedSet(sort_libpaths(list(prefix_libpaths), pkg_config_path)) system_libpaths: OrderedSet[str] = OrderedSet() diff --git a/mesonbuild/dependencies/python.py b/mesonbuild/dependencies/python.py index a74423c..17c807c 100644 --- a/mesonbuild/dependencies/python.py +++ b/mesonbuild/dependencies/python.py @@ -233,8 +233,8 @@ class _PythonDependencyBase(_Base): # `debugoptimized` buildtype may not set debug=True currently, see gh-11645 is_debug_build = debug or buildtype == 'debug' vscrt_debug = False - if mesonlib.OptionKey('b_vscrt') in self.env.coredata.options: - vscrt = self.env.coredata.options[mesonlib.OptionKey('b_vscrt')].value + if mesonlib.OptionKey('b_vscrt') in self.env.coredata.optstore: + vscrt = self.env.coredata.optstore.get_value('b_vscrt') if vscrt in {'mdd', 'mtd', 'from_buildtype', 'static_from_buildtype'}: vscrt_debug = True if is_debug_build and vscrt_debug and not self.variables.get('Py_DEBUG'): diff --git a/mesonbuild/dependencies/qt.py b/mesonbuild/dependencies/qt.py index 65b6a58..86e3214 100644 --- a/mesonbuild/dependencies/qt.py +++ b/mesonbuild/dependencies/qt.py @@ -297,8 +297,8 @@ class QmakeQtDependency(_QtBase, ConfigToolDependency, metaclass=abc.ABCMeta): # Use the buildtype by default, but look at the b_vscrt option if the # compiler supports it. is_debug = self.env.coredata.get_option(mesonlib.OptionKey('buildtype')) == 'debug' - if mesonlib.OptionKey('b_vscrt') in self.env.coredata.options: - if self.env.coredata.options[mesonlib.OptionKey('b_vscrt')].value in {'mdd', 'mtd'}: + if mesonlib.OptionKey('b_vscrt') in self.env.coredata.optstore: + if self.env.coredata.optstore.get_value('b_vscrt') in {'mdd', 'mtd'}: is_debug = True modules_lib_suffix = _get_modules_lib_suffix(self.version, self.env.machines[self.for_machine], is_debug) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 1607c32..be40dbc 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -520,7 +520,7 @@ class Environment: log_dir = 'meson-logs' info_dir = 'meson-info' - def __init__(self, source_dir: str, build_dir: str, options: coredata.SharedCMDOptions) -> None: + def __init__(self, source_dir: str, build_dir: str, cmd_options: coredata.SharedCMDOptions) -> None: self.source_dir = source_dir self.build_dir = build_dir # Do not try to create build directories when build_dir is none. @@ -536,26 +536,26 @@ class Environment: self.coredata: coredata.CoreData = coredata.load(self.get_build_dir(), suggest_reconfigure=False) self.first_invocation = False except FileNotFoundError: - self.create_new_coredata(options) + self.create_new_coredata(cmd_options) except coredata.MesonVersionMismatchException as e: # This is routine, but tell the user the update happened mlog.log('Regenerating configuration from scratch:', str(e)) - coredata.read_cmd_line_file(self.build_dir, options) - self.create_new_coredata(options) + coredata.read_cmd_line_file(self.build_dir, cmd_options) + self.create_new_coredata(cmd_options) except MesonException as e: # If we stored previous command line options, we can recover from # a broken/outdated coredata. if os.path.isfile(coredata.get_cmd_line_file(self.build_dir)): mlog.warning('Regenerating configuration from scratch.', fatal=False) mlog.log('Reason:', mlog.red(str(e))) - coredata.read_cmd_line_file(self.build_dir, options) - self.create_new_coredata(options) + coredata.read_cmd_line_file(self.build_dir, cmd_options) + self.create_new_coredata(cmd_options) else: raise MesonException(f'{str(e)} Try regenerating using "meson setup --wipe".') else: # Just create a fresh coredata in this case self.scratch_dir = '' - self.create_new_coredata(options) + self.create_new_coredata(cmd_options) ## locally bind some unfrozen configuration @@ -627,7 +627,7 @@ class Environment: self.cmakevars = cmakevars.default_missing() # Command line options override those from cross/native files - self.options.update(options.cmd_line_options) + self.options.update(cmd_options.cmd_line_options) # Take default value from env if not set in cross/native files or command line. self._set_default_options_from_env() diff --git a/mesonbuild/interpreter/compiler.py b/mesonbuild/interpreter/compiler.py index 359e8e7..1bdb321 100644 --- a/mesonbuild/interpreter/compiler.py +++ b/mesonbuild/interpreter/compiler.py @@ -270,7 +270,7 @@ class CompilerHolder(ObjectHolder['Compiler']): for idir in i.to_string_list(self.environment.get_source_dir(), self.environment.get_build_dir()): args.extend(self.compiler.get_include_args(idir, False)) if not kwargs['no_builtin_args']: - opts = coredata.OptionsView(self.environment.coredata.options, self.subproject) + opts = coredata.OptionsView(self.environment.coredata.optstore, self.subproject) args += self.compiler.get_option_compile_args(opts) if mode is CompileCheckMode.LINK: args.extend(self.compiler.get_option_link_args(opts)) diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 6474e60..ef28d86 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -1013,7 +1013,7 @@ class Interpreter(InterpreterBase, HoldableObject): kwargs: kwtypes.DoSubproject) -> SubprojectHolder: from ..cmake import CMakeInterpreter with mlog.nested(subp_name): - prefix = self.coredata.options[OptionKey('prefix')].value + prefix = self.coredata.optstore.get_value('prefix') from ..modules.cmake import CMakeSubprojectOptions options = kwargs.get('options') or CMakeSubprojectOptions() @@ -1052,7 +1052,7 @@ class Interpreter(InterpreterBase, HoldableObject): key = OptionKey.from_string(optname).evolve(subproject=self.subproject) if not key.is_project(): - for opts in [self.coredata.options, compilers.base_options]: + for opts in [self.coredata.optstore, compilers.base_options]: v = opts.get(key) if v is None or v.yielding: v = opts.get(key.as_root()) @@ -1061,9 +1061,9 @@ class Interpreter(InterpreterBase, HoldableObject): return v try: - opt = self.coredata.options[key] - if opt.yielding and key.subproject and key.as_root() in self.coredata.options: - popt = self.coredata.options[key.as_root()] + opt = self.coredata.optstore.get_value_object(key) + if opt.yielding and key.subproject and key.as_root() in self.coredata.optstore: + popt = self.coredata.optstore.get_value_object(key.as_root()) if type(opt) is type(popt): opt = popt else: @@ -1543,7 +1543,7 @@ class Interpreter(InterpreterBase, HoldableObject): if self.subproject: options = {} for k in comp.get_options(): - v = copy.copy(self.coredata.options[k]) + v = copy.copy(self.coredata.optstore.get_value_object(k)) k = k.evolve(subproject=self.subproject) options[k] = v self.coredata.add_compiler_options(options, lang, for_machine, self.environment, self.subproject) @@ -3041,13 +3041,13 @@ class Interpreter(InterpreterBase, HoldableObject): break def check_clang_asan_lundef(self) -> None: - if OptionKey('b_lundef') not in self.coredata.options: + if OptionKey('b_lundef') not in self.coredata.optstore: return - if OptionKey('b_sanitize') not in self.coredata.options: + if OptionKey('b_sanitize') not in self.coredata.optstore: return - if (self.coredata.options[OptionKey('b_lundef')].value and - self.coredata.options[OptionKey('b_sanitize')].value != 'none'): - value = self.coredata.options[OptionKey('b_sanitize')].value + if (self.coredata.optstore.get_value('b_lundef') and + self.coredata.optstore.get_value('b_sanitize') != 'none'): + value = self.coredata.optstore.get_value('b_sanitize') mlog.warning(textwrap.dedent(f'''\ Trying to use {value} sanitizer on Clang with b_lundef. This will probably not work. diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index adec0d5..32f05ba 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -24,7 +24,7 @@ from ..interpreterbase import ( from ..interpreter.type_checking import NoneType, ENV_KW, ENV_SEPARATOR_KW, PKGCONFIG_DEFINE_KW from ..dependencies import Dependency, ExternalLibrary, InternalDependency from ..programs import ExternalProgram -from ..mesonlib import HoldableObject, OptionKey, listify, Popen_safe +from ..mesonlib import HoldableObject, listify, Popen_safe import typing as T @@ -90,7 +90,7 @@ class FeatureOptionHolder(ObjectHolder[options.UserFeatureOption]): super().__init__(option, interpreter) if option and option.is_auto(): # TODO: we need to cast here because options is not a TypedDict - auto = T.cast('options.UserFeatureOption', self.env.coredata.options[OptionKey('auto_features')]) + auto = T.cast('options.UserFeatureOption', self.env.coredata.optstore.get_value_object('auto_features')) self.held_object = copy.copy(auto) self.held_object.name = option.name self.methods.update({'enabled': self.enabled_method, diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index 48359de..da96ac4 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -25,6 +25,8 @@ from .optinterpreter import OptionInterpreter if T.TYPE_CHECKING: from typing_extensions import Protocol + from typing import Any + from .options import UserOption import argparse class CMDOptions(coredata.SharedCMDOptions, Protocol): @@ -186,7 +188,7 @@ class Conf: items = [l[i] if l[i] else ' ' * four_column[i] for i in range(4)] mlog.log(*items) - def split_options_per_subproject(self, options: 'coredata.KeyedOptionDictType') -> T.Dict[str, 'coredata.MutableKeyedOptionDictType']: + def split_options_per_subproject(self, options: 'T.Union[dict[OptionKey, UserOption[Any]], coredata.KeyedOptionDictType]') -> T.Dict[str, 'coredata.MutableKeyedOptionDictType']: result: T.Dict[str, 'coredata.MutableKeyedOptionDictType'] = {} for k, o in options.items(): if k.subproject: @@ -224,16 +226,16 @@ class Conf: self._add_line(mlog.normal_yellow(section + ':'), '', '', '') self.print_margin = 2 - def print_options(self, title: str, opts: 'coredata.KeyedOptionDictType') -> None: + def print_options(self, title: str, opts: 'T.Union[dict[OptionKey, UserOption[Any]], coredata.KeyedOptionDictType]') -> None: if not opts: return if title: self.add_title(title) - auto = T.cast('options.UserFeatureOption', self.coredata.options[OptionKey('auto_features')]) + auto = T.cast('options.UserFeatureOption', self.coredata.optstore.get_value_object('auto_features')) for k, o in sorted(opts.items()): printable_value = o.printable_value() root = k.as_root() - if o.yielding and k.subproject and root in self.coredata.options: + if o.yielding and k.subproject and root in self.coredata.optstore: printable_value = '<inherited from main project>' if isinstance(o, options.UserFeatureOption) and o.is_auto(): printable_value = auto.printable_value() @@ -264,7 +266,7 @@ class Conf: test_options: 'coredata.MutableKeyedOptionDictType' = {} core_options: 'coredata.MutableKeyedOptionDictType' = {} module_options: T.Dict[str, 'coredata.MutableKeyedOptionDictType'] = collections.defaultdict(dict) - for k, v in self.coredata.options.items(): + for k, v in self.coredata.optstore.items(): if k in dir_option_names: dir_options[k] = v elif k in test_option_names: @@ -280,17 +282,17 @@ class Conf: host_core_options = self.split_options_per_subproject({k: v for k, v in core_options.items() if k.machine is MachineChoice.HOST}) build_core_options = self.split_options_per_subproject({k: v for k, v in core_options.items() if k.machine is MachineChoice.BUILD}) - host_compiler_options = self.split_options_per_subproject({k: v for k, v in self.coredata.options.items() if k.is_compiler() and k.machine is MachineChoice.HOST}) - build_compiler_options = self.split_options_per_subproject({k: v for k, v in self.coredata.options.items() if k.is_compiler() and k.machine is MachineChoice.BUILD}) - project_options = self.split_options_per_subproject({k: v for k, v in self.coredata.options.items() if k.is_project()}) + host_compiler_options = self.split_options_per_subproject({k: v for k, v in self.coredata.optstore.items() if k.is_compiler() and k.machine is MachineChoice.HOST}) + build_compiler_options = self.split_options_per_subproject({k: v for k, v in self.coredata.optstore.items() if k.is_compiler() and k.machine is MachineChoice.BUILD}) + project_options = self.split_options_per_subproject({k: v for k, v in self.coredata.optstore.items() if k.is_project()}) show_build_options = self.default_values_only or self.build.environment.is_cross_build() self.add_section('Main project options') self.print_options('Core options', host_core_options['']) if show_build_options: self.print_options('', build_core_options['']) - self.print_options('Backend options', {k: v for k, v in self.coredata.options.items() if k.is_backend()}) - self.print_options('Base options', {k: v for k, v in self.coredata.options.items() if k.is_base()}) + self.print_options('Backend options', {k: v for k, v in self.coredata.optstore.items() if k.is_backend()}) + self.print_options('Base options', {k: v for k, v in self.coredata.optstore.items() if k.is_base()}) self.print_options('Compiler options', host_compiler_options.get('', {})) if show_build_options: self.print_options('', build_compiler_options.get('', {})) diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index c678cf7..dea67d8 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -30,6 +30,8 @@ from .mparser import FunctionNode, ArrayNode, ArgumentNode, StringNode if T.TYPE_CHECKING: import argparse + from typing import Any + from .options import UserOption from .interpreter import Interpreter from .mparser import BaseNode @@ -291,7 +293,7 @@ def list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[s dir_options: 'cdata.MutableKeyedOptionDictType' = {} test_options: 'cdata.MutableKeyedOptionDictType' = {} core_options: 'cdata.MutableKeyedOptionDictType' = {} - for k, v in coredata.options.items(): + for k, v in coredata.optstore.items(): if k in dir_option_names: dir_options[k] = v elif k in test_option_names: @@ -302,7 +304,7 @@ def list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[s for s in subprojects: core_options[k.evolve(subproject=s)] = v - def add_keys(opts: 'cdata.KeyedOptionDictType', section: str) -> None: + def add_keys(opts: 'T.Union[dict[OptionKey, UserOption[Any]], cdata.KeyedOptionDictType]', section: str) -> None: for key, opt in sorted(opts.items()): optdict = {'name': str(key), 'value': opt.value, 'section': section, 'machine': key.machine.get_lower_case_name() if coredata.is_per_machine_option(key) else 'any'} @@ -326,14 +328,14 @@ def list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[s optlist.append(optdict) add_keys(core_options, 'core') - add_keys({k: v for k, v in coredata.options.items() if k.is_backend()}, 'backend') - add_keys({k: v for k, v in coredata.options.items() if k.is_base()}, 'base') + add_keys({k: v for k, v in coredata.optstore.items() if k.is_backend()}, 'backend') + add_keys({k: v for k, v in coredata.optstore.items() if k.is_base()}, 'base') add_keys( - {k: v for k, v in sorted(coredata.options.items(), key=lambda i: i[0].machine) if k.is_compiler()}, + {k: v for k, v in sorted(coredata.optstore.items(), key=lambda i: i[0].machine) if k.is_compiler()}, 'compiler', ) add_keys(dir_options, 'directory') - add_keys({k: v for k, v in coredata.options.items() if k.is_project()}, 'user') + add_keys({k: v for k, v in coredata.optstore.items() if k.is_project()}, 'user') add_keys(test_options, 'test') return optlist diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 4405c40..cab7c76 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -906,7 +906,7 @@ class GnomeModule(ExtensionModule): if state.project_args.get(lang): cflags += state.project_args[lang] if mesonlib.OptionKey('b_sanitize') in compiler.base_options: - sanitize = state.environment.coredata.options[mesonlib.OptionKey('b_sanitize')].value + sanitize = state.environment.coredata.optstore.get_value('b_sanitize') cflags += compiler.sanitizer_compile_args(sanitize) sanitize = sanitize.split(',') # These must be first in ldflags diff --git a/mesonbuild/modules/python.py b/mesonbuild/modules/python.py index e84bee1..013723d 100644 --- a/mesonbuild/modules/python.py +++ b/mesonbuild/modules/python.py @@ -207,7 +207,7 @@ class PythonInstallation(_ExternalProgramHolder['PythonExternalProgram']): new_link_args = mesonlib.extract_as_list(kwargs, 'link_args') - is_debug = self.interpreter.environment.coredata.options[OptionKey('debug')].value + is_debug = self.interpreter.environment.coredata.optstore.get_value('debug') if is_debug: new_link_args.append(python_windows_debug_link_exception) else: diff --git a/mesonbuild/modules/rust.py b/mesonbuild/modules/rust.py index 8534dfa..a8e2254 100644 --- a/mesonbuild/modules/rust.py +++ b/mesonbuild/modules/rust.py @@ -231,7 +231,7 @@ class RustModule(ExtensionModule): # bindgen always uses clang, so it's safe to hardcode -I here clang_args.extend([f'-I{x}' for x in i.to_string_list( state.environment.get_source_dir(), state.environment.get_build_dir())]) - if are_asserts_disabled(state.environment.coredata.options): + if are_asserts_disabled(state.environment.coredata.optstore): clang_args.append('-DNDEBUG') for de in kwargs['dependencies']: diff --git a/mesonbuild/msetup.py b/mesonbuild/msetup.py index c1d71e2..931b1eb 100644 --- a/mesonbuild/msetup.py +++ b/mesonbuild/msetup.py @@ -273,9 +273,9 @@ class MesonApp: # collect warnings about unsupported build configurations; must be done after full arg processing # by Interpreter() init, but this is most visible at the end - if env.coredata.options[mesonlib.OptionKey('backend')].value == 'xcode': + if env.coredata.optstore.get_value('backend') == 'xcode': mlog.warning('xcode backend is currently unmaintained, patches welcome') - if env.coredata.options[mesonlib.OptionKey('layout')].value == 'flat': + if env.coredata.optstore.get_value('layout') == 'flat': mlog.warning('-Dlayout=flat is unsupported and probably broken. It was a failed experiment at ' 'making Windows build artifacts runnable while uninstalled, due to PATH considerations, ' 'but was untested by CI and anyways breaks reasonable use of conflicting targets in different subdirs. ' diff --git a/mesonbuild/options.py b/mesonbuild/options.py index 2699dd5..d83a312 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -25,6 +25,7 @@ from .mesonlib import ( from . import mlog import typing as T +from typing import ItemsView DEFAULT_YIELDING = False @@ -473,8 +474,65 @@ BUILTIN_DIR_NOPREFIX_OPTIONS: T.Dict[OptionKey, T.Dict[str, str]] = { OptionKey('purelibdir', module='python'): {}, } - class OptionStore: def __init__(self): - # This class will hold all options for a given build directory - self.dummy = None + self.d: T.Dict['OptionKey', 'UserOption[T.Any]'] = {} + + def __len__(self): + return len(self.d) + + def ensure_key(self, key: T.Union[OptionKey, str]) -> OptionKey: + if isinstance(key, str): + return OptionKey(key) + return key + + def get_value_object(self, key: T.Union[OptionKey, str]) -> 'UserOption[T.Any]': + return self.d[self.ensure_key(key)] + + def get_value(self, key: T.Union[OptionKey, str]) -> 'T.Any': + return self.get_value_object(key).value + + def add_system_option(self, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]'): + key = self.ensure_key(key) + self.d[key] = valobj + + def add_project_option(self, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]'): + key = self.ensure_key(key) + self.d[key] = valobj + + def set_value(self, key: T.Union[OptionKey, str], new_value: 'T.Any') -> bool: + key = self.ensure_key(key) + return self.d[key].set_value(new_value) + + # FIXME, this should be removed.or renamed to "change_type_of_existing_object" or something like that + def set_value_object(self, key: T.Union[OptionKey, str], new_object: 'UserOption[T.Any]') -> bool: + key = self.ensure_key(key) + self.d[key] = new_object + + def remove(self, key): + del self.d[key] + + def __contains__(self, key): + key = self.ensure_key(key) + return key in self.d + + def __repr__(self): + return repr(self.d) + + def keys(self): + return self.d.keys() + + def values(self): + return self.d.values() + + def items(self) -> ItemsView['OptionKey', 'UserOption[T.Any]']: + return self.d.items() + + def update(self, *args, **kwargs): + return self.d.update(*args, **kwargs) + + def setdefault(self, k, o): + return self.d.setdefault(k, o) + + def get(self, *args, **kwargs) -> UserOption: + return self.d.get(*args, **kwargs) diff --git a/mesonbuild/rewriter.py b/mesonbuild/rewriter.py index 0a40a71..78517bf 100644 --- a/mesonbuild/rewriter.py +++ b/mesonbuild/rewriter.py @@ -470,11 +470,11 @@ class Rewriter: cdata = self.interpreter.coredata options = { - **{str(k): v for k, v in cdata.options.items()}, - **{str(k): v for k, v in cdata.options.items()}, - **{str(k): v for k, v in cdata.options.items()}, - **{str(k): v for k, v in cdata.options.items()}, - **{str(k): v for k, v in cdata.options.items()}, + **{str(k): v for k, v in cdata.optstore.items()}, + **{str(k): v for k, v in cdata.optstore.items()}, + **{str(k): v for k, v in cdata.optstore.items()}, + **{str(k): v for k, v in cdata.optstore.items()}, + **{str(k): v for k, v in cdata.optstore.items()}, } for key, val in sorted(cmd['options'].items()): |