From e062baf6bc1aaa45cabff4448420b74e229587ad Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sat, 29 Jun 2024 12:41:50 +0300 Subject: Move project option detection into OptionStore. --- mesonbuild/ast/introspection.py | 2 +- mesonbuild/backend/ninjabackend.py | 2 +- mesonbuild/coredata.py | 6 +++--- mesonbuild/interpreter/interpreter.py | 4 ++-- mesonbuild/mconf.py | 6 +++--- mesonbuild/mintro.py | 2 +- mesonbuild/optinterpreter.py | 5 +++-- mesonbuild/options.py | 8 ++++++++ mesonbuild/utils/universal.py | 4 ++-- unittests/platformagnostictests.py | 7 +++++-- 10 files changed, 29 insertions(+), 17 deletions(-) diff --git a/mesonbuild/ast/introspection.py b/mesonbuild/ast/introspection.py index 1197510..07f82df 100644 --- a/mesonbuild/ast/introspection.py +++ b/mesonbuild/ast/introspection.py @@ -105,7 +105,7 @@ class IntrospectionInterpreter(AstInterpreter): if not os.path.exists(optfile): optfile = os.path.join(self.source_root, self.subdir, 'meson_options.txt') if os.path.exists(optfile): - oi = optinterpreter.OptionInterpreter(self.subproject) + oi = optinterpreter.OptionInterpreter(self.coredata.optstore, self.subproject) oi.process(optfile) assert isinstance(proj_name, str), 'for mypy' self.coredata.update_project_options(oi.options, T.cast('SubProject', proj_name)) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index eabe758..456615e 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -3603,7 +3603,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.optstore.items(): - if k.is_project(): + if self.environment.coredata.optstore.is_project_option(k): 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 # to ensure reproducible output. The order we pass them shouldn't diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 7fb3bca..1bd2269 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -584,7 +584,7 @@ class CoreData: def update_project_options(self, project_options: 'MutableKeyedOptionDictType', subproject: SubProject) -> None: for key, value in project_options.items(): - if not key.is_project(): + if not self.optstore.is_project_option(key): continue if key not in self.optstore: self.optstore.add_project_option(key, value) @@ -608,7 +608,7 @@ class CoreData: # Find any extranious keys for this project and remove them for key in self.optstore.keys() - project_options.keys(): - if key.is_project() and key.subproject == subproject: + if self.optstore.is_project_option(key) and key.subproject == subproject: self.optstore.remove(key) def is_cross_build(self, when_building_for: MachineChoice = MachineChoice.HOST) -> bool: @@ -906,7 +906,7 @@ class OptionsView(abc.Mapping): # FIXME: This is fundamentally the same algorithm than interpreter.get_option_internal(). # We should try to share the code somehow. key = key.evolve(subproject=self.subproject) - if not key.is_project(): + if not key.is_project_hack_for_optionsview(): opt = self.original_options.get(key) if opt is None or opt.yielding: key2 = key.as_root() diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 13f7f22..742d24c 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -1051,7 +1051,7 @@ class Interpreter(InterpreterBase, HoldableObject): def get_option_internal(self, optname: str) -> options.UserOption: key = OptionKey.from_string(optname).evolve(subproject=self.subproject) - if not key.is_project(): + if not self.environment.coredata.optstore.is_project_option(key): for opts in [self.coredata.optstore, compilers.base_options]: v = opts.get(key) if v is None or v.yielding: @@ -1198,7 +1198,7 @@ class Interpreter(InterpreterBase, HoldableObject): # We want fast not cryptographically secure, this is just to # see if the option file has changed self.coredata.options_files[self.subproject] = (option_file, hashlib.sha1(f.read()).hexdigest()) - oi = optinterpreter.OptionInterpreter(self.subproject) + oi = optinterpreter.OptionInterpreter(self.environment.coredata.optstore, self.subproject) oi.process(option_file) self.coredata.update_project_options(oi.options, self.subproject) self.add_build_def_file(option_file) diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index da96ac4..1294479 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -92,7 +92,7 @@ class Conf: with open(opfile, 'rb') as f: ophash = hashlib.sha1(f.read()).hexdigest() if ophash != conf_options[1]: - oi = OptionInterpreter(sub) + oi = OptionInterpreter(self.coredata.optstore, sub) oi.process(opfile) self.coredata.update_project_options(oi.options, sub) self.coredata.options_files[sub] = (opfile, ophash) @@ -101,7 +101,7 @@ class Conf: if not os.path.exists(opfile): opfile = os.path.join(self.source_dir, 'meson_options.txt') if os.path.exists(opfile): - oi = OptionInterpreter(sub) + oi = OptionInterpreter(self.coredata.optstore, sub) oi.process(opfile) self.coredata.update_project_options(oi.options, sub) with open(opfile, 'rb') as f: @@ -284,7 +284,7 @@ class Conf: 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.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()}) + project_options = self.split_options_per_subproject({k: v for k, v in self.coredata.optstore.items() if self.coredata.optstore.is_project_option(k)}) show_build_options = self.default_values_only or self.build.environment.is_cross_build() self.add_section('Main project options') diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index dea67d8..17d1b08 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -335,7 +335,7 @@ def list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[s 'compiler', ) add_keys(dir_options, 'directory') - add_keys({k: v for k, v in coredata.optstore.items() if k.is_project()}, 'user') + add_keys({k: v for k, v in coredata.optstore.items() if coredata.optstore.is_project_option(k)}, 'user') add_keys(test_options, 'test') return optlist diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py index ffa46cd..7c94c15 100644 --- a/mesonbuild/optinterpreter.py +++ b/mesonbuild/optinterpreter.py @@ -64,7 +64,7 @@ optname_regex = re.compile('[^a-zA-Z0-9_-]') class OptionInterpreter: - def __init__(self, subproject: 'SubProject') -> None: + def __init__(self, optionstore, subproject: 'SubProject') -> None: self.options: 'coredata.MutableKeyedOptionDictType' = {} self.subproject = subproject self.option_types: T.Dict[str, T.Callable[..., options.UserOption]] = { @@ -75,6 +75,7 @@ class OptionInterpreter: 'array': self.string_array_parser, 'feature': self.feature_parser, } + self.optionstore = optionstore def process(self, option_file: str) -> None: try: @@ -189,7 +190,7 @@ class OptionInterpreter: if optname_regex.search(opt_name) is not None: raise OptionException('Option names can only contain letters, numbers or dashes.') key = mesonlib.OptionKey.from_string(opt_name).evolve(subproject=self.subproject) - if not key.is_project(): + if self.optionstore.is_reserved_name(key): raise OptionException('Option name %s is reserved.' % opt_name) opt_type = kwargs['type'] diff --git a/mesonbuild/options.py b/mesonbuild/options.py index d83a312..e88710d 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -8,6 +8,7 @@ import argparse from .mesonlib import ( HoldableObject, OptionKey, + OptionType, default_prefix, default_datadir, default_includedir, @@ -536,3 +537,10 @@ class OptionStore: def get(self, *args, **kwargs) -> UserOption: return self.d.get(*args, **kwargs) + + def is_project_option(self, key: OptionKey) -> bool: + """Convenience method to check if this is a project option.""" + return key.type is OptionType.PROJECT + + def is_reserved_name(self, key: OptionKey) -> bool: + return not self.is_project_option(key) diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py index 6aee268..4582336 100644 --- a/mesonbuild/utils/universal.py +++ b/mesonbuild/utils/universal.py @@ -2406,8 +2406,8 @@ class OptionKey: """Convenience method to check if this is a builtin option.""" return self.type is OptionType.COMPILER - def is_project(self) -> bool: - """Convenience method to check if this is a project option.""" + def is_project_hack_for_optionsview(self) -> bool: + """This method will be removed once we can delete OptionsView.""" return self.type is OptionType.PROJECT def is_base(self) -> bool: diff --git a/unittests/platformagnostictests.py b/unittests/platformagnostictests.py index fe598a7..4ac4b7a 100644 --- a/unittests/platformagnostictests.py +++ b/unittests/platformagnostictests.py @@ -18,6 +18,7 @@ from .helpers import is_ci from mesonbuild.mesonlib import EnvironmentVariables, ExecutableSerialisation, MesonException, is_linux, python_command from mesonbuild.mformat import match_path from mesonbuild.optinterpreter import OptionInterpreter, OptionException +from mesonbuild.options import OptionStore from run_tests import Backend @skipIf(is_ci() and not is_linux(), "Run only on fast platforms") @@ -35,7 +36,8 @@ class PlatformAgnosticTests(BasePlatformTests): self.init(testdir, workdir=testdir) def test_invalid_option_names(self): - interp = OptionInterpreter('') + store = OptionStore() + interp = OptionInterpreter(store, '') def write_file(code: str): with tempfile.NamedTemporaryFile('w', dir=self.builddir, encoding='utf-8', delete=False) as f: @@ -68,7 +70,8 @@ class PlatformAgnosticTests(BasePlatformTests): def test_option_validation(self): """Test cases that are not catch by the optinterpreter itself.""" - interp = OptionInterpreter('') + store = OptionStore() + interp = OptionInterpreter(store, '') def write_file(code: str): with tempfile.NamedTemporaryFile('w', dir=self.builddir, encoding='utf-8', delete=False) as f: -- cgit v1.1