From e81acbd6069e8c1ae8e3be7bb83ddc239009d42d Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 4 Dec 2020 17:01:45 -0800 Subject: [PATCH] Use a single coredata dictionary for options This patches takes the options work to it's logical conclusion: A single flat dictionary of OptionKey: UserOptions. This allows us to simplify a large number of cases, as we don't need to check if an option is in this dict or that one (or any of 5 or 6, actually). --- mesonbuild/ast/introspection.py | 4 +- mesonbuild/backend/backends.py | 16 +- mesonbuild/backend/ninjabackend.py | 32 +-- mesonbuild/backend/vs2010backend.py | 31 ++- mesonbuild/backend/xcodebackend.py | 2 +- mesonbuild/build.py | 14 +- mesonbuild/cmake/executor.py | 2 +- mesonbuild/cmake/interpreter.py | 4 +- mesonbuild/compilers/mixins/clike.py | 4 +- mesonbuild/compilers/mixins/emscripten.py | 2 +- mesonbuild/coredata.py | 216 +++++++----------- mesonbuild/dependencies/base.py | 10 +- mesonbuild/dependencies/boost.py | 6 +- mesonbuild/dependencies/ui.py | 6 +- mesonbuild/environment.py | 19 +- mesonbuild/interpreter.py | 77 +++---- mesonbuild/mcompile.py | 2 +- mesonbuild/mconf.py | 34 +-- mesonbuild/mintro.py | 42 ++-- mesonbuild/modules/cmake.py | 6 +- mesonbuild/modules/gnome.py | 12 +- mesonbuild/modules/hotdoc.py | 2 +- mesonbuild/modules/i18n.py | 2 +- mesonbuild/modules/pkgconfig.py | 10 +- mesonbuild/modules/python.py | 2 +- .../modules/unstable_external_project.py | 7 +- mesonbuild/msetup.py | 2 +- mesonbuild/munstable_coredata.py | 4 +- mesonbuild/optinterpreter.py | 7 +- mesonbuild/rewriter.py | 10 +- mesonbuild/scripts/regen_checker.py | 3 +- run_tests.py | 2 +- run_unittests.py | 87 +++---- 33 files changed, 322 insertions(+), 357 deletions(-) diff --git a/mesonbuild/ast/introspection.py b/mesonbuild/ast/introspection.py index 83b684356..97ebb5ac4 100644 --- a/mesonbuild/ast/introspection.py +++ b/mesonbuild/ast/introspection.py @@ -103,7 +103,7 @@ class IntrospectionInterpreter(AstInterpreter): if os.path.exists(self.option_file): oi = optinterpreter.OptionInterpreter(self.subproject) oi.process(self.option_file) - self.coredata.merge_user_options(oi.options) + self.coredata.update_project_options(oi.options) def_opts = self.flatten_args(kwargs.get('default_options', [])) _project_default_options = mesonlib.stringlistify(def_opts) @@ -269,7 +269,7 @@ class IntrospectionInterpreter(AstInterpreter): return new_target def build_library(self, node: BaseNode, args: T.List[TYPE_nvar], kwargs: T.Dict[str, TYPE_nvar]) -> T.Optional[T.Dict[str, T.Any]]: - default_library = self.coredata.get_builtin_option('default_library') + default_library = self.coredata.get_option(OptionKey('default_library')) if default_library == 'shared': return self.build_target(node, args, kwargs, SharedLibrary) elif default_library == 'static': diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index b6d084f61..ec3aca647 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -31,7 +31,7 @@ from .. import mesonlib from .. import mlog from ..compilers import languages_using_ldflags from ..mesonlib import ( - File, MachineChoice, MesonException, OrderedSet, OptionOverrideProxy, + File, MachineChoice, MesonException, OptionType, OrderedSet, OptionOverrideProxy, classify_unity_sources, unholder, OptionKey ) @@ -213,11 +213,11 @@ class Backend: def get_base_options_for_target(self, target: build.BuildTarget) -> OptionOverrideProxy: return OptionOverrideProxy(target.option_overrides_base, - self.environment.coredata.builtins, - {k: v for k, v in self.environment.coredata.base_options.items()}) + {k: v for k, v in self.environment.coredata.options.items() + if k.type in {OptionType.BASE, OptionType.BUILTIN}}) def get_compiler_options_for_target(self, target: build.BuildTarget) -> OptionOverrideProxy: - comp_reg = self.environment.coredata.compiler_options + comp_reg = {k: v for k, v in self.environment.coredata.options.items() if k.is_compiler()} comp_override = target.option_overrides_compiler return OptionOverrideProxy(comp_override, comp_reg) @@ -225,7 +225,7 @@ class Backend: if option_name in target.option_overrides_base: override = target.option_overrides_base[option_name] return self.environment.coredata.validate_option_value(option_name, override) - return self.environment.coredata.get_builtin_option(str(option_name), target.subproject) + return self.environment.coredata.get_option(option_name.evolve(subproject=target.subproject)) def get_target_filename_for_linking(self, target): # On some platforms (msvc for instance), the file that is used for @@ -250,7 +250,7 @@ class Backend: @lru_cache(maxsize=None) def get_target_dir(self, target): - if self.environment.coredata.get_builtin_option('layout') == 'mirror': + if self.environment.coredata.get_option(OptionKey('layout')) == 'mirror': dirname = target.get_subdir() else: dirname = 'meson-out' @@ -541,7 +541,7 @@ class Backend: return paths def determine_rpath_dirs(self, target): - if self.environment.coredata.get_builtin_option('layout') == 'mirror': + if self.environment.coredata.get_option(OptionKey('layout')) == 'mirror': result = target.get_link_dep_subdirs() else: result = OrderedSet() @@ -1183,7 +1183,7 @@ class Backend: self.environment.get_build_dir(), self.environment.get_prefix(), strip_bin, - self.environment.coredata.get_builtin_option('install_umask'), + self.environment.coredata.get_option(OptionKey('install_umask')), self.environment.get_build_command() + ['introspect'], self.environment.coredata.version) self.generate_depmf_install(d) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 4bc76ab45..d66708c59 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -517,7 +517,7 @@ int dummy; outfile.write('# Do not edit by hand.\n\n') outfile.write('ninja_required_version = 1.8.2\n\n') - num_pools = self.environment.coredata.backend_options[OptionKey('backend_max_links')].value + num_pools = self.environment.coredata.options[OptionKey('backend_max_links')].value if num_pools > 0: outfile.write('''pool link_pool depth = {} @@ -538,8 +538,8 @@ int dummy; self.generate_install() self.generate_dist() key = OptionKey('b_coverage') - if (key in self.environment.coredata.base_options and - self.environment.coredata.base_options[key].value): + if (key in self.environment.coredata.options and + self.environment.coredata.options[key].value): self.add_build_comment(NinjaComment('Coverage rules')) self.generate_coverage_rules() self.add_build_comment(NinjaComment('Suffix')) @@ -815,7 +815,7 @@ int dummy; source2object[s] = o obj_list.append(o) - use_pch = self.environment.coredata.base_options.get(OptionKey('b_pch')) + use_pch = self.environment.coredata.options.get(OptionKey('b_pch')) if use_pch and target.has_pch(): pch_objects = self.generate_pch(target, header_deps=header_deps) else: @@ -894,7 +894,7 @@ int dummy; cpp = target.compilers['cpp'] if cpp.get_id() != 'msvc': return False - if self.environment.coredata.compiler_options[OptionKey('std', machine=target.for_machine, lang='cpp')] != 'latest': + if self.environment.coredata.options[OptionKey('std', machine=target.for_machine, lang='cpp')] != 'latest': return False if not mesonlib.current_vs_supports_modules(): return False @@ -1128,9 +1128,9 @@ int dummy; def generate_tests(self): self.serialize_tests() cmd = self.environment.get_build_command(True) + ['test', '--no-rebuild'] - if not self.environment.coredata.get_builtin_option('stdsplit'): + if not self.environment.coredata.get_option(OptionKey('stdsplit')): cmd += ['--no-stdsplit'] - if self.environment.coredata.get_builtin_option('errorlogs'): + if self.environment.coredata.get_option(OptionKey('errorlogs')): cmd += ['--print-errorlogs'] elem = NinjaBuildElement(self.all_outputs, 'meson-test', 'CUSTOM_COMMAND', ['all', 'PHONY']) elem.add_item('COMMAND', cmd) @@ -1513,7 +1513,7 @@ int dummy; valac_outputs.append(vala_c_file) args = self.generate_basic_compiler_args(target, valac) - args += valac.get_colorout_args(self.environment.coredata.base_options.get(OptionKey('b_colorout')).value) + args += valac.get_colorout_args(self.environment.coredata.options.get(OptionKey('b_colorout')).value) # Tell Valac to output everything in our private directory. Sadly this # means it will also preserve the directory components of Vala sources # found inside the build tree (generated sources). @@ -1850,7 +1850,7 @@ int dummy; self.create_target_source_introspection(target, swiftc, compile_args + header_imports + module_includes, relsrc, rel_generated) def generate_static_link_rules(self): - num_pools = self.environment.coredata.backend_options[OptionKey('backend_max_links')].value + num_pools = self.environment.coredata.options[OptionKey('backend_max_links')].value if 'java' in self.environment.coredata.compilers.host: self.generate_java_link() for for_machine in MachineChoice: @@ -1883,7 +1883,7 @@ int dummy; extra=pool)) def generate_dynamic_link_rules(self): - num_pools = self.environment.coredata.backend_options[OptionKey('backend_max_links')].value + num_pools = self.environment.coredata.options[OptionKey('backend_max_links')].value for for_machine in MachineChoice: complist = self.environment.coredata.compilers[for_machine] for langname, compiler in complist.items(): @@ -2499,7 +2499,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) commands += self.get_compile_debugfile_args(compiler, target, rel_obj) # PCH handling - if self.environment.coredata.base_options.get(OptionKey('b_pch')): + if self.environment.coredata.options.get(OptionKey('b_pch')): commands += self.get_pch_include_args(compiler, target) pchlist = target.get_pch(compiler.language) else: @@ -2699,7 +2699,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) commands += linker.get_pie_link_args() elif isinstance(target, build.SharedLibrary): if isinstance(target, build.SharedModule): - options = self.environment.coredata.base_options + options = self.environment.coredata.options commands += linker.get_std_shared_module_link_args(options) else: commands += linker.get_std_shared_lib_link_args() @@ -2939,7 +2939,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) # # We shouldn't check whether we are making a static library, because # in the LTO case we do use a real compiler here. - commands += linker.get_option_link_args(self.environment.coredata.compiler_options) + commands += linker.get_option_link_args(self.environment.coredata.options) dep_targets = [] dep_targets.extend(self.guess_external_link_dependencies(linker, target, commands, internal)) @@ -3033,7 +3033,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.user_options.items(): + for (k, v) in self.environment.coredata.options.items(): 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 @@ -3156,8 +3156,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.base_options and \ - self.environment.coredata.base_options[OptionKey('b_coverage')].value: + if OptionKey('b_coverage') in self.environment.coredata.options and \ + self.environment.coredata.options[OptionKey('b_coverage')].value: 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 ed848280d..6e070a7b8 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -181,9 +181,9 @@ class Vs2010Backend(backends.Backend): self.platform = 'ARM' else: raise MesonException('Unsupported Visual Studio platform: ' + target_machine) - self.buildtype = self.environment.coredata.get_builtin_option('buildtype') - self.optimization = self.environment.coredata.get_builtin_option('optimization') - self.debug = self.environment.coredata.get_builtin_option('debug') + self.buildtype = self.environment.coredata.get_option(OptionKey('buildtype')) + self.optimization = self.environment.coredata.get_option(OptionKey('optimization')) + self.debug = self.environment.coredata.get_option(OptionKey('debug')) sln_filename = os.path.join(self.environment.get_build_dir(), self.build.project_name + '.sln') projlist = self.generate_projects() self.gen_testproj('RUN_TESTS', os.path.join(self.environment.get_build_dir(), 'RUN_TESTS.vcxproj')) @@ -316,7 +316,7 @@ class Vs2010Backend(backends.Backend): prj_templ = 'Project("{%s}") = "%s", "%s", "{%s}"\n' for prj in projlist: coredata = self.environment.coredata - if coredata.get_builtin_option('layout') == 'mirror': + if coredata.get_option(OptionKey('layout')) == 'mirror': self.generate_solution_dirs(ofile, prj[1].parents) target = self.build.targets[prj[0]] lang = 'default' @@ -403,7 +403,7 @@ class Vs2010Backend(backends.Backend): replace_if_different(sln_filename, sln_filename_tmp) def generate_projects(self): - startup_project = self.environment.coredata.backend_options[OptionKey('backend_startup_project')].value + startup_project = self.environment.coredata.options[OptionKey('backend_startup_project')].value projlist = [] startup_idx = 0 for (i, (name, target)) in enumerate(self.build.targets.items()): @@ -785,7 +785,7 @@ class Vs2010Backend(backends.Backend): build_args += compiler.get_optimization_args(self.optimization) build_args += compiler.get_debug_args(self.debug) buildtype_link_args = compiler.get_buildtype_linker_args(self.buildtype) - vscrt_type = self.environment.coredata.base_options[OptionKey('b_vscrt')] + vscrt_type = self.environment.coredata.options[OptionKey('b_vscrt')] project_name = target.name target_name = target.name root = ET.Element('Project', {'DefaultTargets': "Build", @@ -878,7 +878,7 @@ class Vs2010Backend(backends.Backend): # Exception handling has to be set in the xml in addition to the "AdditionalOptions" because otherwise # cl will give warning D9025: overriding '/Ehs' with cpp_eh value if 'cpp' in target.compilers: - eh = self.environment.coredata.compiler_options[OptionKey('eh', machine=target.for_machine, lang='cpp')] + eh = self.environment.coredata.options[OptionKey('eh', machine=target.for_machine, lang='cpp')] if eh.value == 'a': ET.SubElement(clconf, 'ExceptionHandling').text = 'Async' elif eh.value == 's': @@ -926,7 +926,7 @@ class Vs2010Backend(backends.Backend): file_args[l] += compilers.get_base_compile_args( self.get_base_options_for_target(target), comp) file_args[l] += comp.get_option_compile_args( - self.environment.coredata.compiler_options) + self.environment.coredata.options) # Add compile args added using add_project_arguments() for l, args in self.build.projects_args[target.for_machine].get(target.subproject, {}).items(): @@ -940,7 +940,7 @@ class Vs2010Backend(backends.Backend): # Compile args added from the env or cross file: CFLAGS/CXXFLAGS, etc. We want these # to override all the defaults, but not the per-target compile args. for l in file_args.keys(): - opts = self.environment.coredata.compiler_options[OptionKey('args', machine=target.for_machine, lang=l)] + opts = self.environment.coredata.options[OptionKey('args', machine=target.for_machine, lang=l)] file_args[l] += opts.value for args in file_args.values(): # This is where Visual Studio will insert target_args, target_defines, @@ -1075,7 +1075,7 @@ class Vs2010Backend(backends.Backend): ET.SubElement(clconf, 'FavorSizeOrSpeed').text = 'Speed' # Note: SuppressStartupBanner is /NOLOGO and is 'true' by default pch_sources = {} - if self.environment.coredata.base_options.get(OptionKey('b_pch')): + if self.environment.coredata.options.get(OptionKey('b_pch')): for lang in ['c', 'cpp']: pch = target.get_pch(lang) if not pch: @@ -1111,7 +1111,7 @@ class Vs2010Backend(backends.Backend): ET.SubElement(link, 'GenerateDebugInformation').text = 'false' if not isinstance(target, build.StaticLibrary): if isinstance(target, build.SharedModule): - options = self.environment.coredata.base_options + options = self.environment.coredata.options extra_link_args += compiler.get_std_shared_module_link_args(options) # Add link args added using add_project_link_arguments() extra_link_args += self.build.get_project_link_args(compiler, target.subproject, target.for_machine) @@ -1144,8 +1144,7 @@ class Vs2010Backend(backends.Backend): # to be after all internal and external libraries so that unresolved # symbols from those can be found here. This is needed when the # *_winlibs that we want to link to are static mingw64 libraries. - extra_link_args += compiler.get_option_link_args( - self.environment.coredata.compiler_options[compiler.for_machine][comp.language]) + extra_link_args += compiler.get_option_link_args(self.environment.coredata.options) (additional_libpaths, additional_links, extra_link_args) = self.split_link_args(extra_link_args.to_native()) # Add more libraries to be linked if needed @@ -1224,7 +1223,7 @@ class Vs2010Backend(backends.Backend): # /nologo ET.SubElement(link, 'SuppressStartupBanner').text = 'true' # /release - if not self.environment.coredata.get_builtin_option('debug'): + if not self.environment.coredata.get_option(OptionKey('debug')): ET.SubElement(link, 'SetChecksum').text = 'true' meson_file_group = ET.SubElement(root, 'ItemGroup') @@ -1424,9 +1423,9 @@ class Vs2010Backend(backends.Backend): ET.SubElement(midl, 'ProxyFileName').text = '%(Filename)_p.c' # FIXME: No benchmarks? test_command = self.environment.get_build_command() + ['test', '--no-rebuild'] - if not self.environment.coredata.get_builtin_option('stdsplit'): + if not self.environment.coredata.get_option(OptionKey('stdsplit')): test_command += ['--no-stdsplit'] - if self.environment.coredata.get_builtin_option('errorlogs'): + if self.environment.coredata.get_option(OptionKey('errorlogs')): test_command += ['--print-errorlogs'] self.serialize_tests() self.add_custom_build(root, 'run_tests', '"%s"' % ('" "'.join(test_command))) diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py index ef0c956e9..0e39c65b0 100644 --- a/mesonbuild/backend/xcodebackend.py +++ b/mesonbuild/backend/xcodebackend.py @@ -61,7 +61,7 @@ class XCodeBackend(backends.Backend): return str(uuid.uuid4()).upper().replace('-', '')[:24] def get_target_dir(self, target): - dirname = os.path.join(target.get_subdir(), self.environment.coredata.get_builtin_option('buildtype')) + dirname = os.path.join(target.get_subdir(), self.environment.coredata.get_option(mesonlib.OptionKey('buildtype'))) os.makedirs(os.path.join(self.environment.get_build_dir(), dirname), exist_ok=True) return dirname diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 2916976c6..9904cbec4 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -404,7 +404,7 @@ class EnvironmentVariables: return env class Target: - def __init__(self, name, subdir, subproject, build_by_default: bool, for_machine: MachineChoice): + def __init__(self, name: str, subdir: str, subproject: str, build_by_default: bool, for_machine: MachineChoice): if has_path_sep(name): # Fix failing test 53 when this becomes an error. mlog.warning('''Target "{}" has a path separator in its name. @@ -418,7 +418,7 @@ a hard error in the future.'''.format(name)) self.install = False self.build_always_stale = False self.option_overrides_base: T.Dict[OptionKey, str] = {} - self.option_overrides_compiler: 'KeyedOptionDictType' = {} + self.option_overrides_compiler: T.Dict[OptionKey, str] = {} self.extra_files = [] # type: T.List[File] if not hasattr(self, 'typename'): raise RuntimeError('Target type is not set for target class "{}". This is a bug'.format(type(self).__name__)) @@ -545,7 +545,7 @@ class BuildTarget(Target): def __init__(self, name: str, subdir: str, subproject: str, for_machine: MachineChoice, sources: T.List[File], objects, environment: environment.Environment, kwargs): super().__init__(name, subdir, subproject, True, for_machine) - unity_opt = environment.coredata.get_builtin_option('unity') + unity_opt = environment.coredata.get_option(OptionKey('unity')) self.is_unity = unity_opt == 'on' or (unity_opt == 'subprojects' and subproject != '') self.environment = environment self.sources = [] @@ -1075,8 +1075,8 @@ This will become a hard error in a future Meson release.''') k = OptionKey(option) if arg in kwargs: val = kwargs[arg] - elif k in environment.coredata.base_options: - val = environment.coredata.base_options[k].value + elif k in environment.coredata.options: + val = environment.coredata.options[k].value else: val = False @@ -1598,8 +1598,8 @@ class Executable(BuildTarget): sources: T.List[File], objects, environment: environment.Environment, kwargs): self.typename = 'executable' key = OptionKey('b_pie') - if 'pie' not in kwargs and key in environment.coredata.base_options: - kwargs['pie'] = environment.coredata.base_options[key].value + if 'pie' not in kwargs and key in environment.coredata.options: + kwargs['pie'] = environment.coredata.options[key].value super().__init__(name, subdir, subproject, for_machine, sources, objects, environment, kwargs) # Unless overridden, executables have no suffix or prefix. Except on # Windows and with C#/Mono executables where the suffix is 'exe' diff --git a/mesonbuild/cmake/executor.py b/mesonbuild/cmake/executor.py index 21dfd356c..674b854c8 100644 --- a/mesonbuild/cmake/executor.py +++ b/mesonbuild/cmake/executor.py @@ -62,7 +62,7 @@ class CMakeExecutor: self.cmakebin = None return - self.prefix_paths = self.environment.coredata.builtins[OptionKey('cmake_prefix_path', machine=self.for_machine)].value + self.prefix_paths = self.environment.coredata.options[OptionKey('cmake_prefix_path', machine=self.for_machine)].value env_pref_path_raw = get_env_var( self.for_machine, self.environment.is_cross_build(), diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py index 5d2dd7f05..e73dcf9d1 100644 --- a/mesonbuild/cmake/interpreter.py +++ b/mesonbuild/cmake/interpreter.py @@ -362,7 +362,7 @@ class ConverterTarget: cfgs += [x for x in tgt.properties['CONFIGURATIONS'] if x] cfg = cfgs[0] - is_debug = self.env.coredata.get_builtin_option('debug'); + is_debug = self.env.coredata.get_option(OptionKey('debug')); if is_debug: if 'DEBUG' in cfgs: cfg = 'DEBUG' @@ -578,7 +578,7 @@ class ConverterTarget: @lru_cache(maxsize=None) def _all_lang_stds(self, lang: str) -> T.List[str]: try: - res = self.env.coredata.compiler_options[OptionKey('std', machine=MachineChoice.BUILD, lang=lang)].choices + res = self.env.coredata.options[OptionKey('std', machine=MachineChoice.BUILD, lang=lang)].choices except KeyError: return [] diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index 0f30f55c2..3288c00f9 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -394,8 +394,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.base_options[OptionKey('b_vscrt')].value - buildtype = env.coredata.builtins[OptionKey('buildtype')].value + crt_val = env.coredata.options[OptionKey('b_vscrt')].value + buildtype = env.coredata.options[OptionKey('buildtype')].value cargs += self.get_crt_compile_args(crt_val, buildtype) except (KeyError, AttributeError): pass diff --git a/mesonbuild/compilers/mixins/emscripten.py b/mesonbuild/compilers/mixins/emscripten.py index 537ae92d8..fc0b21e39 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 = ['-s', 'USE_PTHREADS=1'] - count: int = env.coredata.compiler_options[OptionKey('thread_count', lang=self.language, machine=self.for_machine)].value + count: int = env.coredata.options[OptionKey('thread_count', lang=self.language, machine=self.for_machine)].value if count: args.extend(['-s', 'PTHREAD_POOL_SIZE={}'.format(count)]) return args diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 6d6583fad..d4d339e31 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -385,16 +385,12 @@ class CoreData: self.meson_command = meson_command self.target_guids = {} self.version = version - self.builtins: 'KeyedOptionDictType' = {} - self.backend_options: 'KeyedOptionDictType' = {} - self.user_options: 'KeyedOptionDictType' = {} - self.compiler_options: 'KeyedOptionDictType' = {} - self.base_options: 'KeyedOptionDictType' = {} + self.options: 'KeyedOptionDictType' = {} self.cross_files = self.__load_config_files(options, scratch_dir, 'cross') self.compilers = PerMachine(OrderedDict(), OrderedDict()) # type: PerMachine[T.Dict[str, Compiler]] - build_cache = DependencyCache(self.builtins, MachineChoice.BUILD) - host_cache = DependencyCache(self.builtins, MachineChoice.BUILD) + build_cache = DependencyCache(self.options, MachineChoice.BUILD) + host_cache = DependencyCache(self.options, MachineChoice.BUILD) self.deps = PerMachine(build_cache, host_cache) # type: PerMachine[DependencyCache] self.compiler_check_cache = OrderedDict() # type: T.Dict[CompilerCheckCacheKey, compiler.CompileResult] @@ -523,10 +519,10 @@ class CoreData: def init_builtins(self, subproject: str) -> None: # Create builtin options with default values for key, opt in BUILTIN_OPTIONS.items(): - self.add_builtin_option(self.builtins, key.evolve(subproject=subproject), opt) + self.add_builtin_option(self.options, key.evolve(subproject=subproject), opt) for for_machine in iter(MachineChoice): for key, opt in BUILTIN_OPTIONS_PER_MACHINE.items(): - self.add_builtin_option(self.builtins, key.evolve(subproject=subproject, machine=for_machine), opt) + self.add_builtin_option(self.options, key.evolve(subproject=subproject, machine=for_machine), opt) @staticmethod def add_builtin_option(opts_map: 'KeyedOptionDictType', key: OptionKey, @@ -542,55 +538,54 @@ class CoreData: def init_backend_options(self, backend_name: str) -> None: if backend_name == 'ninja': - self.backend_options[OptionKey('backend_max_links')] = UserIntegerOption( + self.options[OptionKey('backend_max_links')] = UserIntegerOption( 'Maximum number of linker processes to run or 0 for no ' 'limit', (0, None, 0)) elif backend_name.startswith('vs'): - self.backend_options[OptionKey('backend_startup_project')] = UserStringOption( + self.options[OptionKey('backend_startup_project')] = UserStringOption( 'Default project to execute in Visual Studio', '') - def get_builtin_option(self, optname: str, subproject: str = '') -> T.Union[str, int, bool]: - key = OptionKey.from_string(optname).evolve(subproject=subproject) - for opts in self._get_all_builtin_options(): - v = opts.get(str(key)) - if v is None or v.yielding: - v = opts.get(str(key.as_root())) - if v is None: - continue + def get_option(self, key: OptionKey) -> T.Union[str, int, bool, WrapMode]: + try: + v = self.options[key].value if key.name == 'wrap_mode': - return WrapMode.from_string(v.value) - return v.value - raise RuntimeError(f'Tried to get unknown builtin option {key.name}.') - - def _try_set_builtin_option(self, key: OptionKey, value) -> bool: - for opts in self._get_all_builtin_options(): - opt = opts.get(str(key)) - if opt is None: - continue + return WrapMode[v] + return v + except KeyError: + pass + + try: + v = self.options[key.as_root()] + if v.yielding: + if key.name == 'wrap_mode': + return WrapMode[v.value] + return v.value + except KeyError: + pass + + raise MesonException(f'Tried to get unknown builtin option {str(key)}') + + def set_option(self, key: OptionKey, value) -> None: + if key.is_builtin(): if key.name == 'prefix': value = self.sanitize_prefix(value) else: - prefix = self.builtins[OptionKey('prefix')].value + prefix = self.options[OptionKey('prefix')].value value = self.sanitize_dir_option_value(prefix, key, value) - break - else: - return False - opt.set_value(value) - # Make sure that buildtype matches other settings. - if key.name == 'buildtype': - self.set_others_from_buildtype(value) - else: - self.set_buildtype_from_others() - return True - def set_builtin_option(self, optname: OptionKey, value) -> None: - res = self._try_set_builtin_option(optname, value) - if not res: - raise RuntimeError(f'Tried to set unknown builtin option {str(optname)}') + try: + self.options[key].set_value(value) + except KeyError: + raise MesonException(f'Tried to set unknown builtin option {str(key)}') - def set_others_from_buildtype(self, value): + if key.name == 'buildtype': + self._set_others_from_buildtype(value) + elif key.name in {'debug', 'optimization'}: + self._set_buildtype_from_others() + + def _set_others_from_buildtype(self, value: str) -> None: if value == 'plain': opt = '0' debug = False @@ -609,12 +604,12 @@ class CoreData: else: assert(value == 'custom') return - self.builtins[OptionKey('optimization')].set_value(opt) - self.builtins[OptionKey('debug')].set_value(debug) + self.options[OptionKey('optimization')].set_value(opt) + self.options[OptionKey('debug')].set_value(debug) - def set_buildtype_from_others(self): - opt = self.builtins[OptionKey('optimization')].value - debug = self.builtins[OptionKey('debug')].value + def _set_buildtype_from_others(self) -> None: + opt = self.options[OptionKey('optimization')].value + debug = self.options[OptionKey('debug')].value if opt == '0' and not debug: mode = 'plain' elif opt == '0' and debug: @@ -627,84 +622,47 @@ class CoreData: mode = 'minsize' else: mode = 'custom' - self.builtins[OptionKey('buildtype')].set_value(mode) - - @classmethod - def get_prefixed_options_per_machine( - cls, - options_per_machine # : PerMachine[T.Dict[str, _V]]] - ) -> T.Iterable[T.Tuple[str, _V]]: - return cls._flatten_pair_iterator( - (for_machine.get_prefix(), options_per_machine[for_machine]) - for for_machine in iter(MachineChoice) - ) - - @classmethod - def flatten_lang_iterator( - cls, - outer # : T.Iterable[T.Tuple[str, T.Dict[str, _V]]] - ) -> T.Iterable[T.Tuple[str, _V]]: - return cls._flatten_pair_iterator((lang + '_', opts) for lang, opts in outer) + self.options[OptionKey('buildtype')].set_value(mode) @staticmethod - def _flatten_pair_iterator( - outer # : T.Iterable[T.Tuple[str, T.Dict[str, _V]]] - ) -> T.Iterable[T.Tuple[str, _V]]: - for k0, v0 in outer: - for k1, v1 in v0.items(): - yield (k0 + k1, v1) - - @classmethod - def is_per_machine_option(cls, optname: OptionKey) -> bool: + def is_per_machine_option(optname: OptionKey) -> bool: if optname.name in BUILTIN_OPTIONS_PER_MACHINE: return True return optname.lang is not None - def _get_all_nonbuiltin_options(self) -> T.Iterable[T.Dict[str, UserOption]]: - yield {str(k): v for k, v in self.backend_options.items()} - yield {str(k): v for k, v in self.user_options.items()} - yield {str(k): v for k, v in self.compiler_options.items()} - yield {str(k): v for k, v in self.base_options.items()} - - def _get_all_builtin_options(self) -> T.Iterable[T.Dict[str, UserOption]]: - yield {str(k): v for k, v in self.builtins.items()} - - def get_all_options(self) -> T.Iterable[T.Dict[str, UserOption]]: - yield from self._get_all_nonbuiltin_options() - yield from self._get_all_builtin_options() - def validate_option_value(self, option_name: OptionKey, override_value): - for opts in self.get_all_options(): - opt = opts.get(str(option_name)) - if opt is not None: - try: - return opt.validate_value(override_value) - except MesonException as e: - raise type(e)(('Validation failed for option %s: ' % option_name) + str(e)) \ - .with_traceback(sys.exc_info()[2]) - raise MesonException('Tried to validate unknown option %s.' % option_name) + try: + opt = self.options[option_name] + except KeyError: + raise MesonException(f'Tried to validate unknown option {str(option_name)}') + try: + return opt.validate_value(override_value) + except MesonException as e: + raise type(e)(('Validation failed for option %s: ' % option_name) + str(e)) \ + .with_traceback(sys.exc_info()[2]) def get_external_args(self, for_machine: MachineChoice, lang: str) -> T.Union[str, T.List[str]]: - return self.compiler_options[OptionKey('args', machine=for_machine, lang=lang)].value + return self.options[OptionKey('args', machine=for_machine, lang=lang)].value def get_external_link_args(self, for_machine: MachineChoice, lang: str) -> T.Union[str, T.List[str]]: - return self.compiler_options[OptionKey('link_args', machine=for_machine, lang=lang)].value + return self.options[OptionKey('link_args', machine=for_machine, lang=lang)].value - def merge_user_options(self, options: T.Dict[str, UserOption[T.Any]]) -> None: - for name, value in options.items(): - key = OptionKey.from_string(name) - if key not in self.user_options: - self.user_options[key] = value + def update_project_options(self, options: 'KeyedOptionDictType') -> None: + for key, value in options.items(): + if not key.is_project(): + continue + if key not in self.options: + self.options[key] = value continue - oldval = self.user_options[key] + oldval = self.options[key] if type(oldval) != type(value): - self.user_options[key] = value + self.options[key] = 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.user_options[key] = value + self.options[key] = value try: value.set_value(oldval.value) except MesonException as e: @@ -718,13 +676,13 @@ class CoreData: def copy_build_options_from_regular_ones(self) -> None: assert not self.is_cross_build() for k in BUILTIN_OPTIONS_PER_MACHINE: - o = self.builtins[k] - self.builtins[k.as_build()].set_value(o.value) - for bk, bv in self.compiler_options.items(): + o = self.options[k] + self.options[k.as_build()].set_value(o.value) + for bk, bv in self.options.items(): if bk.machine is MachineChoice.BUILD: hk = bk.as_host() try: - hv = self.compiler_options[hk] + hv = self.options[hk] bv.set_value(hv.value) except KeyError: continue @@ -736,25 +694,19 @@ class CoreData: pfk = OptionKey('prefix') if pfk in options: prefix = self.sanitize_prefix(options[pfk]) - self.builtins[OptionKey('prefix')].set_value(prefix) + self.options[OptionKey('prefix')].set_value(prefix) for key in BULITIN_DIR_NOPREFIX_OPTIONS: if key not in options: - self.builtins[key].set_value(BUILTIN_OPTIONS[key].prefixed_default(key, prefix)) + self.options[key].set_value(BUILTIN_OPTIONS[key].prefixed_default(key, prefix)) unknown_options: T.List[OptionKey] = [] for k, v in options.items(): if k == pfk: continue - if self._try_set_builtin_option(k, v): - continue - for opts in self._get_all_nonbuiltin_options(): - tgt = opts.get(str(k)) - if tgt is None: - continue - tgt.set_value(v) - break - else: + elif k not in self.options: unknown_options.append(k) + else: + self.set_option(k, v) if unknown_options and warn_unknown: unknown_options_str = ', '.join(sorted(str(s) for s in unknown_options)) sub = 'In subproject {}: '.format(subproject) if subproject else '' @@ -767,10 +719,9 @@ class CoreData: def set_default_options(self, default_options: T.MutableMapping[OptionKey, str], subproject: str, env: 'Environment') -> None: # Preserve order: if env.options has 'buildtype' it must come after # 'optimization' if it is in default_options. + options: T.MutableMapping[OptionKey, T.Any] if not subproject: - options: T.MutableMapping[OptionKey, T.Any] = OrderedDict() - for k, v in default_options.items(): - options[k] = v + options = OrderedDict(default_options) options.update(env.options) env.options = options @@ -779,12 +730,15 @@ class CoreData: # Language and backend specific options will be set later when adding # languages and setting the backend (builtin options must be set first # to know which backend we'll use). - options: T.MutableMapping[OptionKey, T.Any] = OrderedDict() + options = OrderedDict() for k, v in chain(default_options.items(), env.options.items()): - # Subproject: skip options for other subprojects + # If this is a subproject, don't use other subproject options if k.subproject and k.subproject != subproject: continue + # If the option is a builtin and is yielding then it's not allowed per subproject. + if subproject and k.is_builtin() and self.options[k.as_root()].yielding: + continue # Skip base, compiler, and backend options, they are handled when # adding languages and setting backend. if k.type in {OptionType.COMPILER, OptionType.BACKEND, OptionType.BASE}: @@ -799,7 +753,7 @@ class CoreData: value = env.options.get(k) if value is not None: o.set_value(value) - self.compiler_options.setdefault(k, o) + self.options.setdefault(k, o) def add_lang_args(self, lang: str, comp: T.Type['Compiler'], for_machine: MachineChoice, env: 'Environment') -> None: @@ -816,13 +770,13 @@ class CoreData: enabled_opts: T.List[OptionKey] = [] for key in comp.base_options: - if key in self.base_options: + if key in self.options: continue oobj = compilers.base_options[key] if key in env.options: oobj.set_value(env.options[key]) enabled_opts.append(key) - self.base_options[key] = oobj + self.options[key] = oobj self.emit_base_options_warnings(enabled_opts) def emit_base_options_warnings(self, enabled_opts: T.List[OptionKey]) -> None: diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 7b8045d40..e3592193e 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -658,7 +658,7 @@ class PkgConfigDependency(ExternalDependency): @staticmethod def setup_env(env: T.MutableMapping[str, str], environment: 'Environment', for_machine: MachineChoice, extra_path: T.Optional[str] = None) -> None: - extra_paths: T.List[str] = environment.coredata.builtins[OptionKey('pkg_config_path', machine=for_machine)].value + extra_paths: T.List[str] = environment.coredata.options[OptionKey('pkg_config_path', machine=for_machine)].value if extra_path: extra_paths.append(extra_path) sysroot = environment.properties[for_machine].get_sys_root() @@ -1485,12 +1485,12 @@ class CMakeDependency(ExternalDependency): cfgs = [x for x in tgt.properties['IMPORTED_CONFIGURATIONS'] if x] cfg = cfgs[0] - if OptionKey('b_vscrt') in self.env.coredata.base_options: - is_debug = self.env.coredata.get_builtin_option('buildtype') == 'debug' - if self.env.coredata.base_options[OptionKey('b_vscrt')].value in {'mdd', 'mtd'}: + if OptionKey('b_vscrt') in self.env.coredata.options: + is_debug = self.env.coredata.get_option(OptionKey('buildtype')) == 'debug' + if self.env.coredata.options[OptionKey('b_vscrt')].value in {'mdd', 'mtd'}: is_debug = True else: - is_debug = self.env.coredata.get_builtin_option('debug') + is_debug = self.env.coredata.get_option(OptionKey('debug')) if is_debug: if 'DEBUG' in cfgs: cfg = 'DEBUG' diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py index e2e4789a3..622ee3774 100644 --- a/mesonbuild/dependencies/boost.py +++ b/mesonbuild/dependencies/boost.py @@ -341,7 +341,7 @@ class BoostLibraryFile(): class BoostDependency(ExternalDependency): def __init__(self, environment: Environment, kwargs: T.Dict[str, T.Any]) -> None: super().__init__('boost', environment, kwargs, language='cpp') - buildtype = environment.coredata.get_builtin_option('buildtype') + buildtype = environment.coredata.get_option(mesonlib.OptionKey('buildtype')) assert isinstance(buildtype, str) self.debug = buildtype.startswith('debug') self.multithreading = kwargs.get('threading', 'multi') == 'multi' @@ -616,8 +616,8 @@ class BoostDependency(ExternalDependency): # MSVC is very picky with the library tags vscrt = '' try: - crt_val = self.env.coredata.base_options[mesonlib.OptionKey('b_vscrt')].value - buildtype = self.env.coredata.builtins[mesonlib.OptionKey('buildtype')].value + crt_val = self.env.coredata.options[mesonlib.OptionKey('b_vscrt')].value + buildtype = self.env.coredata.options[mesonlib.OptionKey('buildtype')].value vscrt = self.clib_compiler.get_crt_compile_args(crt_val, buildtype)[0] except (KeyError, IndexError, AttributeError): pass diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py index 942f69a45..0b0d96df6 100644 --- a/mesonbuild/dependencies/ui.py +++ b/mesonbuild/dependencies/ui.py @@ -382,9 +382,9 @@ class QtBaseDependency(ExternalDependency): # Use the buildtype by default, but look at the b_vscrt option if the # compiler supports it. - is_debug = self.env.coredata.get_builtin_option('buildtype') == 'debug' - if mesonlib.OptionKey('b_vscrt') in self.env.coredata.base_options: - if self.env.coredata.base_options[mesonlib.OptionKey('b_vscrt')].value in {'mdd', 'mtd'}: + 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'}: is_debug = True modules_lib_suffix = self._get_modules_lib_suffix(is_debug) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 3ea078a6a..59675ff9a 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -640,6 +640,7 @@ class Environment: # interfaces which talk about native and cross. self.options = {k.as_host(): v for k, v in self.options.items()} + ## "freeze" now initialized configuration, and "save" to the class. self.machines = machines.default_missing() @@ -938,7 +939,7 @@ class Environment: elif isinstance(comp_class.LINKER_PREFIX, list): check_args = comp_class.LINKER_PREFIX + ['/logo'] + comp_class.LINKER_PREFIX + ['--version'] - check_args += self.coredata.compiler_options[OptionKey('args', lang=comp_class.language, machine=for_machine)].value + check_args += self.coredata.options[OptionKey('args', lang=comp_class.language, machine=for_machine)].value override = [] # type: T.List[str] value = self.lookup_binary_entry(for_machine, comp_class.language + '_ld') @@ -1004,7 +1005,7 @@ class Environment: """ self.coredata.add_lang_args(comp_class.language, comp_class, for_machine, self) extra_args = extra_args or [] - extra_args += self.coredata.compiler_options[OptionKey('args', lang=comp_class.language, machine=for_machine)].value + extra_args += self.coredata.options[OptionKey('args', lang=comp_class.language, machine=for_machine)].value if isinstance(comp_class.LINKER_PREFIX, str): check_args = [comp_class.LINKER_PREFIX + '--version'] + extra_args @@ -2009,25 +2010,25 @@ class Environment: return self.get_libdir() def get_prefix(self) -> str: - return self.coredata.get_builtin_option('prefix') + return self.coredata.get_option(OptionKey('prefix')) def get_libdir(self) -> str: - return self.coredata.get_builtin_option('libdir') + return self.coredata.get_option(OptionKey('libdir')) def get_libexecdir(self) -> str: - return self.coredata.get_builtin_option('libexecdir') + return self.coredata.get_option(OptionKey('libexecdir')) def get_bindir(self) -> str: - return self.coredata.get_builtin_option('bindir') + return self.coredata.get_option(OptionKey('bindir')) def get_includedir(self) -> str: - return self.coredata.get_builtin_option('includedir') + return self.coredata.get_option(OptionKey('includedir')) def get_mandir(self) -> str: - return self.coredata.get_builtin_option('mandir') + return self.coredata.get_option(OptionKey('mandir')) def get_datadir(self) -> str: - return self.coredata.get_builtin_option('datadir') + return self.coredata.get_option(OptionKey('datadir')) def get_compiler_system_dirs(self, for_machine: MachineChoice): for comp in self.coredata.compilers[for_machine].values(): diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 1329ecfe7..def72dd3d 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -78,11 +78,11 @@ class OverrideProgram(dependencies.ExternalProgram): class FeatureOptionHolder(InterpreterObject, ObjectHolder): - def __init__(self, env, name, option): + def __init__(self, env: 'Environment', name, option): InterpreterObject.__init__(self) ObjectHolder.__init__(self, option) if option.is_auto(): - self.held_object = env.coredata.builtins[OptionKey('auto_features')] + self.held_object = env.coredata.options[OptionKey('auto_features')] self.name = name self.methods.update({'enabled': self.enabled_method, 'disabled': self.disabled_method, @@ -1143,7 +1143,7 @@ class CompilerHolder(InterpreterObject): args += self.compiler.get_include_args(idir, False) if not nobuiltins: for_machine = Interpreter.machine_from_native_kwarg(kwargs) - opts = self.environment.coredata.compiler_options + opts = self.environment.coredata.options args += self.compiler.get_option_compile_args(opts) if mode == 'link': args += self.compiler.get_option_link_args(opts) @@ -2151,7 +2151,7 @@ class MesonMain(InterpreterObject): @noPosargs @permittedKwargs({}) def is_unity_method(self, args, kwargs): - optval = self.interpreter.environment.coredata.get_builtin_option('unity') + optval = self.interpreter.environment.coredata.get_option(OptionKey('unity')) if optval == 'on' or (optval == 'subprojects' and self.interpreter.is_subproject()): return True return False @@ -2474,12 +2474,11 @@ class Interpreter(InterpreterBase): def get_non_matching_default_options(self) -> T.Iterator[T.Tuple[str, str, coredata.UserOption]]: env = self.environment for def_opt_name, def_opt_value in self.project_default_options.items(): - for opts in env.coredata.get_all_options(): - cur_opt_value = opts.get(def_opt_name) - if cur_opt_value is not None: - def_opt_value = env.coredata.validate_option_value(def_opt_name, def_opt_value) - if def_opt_value != cur_opt_value.value: - yield (def_opt_name, def_opt_value, cur_opt_value) + cur_opt_value = self.coredata.options.get(def_opt_name) + if cur_opt_value is not None: + def_opt_value = env.coredata.validate_option_value(def_opt_name, def_opt_value) + if def_opt_value != cur_opt_value.value: + yield (str(def_opt_name), def_opt_value, cur_opt_value) def build_func_dict(self): self.funcs.update({'add_global_arguments': self.func_add_global_arguments, @@ -3009,7 +3008,7 @@ external dependencies (including libraries) must go to "dependencies".''') def _do_subproject_cmake(self, subp_name, subdir, subdir_abs, default_options, kwargs): with mlog.nested(): new_build = self.build.copy() - prefix = self.coredata.builtins[OptionKey('prefix')].value + prefix = self.coredata.options[OptionKey('prefix')].value from .modules.cmake import CMakeSubprojectOptions options = kwargs.get('options', CMakeSubprojectOptions()) @@ -3051,20 +3050,20 @@ external dependencies (including libraries) must go to "dependencies".''') return result def get_option_internal(self, optname: str): - # TODO: this optname may be a compiler option key = OptionKey.from_string(optname).evolve(subproject=self.subproject) - for opts in [self.coredata.builtins, self.coredata.base_options, compilers.base_options, self.coredata.compiler_options]: - v = opts.get(key) - if v is None or v.yielding: - v = opts.get(key.as_root()) - if v is not None: - return v + if not key.is_project(): + for opts in [self.coredata.options, compilers.base_options]: + v = opts.get(key) + if v is None or v.yielding: + v = opts.get(key.as_root()) + if v is not None: + return v try: - opt = self.coredata.user_options[key] - if opt.yielding and key.subproject and key.as_root() in self.coredata.user_options: - popt = self.coredata.user_options[key.as_root()] + 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()] if type(opt) is type(popt): opt = popt else: @@ -3118,7 +3117,7 @@ external dependencies (including libraries) must go to "dependencies".''') # The backend is already set when parsing subprojects if self.backend is not None: return - backend = self.coredata.get_builtin_option('backend') + backend = self.coredata.get_option(OptionKey('backend')) from .backend import backends self.backend = backends.get_backend_from_name(backend, self.build, self) @@ -3127,7 +3126,7 @@ external dependencies (including libraries) must go to "dependencies".''') if backend != self.backend.name: if self.backend.name.startswith('vs'): mlog.log('Auto detected Visual Studio backend:', mlog.bold(self.backend.name)) - self.coredata.set_builtin_option('backend', self.backend.name) + self.coredata.set_option(OptionKey('backend'), self.backend.name) # Only init backend options on first invocation otherwise it would # override values previously set from command line. @@ -3158,7 +3157,7 @@ external dependencies (including libraries) must go to "dependencies".''') if os.path.exists(self.option_file): oi = optinterpreter.OptionInterpreter(self.subproject) oi.process(self.option_file) - self.coredata.merge_user_options(oi.options) + self.coredata.update_project_options(oi.options) self.add_build_def_file(self.option_file) # Do not set default_options on reconfigure otherwise it would override @@ -3208,7 +3207,7 @@ external dependencies (including libraries) must go to "dependencies".''') self.build.subproject_dir = self.subproject_dir # Load wrap files from this (sub)project. - wrap_mode = self.coredata.get_builtin_option('wrap_mode') + wrap_mode = self.coredata.get_option(OptionKey('wrap_mode')) if not self.is_subproject() or wrap_mode != WrapMode.nopromote: subdir = os.path.join(self.subdir, spdirname) r = wrap.Resolver(self.environment.get_source_dir(), subdir, wrap_mode) @@ -3520,7 +3519,7 @@ external dependencies (including libraries) must go to "dependencies".''') return progobj fallback = None - wrap_mode = self.coredata.get_builtin_option('wrap_mode') + wrap_mode = self.coredata.get_option(OptionKey('wrap_mode')) if wrap_mode != WrapMode.nofallback and self.environment.wrap_resolver: fallback = self.environment.wrap_resolver.find_program_provider(args) if fallback and wrap_mode == WrapMode.forcefallback: @@ -3824,8 +3823,8 @@ external dependencies (including libraries) must go to "dependencies".''') if self.get_subproject(subp_name): return self.get_subproject_dep(name, display_name, subp_name, varname, kwargs) - wrap_mode = self.coredata.get_builtin_option('wrap_mode') - force_fallback_for = self.coredata.get_builtin_option('force_fallback_for') + wrap_mode = self.coredata.get_option(OptionKey('wrap_mode')) + force_fallback_for = self.coredata.get_option(OptionKey('force_fallback_for')) force_fallback = (force_fallback or wrap_mode == WrapMode.forcefallback or name in force_fallback_for or @@ -3871,11 +3870,11 @@ external dependencies (including libraries) must go to "dependencies".''') # Explicitly listed fallback preferences for specific subprojects # take precedence over wrap-mode - force_fallback_for = self.coredata.get_builtin_option('force_fallback_for') + force_fallback_for = self.coredata.get_option(OptionKey('force_fallback_for')) if name in force_fallback_for or subp_name in force_fallback_for: mlog.log('Looking for a fallback subproject for the dependency', mlog.bold(display_name), 'because:\nUse of fallback was forced for that specific subproject') - elif self.coredata.get_builtin_option('wrap_mode') == WrapMode.nofallback: + elif self.coredata.get_option(OptionKey('wrap_mode')) == WrapMode.nofallback: mlog.log('Not looking for a fallback subproject for the dependency', mlog.bold(display_name), 'because:\nUse of fallback ' 'dependencies is disabled.') @@ -3883,7 +3882,7 @@ external dependencies (including libraries) must go to "dependencies".''') m = 'Dependency {!r} not found and fallback is disabled' raise DependencyException(m.format(display_name)) return self.notfound_dependency() - elif self.coredata.get_builtin_option('wrap_mode') == WrapMode.forcefallback: + elif self.coredata.get_option(OptionKey('wrap_mode')) == WrapMode.forcefallback: mlog.log('Looking for a fallback subproject for the dependency', mlog.bold(display_name), 'because:\nUse of fallback dependencies is forced.') else: @@ -4772,15 +4771,15 @@ different subdirectory. break def check_clang_asan_lundef(self) -> None: - if OptionKey('b_lundef') not in self.coredata.base_options: + if OptionKey('b_lundef') not in self.coredata.options: return - if OptionKey('b_sanitize') not in self.coredata.base_options: + if OptionKey('b_sanitize') not in self.coredata.options: return - if (self.coredata.base_options[OptionKey('b_lundef')].value and - self.coredata.base_options[OptionKey('b_sanitize')].value != 'none'): + if (self.coredata.options[OptionKey('b_lundef')].value and + self.coredata.options[OptionKey('b_sanitize')].value != 'none'): mlog.warning('''Trying to use {} sanitizer on Clang with b_lundef. This will probably not work. -Try setting b_lundef to false instead.'''.format(self.coredata.base_options[OptionKey('b_sanitize')].value), +Try setting b_lundef to false instead.'''.format(self.coredata.options[OptionKey('b_sanitize')].value), location=self.current_node) def evaluate_subproject_info(self, path_from_source_root, subproject_dir): @@ -4878,8 +4877,8 @@ Try setting b_lundef to false instead.'''.format(self.coredata.base_options[Opti key = OptionKey('b_staticpic') if 'pic' in kwargs: pic = kwargs['pic'] - elif key in self.environment.coredata.base_options: - pic = self.environment.coredata.base_options[key].value + elif key in self.environment.coredata.options: + pic = self.environment.coredata.options[key].value if pic: # Exclude sources from args and kwargs to avoid building them twice @@ -4896,7 +4895,7 @@ Try setting b_lundef to false instead.'''.format(self.coredata.base_options[Opti return BothLibrariesHolder(shared_holder, static_holder, self) def build_library(self, node, args, kwargs): - default_library = self.coredata.get_builtin_option('default_library', self.subproject) + default_library = self.coredata.get_option(OptionKey('default_library', subproject=self.subproject)) if default_library == 'shared': return self.build_target(node, args, kwargs, SharedLibraryHolder) elif default_library == 'static': diff --git a/mesonbuild/mcompile.py b/mesonbuild/mcompile.py index 41ed1b79a..140e88f74 100644 --- a/mesonbuild/mcompile.py +++ b/mesonbuild/mcompile.py @@ -47,7 +47,7 @@ def get_backend_from_coredata(builddir: Path) -> str: """ Gets `backend` option value from coredata """ - backend = coredata.load(str(builddir)).get_builtin_option('backend') + backend = coredata.load(str(builddir)).get_option(mesonlib.OptionKey('backend')) assert isinstance(backend, str) return backend diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index d6584d51a..686a3367d 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -192,26 +192,32 @@ class Conf: dir_option_names = set(coredata.BUILTIN_DIR_OPTIONS) test_option_names = {OptionKey('errorlogs'), - OptionKey('stdsplit')} - core_option_names = [k for k in self.coredata.builtins if k not in dir_option_names | test_option_names] - - dir_options = {k: o for k, o in self.coredata.builtins.items() if k in dir_option_names} - test_options = {k: o for k, o in self.coredata.builtins.items() if k in test_option_names} - core_options = {k: o for k, o in self.coredata.builtins.items() if k in core_option_names} - - host_core_options = self.split_options_per_subproject({k: v for k, v in self.coredata.builtins.items() if k.machine is MachineChoice.HOST}) - build_core_options = self.split_options_per_subproject({k: v for k, v in self.coredata.builtins.items() if k.machine is MachineChoice.BUILD}) - host_compiler_options = self.split_options_per_subproject({k: v for k, v in self.coredata.compiler_options.items() if k.machine is MachineChoice.HOST}) - build_compiler_options = self.split_options_per_subproject({k: v for k, v in self.coredata.compiler_options.items() if k.machine is MachineChoice.BUILD}) - project_options = self.split_options_per_subproject(self.coredata.user_options) + OptionKey('stdsplit')} + + dir_options: 'coredata.KeyedOptionDictType' = {} + test_options: 'coredata.KeyedOptionDictType' = {} + core_options: 'coredata.KeyedOptionDictType' = {} + for k, v in self.coredata.options.items(): + if k in dir_option_names: + dir_options[k] = v + elif k in test_option_names: + test_options[k] = v + elif k.is_builtin(): + core_options[k] = v + + 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()}) 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', {str(k): v for k, v in self.coredata.backend_options.items()}) - self.print_options('Base options', {str(k): v for k, v in self.coredata.base_options.items()}) + self.print_options('Backend options', {str(k): v for k, v in self.coredata.options.items()}) + self.print_options('Base options', {str(k): v for k, v in self.coredata.options.items()}) 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 b1d283135..9121fc766 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -21,6 +21,7 @@ project files and don't need this info.""" import collections import json +from mesonbuild.compilers import d from . import build, coredata as cdata from . import mesonlib from .ast import IntrospectionInterpreter, build_target_functions, AstConditionLevel, AstIDGenerator, AstIndentationGenerator, AstJSONPrinter @@ -212,21 +213,30 @@ def list_buildoptions_from_source(intr: IntrospectionInterpreter) -> T.List[T.Di def list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[str]] = None) -> T.List[T.Dict[str, T.Union[str, bool, int, T.List[str]]]]: optlist = [] # type: T.List[T.Dict[str, T.Union[str, bool, int, T.List[str]]]] + subprojects = subprojects or [] dir_option_names = set(cdata.BUILTIN_DIR_OPTIONS) test_option_names = {OptionKey('errorlogs'), OptionKey('stdsplit')} - core_option_names = {k for k in coredata.builtins if k not in dir_option_names | test_option_names} - dir_options = {str(k): o for k, o in coredata.builtins.items() if k in dir_option_names} - test_options = {str(k): o for k, o in coredata.builtins.items() if k in test_option_names} - core_options = {str(k): o for k, o in coredata.builtins.items() if k in core_option_names} - for s in subprojects or []: - core_options.update({str(k.evolve(subproject=s)): v for k, v in coredata.builtins.items() if not v.yielding}) - - def add_keys(options: 'cdata.OptionDictType', section: str, machine: str = 'any') -> None: + dir_options: 'cdata.KeyedOptionDictType' = {} + test_options: 'cdata.KeyedOptionDictType' = {} + core_options: 'cdata.KeyedOptionDictType' = {} + for k, v in coredata.options.items(): + if k in dir_option_names: + dir_options[k] = v + elif k in test_option_names: + test_options[k] = v + elif k.is_builtin(): + core_options[k] = v + if not v.yielding: + for s in subprojects: + core_options[k.evolve(subproject=s)] = v + + def add_keys(options: 'cdata.KeyedOptionDictType', section: str) -> None: for key, opt in sorted(options.items()): - optdict = {'name': key, 'value': opt.value, 'section': section, 'machine': machine} + 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'} if isinstance(opt, cdata.UserStringOption): typestr = 'string' elif isinstance(opt, cdata.UserBooleanOption): @@ -245,20 +255,14 @@ def list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[s optlist.append(optdict) add_keys(core_options, 'core') - add_keys({str(k): v for k, v in coredata.backend_options.items()}, 'backend') - add_keys({str(k): v for k, v in coredata.base_options.items()}, 'base') - add_keys( - {str(k): v for k, v in coredata.compiler_options.items() if k.machine is MachineChoice.HOST}, - 'compiler', - machine='host', - ) + 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( - {str(k): v for k, v in coredata.compiler_options.items() if k.machine is MachineChoice.BUILD}, + {k: v for k, v in sorted(coredata.options.items(), key=lambda i: i[0].machine) if k.is_compiler()}, 'compiler', - machine='build', ) add_keys(dir_options, 'directory') - add_keys({str(k): v for k, v in coredata.user_options.items()}, 'user') + add_keys({k: v for k, v in coredata.options.items() if k.is_project()}, 'user') add_keys(test_options, 'test') return optlist diff --git a/mesonbuild/modules/cmake.py b/mesonbuild/modules/cmake.py index 35c85a790..f6afaf35c 100644 --- a/mesonbuild/modules/cmake.py +++ b/mesonbuild/modules/cmake.py @@ -269,7 +269,7 @@ class CmakeModule(ExtensionModule): pkgroot = kwargs.get('install_dir', None) if pkgroot is None: - pkgroot = os.path.join(state.environment.coredata.get_builtin_option('libdir'), 'cmake', name) + pkgroot = os.path.join(state.environment.coredata.get_option(mesonlib.OptionKey('libdir')), 'cmake', name) if not isinstance(pkgroot, str): raise mesonlib.MesonException('Install_dir must be a string.') @@ -342,7 +342,7 @@ class CmakeModule(ExtensionModule): (ofile_path, ofile_fname) = os.path.split(os.path.join(state.subdir, '{}Config.cmake'.format(name))) ofile_abs = os.path.join(state.environment.build_dir, ofile_path, ofile_fname) - install_dir = kwargs.get('install_dir', os.path.join(state.environment.coredata.get_builtin_option('libdir'), 'cmake', name)) + install_dir = kwargs.get('install_dir', os.path.join(state.environment.coredata.get_option(mesonlib.OptionKey('libdir')), 'cmake', name)) if not isinstance(install_dir, str): raise mesonlib.MesonException('"install_dir" must be a string.') @@ -352,7 +352,7 @@ class CmakeModule(ExtensionModule): if not isinstance(conf, ConfigurationDataHolder): raise mesonlib.MesonException('Argument "configuration" is not of type configuration_data') - prefix = state.environment.coredata.get_builtin_option('prefix') + prefix = state.environment.coredata.get_option(mesonlib.OptionKey('prefix')) abs_install_dir = install_dir if not os.path.isabs(abs_install_dir): abs_install_dir = os.path.join(prefix, install_dir) diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 565fd82a9..21570bd8b 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -212,7 +212,7 @@ class GnomeModule(ExtensionModule): if install_header: h_kwargs['install'] = install_header h_kwargs['install_dir'] = kwargs.get('install_dir', - state.environment.coredata.get_builtin_option('includedir')) + state.environment.coredata.get_option(mesonlib.OptionKey('includedir'))) target_h = GResourceHeaderTarget(args[0] + '_h', state.subdir, state.subproject, h_kwargs) rv = [target_c, target_h] return ModuleReturnValue(rv, rv) @@ -613,7 +613,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.base_options[mesonlib.OptionKey('b_sanitize')].value + sanitize = state.environment.coredata.options[mesonlib.OptionKey('b_sanitize')].value cflags += compiler.sanitizer_compile_args(sanitize) sanitize = sanitize.split(',') # These must be first in ldflags @@ -1175,7 +1175,7 @@ class GnomeModule(ExtensionModule): targets = [] install_header = kwargs.get('install_header', False) - install_dir = kwargs.get('install_dir', state.environment.coredata.get_builtin_option('includedir')) + install_dir = kwargs.get('install_dir', state.environment.coredata.get_option(mesonlib.OptionKey('includedir'))) output = namebase + '.c' # Added in https://gitlab.gnome.org/GNOME/glib/commit/e4d68c7b3e8b01ab1a4231bf6da21d045cb5a816 (2.55.2) @@ -1332,7 +1332,7 @@ class GnomeModule(ExtensionModule): custom_kwargs['install'] = install_header if 'install_dir' not in custom_kwargs: custom_kwargs['install_dir'] = \ - state.environment.coredata.get_builtin_option('includedir') + state.environment.coredata.get_option(mesonlib.OptionKey('includedir')) h_target = self._make_mkenum_custom_target(state, h_sources, h_output, h_cmd, custom_kwargs) @@ -1361,7 +1361,7 @@ class GnomeModule(ExtensionModule): custom_kwargs['install'] = install_header if 'install_dir' not in custom_kwargs: custom_kwargs['install_dir'] = \ - state.environment.coredata.get_builtin_option('includedir') + state.environment.coredata.get_option(mesonlib.OptionKey('includedir')) target = self._make_mkenum_custom_target(state, sources, basename, generic_cmd, custom_kwargs) return ModuleReturnValue(target, [target]) @@ -1691,7 +1691,7 @@ G_END_DECLS''' 'depends': vapi_depends, } install_dir = kwargs.get('install_dir', - os.path.join(state.environment.coredata.get_builtin_option('datadir'), + os.path.join(state.environment.coredata.get_option(mesonlib.OptionKey('datadir')), 'vala', 'vapi')) if kwargs.get('install'): custom_kwargs['install'] = kwargs['install'] diff --git a/mesonbuild/modules/hotdoc.py b/mesonbuild/modules/hotdoc.py index 5c04e2740..ee756e71c 100644 --- a/mesonbuild/modules/hotdoc.py +++ b/mesonbuild/modules/hotdoc.py @@ -326,7 +326,7 @@ class HotdocTargetBuilder: for path in self.include_paths.keys(): self.cmd.extend(['--include-path', path]) - if self.state.environment.coredata.get_builtin_option('werror', self.state.subproject): + if self.state.environment.coredata.get_option(mesonlib.OptionKey('werror', subproject=self.state.subproject)): self.cmd.append('--fatal-warning') self.generate_hotdoc_config() diff --git a/mesonbuild/modules/i18n.py b/mesonbuild/modules/i18n.py index 2652e7d2a..d48f83bc4 100644 --- a/mesonbuild/modules/i18n.py +++ b/mesonbuild/modules/i18n.py @@ -172,7 +172,7 @@ class I18nModule(ExtensionModule): install = kwargs.get('install', True) if install: - install_dir = kwargs.get('install_dir', state.environment.coredata.get_builtin_option('localedir')) + install_dir = kwargs.get('install_dir', state.environment.coredata.get_option(mesonlib.OptionKey('localedir'))) script = state.environment.get_build_command() args = ['--internal', 'gettext', 'install', '--subdir=' + state.subdir, diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 7e19d7177..7d347a6f1 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -331,10 +331,10 @@ class PkgConfigModule(ExtensionModule): srcdir = PurePath(state.environment.get_source_dir()) else: outdir = state.environment.scratch_dir - prefix = PurePath(coredata.get_builtin_option('prefix')) + prefix = PurePath(coredata.get_option(mesonlib.OptionKey('prefix'))) # These always return paths relative to prefix - libdir = PurePath(coredata.get_builtin_option('libdir')) - incdir = PurePath(coredata.get_builtin_option('includedir')) + libdir = PurePath(coredata.get_option(mesonlib.OptionKey('libdir'))) + incdir = PurePath(coredata.get_option(mesonlib.OptionKey('includedir'))) fname = os.path.join(outdir, pcfile) with open(fname, 'w', encoding='utf-8') as ofile: if not dataonly: @@ -531,9 +531,9 @@ class PkgConfigModule(ExtensionModule): pkgroot = kwargs.get('install_dir', default_install_dir) if pkgroot is None: if mesonlib.is_freebsd(): - pkgroot = os.path.join(state.environment.coredata.get_builtin_option('prefix'), 'libdata', 'pkgconfig') + pkgroot = os.path.join(state.environment.coredata.get_option(mesonlib.OptionKey('prefix')), 'libdata', 'pkgconfig') else: - pkgroot = os.path.join(state.environment.coredata.get_builtin_option('libdir'), 'pkgconfig') + pkgroot = os.path.join(state.environment.coredata.get_option(mesonlib.OptionKey('libdir')), 'pkgconfig') if not isinstance(pkgroot, str): raise mesonlib.MesonException('Install_dir must be a string.') self.generate_pkgconfig_file(state, deps, subdirs, name, description, url, diff --git a/mesonbuild/modules/python.py b/mesonbuild/modules/python.py index ff0df2f9d..564d18143 100644 --- a/mesonbuild/modules/python.py +++ b/mesonbuild/modules/python.py @@ -288,7 +288,7 @@ class PythonInstallation(ExternalProgramHolder): ExternalProgramHolder.__init__(self, python, interpreter.subproject) self.interpreter = interpreter self.subproject = self.interpreter.subproject - prefix = self.interpreter.environment.coredata.get_builtin_option('prefix') + prefix = self.interpreter.environment.coredata.get_option(mesonlib.OptionKey('prefix')) self.variables = info['variables'] self.paths = info['paths'] install_paths = info['install_paths'] diff --git a/mesonbuild/modules/unstable_external_project.py b/mesonbuild/modules/unstable_external_project.py index 7bb761f7d..7249078ac 100644 --- a/mesonbuild/modules/unstable_external_project.py +++ b/mesonbuild/modules/unstable_external_project.py @@ -26,6 +26,7 @@ from ..interpreter import Interpreter, DependencyHolder, InstallDir from ..compilers.compilers import cflags_mapping, cexe_mapping from ..dependencies.base import InternalDependency, PkgConfigDependency from ..environment import Environment +from ..mesonlib import OptionKey class ExternalProject(InterpreterObject): def __init__(self, @@ -62,9 +63,9 @@ class ExternalProject(InterpreterObject): self.src_dir = Path(self.env.get_source_dir(), self.subdir) self.build_dir = Path(self.env.get_build_dir(), self.subdir, 'build') self.install_dir = Path(self.env.get_build_dir(), self.subdir, 'dist') - self.prefix = Path(self.env.coredata.get_builtin_option('prefix')) - self.libdir = Path(self.env.coredata.get_builtin_option('libdir')) - self.includedir = Path(self.env.coredata.get_builtin_option('includedir')) + self.prefix = Path(self.env.coredata.get_option(OptionKey('prefix'))) + self.libdir = Path(self.env.coredata.get_option(OptionKey('libdir'))) + self.includedir = Path(self.env.coredata.get_option(OptionKey('includedir'))) # On Windows if the prefix is "c:/foo" and DESTDIR is "c:/bar", `make` # will install files into "c:/bar/c:/foo" which is an invalid path. diff --git a/mesonbuild/msetup.py b/mesonbuild/msetup.py index 55c9e0937..11fe3ce4f 100644 --- a/mesonbuild/msetup.py +++ b/mesonbuild/msetup.py @@ -177,7 +177,7 @@ class MesonApp: mlog.initialize(env.get_log_dir(), self.options.fatal_warnings) if self.options.profile: mlog.set_timestamp_start(time.monotonic()) - if env.coredata.builtins[mesonlib.OptionKey('backend')].value == 'xcode': + if env.coredata.options[mesonlib.OptionKey('backend')].value == 'xcode': mlog.warning('xcode backend is currently unmaintained, patches welcome') with mesonlib.BuildDirLock(self.build_dir): self._generate(env) diff --git a/mesonbuild/munstable_coredata.py b/mesonbuild/munstable_coredata.py index 5463f1625..0ca8f3398 100644 --- a/mesonbuild/munstable_coredata.py +++ b/mesonbuild/munstable_coredata.py @@ -14,7 +14,7 @@ from . import coredata as cdata -from .mesonlib import MachineChoice +from .mesonlib import MachineChoice, OptionKey import os.path import pprint @@ -59,7 +59,7 @@ def run(options): print('') coredata = cdata.load(options.builddir) - backend = coredata.get_builtin_option('backend') + backend = coredata.get_option(OptionKey('backend')) for k, v in sorted(coredata.__dict__.items()): if k in ('backend_options', 'base_options', 'builtins', 'compiler_options', 'user_options'): # use `meson configure` to view these diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py index 0b18f7e67..dc8c3ce5c 100644 --- a/mesonbuild/optinterpreter.py +++ b/mesonbuild/optinterpreter.py @@ -137,7 +137,7 @@ option_types = {'string': string_parser, class OptionInterpreter: def __init__(self, subproject: str) -> None: - self.options: T.Dict[str, coredata.UserOption] = {} + self.options: 'coredata.KeyedOptionDictType' = {} self.subproject = subproject def process(self, option_file: str) -> None: @@ -227,8 +227,7 @@ class OptionInterpreter: raise OptionException('Option names can only contain letters, numbers or dashes.') if is_invalid_name(opt_name): raise OptionException('Option name %s is reserved.' % opt_name) - if self.subproject != '': - opt_name = self.subproject + ':' + opt_name + key = mesonlib.OptionKey(opt_name, self.subproject) if 'yield' in kwargs: FeatureNew.single_use('option yield', '0.45.0', self.subproject) @@ -248,4 +247,4 @@ class OptionInterpreter: opt = option_types[opt_type](opt_name, description, kwargs) if opt.description == '': opt.description = opt_name - self.options[opt_name] = opt + self.options[key] = opt diff --git a/mesonbuild/rewriter.py b/mesonbuild/rewriter.py index fbbdcc184..6b7a98747 100644 --- a/mesonbuild/rewriter.py +++ b/mesonbuild/rewriter.py @@ -464,11 +464,11 @@ class Rewriter: cdata = self.interpreter.coredata options = { - **{str(k): v for k, v in cdata.builtins.items()}, - **{str(k): v for k, v in cdata.backend_options.items()}, - **{str(k): v for k, v in cdata.base_options.items()}, - **{str(k): v for k, v in cdata.compiler_options.items()}, - **{str(k): v for k, v in cdata.user_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.options.items()}, } for key, val in sorted(cmd['options'].items()): diff --git a/mesonbuild/scripts/regen_checker.py b/mesonbuild/scripts/regen_checker.py index fa98f5989..11877831f 100644 --- a/mesonbuild/scripts/regen_checker.py +++ b/mesonbuild/scripts/regen_checker.py @@ -17,6 +17,7 @@ import pickle, subprocess import typing as T from ..coredata import CoreData from ..backend.vs2010backend import RegenInfo +from ..mesonlib import OptionKey # This could also be used for XCode. @@ -52,7 +53,7 @@ def run(args: T.List[str]) -> int: with open(coredata_file, 'rb') as f: coredata = pickle.load(f) assert isinstance(coredata, CoreData) - backend = coredata.get_builtin_option('backend') + backend = coredata.get_option(OptionKey('backend')) assert isinstance(backend, str) regen_timestamp = os.stat(dumpfile).st_mtime if need_regen(regeninfo, regen_timestamp): diff --git a/run_tests.py b/run_tests.py index ec58ac066..da894c055 100755 --- a/run_tests.py +++ b/run_tests.py @@ -128,7 +128,7 @@ def get_fake_env(sdir='', bdir=None, prefix='', opts=None): if opts is None: opts = get_fake_options(prefix) env = Environment(sdir, bdir, opts) - env.coredata.compiler_options[OptionKey('args', lang='c')] = FakeCompilerOptions() + env.coredata.options[OptionKey('args', lang='c')] = FakeCompilerOptions() env.machines.host.cpu_family = 'x86_64' # Used on macOS inside find_library return env diff --git a/run_unittests.py b/run_unittests.py index cba46c5bc..1ff54eb37 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -873,7 +873,7 @@ class InternalTests(unittest.TestCase): env = get_fake_env() compiler = env.detect_c_compiler(MachineChoice.HOST) env.coredata.compilers.host = {'c': compiler} - env.coredata.compiler_options[OptionKey('link_args', lang='c')] = FakeCompilerOptions() + env.coredata.options[OptionKey('link_args', lang='c')] = FakeCompilerOptions() p1 = Path(tmpdir) / '1' p2 = Path(tmpdir) / '2' p1.mkdir() @@ -1413,10 +1413,10 @@ class DataTests(unittest.TestCase): debug = False else: raise RuntimeError('Invalid debug value {!r} in row:\n{}'.format(debug, m.group())) - env.coredata.set_builtin_option(OptionKey('buildtype'), buildtype) - self.assertEqual(env.coredata.builtins[OptionKey('buildtype')].value, buildtype) - self.assertEqual(env.coredata.builtins[OptionKey('optimization')].value, opt) - self.assertEqual(env.coredata.builtins[OptionKey('debug')].value, debug) + env.coredata.set_option(OptionKey('buildtype'), buildtype) + self.assertEqual(env.coredata.options[OptionKey('buildtype')].value, buildtype) + self.assertEqual(env.coredata.options[OptionKey('optimization')].value, opt) + self.assertEqual(env.coredata.options[OptionKey('debug')].value, debug) def test_cpu_families_documented(self): with open("docs/markdown/Reference-tables.md", encoding='utf-8') as f: @@ -3688,29 +3688,29 @@ class AllPlatformTests(BasePlatformTests): # configuration, and as a bonus, test that --profile-self works. self.init(testdir, extra_args=['--profile-self', '--fatal-meson-warnings']) obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.builtins[OptionKey('default_library')].value, 'static') - self.assertEqual(obj.builtins[OptionKey('warning_level')].value, '1') - self.assertEqual(obj.user_options[OptionKey('set_sub_opt')].value, True) - self.assertEqual(obj.user_options[OptionKey('subp_opt', 'subp')].value, 'default3') + self.assertEqual(obj.options[OptionKey('default_library')].value, 'static') + self.assertEqual(obj.options[OptionKey('warning_level')].value, '1') + self.assertEqual(obj.options[OptionKey('set_sub_opt')].value, True) + self.assertEqual(obj.options[OptionKey('subp_opt', 'subp')].value, 'default3') self.wipe() # warning_level is special, it's --warnlevel instead of --warning-level # for historical reasons self.init(testdir, extra_args=['--warnlevel=2', '--fatal-meson-warnings']) obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.builtins[OptionKey('warning_level')].value, '2') + self.assertEqual(obj.options[OptionKey('warning_level')].value, '2') self.setconf('--warnlevel=3') obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.builtins[OptionKey('warning_level')].value, '3') + self.assertEqual(obj.options[OptionKey('warning_level')].value, '3') self.wipe() # But when using -D syntax, it should be 'warning_level' self.init(testdir, extra_args=['-Dwarning_level=2', '--fatal-meson-warnings']) obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.builtins[OptionKey('warning_level')].value, '2') + self.assertEqual(obj.options[OptionKey('warning_level')].value, '2') self.setconf('-Dwarning_level=3') obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.builtins[OptionKey('warning_level')].value, '3') + self.assertEqual(obj.options[OptionKey('warning_level')].value, '3') self.wipe() # Mixing --option and -Doption is forbidden @@ -3734,15 +3734,15 @@ class AllPlatformTests(BasePlatformTests): # --default-library should override default value from project() self.init(testdir, extra_args=['--default-library=both', '--fatal-meson-warnings']) obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.builtins[OptionKey('default_library')].value, 'both') + self.assertEqual(obj.options[OptionKey('default_library')].value, 'both') self.setconf('--default-library=shared') obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.builtins[OptionKey('default_library')].value, 'shared') + self.assertEqual(obj.options[OptionKey('default_library')].value, 'shared') if self.backend is Backend.ninja: # reconfigure target works only with ninja backend self.build('reconfigure') obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.builtins[OptionKey('default_library')].value, 'shared') + self.assertEqual(obj.options[OptionKey('default_library')].value, 'shared') self.wipe() # Should warn on unknown options @@ -3777,22 +3777,22 @@ class AllPlatformTests(BasePlatformTests): # Test we can set subproject option self.init(testdir, extra_args=['-Dsubp:subp_opt=foo', '--fatal-meson-warnings']) obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.user_options[OptionKey('subp_opt', 'subp')].value, 'foo') + self.assertEqual(obj.options[OptionKey('subp_opt', 'subp')].value, 'foo') self.wipe() # c_args value should be parsed with split_args self.init(testdir, extra_args=['-Dc_args=-Dfoo -Dbar "-Dthird=one two"', '--fatal-meson-warnings']) obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.compiler_options[OptionKey('args', lang='c')].value, ['-Dfoo', '-Dbar', '-Dthird=one two']) + self.assertEqual(obj.options[OptionKey('args', lang='c')].value, ['-Dfoo', '-Dbar', '-Dthird=one two']) self.setconf('-Dc_args="foo bar" one two') obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.compiler_options[OptionKey('args', lang='c')].value, ['foo bar', 'one', 'two']) + self.assertEqual(obj.options[OptionKey('args', lang='c')].value, ['foo bar', 'one', 'two']) self.wipe() self.init(testdir, extra_args=['-Dset_percent_opt=myoption%', '--fatal-meson-warnings']) obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.user_options[OptionKey('set_percent_opt')].value, 'myoption%') + self.assertEqual(obj.options[OptionKey('set_percent_opt')].value, 'myoption%') self.wipe() # Setting a 2nd time the same option should override the first value @@ -3803,19 +3803,19 @@ class AllPlatformTests(BasePlatformTests): '-Dc_args=-Dfoo', '-Dc_args=-Dbar', '-Db_lundef=false', '--fatal-meson-warnings']) obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.builtins[OptionKey('bindir')].value, 'bar') - self.assertEqual(obj.builtins[OptionKey('buildtype')].value, 'release') - self.assertEqual(obj.base_options[OptionKey('b_sanitize')].value, 'thread') - self.assertEqual(obj.compiler_options[OptionKey('args', lang='c')].value, ['-Dbar']) + self.assertEqual(obj.options[OptionKey('bindir')].value, 'bar') + self.assertEqual(obj.options[OptionKey('buildtype')].value, 'release') + self.assertEqual(obj.options[OptionKey('b_sanitize')].value, 'thread') + self.assertEqual(obj.options[OptionKey('args', lang='c')].value, ['-Dbar']) self.setconf(['--bindir=bar', '--bindir=foo', '-Dbuildtype=release', '-Dbuildtype=plain', '-Db_sanitize=thread', '-Db_sanitize=address', '-Dc_args=-Dbar', '-Dc_args=-Dfoo']) obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.builtins[OptionKey('bindir')].value, 'foo') - self.assertEqual(obj.builtins[OptionKey('buildtype')].value, 'plain') - self.assertEqual(obj.base_options[OptionKey('b_sanitize')].value, 'address') - self.assertEqual(obj.compiler_options[OptionKey('args', lang='c')].value, ['-Dfoo']) + self.assertEqual(obj.options[OptionKey('bindir')].value, 'foo') + self.assertEqual(obj.options[OptionKey('buildtype')].value, 'plain') + self.assertEqual(obj.options[OptionKey('b_sanitize')].value, 'address') + self.assertEqual(obj.options[OptionKey('args', lang='c')].value, ['-Dfoo']) self.wipe() except KeyError: # Ignore KeyError, it happens on CI for compilers that does not @@ -3829,25 +3829,25 @@ class AllPlatformTests(BasePlatformTests): # Verify default values when passing no args self.init(testdir) obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.builtins[OptionKey('warning_level')].value, '0') + self.assertEqual(obj.options[OptionKey('warning_level')].value, '0') self.wipe() # verify we can override w/ --warnlevel self.init(testdir, extra_args=['--warnlevel=1']) obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.builtins[OptionKey('warning_level')].value, '1') + self.assertEqual(obj.options[OptionKey('warning_level')].value, '1') self.setconf('--warnlevel=0') obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.builtins[OptionKey('warning_level')].value, '0') + self.assertEqual(obj.options[OptionKey('warning_level')].value, '0') self.wipe() # verify we can override w/ -Dwarning_level self.init(testdir, extra_args=['-Dwarning_level=1']) obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.builtins[OptionKey('warning_level')].value, '1') + self.assertEqual(obj.options[OptionKey('warning_level')].value, '1') self.setconf('-Dwarning_level=0') obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.builtins[OptionKey('warning_level')].value, '0') + self.assertEqual(obj.options[OptionKey('warning_level')].value, '0') self.wipe() def test_feature_check_usage_subprojects(self): @@ -4254,7 +4254,8 @@ class AllPlatformTests(BasePlatformTests): self.init(testdir, default_args=False) res_wb = self.introspect('--buildoptions') self.maxDiff = None - self.assertListEqual(res_nb, res_wb) + # XXX: These now generate in a different order, is that okay? + self.assertListEqual(sorted(res_nb, key=lambda x: x['name']), sorted(res_wb, key=lambda x: x['name'])) def test_meson_configure_from_source_does_not_crash(self): testdir = os.path.join(self.unit_test_dir, '59 introspect buildoptions') @@ -4505,20 +4506,20 @@ class AllPlatformTests(BasePlatformTests): with open(introfile, 'r') as fp: res1 = json.load(fp) - self.setconf('-Dcpp_std=c++14') - self.setconf('-Dbuildtype=release') - - for idx, i in enumerate(res1): + for i in res1: if i['name'] == 'cpp_std': - res1[idx]['value'] = 'c++14' + i['value'] = 'c++14' if i['name'] == 'build.cpp_std': - res1[idx]['value'] = 'c++14' + i['value'] = 'c++14' if i['name'] == 'buildtype': - res1[idx]['value'] = 'release' + i['value'] = 'release' if i['name'] == 'optimization': - res1[idx]['value'] = '3' + i['value'] = '3' if i['name'] == 'debug': - res1[idx]['value'] = False + i['value'] = False + + self.setconf('-Dcpp_std=c++14') + self.setconf('-Dbuildtype=release') with open(introfile, 'r') as fp: res2 = json.load(fp)