diff --git a/mesonbuild/ast/introspection.py b/mesonbuild/ast/introspection.py index 3d2211677056..dc231fec0190 100644 --- a/mesonbuild/ast/introspection.py +++ b/mesonbuild/ast/introspection.py @@ -283,7 +283,7 @@ def build_target(self, node: BaseNode, args: T.List[TYPE_var], kwargs_raw: T.Dic return new_target def build_library(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> T.Union[IntrospectionBuildTarget, UnknownValue]: - default_library = self.coredata.optstore.get_value_for(OptionKey('default_library', subproject=self.subproject)) + default_library = self.coredata.optstore.get_value_for(OptionKey('default_library', subproject=self.subproject), str) 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 7494b1ac19ba..483003c96603 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -27,7 +27,7 @@ from .. import compilers from ..compilers import detect, lang_suffixes from ..mesonlib import ( - File, MachineChoice, MesonException, MesonBugException, OrderedSet, + File, MachineChoice, MesonException, OrderedSet, ExecutableSerialisation, EnvironmentException, classify_unity_sources, get_compiler_for_source, get_rsp_threshold, unique_list @@ -43,7 +43,6 @@ from ..interpreter import Test from ..linkers.linkers import StaticLinker from ..mesonlib import FileMode, FileOrString - from ..options import ElementaryOptionValues from typing_extensions import Literal, TypedDict, NotRequired @@ -379,7 +378,7 @@ def get_target_dir(self, target: build.AnyTargetType) -> str: if isinstance(target, build.RunTarget): # this produces no output, only a dummy top-level name dirname = '' - elif self.environment.coredata.optstore.get_value_for(OptionKey('layout')) == 'mirror': + elif self.environment.coredata.optstore.get_value_for(OptionKey('layout'), str) == 'mirror': dirname = target.get_builddir() else: dirname = 'meson-out' @@ -438,8 +437,7 @@ def generate_unity_files(self, target: build.BuildTarget, unity_src: str) -> T.L abs_files: T.List[str] = [] result: T.List[mesonlib.File] = [] compsrcs = classify_unity_sources(target.compilers.values(), unity_src) - unity_size = self.get_target_option(target, 'unity_size') - assert isinstance(unity_size, int), 'for mypy' + unity_size = self.environment.coredata.optstore.get_option_for_target(target, OptionKey('unity_size'), int) def init_language_file(suffix: str, unity_file_number: int) -> T.TextIO: unity_src = self.get_unity_source_file(target, suffix, unity_file_number) @@ -801,7 +799,7 @@ def object_filename_from_source(self, target: build.BuildTarget, compiler: Compi object_suffix = machine.get_object_suffix() # For the TASKING compiler, in case of LTO or prelinking the object suffix has to be .mil if compiler.get_id() == 'tasking': - use_lto = self.get_target_option(target, 'b_lto') + use_lto = self.environment.coredata.optstore.get_option_for_target(target, OptionKey('b_lto'), bool) if use_lto or (isinstance(target, build.StaticLibrary) and target.prelink): if not source.rsplit('.', 1)[1] in lang_suffixes['c']: if isinstance(target, build.StaticLibrary) and not target.prelink: @@ -853,8 +851,8 @@ def _determine_ext_objs(self, extobj: 'build.ExtractedObjects') -> T.List[str]: if self.is_unity(extobj.target): compsrcs = classify_unity_sources(extobj.target.compilers.values(), sources) sources = [] - unity_size = self.get_target_option(extobj.target, 'unity_size') - assert isinstance(unity_size, int), 'for mypy' + unity_size = self.environment.coredata.optstore.get_option_for_target( + extobj.target, OptionKey('unity_size'), int) for comp, srcs in compsrcs.items(): if comp.language in LANGS_CANT_UNITY: @@ -905,10 +903,8 @@ def create_msvc_pch_implementation(self, target: build.BuildTarget, lang: str, p return pch_rel_to_build def target_uses_pch(self, target: build.BuildTarget) -> bool: - try: - return T.cast('bool', self.get_target_option(target, 'b_pch')) - except (KeyError, AttributeError): - return False + return self.environment.coredata.optstore.get_option_for_target( + target, OptionKey('b_pch'), bool, default=False) @staticmethod def escape_extra_args(args: T.List[str]) -> T.List[str]: @@ -939,24 +935,25 @@ def generate_basic_compiler_args(self, target: build.BuildTarget, compiler: 'Com # Add things like /NOLOGO or -pipe; usually can't be overridden commands += compiler.get_always_args() # warning_level is a string, but mypy can't determine that - commands += compiler.get_warn_args(T.cast('str', self.get_target_option(target, 'warning_level'))) + commands += compiler.get_warn_args(self.environment.coredata.optstore.get_option_for_target( + target, OptionKey('warning_level'), str)) # Add -Werror if werror=true is set in the build options set on the # command-line or default_options inside project(). This only sets the # action to be done for warnings if/when they are emitted, so it's ok # to set it after or get_warn_args(). - if self.get_target_option(target, 'werror'): + if self.environment.coredata.optstore.get_option_for_target(target, OptionKey('werror'), bool): commands += compiler.get_werror_args() # Add compile args for c_* or cpp_* build options set on the # command-line or default_options inside project(). - commands += compiler.get_option_compile_args(target, target.subproject) - commands += compiler.get_option_std_args(target, target.subproject) + commands += compiler.get_option_compile_args(target) + commands += compiler.get_option_std_args(target) - optimization = self.get_target_option(target, 'optimization') - assert isinstance(optimization, str), 'for mypy' + optimization = self.environment.coredata.optstore.get_option_for_target( + target, OptionKey('optimization'), str) commands += compiler.get_optimization_args(optimization) - debug = self.get_target_option(target, 'debug') - assert isinstance(debug, bool), 'for mypy' + debug = self.environment.coredata.optstore.get_option_for_target( + target, OptionKey('debug'), bool) commands += compiler.get_debug_args(debug) # Add compile args added using add_project_arguments() @@ -967,7 +964,7 @@ def generate_basic_compiler_args(self, target: build.BuildTarget, compiler: 'Com # Compile args added from the env: CFLAGS/CXXFLAGS, etc, or the cross # file. We want these to override all the defaults, but not the # per-target compile args. - commands += self.environment.coredata.get_external_args(target.for_machine, compiler.get_language()) + commands += self.environment.coredata.optstore.get_external_args(target.for_machine, compiler.get_language()) # Using both /Z7 or /ZI and /Zi at the same times produces a compiler warning. # We do not add /Z7 or /ZI by default. If it is being used it is because the user has explicitly enabled it. # /Zi needs to be removed in that case to avoid cl's warning to that effect (D9025 : overriding '/Zi' with '/ZI') @@ -1298,8 +1295,7 @@ def construct_target_rel_paths(self, t: build.AnyTargetType, workdir: T.Optional def generate_depmf_install(self, d: InstallData) -> None: depmf_path = self.build.dep_manifest_name if depmf_path is None: - option_dir = self.environment.coredata.optstore.get_value_for(OptionKey('licensedir')) - assert isinstance(option_dir, str), 'for mypy' + option_dir = self.environment.coredata.optstore.get_value_for(OptionKey('licensedir'), str) if option_dir: depmf_path = os.path.join(option_dir, 'depmf.json') else: @@ -1649,7 +1645,8 @@ def create_install_data(self) -> InstallData: # TODO go through all candidates, like others strip_bin = [detect.defaults['strip'][0]] - umask = self.environment.coredata.optstore.get_value_for(OptionKey('install_umask')) + # Cannot used typed getter because of union type + umask = self.environment.coredata.optstore.get_value_for_untyped(OptionKey('install_umask')) assert isinstance(umask, (str, int)), 'for mypy' d = InstallData(self.environment.get_source_dir(), @@ -1681,9 +1678,7 @@ def guess_install_tag(self, fname: str, outdir: T.Optional[str] = None) -> T.Opt bindir = Path(prefix, self.environment.get_bindir()) libdir = Path(prefix, self.environment.get_libdir()) incdir = Path(prefix, self.environment.get_includedir()) - _ldir = self.environment.coredata.optstore.get_value_for(OptionKey('localedir')) - assert isinstance(_ldir, str), 'for mypy' - localedir = Path(prefix, _ldir) + localedir = Path(prefix, self.environment.coredata.optstore.get_value_for(OptionKey('localedir'), str)) dest_path = Path(prefix, outdir, Path(fname).name) if outdir else Path(prefix, fname) if bindir in dest_path.parents: return 'runtime' @@ -1738,8 +1733,8 @@ def generate_target_install(self, d: InstallData) -> None: # TODO: Create GNUStrip/AppleStrip/etc. hierarchy for more # fine-grained stripping of static archives. can_strip = not isinstance(t, build.StaticLibrary) - should_strip = can_strip and self.get_target_option(t, 'strip') - assert isinstance(should_strip, bool), 'for mypy' + should_strip = can_strip and self.environment.coredata.optstore.get_option_for_target( + t, OptionKey('strip'), bool) # Install primary build output (library/executable/jar, etc) # Done separately because of strip/aliases/rpath if first_outdir is not False: @@ -2082,7 +2077,7 @@ def compile_target_to_generator(self, target: build.CompileTarget) -> build.Gene def is_unity(self, target: build.BuildTarget) -> bool: if isinstance(target, build.CompileTarget): return False - val = self.get_target_option(target, 'unity') + val = self.environment.coredata.optstore.get_option_for_target(target, OptionKey('unity'), str) if val == 'on': return True if val == 'off': @@ -2090,12 +2085,3 @@ def is_unity(self, target: build.BuildTarget) -> bool: if val == 'subprojects': return target.subproject != '' raise MesonException(f'Internal error: invalid option type for "unity": {val}') - - def get_target_option(self, target: build.BuildTarget, name: T.Union[str, OptionKey]) -> ElementaryOptionValues: - if isinstance(name, str): - key = OptionKey(name, subproject=target.subproject) - elif isinstance(name, OptionKey): - key = name - else: - raise MesonBugException('Internal error: invalid option type.') - return self.environment.coredata.get_option_for_target(target, key) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index b45dbaa9b53a..e9b5fd63f439 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -612,7 +612,7 @@ def generate(self, capture: bool = False, vslite_ctx: T.Optional[T.Dict] = None) self.allow_thin_archives[for_machine] = False ninja = tooldetect.detect_ninja_command_and_version(log=True) - if self.environment.coredata.optstore.get_value_for(OptionKey('vsenv')): + if self.environment.coredata.optstore.get_value_for(OptionKey('vsenv'), bool): builddir = Path(self.environment.get_build_dir()) try: # For prettier printing, reduce to a relative path. If @@ -637,7 +637,7 @@ def generate(self, capture: bool = False, vslite_ctx: T.Optional[T.Dict] = None) outfile.write('# Do not edit by hand.\n\n') outfile.write('ninja_required_version = 1.8.2\n\n') - num_pools = self.environment.coredata.optstore.get_value_for('backend_max_links') + num_pools = self.environment.coredata.optstore.get_value_for(OptionKey('backend_max_links'), int) if num_pools > 0: outfile.write(f'''pool link_pool depth = {num_pools} @@ -669,9 +669,7 @@ def generate(self, capture: bool = False, vslite_ctx: T.Optional[T.Dict] = None) mlog.log_timestamp("Install generated") self.generate_dist() mlog.log_timestamp("Dist generated") - key = OptionKey('b_coverage') - if key in self.environment.coredata.optstore and\ - self.environment.coredata.optstore.get_value_for('b_coverage'): + if self.environment.coredata.optstore.get_value_for(OptionKey('b_coverage'), bool, default=False): gcovr_exe, gcovr_version, lcov_exe, lcov_version, genhtml_exe, llvm_cov_exe = tooldetect.find_coverage_tools(self.environment.coredata) mlog.debug(f'Using {gcovr_exe} ({gcovr_version}), {lcov_exe} and {llvm_cov_exe} for code coverage') if gcovr_exe or (lcov_exe and genhtml_exe): @@ -1136,9 +1134,8 @@ def should_use_dyndeps_for_target(self, target: 'build.BuildTarget') -> bool: cpp = target.compilers['cpp'] if cpp.get_id() != 'msvc': return False - cppversion = self.get_target_option(target, OptionKey('cpp_std', - machine=target.for_machine, - subproject=target.subproject)) + cppversion = self.environment.coredata.optstore.get_option_for_target( + target, OptionKey('cpp_std', machine=target.for_machine, subproject=target.subproject), str) if cppversion not in ('latest', 'c++latest', 'vc++latest'): return False if not mesonlib.current_vs_supports_modules(): @@ -1375,9 +1372,9 @@ def generate_install(self) -> None: def generate_tests(self) -> None: self.serialize_tests() cmd = self.environment.get_build_command(True) + ['test', '--no-rebuild'] - if not self.environment.coredata.optstore.get_value_for(OptionKey('stdsplit')): + if not self.environment.coredata.optstore.get_value_for(OptionKey('stdsplit'), bool): cmd += ['--no-stdsplit'] - if self.environment.coredata.optstore.get_value_for(OptionKey('errorlogs')): + if self.environment.coredata.optstore.get_value_for(OptionKey('errorlogs'), bool): cmd += ['--print-errorlogs'] elem = self.create_phony_target('test', 'CUSTOM_COMMAND', ['all', 'meson-test-prereq', 'PHONY']) elem.add_item('COMMAND', cmd) @@ -1765,7 +1762,9 @@ def generate_vala_compile(self, target: build.BuildTarget) -> \ valac_outputs.append(vala_c_file) args = self.generate_basic_compiler_args(target, valac) - args += valac.get_colorout_args(self.get_target_option(target, 'b_colorout')) + args += valac.get_colorout_args( + self.environment.coredata.optstore.get_option_for_target( + target, OptionKey('b_colorout'), str)) # 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). @@ -1842,15 +1841,18 @@ def generate_cython_transpile(self, target: build.BuildTarget) -> \ args: T.List[str] = [] args += cython.get_always_args() - args += cython.get_debug_args(self.get_target_option(target, 'debug')) - args += cython.get_optimization_args(self.get_target_option(target, 'optimization')) - args += cython.get_option_compile_args(target, target.subproject) - args += cython.get_option_std_args(target, target.subproject) + args += cython.get_debug_args(self.environment.coredata.optstore.get_option_for_target( + target, OptionKey('debug'), bool)) + args += cython.get_optimization_args(self.environment.coredata.optstore.get_option_for_target( + target, OptionKey('optimization'), str)) + args += cython.get_option_compile_args(target) + args += cython.get_option_std_args(target) args += self.build.get_global_args(cython, target.for_machine) args += self.build.get_project_args(cython, target) args += target.get_extra_args('cython') - ext = self.get_target_option(target, OptionKey('cython_language', machine=target.for_machine)) + ext = self.environment.coredata.optstore.get_option_for_target( + target, OptionKey('cython_language', machine=target.for_machine), str) pyx_sources = [] # Keep track of sources we're adding to build @@ -2195,7 +2197,7 @@ def _link_library(libname: str, static: bool, bundle: bool = False) -> None: # against are dynamic or this is a dynamic library itself, # otherwise we'll end up with multiple implementations of libstd. has_rust_shared_deps = True - elif self.get_target_option(target, 'rust_dynamic_std'): + elif self.environment.coredata.optstore.get_option_for_target(target, OptionKey('rust_dynamic_std'), bool): if target.rust_crate_type == 'staticlib': # staticlib crates always include a copy of the Rust libstd, # therefore it is not possible to also link it dynamically. @@ -2438,7 +2440,7 @@ def _rsp_options(self, tool: T.Union['Compiler', 'StaticLinker', 'DynamicLinker' return options def generate_static_link_rules(self) -> None: - num_pools = self.environment.coredata.optstore.get_value_for('backend_max_links') + num_pools = self.environment.coredata.optstore.get_value_for(OptionKey('backend_max_links'), int) if 'java' in self.environment.coredata.compilers.host: self.generate_java_link() for for_machine in MachineChoice: @@ -2486,7 +2488,7 @@ def generate_static_link_rules(self) -> None: self.add_rule(NinjaRule(rule, cmdlist, args, description, **options, extra=pool)) def generate_dynamic_link_rules(self) -> None: - num_pools = self.environment.coredata.optstore.get_value_for('backend_max_links') + num_pools = self.environment.coredata.optstore.get_value_for(OptionKey('backend_max_links'), int) for for_machine in MachineChoice: complist = self.environment.coredata.compilers[for_machine] for langname, compiler in complist.items(): @@ -3253,7 +3255,7 @@ def generate_single_compile(self, target: build.BuildTarget, src, # then compilation rule name is a special one to output MIL files # instead of object files for .c files if compiler.get_id() == 'tasking': - target_lto = self.get_target_option(target, OptionKey('b_lto', machine=target.for_machine, subproject=target.subproject)) + target_lto = self.environment.coredata.optstore.get_option_for_target(target, OptionKey('b_lto', target.subproject, target.for_machine), bool) if ((isinstance(target, build.StaticLibrary) and target.prelink) or target_lto) and src.rsplit('.', 1)[1] in compilers.lang_suffixes['c']: compiler_name = self.get_compiler_rule_name('tasking_mil_compile', compiler.for_machine) else: @@ -3341,13 +3343,10 @@ def quote_make_target(targetName: str) -> str: def target_uses_import_std(self, target: build.BuildTarget) -> bool: if 'cpp' not in target.compilers: return False - try: - if self.environment.coredata.get_option_for_target(target, 'cpp_importstd') == 'true': - return True - except KeyError: - return False + return self.environment.coredata.optstore.get_option_for_target( + target, OptionKey('cpp_importstd'), str, default='false') == 'true' - def handle_cpp_import_std(self, target: build.BuildTarget, compiler): + def handle_cpp_import_std(self, target: build.BuildTarget, compiler: Compiler): istd_args = [] istd_dep = [] if not self.target_uses_import_std(target): @@ -3361,7 +3360,7 @@ def handle_cpp_import_std(self, target: build.BuildTarget, compiler): mod_file = 'gcm.cache/std.gcm' mod_obj_file = 'std.o' elem = NinjaBuildElement(self.all_outputs, [mod_file, mod_obj_file], 'CUSTOM_COMMAND', []) - compile_args = compiler.get_option_compile_args(target, self.environment) + compile_args = compiler.get_option_compile_args(target) compile_args += compiler.get_option_std_args(target, self.environment) compile_args += ['-c', '-fmodules', '-fsearch-include-path', 'bits/std.cc'] elem.add_item('COMMAND', compiler.exelist + compile_args) @@ -3379,7 +3378,7 @@ def handle_cpp_import_std(self, target: build.BuildTarget, compiler): raise SystemExit('VS std import header could not be located.') in_file_str = str(in_file) elem = NinjaBuildElement(self.all_outputs, [mod_file, mod_obj_file], 'CUSTOM_COMMAND', [in_file_str]) - compile_args = compiler.get_option_compile_args(target, self.environment) + compile_args = compiler.get_option_compile_args(target) compile_args += compiler.get_option_std_args(target, self.environment) compile_args += ['/nologo', '/c', '/O2', in_file_str] elem.add_item('COMMAND', compiler.exelist + compile_args) @@ -3774,9 +3773,10 @@ def generate_link(self, target: build.BuildTarget, outname, obj_list, linker: T. # Add things like /NOLOGO; usually can't be overridden commands += linker.get_linker_always_args() # Add buildtype linker args: optimization level, etc. - commands += linker.get_optimization_link_args(self.get_target_option(target, 'optimization')) + commands += linker.get_optimization_link_args( + self.environment.coredata.optstore.get_option_for_target(target, OptionKey('optimization'), str)) # Add /DEBUG and the pdb filename when using MSVC - if self.get_target_option(target, 'debug'): + if self.environment.coredata.optstore.get_option_for_target(target, OptionKey('debug'), bool): commands += self.get_link_debugfile_args(linker, target) debugfile = self.get_link_debugfile_name(linker, target) if debugfile is not None: @@ -3866,7 +3866,8 @@ def generate_link(self, target: build.BuildTarget, outname, obj_list, linker: T. elem = NinjaBuildElement(self.all_outputs, outname, linker_rule, obj_list, implicit_outs=implicit_outs) elem.add_dep(dep_targets + custom_target_libraries) if linker.get_id() == 'tasking': - if len([x for x in dep_targets + custom_target_libraries if x.endswith('.ma')]) > 0 and not self.get_target_option(target, OptionKey('b_lto', target.subproject, target.for_machine)): + if (any(x for x in dep_targets + custom_target_libraries if x.endswith('.ma')) and not + self.environment.coredata.optstore.get_option_for_target(target, OptionKey('b_lto', target.subproject, target.for_machine), bool)): raise MesonException(f'Tried to link the target named \'{target.name}\' with a MIL archive without LTO enabled! This causes the compiler to ignore the archive.') # Compiler args must be included in TI C28x linker commands. @@ -4012,8 +4013,7 @@ def generate_clangtool(self, name: str, extra_arg: T.Optional[str] = None, need_ if extra_arg: target_name += f'-{extra_arg}' extra_args.append(f'--{extra_arg}') - colorout = self.environment.coredata.optstore.get_value_for('b_colorout') \ - if OptionKey('b_colorout') in self.environment.coredata.optstore else 'always' + colorout = self.environment.coredata.optstore.get_value_for(OptionKey('b_colorout'), str, default='always') assert isinstance(colorout, str), 'for mypy' extra_args.extend(['--color', colorout]) if not os.path.exists(os.path.join(self.environment.source_dir, '.clang-' + name)) and \ @@ -4120,8 +4120,7 @@ def generate_ending(self) -> None: if ctlist: elem.add_dep(self.generate_custom_target_clean(ctlist)) - if OptionKey('b_coverage') in self.environment.coredata.optstore and \ - self.environment.coredata.optstore.get_value_for('b_coverage'): + if self.environment.coredata.optstore.get_value_for(OptionKey('b_coverage'), bool, default=False): 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 4f78f6708454..5fbc6702570c 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -275,13 +275,10 @@ def generate(self, else: raise MesonException('Unsupported Visual Studio platform: ' + build_machine) - self.buildtype = self.environment.coredata.optstore.get_value_for(OptionKey('buildtype')) - self.optimization = self.environment.coredata.optstore.get_value_for(OptionKey('optimization')) - self.debug = self.environment.coredata.optstore.get_value_for(OptionKey('debug')) - try: - self.sanitize = self.environment.coredata.optstore.get_value_for(OptionKey('b_sanitize')) - except KeyError: - self.sanitize = [] + self.buildtype = self.environment.coredata.optstore.get_value_for(OptionKey('buildtype'), str) + self.optimization = self.environment.coredata.optstore.get_value_for(OptionKey('optimization'), str) + self.debug = self.environment.coredata.optstore.get_value_for(OptionKey('debug'), bool) + self.sanitize = self.environment.coredata.optstore.get_value_for(OptionKey('b_sanitize'), list, default=[]) sln_filename = os.path.join(self.environment.get_build_dir(), self.build.project_name + '.sln') projlist = self.generate_projects(vslite_ctx) self.gen_testproj() @@ -428,7 +425,7 @@ def generate_solution(self, sln_filename: str, projlist: T.List[Project]) -> Non ofile.write('# Visual Studio %s\n' % self.sln_version_comment) prj_templ = 'Project("{%s}") = "%s", "%s", "{%s}"\n' for prj in projlist: - if self.environment.coredata.optstore.get_value_for(OptionKey('layout')) == 'mirror': + if self.environment.coredata.optstore.get_value_for(OptionKey('layout'), str) == 'mirror': self.generate_solution_dirs(ofile, prj[1].parents) target = self.build.targets[prj[0]] lang = 'default' @@ -540,7 +537,7 @@ def generate_solution(self, sln_filename: str, projlist: T.List[Project]) -> Non replace_if_different(sln_filename, sln_filename_tmp) def generate_projects(self, vslite_ctx: dict = None) -> T.List[Project]: - startup_project = self.environment.coredata.optstore.get_value_for('backend_startup_project') + startup_project = self.environment.coredata.optstore.get_value_for(OptionKey('backend_startup_project'), str) projlist: T.List[Project] = [] startup_idx = 0 for (i, (name, target)) in enumerate(self.build.targets.items()): @@ -1030,8 +1027,7 @@ def get_args_defines_and_inc_dirs(self, target: build.BuildTarget, compiler: com file_args[l] += comp.get_always_args() file_args[l] += compilers.get_base_compile_args( target, comp, self.environment) - file_args[l] += comp.get_option_compile_args( - target, target.subproject) + file_args[l] += comp.get_option_compile_args(target) file_args[l] += comp.get_option_std_args( target, target.subproject) @@ -1047,7 +1043,8 @@ def get_args_defines_and_inc_dirs(self, target: build.BuildTarget, compiler: com # 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 lang in file_args.keys(): - file_args[lang] += self.get_target_option(target, OptionKey(f'{lang}_args', machine=target.for_machine)) + file_args[lang] += self.environment.coredata.optstore.get_option_for_target( + target, OptionKey(f'{lang}_args', target.subproject, target.for_machine), list) for args in file_args.values(): # This is where Visual Studio will insert target_args, target_defines, # etc, which are added later from external deps (see below). @@ -1322,8 +1319,8 @@ def add_non_makefile_vcxproj_elements( # FIXME: Should the following just be set in create_basic_project(), even if # irrelevant for current target? - lto = self.get_target_option(target, 'b_lto') - pgo = self.get_target_option(target, 'b_pgo') + lto = self.environment.coredata.optstore.get_option_for_target(target, OptionKey('b_lto'), bool) + pgo = self.environment.coredata.optstore.get_option_for_target(target, OptionKey('b_pgo'), str) if lto: if pgo == 'off': @@ -1348,8 +1345,9 @@ def add_non_makefile_vcxproj_elements( if True in ((dep.name == 'openmp') for dep in target.get_external_deps()): ET.SubElement(clconf, 'OpenMPSupport').text = 'true' # CRT type; debug or release - vscrt_type = self.get_target_option(target, 'b_vscrt') - vscrt_val = compiler.get_crt_val(vscrt_type, self.environment) + vscrt_type = self.environment.coredata.optstore.get_option_for_target( + target, OptionKey('b_vscrt'), str) + vscrt_val = compiler.get_crt_val(vscrt_type) if vscrt_val == 'mdd': ET.SubElement(type_config, 'UseDebugLibraries').text = 'true' ET.SubElement(clconf, 'RuntimeLibrary').text = 'MultiThreadedDebugDLL' @@ -1386,7 +1384,7 @@ def add_non_makefile_vcxproj_elements( # 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.get_option_for_target(target, OptionKey('cpp_eh', machine=target.for_machine)) + eh = self.environment.coredata.optstore.get_option_for_target(target, OptionKey('cpp_eh', machine=target.for_machine), str) if eh == 'a': ET.SubElement(clconf, 'ExceptionHandling').text = 'Async' elif eh == 's': @@ -1404,10 +1402,11 @@ def add_non_makefile_vcxproj_elements( ET.SubElement(clconf, 'PreprocessorDefinitions').text = ';'.join(target_defines) ET.SubElement(clconf, 'FunctionLevelLinking').text = 'true' # Warning level - warning_level = T.cast('str', self.get_target_option(target, 'warning_level')) + warning_level = self.environment.coredata.optstore.get_option_for_target( + target, OptionKey('warning_level'), str) warning_level = 'EnableAllWarnings' if warning_level == 'everything' else 'Level' + str(1 + int(warning_level)) ET.SubElement(clconf, 'WarningLevel').text = warning_level - if self.get_target_option(target, 'werror'): + if self.environment.coredata.optstore.get_option_for_target(target, OptionKey('werror'), bool): ET.SubElement(clconf, 'TreatWarningAsError').text = 'true' # Optimization flags o_flags = split_o_flags_args(build_args) @@ -1572,8 +1571,8 @@ def add_non_makefile_vcxproj_elements( # /nologo ET.SubElement(link, 'SuppressStartupBanner').text = 'true' # /release - addchecksum = self.get_target_option(target, 'buildtype') != 'debug' - if addchecksum: + buildtype = self.environment.coredata.optstore.get_option_for_target(target, OptionKey('buildtype'), str) + if buildtype != 'debug': ET.SubElement(link, 'SetChecksum').text = 'true' # Visual studio doesn't simply allow the src files of a project to be added with the 'Condition=...' attribute, @@ -1848,7 +1847,7 @@ def path_normalize_add(path, lis): # build system as possible. self.add_target_deps(root, target) self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname) - if self.environment.coredata.optstore.get_value_for(OptionKey('layout')) == 'mirror': + if self.environment.coredata.optstore.get_value_for(OptionKey('layout'), str) == 'mirror': self.gen_vcxproj_filters(target, ofname) return True @@ -2017,9 +2016,9 @@ def gen_testproj(self): meson_build_dir_for_buildtype = build_dir_tail[:-2] + buildtype # Get the buildtype suffixed 'builddir_[debug/release/etc]' from 'builddir_vs', for example. proj_to_build_dir_for_buildtype = str(os.path.join(proj_to_multiconfigured_builds_parent_dir, meson_build_dir_for_buildtype)) test_cmd = f'{nmake_base_meson_command} test -C "{proj_to_build_dir_for_buildtype}" --no-rebuild' - if not self.environment.coredata.optstore.get_value_for(OptionKey('stdsplit')): + if not self.environment.coredata.optstore.get_value_for(OptionKey('stdsplit'), bool): test_cmd += ' --no-stdsplit' - if self.environment.coredata.optstore.get_value_for(OptionKey('errorlogs')): + if self.environment.coredata.optstore.get_value_for(OptionKey('errorlogs'), bool): test_cmd += ' --print-errorlogs' condition = f'\'$(Configuration)|$(Platform)\'==\'{buildtype}|{self.platform}\'' prop_group = ET.SubElement(root, 'PropertyGroup', Condition=condition) @@ -2041,9 +2040,9 @@ def gen_testproj(self): 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.optstore.get_value_for(OptionKey('stdsplit')): + if not self.environment.coredata.optstore.get_value_for(OptionKey('stdsplit'), bool): test_command += ['--no-stdsplit'] - if self.environment.coredata.optstore.get_value_for(OptionKey('errorlogs')): + if self.environment.coredata.optstore.get_value_for(OptionKey('errorlogs'), bool): 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 dae1f9b99011..bf4a06e931e8 100644 --- a/mesonbuild/backend/xcodebackend.py +++ b/mesonbuild/backend/xcodebackend.py @@ -239,7 +239,7 @@ class XCodeBackend(backends.Backend): def __init__(self, build: T.Optional[build.Build]): super().__init__(build) self.project_uid = self.environment.coredata.lang_guids['default'].replace('-', '')[:24] - self.buildtype = T.cast('str', self.environment.coredata.optstore.get_value_for(OptionKey('buildtype'))) + self.buildtype = self.environment.coredata.optstore.get_value_for(OptionKey('buildtype'), str) self.project_conflist = self.gen_id() self.maingroup_id = self.gen_id() self.all_id = self.gen_id() @@ -281,7 +281,7 @@ def gen_id(self) -> str: @functools.lru_cache(maxsize=None) def get_target_dir(self, target: build.AnyTargetType) -> str: - dirname = os.path.join(target.get_subdir(), T.cast('str', self.environment.coredata.optstore.get_value_for(OptionKey('buildtype')))) + dirname = os.path.join(target.get_subdir(), self.environment.coredata.optstore.get_value_for(OptionKey('buildtype'), str)) #os.makedirs(os.path.join(self.environment.get_build_dir(), dirname), exist_ok=True) return dirname @@ -1740,8 +1740,10 @@ def generate_single_build_target(self, objects_dict: PbxDict, target_name: str, if compiler is None: continue # Start with warning args - warn_args = compiler.get_warn_args(self.get_target_option(target, 'warning_level')) - std_args = compiler.get_option_compile_args(target, target.subproject) + warn_args = compiler.get_warn_args( + self.environment.coredata.optstore.get_option_for_target( + target, OptionKey('warning_level'), str)) + std_args = compiler.get_option_compile_args(target) std_args += compiler.get_option_std_args(target, target.subproject) # Add compile args added using add_project_arguments() pargs = self.build.get_project_args(compiler, target) @@ -1791,9 +1793,11 @@ def generate_single_build_target(self, objects_dict: PbxDict, target_name: str, if target.suffix: suffix = '.' + target.suffix settings_dict.add_item('EXECUTABLE_SUFFIX', suffix) - settings_dict.add_item('GCC_GENERATE_DEBUGGING_SYMBOLS', BOOL2XCODEBOOL[self.get_target_option(target, 'debug')]) + settings_dict.add_item('GCC_GENERATE_DEBUGGING_SYMBOLS', BOOL2XCODEBOOL[ + self.environment.coredata.optstore.get_option_for_target(target, OptionKey('debug'), bool)]) settings_dict.add_item('GCC_INLINES_ARE_PRIVATE_EXTERN', 'NO') - opt_flag = OPT2XCODEOPT[self.get_target_option(target, 'optimization')] + opt_flag = OPT2XCODEOPT[ + self.environment.coredata.optstore.get_option_for_target(target, OptionKey('optimization'), str)] if opt_flag is not None: settings_dict.add_item('GCC_OPTIMIZATION_LEVEL', opt_flag) if target.has_pch: diff --git a/mesonbuild/build.py b/mesonbuild/build.py index d688af892fee..69d2ff7fe61e 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1051,7 +1051,7 @@ def process_compilers_late(self) -> None: # In the case of cython it's possible that we have an # implementation detail language - if self.uses_cython() and lang == self.environment.coredata.get_option_for_target(self, 'cython_language'): + if self.uses_cython() and lang == self.environment.coredata.optstore.get_option_for_target(self, OptionKey('cython_language'), str): self.compilers[lang] = self.environment.coredata.compilers[self.for_machine][lang] is_error = False @@ -1186,8 +1186,7 @@ def process_compilers(self) -> T.List[Language]: if 'vala' in self.compilers and 'c' not in self.compilers: self.compilers['c'] = self.all_compilers['c'] if 'cython' in self.compilers: - _value = self.environment.coredata.get_option_for_target(self, 'cython_language') - assert isinstance(_value, str), 'for mypy' + _value = self.environment.coredata.optstore.get_option_for_target(self, OptionKey('cython_language'), str) value = T.cast('Language', _value) try: self.compilers[value] = self.all_compilers[value] @@ -1449,9 +1448,7 @@ def _extract_pic_pie(self, kwargs: T.Union[StaticLibraryKeywordArguments, Execut if kwargs.get(arg) is not None: return kwargs[arg] elif k in self.environment.coredata.optstore: - val = self.environment.coredata.get_option_for_target(self, k) - assert isinstance(val, bool), 'for mypy' - return val + return self.environment.coredata.optstore.get_option_for_target(self, k, bool) return False def install_dir_names(self) -> T.List[T.Optional[str]]: @@ -1851,7 +1848,8 @@ def process_vs_module_defs_kw(self, kwargs: ExecutableKeywordArguments) -> None: self.process_link_depends([path]) def extract_targets_as_list(self, kwargs: BuildTargetKeywordArguments, key: T.Literal['link_with', 'link_whole']) -> T.List[LibTypes]: - bl_type = self.environment.coredata.optstore.get_value_for(OptionKey('default_both_libraries')) + bl_type = self.environment.coredata.optstore.get_value_for( + OptionKey('default_both_libraries'), str) if bl_type == 'auto': if isinstance(self, StaticLibrary): bl_type = 'static' @@ -1874,7 +1872,7 @@ def get(self, lib_type: T.Literal['static', 'shared']) -> LibTypes: def determine_rpath_dirs(self) -> T.Tuple[str, ...]: result: OrderedSet[str] - if self.environment.coredata.optstore.get_value_for(OptionKey('layout')) == 'mirror': + if self.environment.coredata.optstore.get_value_for(OptionKey('layout'), str) == 'mirror': # Need a copy here result = OrderedSet(self.get_link_dep_subdirs()) else: @@ -1942,7 +1940,7 @@ def get_external_rpath_dirs(self) -> T.Set[str]: args: T.List[str] = [] for lang in LANGUAGES_USING_LDFLAGS: try: - args += self.environment.coredata.get_external_link_args(self.for_machine, lang) + args += self.environment.coredata.optstore.get_external_link_args(self.for_machine, lang) except KeyError: pass return self.get_rpath_dirs_from_link_args(args) @@ -2281,7 +2279,7 @@ def post_init(self) -> None: machine.is_windows() and ('cs' in self.compilers or self.uses_rust() or self.get_using_msvc()) # .pdb file is created only when debug symbols are enabled - and self.environment.coredata.optstore.get_value_for(OptionKey("debug")) + and self.environment.coredata.optstore.get_value_for(OptionKey("debug"), bool) ) if create_debug_file: # If the target is has a standard exe extension (i.e. 'foo.exe'), @@ -2384,8 +2382,7 @@ def post_init(self) -> None: self.outputs[0] = self.filename def determine_default_prefix_and_suffix(self) -> T.Tuple[str, str]: - scheme = self.environment.coredata.get_option_for_target(self, 'namingscheme') - assert isinstance(scheme, str), 'for mypy' + scheme = self.environment.coredata.optstore.get_option_for_target(self, OptionKey('namingscheme'), str) if scheme == 'platform': schemename = self.get_platform_scheme_name() prefix, suffix = DEFAULT_STATIC_LIBRARY_NAMES[schemename] @@ -2411,15 +2408,13 @@ def determine_default_prefix_and_suffix(self) -> T.Tuple[str, str]: suffix = 'rlib' elif self.rust_crate_type == 'staticlib': suffix = 'a' - elif self.environment.machines[self.for_machine].is_os2() and self.environment.coredata.optstore.get_value_for(OptionKey('os2_emxomf')): + elif self.environment.machines[self.for_machine].is_os2() and self.environment.coredata.optstore.get_value_for(OptionKey('os2_emxomf'), bool): suffix = 'lib' else: suffix = 'a' if 'c' in self.compilers and self.compilers['c'].get_id() == 'tasking' and not self.prelink: key = OptionKey('b_lto', self.subproject, self.for_machine) - v = self.environment.coredata.get_option_for_target(self, key) - assert isinstance(v, bool), 'for mypy' - if v: + if self.environment.coredata.optstore.get_option_for_target(self, key, bool): suffix = 'ma' return (prefix, suffix) @@ -2567,8 +2562,7 @@ def get_default_install_dir(self) -> T.Tuple[str, str]: return self.environment.get_shared_lib_dir(), '{libdir_shared}' def determine_naming_info(self) -> T.Tuple[str, str, str, str, bool]: - scheme = self.environment.coredata.get_option_for_target(self, 'namingscheme') - assert isinstance(scheme, str), 'for mypy' + scheme = self.environment.coredata.optstore.get_option_for_target(self, OptionKey('namingscheme'), str) if scheme == 'platform': schemename = self.get_platform_scheme_name() prefix, suffix, import_suffix = DEFAULT_SHARED_LIBRARY_NAMES[schemename] @@ -2599,7 +2593,7 @@ def determine_naming_info(self) -> T.Tuple[str, str, str, str, bool]: # Import library is called foo.dll.lib import_filename_tpl = '{0.prefix}{0.name}.dll.lib' # .pdb file is only created when debug symbols are enabled - create_debug_file = self.environment.coredata.optstore.get_value_for(OptionKey("debug")) + create_debug_file = self.environment.coredata.optstore.get_value_for(OptionKey("debug"), bool) elif self.get_using_msvc(): # Shared library is of the form foo.dll prefix = prefix if prefix is not None else '' @@ -2607,7 +2601,7 @@ def determine_naming_info(self) -> T.Tuple[str, str, str, str, bool]: import_suffix = import_suffix if import_suffix is not None else 'lib' import_filename_tpl = '{0.prefix}{0.name}.' + import_suffix # .pdb file is only created when debug symbols are enabled - create_debug_file = self.environment.coredata.optstore.get_value_for(OptionKey("debug")) + create_debug_file = self.environment.coredata.optstore.get_value_for(OptionKey("debug"), bool) # Assume GCC-compatible naming else: # Shared library is of the form libfoo.dll @@ -2654,7 +2648,7 @@ def determine_naming_info(self) -> T.Tuple[str, str, str, str, bool]: suffix = suffix if suffix is not None else 'dll' # Import library is called foo_dll.a or foo_dll.lib if import_suffix is None: - import_suffix = '_dll.lib' if self.environment.coredata.optstore.get_value_for(OptionKey('os2_emxomf')) else '_dll.a' + import_suffix = '_dll.lib' if self.environment.coredata.optstore.get_value_for(OptionKey('os2_emxomf'), bool) else '_dll.a' import_filename_tpl = '{0.prefix}{0.name}' + import_suffix filename_tpl = '{0.shortname}' if self.shortname else '{0.prefix}{0.name}' if self.soversion: diff --git a/mesonbuild/cargo/interpreter.py b/mesonbuild/cargo/interpreter.py index 6ffae639bf14..b9e86d4ca435 100644 --- a/mesonbuild/cargo/interpreter.py +++ b/mesonbuild/cargo/interpreter.py @@ -671,7 +671,7 @@ def _get_cfgs(self, machine: MachineChoice) -> T.Dict[str, str]: machine = MachineChoice.HOST rustc = T.cast('RustCompiler', self.environment.coredata.compilers[machine]['rust']) cfgs = rustc.get_cfgs().copy() - rustflags = self.environment.coredata.get_external_args(machine, 'rust') + rustflags = self.environment.coredata.optstore.get_external_args(machine, 'rust') rustflags_i = iter(rustflags) for i in rustflags_i: if i == '--cfg': diff --git a/mesonbuild/cmake/common.py b/mesonbuild/cmake/common.py index 3fd20a31972d..62ade16a9b1e 100644 --- a/mesonbuild/cmake/common.py +++ b/mesonbuild/cmake/common.py @@ -56,15 +56,13 @@ def cmake_is_debug(env: 'Environment') -> bool: if 'b_vscrt' in env.coredata.optstore: - is_debug = env.coredata.optstore.get_value_for('buildtype') == 'debug' - if env.coredata.optstore.get_value_for('b_vscrt') in {'mdd', 'mtd'}: + is_debug = env.coredata.optstore.get_value_for(OptionKey('buildtype'), str) == 'debug' + if env.coredata.optstore.get_value_for(OptionKey('b_vscrt'), str) in {'mdd', 'mtd'}: is_debug = True - return is_debug else: # Don't directly assign to is_debug to make mypy happy - debug_opt = env.coredata.optstore.get_value_for('debug') - assert isinstance(debug_opt, bool) - return debug_opt + is_debug = env.coredata.optstore.get_value_for(OptionKey('debug'), bool) + return is_debug class CMakeException(MesonException): pass @@ -108,8 +106,7 @@ def _flags_to_list(raw: str) -> T.List[str]: return res def cmake_get_generator_args(env: 'Environment') -> T.List[str]: - backend_name = env.coredata.optstore.get_value_for(OptionKey('backend')) - assert isinstance(backend_name, str) + backend_name = env.coredata.optstore.get_value_for(OptionKey('backend'), str) assert backend_name in backend_generator_map return ['-G', backend_generator_map[backend_name]] diff --git a/mesonbuild/cmake/executor.py b/mesonbuild/cmake/executor.py index a174bc7eb6de..adde396e17ff 100644 --- a/mesonbuild/cmake/executor.py +++ b/mesonbuild/cmake/executor.py @@ -53,8 +53,7 @@ def __init__(self, environment: 'Environment', version: str, for_machine: Machin return prefpath = self.environment.coredata.optstore.get_value_for( - OptionKey(name='cmake_prefix_path', machine=for_machine)) - assert isinstance(prefpath, list) + OptionKey(name='cmake_prefix_path', machine=for_machine), list) self.prefix_paths = prefpath if self.prefix_paths: self.extra_cmake_args += ['-DCMAKE_PREFIX_PATH={}'.format(';'.join(self.prefix_paths))] diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py index f369d7b38c6f..bd8c9b5d717f 100644 --- a/mesonbuild/cmake/interpreter.py +++ b/mesonbuild/cmake/interpreter.py @@ -801,7 +801,7 @@ def __init__(self, subdir: Path, env: 'Environment', backend: 'Backend'): self.src_dir = Path(env.get_source_dir(), subdir) self.build_dir_rel = subdir / '__CMake_build' self.build_dir = Path(env.get_build_dir()) / self.build_dir_rel - self.install_prefix = Path(T.cast('str', env.coredata.optstore.get_value_for(OptionKey('prefix')))) + self.install_prefix = Path(env.coredata.optstore.get_value_for(OptionKey('prefix'), str)) self.env = env self.for_machine = MachineChoice.HOST # TODO make parameter self.backend_name = backend.name @@ -851,12 +851,12 @@ def configure(self, extra_cmake_options: T.List[str]) -> CMakeExecutor: cmake_args = [] cmake_args += cmake_get_generator_args(self.env) cmake_args += [f'-DCMAKE_INSTALL_PREFIX={self.install_prefix}'] - libdir = self.env.coredata.optstore.get_value_for(OptionKey('libdir')) + libdir = self.env.coredata.optstore.get_value_for(OptionKey('libdir'), str) cmake_args += [f'-DCMAKE_INSTALL_LIBDIR={libdir}'] cmake_args += extra_cmake_options if not any(arg.startswith('-DCMAKE_BUILD_TYPE=') for arg in cmake_args): # Our build type is favored over any CMAKE_BUILD_TYPE environment variable - buildtype = T.cast('str', self.env.coredata.optstore.get_value_for(OptionKey('buildtype'))) + buildtype = self.env.coredata.optstore.get_value_for(OptionKey('buildtype'), str) if buildtype in BUILDTYPE_MAP: cmake_args += [f'-DCMAKE_BUILD_TYPE={BUILDTYPE_MAP[buildtype]}'] trace_args = self.trace.trace_args() diff --git a/mesonbuild/compilers/asm.py b/mesonbuild/compilers/asm.py index c8dfc2371f83..8962e36fec7e 100644 --- a/mesonbuild/compilers/asm.py +++ b/mesonbuild/compilers/asm.py @@ -91,7 +91,7 @@ def get_always_args(self) -> T.List[str]: define = 'MACHO' elif self.info.is_os2(): cpu = '' - if self.environment.coredata.optstore.get_value_for(OptionKey('os2_emxomf')): + if self.environment.coredata.optstore.get_value_for(OptionKey('os2_emxomf'), bool): plat = 'obj2' define = 'OBJ2' else: @@ -148,16 +148,16 @@ def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:])) return parameter_list - def get_crt_compile_args(self, crt_val: str, env: Environment) -> T.List[str]: + def get_crt_compile_args(self, crt_val: str) -> T.List[str]: return [] # Linking ASM-only objects into an executable or DLL # require this, otherwise it'll fail to find # _WinMain or _DllMainCRTStartup. - def get_crt_link_args(self, crt_val: str, env: Environment) -> T.List[str]: + def get_crt_link_args(self, crt_val: str) -> T.List[str]: if not isinstance(self.linker, VisualStudioLikeLinkerMixin): return [] - return self.crt_args[self.get_crt_val(crt_val, env)] + return self.crt_args[self.get_crt_val(crt_val)] class YasmCompiler(NasmCompiler): id = 'yasm' @@ -233,7 +233,7 @@ def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:])) return parameter_list - def get_crt_compile_args(self, crt_val: str, env: Environment) -> T.List[str]: + def get_crt_compile_args(self, crt_val: str) -> T.List[str]: return [] def depfile_for_object(self, objfile: str) -> T.Optional[str]: @@ -281,7 +281,7 @@ def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:])) return parameter_list - def get_crt_compile_args(self, crt_val: str, env: Environment) -> T.List[str]: + def get_crt_compile_args(self, crt_val: str) -> T.List[str]: return [] def get_depfile_format(self) -> str: @@ -309,7 +309,7 @@ def needs_static_linker(self) -> bool: def get_always_args(self) -> T.List[str]: return [] - def get_crt_compile_args(self, crt_val: str, env: Environment) -> T.List[str]: + def get_crt_compile_args(self, crt_val: str) -> T.List[str]: return [] def get_depfile_suffix(self) -> str: @@ -334,7 +334,7 @@ def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, 'everything': []} self.can_compile_suffixes.add('s') - def get_crt_compile_args(self, crt_val: str, env: Environment) -> T.List[str]: + def get_crt_compile_args(self, crt_val: str) -> T.List[str]: return [] def get_optimization_args(self, optimization_level: str) -> T.List[str]: diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 2bff42b1d97a..ef7380174fe3 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -44,6 +44,7 @@ from ..mesonlib import MachineChoice from .compilers import CompileCheckMode from ..build import BuildTarget + from ..interpreterbase import SubProject CompilerMixinBase = Compiler else: @@ -127,22 +128,32 @@ def get_options(self) -> 'MutableKeyedOptionDictType': gnu_winlibs) return opts - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: - args = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + @T.overload + def get_option_std_args(self, target: BuildTarget) -> T.List[str]: ... + + @T.overload + def get_option_std_args(self, target: None, subproject: SubProject) -> T.List[str]: ... + + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject + args: T.List[str] = [] + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append('-std=' + std) return args - def get_option_link_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + @T.overload + def get_option_link_args(self, target: BuildTarget) -> T.List[str]: ... + + @T.overload + def get_option_link_args(self, target: None, subproject: SubProject) -> T.List[str]: ... + + def get_option_link_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject if self.info.is_windows() or self.info.is_cygwin(): - retval = self.get_compileropt_value('winlibs', target, subproject) - assert isinstance(retval, list) - libs: T.List[str] = retval.copy() - for l in libs: - assert isinstance(l, str) - return libs + key = self.form_compileropt_key('winlibs', subproject) + return self.environment.coredata.optstore.get_option_for_maybe_target(target, key, list).copy() return [] @@ -212,15 +223,16 @@ def get_options(self) -> 'MutableKeyedOptionDictType': std_opt.set_versions(['c90', 'c99', 'c11'], gnu=True) return opts - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: - args = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject + args: T.List[str] = [] + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append('-std=' + std) return args - def get_option_link_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_link_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: return [] @@ -255,25 +267,26 @@ def get_options(self) -> 'MutableKeyedOptionDictType': gnu_winlibs) return opts - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: - args = [] - key = OptionKey('c_std', machine=self.for_machine) - std = self.get_compileropt_value(key, target, subproject) - assert isinstance(std, str) + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject + args: T.List[str] = [] + key = OptionKey('c_std', subproject, self.for_machine) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append('-std=' + std) return args - def get_option_link_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + @T.overload + def get_option_link_args(self, target: BuildTarget) -> T.List[str]: ... + + @T.overload + def get_option_link_args(self, target: None, subproject: SubProject) -> T.List[str]: ... + + def get_option_link_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject if self.info.is_windows() or self.info.is_cygwin(): - # without a typeddict mypy can't figure this out - retval = self.get_compileropt_value('winlibs', target, subproject) - - assert isinstance(retval, list) - libs: T.List[str] = retval.copy() - for l in libs: - assert isinstance(l, str) - return libs + key = self.form_compileropt_key('winlibs', subproject) + return self.environment.coredata.optstore.get_option_for_maybe_target(target, key, list).copy() return [] def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: @@ -308,10 +321,11 @@ def get_options(self) -> 'MutableKeyedOptionDictType': std_opt.set_versions(cppstd_choices, gnu=True) return opts - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject args: T.List[str] = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append('-std=' + std) return args @@ -382,10 +396,11 @@ def get_options(self) -> 'MutableKeyedOptionDictType': std_opt.set_versions(stds, gnu=True) return opts - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject args: T.List[str] = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append('-std=' + std) return args @@ -409,13 +424,10 @@ def get_options(self) -> MutableKeyedOptionDictType: msvc_winlibs) return opts - def get_option_link_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: - retval = self.get_compileropt_value('winlibs', target, subproject) - assert isinstance(retval, list) - libs: T.List[str] = retval.copy() - for l in libs: - assert isinstance(l, str) - return libs + def get_option_link_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject + key = self.form_compileropt_key('winlibs', subproject) + return self.environment.coredata.optstore.get_option_for_maybe_target(target, key, list).copy() class VisualStudioCCompiler(MSVCCompiler, VisualStudioLikeCCompilerMixin, CCompiler): @@ -444,9 +456,11 @@ def get_options(self) -> 'MutableKeyedOptionDictType': std_opt.set_versions(stds, gnu=True, gnu_deprecated=True) return opts - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: - args = [] - std = self.get_compileropt_value('std', target, subproject) + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject + args: T.List[str] = [] + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) # As of MVSC 16.8, /std:c11 and /std:c17 are the only valid C standard options. if std in {'c11'}: @@ -465,9 +479,10 @@ def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoic env, linker=linker, full_version=full_version) ClangClCompiler.__init__(self, target) - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != "none": return [f'/clang:-std={std}'] return [] @@ -493,10 +508,11 @@ def get_options(self) -> 'MutableKeyedOptionDictType': std_opt.set_versions(['c89', 'c99', 'c11']) return opts - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject args: T.List[str] = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std == 'c89': mlog.log("ICL doesn't explicitly implement c89, setting the standard to 'none', which is close.", once=True) elif std != 'none': @@ -526,10 +542,11 @@ def get_options(self) -> 'MutableKeyedOptionDictType': std_opt.set_versions(['c89', 'c99', 'c11']) return opts - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: - args = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject + args: T.List[str] = [] + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append('--' + std) return args @@ -559,10 +576,11 @@ def get_options(self) -> 'MutableKeyedOptionDictType': def get_no_stdinc_args(self) -> T.List[str]: return [] - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: - args = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject + args: T.List[str] = [] + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std == 'c89': args.append('-lang=c') elif std == 'c99': @@ -607,10 +625,11 @@ def get_options(self) -> 'MutableKeyedOptionDictType': def get_no_stdinc_args(self) -> T.List[str]: return [] - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: - args = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject + args: T.List[str] = [] + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append('-ansi') args.append('-std=' + std) @@ -702,10 +721,11 @@ def get_options(self) -> 'MutableKeyedOptionDictType': def get_no_stdinc_args(self) -> T.List[str]: return [] - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: - args = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject + args: T.List[str] = [] + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append('--' + std) return args @@ -736,10 +756,11 @@ def get_options(self) -> 'MutableKeyedOptionDictType': self._update_language_stds(opts, ['c99']) return opts - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: - args = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject + args: T.List[str] = [] + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append('-lang') args.append(std) @@ -764,9 +785,11 @@ def get_options(self) -> 'MutableKeyedOptionDictType': self._update_language_stds(opts, ['c99']) return opts - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: - args = [] - std = self.get_compileropt_value('std', target, subproject) + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject + args: T.List[str] = [] + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) assert isinstance(std, str) if std != 'none': args.append('-lang ' + std) diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 370ccc3f2b07..28c471d552b8 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -36,6 +36,7 @@ from ..linkers.linkers import DynamicLinker from ..mesonlib import MachineChoice from ..dependencies import Dependency + from ..interpreterbase import SubProject # See the comment on `lang_suffixes` if modifying this list. Language = Literal[ @@ -239,34 +240,6 @@ class CompileCheckMode(enum.Enum): } -def option_enabled(boptions: T.Set[OptionKey], - target: 'BuildTarget', - env: 'Environment', - option: T.Union[str, OptionKey]) -> bool: - if isinstance(option, str): - option = OptionKey(option) - try: - if option not in boptions: - return False - ret = env.coredata.get_option_for_target(target, option) - assert isinstance(ret, bool), 'must return bool' # could also be str - return ret - except KeyError: - return False - - -def get_option_value_for_target(env: 'Environment', target: 'BuildTarget', opt: OptionKey, fallback: '_T') -> '_T': - """Get the value of an option, or the fallback value.""" - try: - v = env.coredata.get_option_for_target(target, opt) - except (KeyError, AttributeError): - return fallback - - assert isinstance(v, type(fallback)), f'Should have {type(fallback)!r} but was {type(v)!r}' - # Mypy doesn't understand that the above assert ensures that v is type _T - return v - - def are_asserts_disabled(target: 'BuildTarget', env: 'Environment') -> bool: """Should debug assertions be disabled @@ -274,25 +247,27 @@ def are_asserts_disabled(target: 'BuildTarget', env: 'Environment') -> bool: :param env: the environment :return: whether to disable assertions or not """ - return (env.coredata.get_option_for_target(target, 'b_ndebug') == 'true' or - (env.coredata.get_option_for_target(target, 'b_ndebug') == 'if-release' and - env.coredata.get_option_for_target(target, 'buildtype') in {'release', 'plain'})) + key = OptionKey('b_ndebug', target.subproject, target.for_machine) + return (env.coredata.optstore.get_option_for_target(target, key, str) == 'true' or + (env.coredata.optstore.get_option_for_target(target, key, str) == 'if-release' and + env.coredata.optstore.get_option_for_target(target, key.evolve(name='buildtype'), str) in {'release', 'plain'})) def are_asserts_disabled_for_subproject(subproject: str, env: 'Environment') -> bool: key = OptionKey('b_ndebug', subproject) - return (env.coredata.optstore.get_value_for(key) == 'true' or - (env.coredata.optstore.get_value_for(key) == 'if-release' and - env.coredata.optstore.get_value_for(key.evolve(name='buildtype')) in {'release', 'plain'})) + return (env.coredata.optstore.get_value_for(key, str) == 'true' or + (env.coredata.optstore.get_value_for(key, str) == 'if-release' and + env.coredata.optstore.get_value_for(key.evolve(name='buildtype'), str) in {'release', 'plain'})) +# TODO: remove use of try/except, use default= instead def get_base_compile_args(target: 'BuildTarget', compiler: 'Compiler', env: 'Environment') -> T.List[str]: args: T.List[str] = [] lto = False try: - if env.coredata.get_option_for_target(target, 'b_lto'): - num_threads = get_option_value_for_target(env, target, OptionKey('b_lto_threads'), 0) - ltomode = get_option_value_for_target(env, target, OptionKey('b_lto_mode'), 'default') + if env.coredata.optstore.get_option_for_target(target, OptionKey('b_lto'), bool): + num_threads = env.coredata.optstore.get_option_for_target(target, OptionKey('b_lto_threads'), int, default=0) + ltomode = env.coredata.optstore.get_option_for_target(target, OptionKey('b_lto_mode'), str, default='default') args.extend(compiler.get_lto_compile_args( target=target, threads=num_threads, @@ -301,14 +276,12 @@ def get_base_compile_args(target: 'BuildTarget', compiler: 'Compiler', env: 'Env except (KeyError, AttributeError): pass try: - clrout = env.coredata.get_option_for_target(target, 'b_colorout') - assert isinstance(clrout, str) + clrout = env.coredata.optstore.get_option_for_target(target, OptionKey('b_colorout'), str) args += compiler.get_colorout_args(clrout) except KeyError: pass try: - sanitize = env.coredata.get_option_for_target(target, 'b_sanitize') - assert isinstance(sanitize, list) + sanitize = env.coredata.optstore.get_option_for_target(target, OptionKey('b_sanitize'), list) if sanitize == ['none']: sanitize = [] sanitize_args = compiler.sanitizer_compile_args(target, sanitize) @@ -321,7 +294,7 @@ def get_base_compile_args(target: 'BuildTarget', compiler: 'Compiler', env: 'Env except KeyError: pass try: - pgo_val = env.coredata.get_option_for_target(target, 'b_pgo') + pgo_val = env.coredata.optstore.get_option_for_target(target, OptionKey('b_pgo'), str) if pgo_val == 'generate': args.extend(compiler.get_profile_generate_args()) elif pgo_val == 'use': @@ -329,7 +302,7 @@ def get_base_compile_args(target: 'BuildTarget', compiler: 'Compiler', env: 'Env except (KeyError, AttributeError): pass try: - if env.coredata.get_option_for_target(target, 'b_coverage'): + if env.coredata.optstore.get_option_for_target(target, OptionKey('b_coverage'), bool): args += compiler.get_coverage_args() except (KeyError, AttributeError): pass @@ -338,13 +311,13 @@ def get_base_compile_args(target: 'BuildTarget', compiler: 'Compiler', env: 'Env except KeyError: pass # This does not need a try...except - bitcode = option_enabled(compiler.base_options, target, env, 'b_bitcode') + bitcode = env.coredata.optstore.get_option_for_target(target, OptionKey('b_bitcode'), bool, default=False) args.extend(compiler.get_embed_bitcode_args(bitcode, lto)) try: - crt_val = env.coredata.get_option_for_target(target, 'b_vscrt') - assert isinstance(crt_val, str) + crt_val = env.coredata.optstore.get_option_for_target(target, OptionKey('b_vscrt'), str) + # TODO: Is this attributeError posible? try: - args += compiler.get_crt_compile_args(crt_val, env) + args += compiler.get_crt_compile_args(crt_val) except AttributeError: pass except KeyError: @@ -357,19 +330,16 @@ def get_base_link_args(target: 'BuildTarget', args: T.List[str] = [] build_dir = env.get_build_dir() try: - if env.coredata.get_option_for_target(target, 'b_lto'): - if env.coredata.get_option_for_target(target, 'werror'): - args.extend(linker.get_werror_args()) - + if env.coredata.optstore.get_option_for_target(target, OptionKey('b_lto'), bool, default=False): thinlto_cache_dir = None cachedir_key = OptionKey('b_thinlto_cache') - if get_option_value_for_target(env, target, cachedir_key, False): - thinlto_cache_dir = get_option_value_for_target(env, target, OptionKey('b_thinlto_cache_dir'), '') + if env.coredata.optstore.get_option_for_target(target, cachedir_key, bool, default=False): + thinlto_cache_dir = env.coredata.optstore.get_option_for_target(target, OptionKey('b_thinlto_cache_dir'), str, default='') if thinlto_cache_dir == '': thinlto_cache_dir = os.path.join(build_dir, 'meson-private', 'thinlto-cache') - os.makedirs(thinlto_cache_dir, exist_ok=True) - num_threads = get_option_value_for_target(env, target, OptionKey('b_lto_threads'), 0) - lto_mode = get_option_value_for_target(env, target, OptionKey('b_lto_mode'), 'default') + os.mkdir(thinlto_cache_dir) + num_threads = env.coredata.optstore.get_option_for_target(target, OptionKey('b_lto_threads'), int, default=0) + lto_mode = env.coredata.optstore.get_option_for_target(target, OptionKey('b_lto_mode'), str, default='default') args.extend(linker.get_lto_link_args( target=target, threads=num_threads, @@ -380,8 +350,7 @@ def get_base_link_args(target: 'BuildTarget', except (KeyError, AttributeError): pass try: - sanitizer = env.coredata.get_option_for_target(target, 'b_sanitize') - assert isinstance(sanitizer, list) + sanitizer = env.coredata.optstore.get_option_for_target(target, OptionKey('b_sanitize'), list) if sanitizer == ['none']: sanitizer = [] sanitizer_args = linker.sanitizer_link_args(target, sanitizer) @@ -394,7 +363,7 @@ def get_base_link_args(target: 'BuildTarget', except KeyError: pass try: - pgo_val = env.coredata.get_option_for_target(target, 'b_pgo') + pgo_val = env.coredata.optstore.get_option_for_target(target, OptionKey('b_pgo'), str) if pgo_val == 'generate': args.extend(linker.get_profile_generate_args()) elif pgo_val == 'use': @@ -402,13 +371,13 @@ def get_base_link_args(target: 'BuildTarget', except (KeyError, AttributeError): pass try: - if env.coredata.get_option_for_target(target, 'b_coverage'): + if env.coredata.optstore.get_option_for_target(target, OptionKey('b_coverage'), bool): args += linker.get_coverage_link_args() except (KeyError, AttributeError): pass - as_needed = option_enabled(linker.base_options, target, env, 'b_asneeded') - bitcode = option_enabled(linker.base_options, target, env, 'b_bitcode') + as_needed = env.coredata.optstore.get_option_for_target(target, OptionKey('b_asneeded'), bool, default=False) + bitcode = env.coredata.optstore.get_option_for_target(target, OptionKey('b_bitcode'), bool, default=False) # Shared modules cannot be built with bitcode_bundle because # -bitcode_bundle is incompatible with -undefined and -bundle if bitcode and not target.typename == 'shared module': @@ -423,18 +392,15 @@ def get_base_link_args(target: 'BuildTarget', from ..build import SharedModule args.extend(linker.headerpad_args()) if (not isinstance(target, SharedModule) and - option_enabled(linker.base_options, target, env, 'b_lundef')): + env.coredata.optstore.get_option_for_target(target, OptionKey('b_lundef'), bool, default=False)): args.extend(linker.no_undefined_link_args()) else: args.extend(linker.get_allow_undefined_link_args()) try: - crt_val = env.coredata.get_option_for_target(target, 'b_vscrt') - assert isinstance(crt_val, str) + crt_val = env.coredata.optstore.get_option_for_target(target, OptionKey('b_vscrt'), str) try: - crtargs = linker.get_crt_link_args(crt_val, env) - assert isinstance(crtargs, list) - args += crtargs + args.extend(linker.get_crt_link_args(crt_val)) except AttributeError: pass except KeyError: @@ -651,13 +617,31 @@ def make_option_name(self, key: OptionKey) -> str: def get_options(self) -> 'MutableKeyedOptionDictType': return {} - def get_option_compile_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + @T.overload + def get_option_compile_args(self, target: BuildTarget) -> T.List[str]: ... + + @T.overload + def get_option_compile_args(self, target: None, subproject: SubProject) -> T.List[str]: ... + + def get_option_compile_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: return [] - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + @T.overload + def get_option_std_args(self, target: BuildTarget) -> T.List[str]: ... + + @T.overload + def get_option_std_args(self, target: None, subproject: SubProject) -> T.List[str]: ... + + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: return [] - def get_option_link_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + @T.overload + def get_option_link_args(self, target: BuildTarget) -> T.List[str]: ... + + @T.overload + def get_option_link_args(self, target: None, subproject: SubProject) -> T.List[str]: ... + + def get_option_link_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: return self.linker.get_option_link_args(target, subproject) def check_header(self, hname: str, prefix: str, *, @@ -1123,7 +1107,7 @@ def get_build_link_args(self, target: BuildTarget, build: build.Build) -> T.List # override all the defaults but not the per-target link args. return build.get_project_link_args(self, target) \ + build.get_global_link_args(self, self.for_machine) \ - + self.environment.coredata.get_external_link_args(self.for_machine, self.get_language()) + + self.environment.coredata.optstore.get_external_link_args(self.for_machine, self.get_language()) def get_target_link_args(self, target: 'BuildTarget') -> T.List[str]: return target.link_args @@ -1160,7 +1144,7 @@ def get_assert_args(self, disable: bool) -> T.List[str]: """ return [] - def get_crt_val(self, crt_val: str, env: Environment) -> str: + def get_crt_val(self, crt_val: str) -> str: if crt_val in options.MSCRT_VALS: return crt_val assert crt_val in {'from_buildtype', 'static_from_buildtype'} @@ -1172,7 +1156,7 @@ def get_crt_val(self, crt_val: str, env: Environment) -> str: rel = 'mt' # Match what build type flags used to do. - buildtype = env.coredata.optstore.get_value_for('buildtype') + buildtype = self.environment.coredata.optstore.get_value_for(OptionKey('buildtype'), str) if buildtype == 'plain': return 'none' elif buildtype == 'debug': @@ -1183,10 +1167,10 @@ def get_crt_val(self, crt_val: str, env: Environment) -> str: assert buildtype == 'custom' raise EnvironmentException('Requested C runtime based on buildtype, but buildtype is "custom".') - def get_crt_compile_args(self, crt_val: str, env: Environment) -> T.List[str]: + def get_crt_compile_args(self, crt_val: str) -> T.List[str]: raise EnvironmentException('This compiler does not support Windows CRT selection') - def get_crt_link_args(self, crt_val: str, env: Environment) -> T.List[str]: + def get_crt_link_args(self, crt_val: str) -> T.List[str]: raise EnvironmentException('This compiler does not support Windows CRT selection') def get_compile_only_args(self) -> T.List[str]: @@ -1507,10 +1491,10 @@ def build_wrapper_args(self, if mode is CompileCheckMode.COMPILE: # Add DFLAGS from the env - args += self.environment.coredata.get_external_args(self.for_machine, self.language) + args += self.environment.coredata.optstore.get_external_args(self.for_machine, self.language) elif mode is CompileCheckMode.LINK: # Add LDFLAGS from the env - args += self.environment.coredata.get_external_link_args(self.for_machine, self.language) + args += self.environment.coredata.optstore.get_external_link_args(self.for_machine, self.language) # extra_args must override all other arguments, so we add them last args += extra_args return args @@ -1594,20 +1578,8 @@ def get_preprocessor(self) -> Compiler: """ raise EnvironmentException(f'{self.get_id()} does not support preprocessor') - def form_compileropt_key(self, basename: str) -> OptionKey: - return OptionKey(f'{self.language}_{basename}', machine=self.for_machine) - - def get_compileropt_value(self, - key: T.Union[str, OptionKey], - target: T.Optional[BuildTarget], - subproject: T.Optional[str] = None - ) -> options.ElementaryOptionValues: - if isinstance(key, str): - key = self.form_compileropt_key(key) - if target: - return self.environment.coredata.get_option_for_target(target, key) - else: - return self.environment.coredata.optstore.get_value_for(key.evolve(subproject=subproject)) + def form_compileropt_key(self, basename: str, subproject: T.Optional[SubProject] = None) -> OptionKey: + return OptionKey(f'{self.language}_{basename}', subproject=subproject, machine=self.for_machine) def _update_language_stds(self, opts: MutableKeyedOptionDictType, value: T.List[str]) -> None: key = self.form_compileropt_key('std') diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index 5d319f9939eb..7d758931f7bc 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -41,6 +41,7 @@ from ..linkers.linkers import DynamicLinker from ..mesonlib import MachineChoice from ..build import BuildTarget + from ..interpreterbase import SubProject CompilerMixinBase = CLikeCompiler else: CompilerMixinBase = object @@ -261,16 +262,18 @@ def get_options(self) -> 'MutableKeyedOptionDictType': gnu_winlibs) return opts - def get_option_compile_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_compile_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: args: T.List[str] = [] - rtti = self.get_compileropt_value('rtti', target, subproject) - debugstl = self.get_compileropt_value('debugstl', target, subproject) - eh = self.get_compileropt_value('eh', target, subproject) + # We should only get `None, subproject` or `BuildTarget` + subproject = subproject if subproject is not None else target.subproject - assert isinstance(rtti, bool) - assert isinstance(eh, str) - assert isinstance(debugstl, bool) + key = self.form_compileropt_key('rtti', subproject) + rtti = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, bool) + key = self.form_compileropt_key('debugstl', subproject) + debugstl = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, bool) + key = self.form_compileropt_key('eh', subproject) + eh = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) non_msvc_eh_options(eh, args) @@ -289,23 +292,20 @@ def get_option_compile_args(self, target: 'BuildTarget', subproject: T.Optional[ return args - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject args: T.List[str] = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append(self._find_best_cpp_std(std)) return args - def get_option_link_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_link_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject if self.info.is_windows() or self.info.is_cygwin(): - # without a typedict mypy can't understand this. - retval = self.get_compileropt_value('winlibs', target, subproject) - assert isinstance(retval, list) - libs = retval[:] - for l in libs: - assert isinstance(l, str) - return libs + key = self.form_compileropt_key('winlibs', subproject) + return self.environment.coredata.optstore.get_option_for_maybe_target(target, key, list).copy() return [] def get_assert_args(self, disable: bool) -> T.List[str]: @@ -366,10 +366,11 @@ def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_ ClangCPPCompiler.__init__(self, ccache, exelist, version, for_machine, env, linker=linker, defines=defines, full_version=full_version) - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject args: T.List[str] = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append(self._find_best_cpp_std(std)) return args @@ -409,20 +410,21 @@ def get_options(self) -> 'MutableKeyedOptionDictType': std_opt.set_versions(['c++98', 'c++03', 'c++11', 'c++14', 'c++17'], gnu=True) return opts - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject args: T.List[str] = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append('-std=' + std) - eh = self.get_compileropt_value('eh', target, subproject) - assert isinstance(eh, str) + key = self.form_compileropt_key('eh', subproject) + eh = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) non_msvc_eh_options(eh, args) return args - def get_option_link_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_link_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: return [] @@ -481,16 +483,18 @@ def get_options(self) -> 'MutableKeyedOptionDictType': return opts - def get_option_compile_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_compile_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: args: T.List[str] = [] - rtti = self.get_compileropt_value('rtti', target, subproject) - debugstl = self.get_compileropt_value('debugstl', target, subproject) - eh = self.get_compileropt_value('eh', target, subproject) + # We should only get `None, subproject` or `BuildTarget` + subproject = subproject if subproject is not None else target.subproject - assert isinstance(rtti, bool) - assert isinstance(eh, str) - assert isinstance(debugstl, bool) + key = self.form_compileropt_key('rtti', subproject) + rtti = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, bool) + key = self.form_compileropt_key('debugstl', subproject) + debugstl = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, bool) + key = self.form_compileropt_key('eh', subproject) + eh = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) non_msvc_eh_options(eh, args) @@ -502,23 +506,20 @@ def get_option_compile_args(self, target: 'BuildTarget', subproject: T.Optional[ args.append('-D_GLIBCXX_DEBUG=1') return args - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject args: T.List[str] = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append(self._find_best_cpp_std(std)) return args - def get_option_link_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_link_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject if self.info.is_windows() or self.info.is_cygwin(): - # without a typedict mypy can't understand this. - retval = self.get_compileropt_value('winlibs', target, subproject) - assert isinstance(retval, list) - libs: T.List[str] = retval[:] - for l in libs: - assert isinstance(l, str) - return libs + key = self.form_compileropt_key('winlibs', subproject) + return self.environment.coredata.optstore.get_option_for_maybe_target(target, key, list).copy() return [] def get_assert_args(self, disable: bool) -> T.List[str]: @@ -582,10 +583,11 @@ def get_options(self) -> 'MutableKeyedOptionDictType': std_opt.set_versions(cppstd_choices) return opts - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject args: T.List[str] = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append(self._find_best_cpp_std(std)) return args @@ -650,23 +652,27 @@ def has_function(self, funcname: str, prefix: str, *, return super().has_function(funcname, prefix, extra_args=extra_args, dependencies=dependencies) # Elbrus C++ compiler does not support RTTI, so don't check for it. - def get_option_compile_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_compile_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: args: T.List[str] = [] - eh = self.get_compileropt_value('eh', target, subproject) - assert isinstance(eh, str) + # We should only get `None, subproject` or `BuildTarget` + subproject = subproject if subproject is not None else target.subproject + + key = self.form_compileropt_key('eh', subproject) + eh = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) non_msvc_eh_options(eh, args) - debugstl = self.get_compileropt_value('debugstl', target, subproject) - assert isinstance(debugstl, bool) + key = self.form_compileropt_key('debugstl', subproject) + debugstl = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, bool) if debugstl: args.append('-D_GLIBCXX_DEBUG=1') return args - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject args: T.List[str] = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append(self._find_best_cpp_std(std)) return args @@ -728,12 +734,18 @@ def get_options(self) -> 'MutableKeyedOptionDictType': self._update_language_stds(opts, c_stds + g_stds) return opts - def get_option_compile_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_compile_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: args: T.List[str] = [] - rtti = self.get_compileropt_value('rtti', target, subproject) - debugstl = self.get_compileropt_value('debugstl', target, subproject) - eh = self.get_compileropt_value('eh', target, subproject) + # We should only get `None, subproject` or `BuildTarget` + subproject = subproject if subproject is not None else target.subproject + + key = self.form_compileropt_key('rtti', subproject) + rtti = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, bool) + key = self.form_compileropt_key('debugstl', subproject) + debugstl = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, bool) + key = self.form_compileropt_key('eh', subproject) + eh = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) assert isinstance(rtti, bool) assert isinstance(eh, str) @@ -747,10 +759,11 @@ def get_option_compile_args(self, target: 'BuildTarget', subproject: T.Optional[ args.append('-D_GLIBCXX_DEBUG=1') return args - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject args: T.List[str] = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': remap_cpp03 = { 'c++03': 'c++98', @@ -760,7 +773,7 @@ def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = return args - def get_option_link_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_link_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: return [] @@ -787,14 +800,17 @@ class VisualStudioLikeCPPCompilerMixin(CompilerMixinBase): 'c++latest': (False, "latest"), } - def get_option_link_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: - # need a typeddict for this - key = self.form_compileropt_key('winlibs').evolve(subproject=subproject) - if target: - value = self.environment.coredata.get_option_for_target(target, key) - else: - value = self.environment.coredata.optstore.get_value_for(key) - return T.cast('T.List[str]', value)[:] + @T.overload + def get_option_link_args(self, target: BuildTarget) -> T.List[str]: ... + + @T.overload + def get_option_link_args(self, target: None, subproject: SubProject) -> T.List[str]: ... + + def get_option_link_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject + key = self.form_compileropt_key('winlibs', subproject) + value = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, list) + return value.copy() def _get_options_impl(self, opts: 'MutableKeyedOptionDictType', cpp_stds: T.List[str]) -> 'MutableKeyedOptionDictType': opts = super().get_options() @@ -830,14 +846,22 @@ def _get_options_impl(self, opts: 'MutableKeyedOptionDictType', cpp_stds: T.List choices=['false', 'true']) return opts - def get_option_compile_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + @T.overload + def get_option_compile_args(self, target: BuildTarget) -> T.List[str]: ... + + @T.overload + def get_option_compile_args(self, target: None, subproject: SubProject) -> T.List[str]: ... + + def get_option_compile_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: args: T.List[str] = [] - eh = self.get_compileropt_value('eh', target, subproject) - rtti = self.get_compileropt_value('rtti', target, subproject) + # We should only get `None, subproject` or `BuildTarget` + subproject = subproject if subproject is not None else target.subproject - assert isinstance(rtti, bool) - assert isinstance(eh, str) + key = self.form_compileropt_key('rtti', subproject) + rtti = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, bool) + key = self.form_compileropt_key('eh', subproject) + eh = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if eh == 'default': args.append('/EHsc') @@ -851,10 +875,17 @@ def get_option_compile_args(self, target: 'BuildTarget', subproject: T.Optional[ return args - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + @T.overload + def get_option_std_args(self, target: BuildTarget) -> T.List[str]: ... + + @T.overload + def get_option_std_args(self, target: None, subproject: SubProject) -> T.List[str]: ... + + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject args: T.List[str] = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) permissive, ver = self.VC_VERSION_MAP[std] if ver is not None: @@ -874,21 +905,29 @@ class CPP11AsCPP14Mixin(CompilerMixinBase): This is a limitation of Clang and MSVC that ICL doesn't share. """ - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + @T.overload + def get_option_std_args(self, target: BuildTarget) -> T.List[str]: ... + + @T.overload + def get_option_std_args(self, target: None, subproject: SubProject) -> T.List[str]: ... + + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject # Note: there is no explicit flag for supporting C++11; we attempt to do the best we can # which means setting the C++ standard version to C++14, in compilers that support it # (i.e., after VS2015U3) # if one is using anything before that point, one cannot set the standard. - stdkey = self.form_compileropt_key('std').evolve(subproject=subproject) - if target is not None: - std = self.environment.coredata.get_option_for_target(target, stdkey) - else: - std = self.environment.coredata.optstore.get_value_for(stdkey) + stdkey = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, stdkey, str) if std in {'vc++11', 'c++11'}: mlog.warning(self.id, 'does not support C++11;', 'attempting best effort; setting the standard to C++14', once=True, fatal=False) - original_args = super().get_option_std_args(target, subproject) + + if target is not None: + original_args = super().get_option_std_args(target) + else: + original_args = super().get_option_std_args(target, subproject) std_mapping = {'/std:c++11': '/std:c++14'} processed_args = [std_mapping.get(x, x) for x in original_args] return processed_args @@ -924,12 +963,24 @@ def get_options(self) -> 'MutableKeyedOptionDictType': cpp_stds.extend(['c++20', 'vc++20']) return self._get_options_impl(super().get_options(), cpp_stds) - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: - std = self.get_compileropt_value('std', target, subproject) + @T.overload + def get_option_std_args(self, target: BuildTarget) -> T.List[str]: ... + + @T.overload + def get_option_std_args(self, target: None, subproject: SubProject) -> T.List[str]: ... + + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none' and version_compare(self.version, '<19.00.24210'): mlog.warning('This version of MSVC does not support cpp_std arguments', fatal=False) - args = super().get_option_std_args(target, subproject) + args: T.List[str] # pylint fails to deduce the type of args without this + if target is not None: + args = super().get_option_std_args(target) + else: + args = super().get_option_std_args(target, subproject) if version_compare(self.version, '<19.11'): try: @@ -1008,17 +1059,18 @@ def get_options(self) -> 'MutableKeyedOptionDictType': std_opt.set_versions(['c++03', 'c++11']) return opts - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: args: T.List[str] = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + subproject = subproject if subproject is not None else target.subproject + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std == 'c++11': args.append('--cpp11') elif std == 'c++03': args.append('--cpp') return args - def get_option_link_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_link_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: return [] def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: @@ -1043,7 +1095,7 @@ def get_compile_only_args(self) -> T.List[str]: def get_output_args(self, outputname: str) -> T.List[str]: return [f'-output=obj={outputname}'] - def get_option_link_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_link_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: return [] def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]: @@ -1065,10 +1117,11 @@ def get_options(self) -> 'MutableKeyedOptionDictType': std_opt.set_versions(['c++03']) return opts - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: args: T.List[str] = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + subproject = subproject if subproject is not None else target.subproject + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append('--' + std) return args @@ -1076,7 +1129,7 @@ def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = def get_always_args(self) -> T.List[str]: return [] - def get_option_link_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_link_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: return [] class C2000CPPCompiler(TICPPCompiler): @@ -1104,10 +1157,11 @@ def get_options(self) -> 'MutableKeyedOptionDictType': self._update_language_stds(opts, []) return opts - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: args: T.List[str] = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + subproject = subproject if subproject is not None else target.subproject + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append('-lang') args.append(std) @@ -1131,10 +1185,11 @@ def get_options(self) -> 'MutableKeyedOptionDictType': self._update_language_stds(opts, []) return opts - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: args: T.List[str] = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + subproject = subproject if subproject is not None else target.subproject + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append('-lang ' + std) return args diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py index 485adddfc695..75d203e4fd1a 100644 --- a/mesonbuild/compilers/cuda.py +++ b/mesonbuild/compilers/cuda.py @@ -19,6 +19,7 @@ from ..environment import Environment # noqa: F401 from ..linkers.linkers import DynamicLinker from ..mesonlib import MachineChoice + from ..interpreterbase import SubProject cuda_optimization_args: T.Dict[str, T.List[str]] = { @@ -537,7 +538,7 @@ def _sanity_check_compile_args(self, sourcename: str, binname: str # Use the -ccbin option, if available, even during sanity checking. # Otherwise, on systems where CUDA does not support the default compiler, # NVCC becomes unusable. - flags += self._get_ccbin_args(None, '') + flags += self._get_ccbin_args(None, T.cast('SubProject', '')) # If cross-compiling, we can't run the sanity check, only compile it. if self.is_cross and not self.environment.has_exe_wrapper(): @@ -609,34 +610,61 @@ def get_options(self) -> 'MutableKeyedOptionDictType': return opts - def get_option_compile_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + @T.overload + def get_option_compile_args(self, target: BuildTarget) -> T.List[str]: ... + + @T.overload + def get_option_compile_args(self, target: None, subproject: SubProject) -> T.List[str]: ... + + def get_option_compile_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: args = self._get_ccbin_args(target, subproject) + # We should only get `None, subproject` or `BuildTarget` + subproject = subproject if subproject is not None else target.subproject + try: - host_compiler_args = self.host_compiler.get_option_compile_args(target, subproject) + if target is not None: + host_compiler_args = self.host_compiler.get_option_compile_args(target) + else: + host_compiler_args = self.host_compiler.get_option_compile_args(target, subproject) except KeyError: host_compiler_args = [] return args + self._to_host_flags(host_compiler_args) - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + @T.overload + def get_option_std_args(self, target: BuildTarget) -> T.List[str]: ... + + @T.overload + def get_option_std_args(self, target: None, subproject: SubProject) -> T.List[str]: ... + + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject # On Windows, the version of the C++ standard used by nvcc is dictated by # the combination of CUDA version and MSVC version; the --std= is thus ignored # and attempting to use it will result in a warning: https://stackoverflow.com/a/51272091/741027 if not is_windows(): - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': return ['--std=' + std] try: - host_compiler_args = self.host_compiler.get_option_std_args(target, subproject) + if target is not None: + host_compiler_args = self.host_compiler.get_option_std_args(target) + else: + host_compiler_args = self.host_compiler.get_option_std_args(target, subproject) except KeyError: host_compiler_args = [] return self._to_host_flags(host_compiler_args) - def get_option_link_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_link_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = subproject if subproject is not None else target.subproject args = self._get_ccbin_args(target, subproject) - return args + self._to_host_flags(self.host_compiler.get_option_link_args(target, subproject), Phase.LINKER) + if target is not None: + host_args = self.host_compiler.get_option_std_args(target) + else: + host_args = self.host_compiler.get_option_std_args(target, subproject) + return args + self._to_host_flags(host_args, Phase.LINKER) def get_soname_args(self, prefix: str, shlib_name: str, suffix: str, soversion: str, darwin_versions: T.Tuple[str, str]) -> T.List[str]: @@ -725,17 +753,17 @@ def find_library(self, libname: str, extra_dirs: T.List[str], libtype: LibType = skip_link_check: bool = False) -> T.Optional[T.List[str]]: return self.host_compiler.find_library(libname, extra_dirs, libtype, lib_prefix_warning, ignore_system_dirs, skip_link_check) - def get_crt_compile_args(self, crt_val: str, env: Environment) -> T.List[str]: - return self._to_host_flags(self.host_compiler.get_crt_compile_args(crt_val, env)) + def get_crt_compile_args(self, crt_val: str) -> T.List[str]: + return self._to_host_flags(self.host_compiler.get_crt_compile_args(crt_val)) - def get_crt_link_args(self, crt_val: str, env: Environment) -> T.List[str]: + def get_crt_link_args(self, crt_val: str) -> T.List[str]: # nvcc defaults to static, release version of msvc runtime and provides no # native option to override it; override it with /NODEFAULTLIB host_link_arg_overrides = [] - host_crt_compile_args = self.host_compiler.get_crt_compile_args(crt_val, env) + host_crt_compile_args = self.host_compiler.get_crt_compile_args(crt_val) if any(arg in {'/MDd', '/MD', '/MTd'} for arg in host_crt_compile_args): host_link_arg_overrides += ['/NODEFAULTLIB:LIBCMT.lib'] - return self._to_host_flags(host_link_arg_overrides + self.host_compiler.get_crt_link_args(crt_val, env), Phase.LINKER) + return self._to_host_flags(host_link_arg_overrides + self.host_compiler.get_crt_link_args(crt_val), Phase.LINKER) def get_target_link_args(self, target: 'BuildTarget') -> T.List[str]: return self._to_host_flags(super().get_target_link_args(target), Phase.LINKER) @@ -747,16 +775,14 @@ def get_dependency_link_args(self, dep: 'Dependency') -> T.List[str]: return self._to_host_flags(super().get_dependency_link_args(dep), Phase.LINKER) def _get_ccbin_args(self, target: 'T.Optional[BuildTarget]', - subproject: T.Optional[str] = None) -> T.List[str]: - key = self.form_compileropt_key('ccbindir').evolve(subproject=subproject) - if target: - ccbindir = self.environment.coredata.get_option_for_target(target, key) - else: - ccbindir = self.environment.coredata.optstore.get_value_for(key) - if isinstance(ccbindir, str) and ccbindir != '': + subproject: T.Optional[SubProject] = None) -> T.List[str]: + subproject = target.subproject if subproject is None else subproject + key = self.form_compileropt_key('ccbindir', subproject) + ccbindir = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) + + if ccbindir != '': return [self._shield_nvcc_list_arg('-ccbin='+ccbindir, False)] - else: - return [] + return [] def get_profile_generate_args(self) -> T.List[str]: return ['-Xcompiler=' + x for x in self.host_compiler.get_profile_generate_args()] diff --git a/mesonbuild/compilers/cython.py b/mesonbuild/compilers/cython.py index e3e5a3ef601f..1ae5bfbef24b 100644 --- a/mesonbuild/compilers/cython.py +++ b/mesonbuild/compilers/cython.py @@ -15,6 +15,7 @@ if T.TYPE_CHECKING: from ..options import MutableKeyedOptionDictType from ..build import BuildTarget + from ..interpreterbase import SubProject class CythonCompiler(Compiler): @@ -57,7 +58,8 @@ def get_pic_args(self) -> T.List[str]: def _sanity_check_filenames(self) -> T.Tuple[str, T.Optional[str], str]: sourcename, _, binname = super()._sanity_check_filenames() - lang = self.get_compileropt_value('language', None) + key = self.form_compileropt_key('language', None) + lang = self.environment.coredata.optstore.get_value_for(key, str) assert isinstance(lang, str) # This is almost certainly not good enough @@ -69,8 +71,8 @@ def _sanity_check_filenames(self) -> T.Tuple[str, T.Optional[str], str]: def _transpiled_sanity_check_compile_args( self, compiler: Compiler, sourcename: str, binname: str ) -> T.Tuple[T.List[str], T.List[str]]: - version = self.get_compileropt_value('version', None) - assert isinstance(version, str) + key = self.form_compileropt_key('version', None) + version = self.environment.coredata.optstore.get_value_for(key, str) from ..dependencies import find_external_dependency with mlog.no_logging(): @@ -92,7 +94,7 @@ def _transpiled_sanity_check_compile_args( def _sanity_check_compile_args(self, sourcename: str, binname: str ) -> T.Tuple[T.List[str], T.List[str]]: args, largs = super()._sanity_check_compile_args(sourcename, binname) - args.extend(self.get_option_compile_args(None)) + args.extend(self.get_option_compile_args(None, T.cast('SubProject', ''))) return args, largs def _sanity_check_source_code(self) -> str: @@ -131,14 +133,18 @@ def get_options(self) -> 'MutableKeyedOptionDictType': return opts - def get_option_compile_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_compile_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: args: T.List[str] = [] - version = self.get_compileropt_value('version', target, subproject) - assert isinstance(version, str) + + # We should only get `None, subproject` or `BuildTarget` + subproject = subproject if subproject is not None else target.subproject + + key = self.form_compileropt_key('version', None) + version = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) args.append(f'-{version}') - lang = self.get_compileropt_value('language', target, subproject) - assert isinstance(lang, str) + key = self.form_compileropt_key('language', None) + lang = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if lang == 'cpp': args.append('--cplus') return args diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index 38997fb28ade..31c342303a55 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -371,10 +371,10 @@ def get_debug_args(self, is_debug: bool) -> T.List[str]: return clike_debug_args[is_debug] + ddebug_args - def _get_crt_args(self, crt_val: str, env: Environment) -> T.List[str]: + def _get_crt_args(self, crt_val: str) -> T.List[str]: if not self.info.is_windows(): return [] - return self.mscrt_args[self.get_crt_val(crt_val, env)] + return self.mscrt_args[self.get_crt_val(crt_val)] def get_soname_args(self, prefix: str, shlib_name: str, suffix: str, soversion: str, darwin_versions: T.Tuple[str, str]) -> T.List[str]: @@ -527,10 +527,10 @@ def _get_target_arch_args(self) -> T.List[str]: return ['-m32'] return [] - def get_crt_compile_args(self, crt_val: str, env: Environment) -> T.List[str]: + def get_crt_compile_args(self, crt_val: str) -> T.List[str]: return [] - def get_crt_link_args(self, crt_val: str, env: Environment) -> T.List[str]: + def get_crt_link_args(self, crt_val: str) -> T.List[str]: return [] def _get_compile_extra_args(self, extra_args: T.Union[T.List[str], T.Callable[[CompileCheckMode], T.List[str]], None] = None) -> T.List[str]: @@ -718,8 +718,8 @@ def get_warn_args(self, level: str) -> T.List[str]: def get_pic_args(self) -> T.List[str]: return ['-relocation-model=pic'] - def get_crt_link_args(self, crt_val: str, env: Environment) -> T.List[str]: - return self._get_crt_args(crt_val, env) + def get_crt_link_args(self, crt_val: str) -> T.List[str]: + return self._get_crt_args(crt_val) def unix_args_to_native(self, args: T.List[str]) -> T.List[str]: return self._unix_args_to_native(args, self.info, self.linker.id) @@ -803,8 +803,8 @@ def _get_target_arch_args(self) -> T.List[str]: return ['-m32'] return [] - def get_crt_compile_args(self, crt_val: str, env: Environment) -> T.List[str]: - return self._get_crt_args(crt_val, env) + def get_crt_compile_args(self, crt_val: str) -> T.List[str]: + return self._get_crt_args(crt_val) def unix_args_to_native(self, args: T.List[str]) -> T.List[str]: return self._unix_args_to_native(args, self.info, self.linker.id) diff --git a/mesonbuild/compilers/detect.py b/mesonbuild/compilers/detect.py index bc2bc90565aa..952a23a2ccbf 100644 --- a/mesonbuild/compilers/detect.py +++ b/mesonbuild/compilers/detect.py @@ -172,7 +172,7 @@ def detect_static_linker(env: 'Environment', compiler: Compiler) -> StaticLinker trials = [defaults['cuda_static_linker']] + default_linkers elif compiler.get_argument_syntax() == 'msvc': trials = [defaults['vs_static_linker'], defaults['clang_cl_static_linker']] - elif env.machines[compiler.for_machine].is_os2() and env.coredata.optstore.get_value_for(OptionKey('os2_emxomf')): + elif env.machines[compiler.for_machine].is_os2() and env.coredata.optstore.get_value_for(OptionKey('os2_emxomf'), bool): trials = [defaults['emxomf_static_linker']] + default_linkers elif compiler.id == 'gcc': # Use gcc-ar if available; needed for LTO diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index d468bd547bb7..4de1de9881b6 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -34,6 +34,7 @@ from ..linkers.linkers import DynamicLinker from ..mesonlib import MachineChoice from ..build import BuildTarget + from ..interpreterbase import SubProject class FortranCompiler(CLikeCompiler, Compiler): @@ -56,8 +57,8 @@ def has_function(self, funcname: str, prefix: str, *, 'that example is to see if the compiler has Fortran 2008 Block element.') def _get_basic_compiler_args(self, mode: CompileCheckMode) -> T.Tuple[T.List[str], T.List[str]]: - cargs = self.environment.coredata.get_external_args(self.for_machine, self.language) - largs = self.environment.coredata.get_external_link_args(self.for_machine, self.language) + cargs = self.environment.coredata.optstore.get_external_args(self.for_machine, self.language) + largs = self.environment.coredata.optstore.get_external_link_args(self.for_machine, self.language) return cargs, largs def _sanity_check_source_code(self) -> str: @@ -284,10 +285,11 @@ def get_options(self) -> 'MutableKeyedOptionDictType': self._update_language_stds(opts, fortran_stds) return opts - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: args: T.List[str] = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + subproject = subproject if subproject is not None else target.subproject + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append('-std=' + std) return args @@ -414,11 +416,13 @@ def get_options(self) -> 'MutableKeyedOptionDictType': self._update_language_stds(opts, ['none', 'legacy', 'f95', 'f2003', 'f2008', 'f2018']) return opts - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: args: T.List[str] = [] - std = self.get_compileropt_value('std', target, subproject) + subproject = subproject if subproject is not None else target.subproject + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) + stds = {'legacy': 'none', 'f95': 'f95', 'f2003': 'f03', 'f2008': 'f08', 'f2018': 'f18'} - assert isinstance(std, str) if std != 'none': args.append('-stand=' + stds[std]) return args @@ -472,11 +476,13 @@ def get_options(self) -> 'MutableKeyedOptionDictType': self._update_language_stds(opts, ['none', 'legacy', 'f95', 'f2003', 'f2008', 'f2018']) return opts - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: args: T.List[str] = [] - std = self.get_compileropt_value('std', target, subproject) + subproject = subproject if subproject is not None else target.subproject + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) + stds = {'legacy': 'none', 'f95': 'f95', 'f2003': 'f03', 'f2008': 'f08', 'f2018': 'f18'} - assert isinstance(std, str) if std != 'none': args.append('/stand:' + stds[std]) return args diff --git a/mesonbuild/compilers/mixins/clang.py b/mesonbuild/compilers/mixins/clang.py index f52f4e1181ab..69d29b70f1bc 100644 --- a/mesonbuild/compilers/mixins/clang.py +++ b/mesonbuild/compilers/mixins/clang.py @@ -21,7 +21,6 @@ from ...options import MutableKeyedOptionDictType from ...dependencies import Dependency # noqa: F401 from ...build import BuildTarget - from ...environment import Environment from ..compilers import Compiler CompilerMixinBase = Compiler @@ -91,16 +90,16 @@ def __init__(self, defines: T.Optional[T.Dict[str, str]]): # All Clang backends can also do LLVM IR self.can_compile_suffixes.add('ll') - def get_crt_compile_args(self, crt_val: str, env: Environment) -> T.List[str]: + def get_crt_compile_args(self, crt_val: str) -> T.List[str]: if not isinstance(self.linker, VisualStudioLikeLinkerMixin): return [] - crt_val = self.get_crt_val(crt_val, env) + crt_val = self.get_crt_val(crt_val) return self.CRT_D_ARGS[crt_val] - def get_crt_link_args(self, crt_val: str, env: Environment) -> T.List[str]: + def get_crt_link_args(self, crt_val: str) -> T.List[str]: if not isinstance(self.linker, VisualStudioLikeLinkerMixin): return [] - crt_val = self.get_crt_val(crt_val, env) + crt_val = self.get_crt_val(crt_val) return self.CRT_ARGS[crt_val] def get_colorout_args(self, colortype: str) -> T.List[str]: diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index 9cbf64d5a4d7..9b03d37cde2a 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -27,6 +27,7 @@ from ... import mlog from ...linkers.linkers import GnuLikeDynamicLinkerMixin, SolarisDynamicLinker, CompCertDynamicLinker from ...mesonlib import LibType +from ...options import OptionKey from .. import compilers from ..compilers import CompileCheckMode from .visualstudio import VisualStudioLikeCompiler @@ -331,15 +332,14 @@ def _get_basic_compiler_args(self, mode: CompileCheckMode) -> T.Tuple[T.List[str # 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 = self.environment.coredata.optstore.get_value_for('b_vscrt') - assert isinstance(crt_val, str), 'for mypy' - cargs += self.get_crt_compile_args(crt_val, self.environment) - largs += self.get_crt_link_args(crt_val, self.environment) + crt_val = self.environment.coredata.optstore.get_value_for(OptionKey('b_vscrt'), str) + cargs += self.get_crt_compile_args(crt_val) + largs += self.get_crt_link_args(crt_val) except (KeyError, AttributeError): pass # Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS and CPPFLAGS from the env - sys_args = self.environment.coredata.get_external_args(self.for_machine, self.language) + sys_args = self.environment.coredata.optstore.get_external_args(self.for_machine, self.language) if isinstance(sys_args, str): sys_args = [sys_args] # Apparently it is a thing to inject linker flags both @@ -355,7 +355,7 @@ def _get_basic_compiler_args(self, mode: CompileCheckMode) -> T.Tuple[T.List[str largs += self.use_linker_args(ld_value[0], self.version) # Add LDFLAGS from the env - sys_ld_args = self.environment.coredata.get_external_link_args(self.for_machine, self.language) + sys_ld_args = self.environment.coredata.optstore.get_external_link_args(self.for_machine, self.language) # CFLAGS and CXXFLAGS go to both linking and compiling, but we want them # to only appear on the command line once. Remove dupes. largs += [x for x in sys_ld_args if x not in cleaned_sys_args] @@ -1192,7 +1192,7 @@ def find_framework_paths(self) -> T.List[str]: commands = self.get_exelist(ccache=False) + ['-v', '-E', '-'] commands += self.get_always_args() # Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS from the env - commands += self.environment.coredata.get_external_args(self.for_machine, self.language) + commands += self.environment.coredata.optstore.get_external_args(self.for_machine, self.language) mlog.debug('Finding framework path by running: ', ' '.join(commands), '\n') os_env = os.environ.copy() os_env['LC_ALL'] = 'C' @@ -1242,11 +1242,11 @@ def find_framework(self, name: str, extra_dirs: T.List[str], # TODO: should probably check for macOS? return self._find_framework_impl(name, extra_dirs, allow_system) - def get_crt_compile_args(self, crt_val: str, env: Environment) -> T.List[str]: + def get_crt_compile_args(self, crt_val: str) -> T.List[str]: # TODO: does this belong here or in GnuLike or maybe PosixLike? return [] - def get_crt_link_args(self, crt_val: str, env: Environment) -> T.List[str]: + def get_crt_link_args(self, crt_val: str) -> T.List[str]: # TODO: does this belong here or in GnuLike or maybe PosixLike? return [] diff --git a/mesonbuild/compilers/mixins/elbrus.py b/mesonbuild/compilers/mixins/elbrus.py index e020123891f0..de37408ec104 100644 --- a/mesonbuild/compilers/mixins/elbrus.py +++ b/mesonbuild/compilers/mixins/elbrus.py @@ -18,6 +18,7 @@ if T.TYPE_CHECKING: from ...build import BuildTarget + from ...interpreterbase import SubProject class ElbrusCompiler(GnuLikeCompiler): @@ -82,14 +83,11 @@ def get_pch_suffix(self) -> str: # Actually it's not supported for now, but probably will be supported in future return 'pch' - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: args: T.List[str] = [] + subproject = subproject if subproject is not None else target.subproject key = OptionKey(f'{self.language}_std', subproject=subproject, machine=self.for_machine) - if target: - std = self.environment.coredata.get_option_for_target(target, key) - else: - std = self.environment.coredata.optstore.get_value_for(key) - assert isinstance(std, str) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append('-std=' + std) return args diff --git a/mesonbuild/compilers/mixins/emscripten.py b/mesonbuild/compilers/mixins/emscripten.py index 3dd65b2c1052..23e5817728bc 100644 --- a/mesonbuild/compilers/mixins/emscripten.py +++ b/mesonbuild/compilers/mixins/emscripten.py @@ -49,8 +49,8 @@ def _get_compile_output(self, dirname: str, mode: CompileCheckMode) -> str: def thread_link_flags(self) -> T.List[str]: args = ['-pthread'] - count = self.environment.coredata.optstore.get_value_for(OptionKey(f'{self.language}_thread_count', machine=self.for_machine)) - assert isinstance(count, int) + count = self.environment.coredata.optstore.get_value_for( + OptionKey(f'{self.language}_thread_count', machine=self.for_machine), int) if count: args.append(f'-sPTHREAD_POOL_SIZE={count}') return args diff --git a/mesonbuild/compilers/mixins/gnu.py b/mesonbuild/compilers/mixins/gnu.py index 776f9eda1626..8830e60c5e9b 100644 --- a/mesonbuild/compilers/mixins/gnu.py +++ b/mesonbuild/compilers/mixins/gnu.py @@ -658,7 +658,7 @@ def get_profile_use_args(self) -> T.List[str]: def get_always_args(self) -> T.List[str]: args: T.List[str] = [] - if self.info.is_os2() and self.environment.coredata.optstore.get_value_for(OptionKey('os2_emxomf')): + if self.info.is_os2() and self.environment.coredata.optstore.get_value_for(OptionKey('os2_emxomf'), bool): args += ['-Zomf'] return super().get_always_args() + args diff --git a/mesonbuild/compilers/mixins/islinker.py b/mesonbuild/compilers/mixins/islinker.py index 1c0361918991..7eb891f6aa1e 100644 --- a/mesonbuild/compilers/mixins/islinker.py +++ b/mesonbuild/compilers/mixins/islinker.py @@ -20,6 +20,7 @@ from ...compilers.compilers import Compiler from ...build import BuildTarget from ...options import OptionStore + from ...interpreterbase import SubProject else: # This is a bit clever, for mypy we pretend that these mixins descend from # Compiler, so we get all of the methods and attributes defined for us, but @@ -59,7 +60,7 @@ def get_linker_always_args(self) -> T.List[str]: def get_linker_lib_prefix(self) -> str: return '' - def get_option_link_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_link_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: return [] def has_multi_link_args(self, args: T.List[str]) -> T.Tuple[bool, bool]: diff --git a/mesonbuild/compilers/mixins/visualstudio.py b/mesonbuild/compilers/mixins/visualstudio.py index a809dbf62218..acf1bbc7bdc1 100644 --- a/mesonbuild/compilers/mixins/visualstudio.py +++ b/mesonbuild/compilers/mixins/visualstudio.py @@ -20,7 +20,6 @@ if T.TYPE_CHECKING: from ...build import BuildTarget - from ...environment import Environment from .clike import CLikeCompiler as Compiler else: # This is a bit clever, for mypy we pretend that these mixins descend from @@ -317,8 +316,8 @@ def get_default_include_dirs(self) -> T.List[str]: return [] return os.environ['INCLUDE'].split(os.pathsep) - def get_crt_compile_args(self, crt_val: str, env: Environment) -> T.List[str]: - crt_val = self.get_crt_val(crt_val, env) + def get_crt_compile_args(self, crt_val: str) -> T.List[str]: + crt_val = self.get_crt_val(crt_val) return self.crt_args[crt_val] def has_func_attribute(self, name: str) -> T.Tuple[bool, bool]: diff --git a/mesonbuild/compilers/objc.py b/mesonbuild/compilers/objc.py index 7b196ccb9bb7..f4b88ae7a2e2 100644 --- a/mesonbuild/compilers/objc.py +++ b/mesonbuild/compilers/objc.py @@ -20,6 +20,7 @@ from ..mesonlib import MachineChoice from ..build import BuildTarget from ..options import MutableKeyedOptionDictType + from ..interpreterbase import SubProject class ObjCCompiler(CLikeCompiler, Compiler): @@ -50,10 +51,10 @@ def get_display_language() -> str: def _sanity_check_source_code(self) -> str: return '#import\nint main(void) { return 0; }\n' - def form_compileropt_key(self, basename: str) -> OptionKey: + def form_compileropt_key(self, basename: str, subproject: T.Optional[SubProject] = None) -> OptionKey: if basename == 'std': - return OptionKey(f'c_{basename}', machine=self.for_machine) - return super().form_compileropt_key(basename) + return OptionKey('c_std}', subproject=subproject, machine=self.for_machine) + return super().form_compileropt_key(basename, subproject) class GnuObjCCompiler(GnuCStds, GnuCompiler, ObjCCompiler): @@ -74,14 +75,11 @@ def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_ self.supported_warn_args(gnu_common_warning_args) + self.supported_warn_args(gnu_objc_warning_args))} - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: args: T.List[str] = [] + subproject = subproject if subproject is not None else target.subproject key = OptionKey('c_std', subproject=subproject, machine=self.for_machine) - if target: - std = self.environment.coredata.get_option_for_target(target, key) - else: - std = self.environment.coredata.optstore.get_value_for(key) - assert isinstance(std, str) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append('-std=' + std) return args @@ -102,21 +100,21 @@ def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_ '3': default_warn_args + ['-Wextra', '-Wpedantic'], 'everything': ['-Weverything']} - def form_compileropt_key(self, basename: str) -> OptionKey: + def form_compileropt_key(self, basename: str, subproject: T.Optional[SubProject] = None) -> OptionKey: if basename == 'std': - return OptionKey('c_std', machine=self.for_machine) - return super().form_compileropt_key(basename) + return OptionKey('c_std', subproject=subproject, machine=self.for_machine) + return super().form_compileropt_key(basename, subproject) def make_option_name(self, key: OptionKey) -> str: if key.name == 'std': return 'c_std' return super().make_option_name(key) - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: - args = [] - key = OptionKey('c_std', machine=self.for_machine) - std = self.get_compileropt_value(key, target, subproject) - assert isinstance(std, str) + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + args: T.List[str] = [] + subproject = subproject if subproject is not None else target.subproject + key = OptionKey('c_std', subproject, self.for_machine) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append('-std=' + std) return args diff --git a/mesonbuild/compilers/objcpp.py b/mesonbuild/compilers/objcpp.py index ad047d78626b..b2c605074275 100644 --- a/mesonbuild/compilers/objcpp.py +++ b/mesonbuild/compilers/objcpp.py @@ -20,6 +20,7 @@ from ..mesonlib import MachineChoice from ..build import BuildTarget from ..options import MutableKeyedOptionDictType + from ..interpreterbase import SubProject class ObjCPPCompiler(CLikeCompiler, Compiler): @@ -34,10 +35,10 @@ def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_ full_version=full_version, linker=linker) CLikeCompiler.__init__(self) - def form_compileropt_key(self, basename: str) -> OptionKey: + def form_compileropt_key(self, basename: str, subproject: T.Optional[SubProject] = None) -> OptionKey: if basename == 'std': - return OptionKey('cpp_std', machine=self.for_machine) - return super().form_compileropt_key(basename) + return OptionKey('cpp_std', subproject=subproject, machine=self.for_machine) + return super().form_compileropt_key(basename, subproject) def make_option_name(self, key: OptionKey) -> str: if key.name == 'std': @@ -78,14 +79,11 @@ def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_ self.supported_warn_args(gnu_common_warning_args) + self.supported_warn_args(gnu_objc_warning_args))} - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: args: T.List[str] = [] + subproject = subproject if subproject is not None else target.subproject key = OptionKey('cpp_std', subproject=subproject, machine=self.for_machine) - if target: - std = self.environment.coredata.get_option_for_target(target, key) - else: - std = self.environment.coredata.optstore.get_value_for(key) - assert isinstance(std, str) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append('-std=' + std) return args @@ -107,11 +105,11 @@ def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_ '3': default_warn_args + ['-Wextra', '-Wpedantic'], 'everything': ['-Weverything']} - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: - args = [] - key = OptionKey('cpp_std', machine=self.for_machine) - std = self.get_compileropt_value(key, target, subproject) - assert isinstance(std, str) + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + args: T.List[str] = [] + subproject = subproject if subproject is not None else target.subproject + key = OptionKey('cpp_std', subproject, self.for_machine) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append('-std=' + std) return args diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py index 919baca86db4..43e9dde7664a 100644 --- a/mesonbuild/compilers/rust.py +++ b/mesonbuild/compilers/rust.py @@ -26,6 +26,7 @@ from ..mesonlib import MachineChoice from ..dependencies import Dependency from ..build import BuildTarget + from ..interpreterbase import SubProject from typing_extensions import Protocol @@ -155,7 +156,8 @@ def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoic self.has_check_cfg = version_compare(version, '>=1.80.0') def init_from_options(self) -> None: - nightly_opt = self.get_compileropt_value('nightly', None) + key = self.form_compileropt_key('nightly', None) + nightly_opt = self.environment.coredata.optstore.get_value_for(key, str) if nightly_opt == 'enabled' and not self.is_nightly: raise EnvironmentException(f'Rust compiler {self.name_string()} is not a nightly compiler as required by the "nightly" option.') self.allow_nightly = nightly_opt != 'disabled' and self.is_nightly @@ -269,7 +271,7 @@ def get_nightly(self, target: T.Optional[BuildTarget]) -> bool: if not target: return self.allow_nightly key = self.form_compileropt_key('nightly') - nightly_opt = self.environment.coredata.get_option_for_target(target, key) + nightly_opt = self.environment.coredata.optstore.get_option_for_target(target, key, str) if nightly_opt == 'enabled' and not self.is_nightly: raise EnvironmentException(f'Rust compiler {self.name_string()} is not a nightly compiler as required by the "nightly" option.') return nightly_opt != 'disabled' and self.is_nightly @@ -386,25 +388,26 @@ def get_dependency_compile_args(self, dep: 'Dependency') -> T.List[str]: # provided by the linker flags. return [] - def get_option_std_args(self, target: BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: - args = [] - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + def get_option_std_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: + args: T.List[str] = [] + subproject = subproject if subproject is not None else target.subproject + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args.append('--edition=' + std) return args - def get_crt_compile_args(self, crt_val: str, env: Environment) -> T.List[str]: + def get_crt_compile_args(self, crt_val: str) -> T.List[str]: # Rust handles this for us, we don't need to do anything return [] - def get_crt_link_args(self, crt_val: str, env: Environment) -> T.List[str]: + def get_crt_link_args(self, crt_val: str) -> T.List[str]: if not isinstance(self.linker, VisualStudioLikeLinkerMixin): return [] # Rustc always use non-debug Windows runtime. Inject the one selected # by Meson options instead. # https://github.com/rust-lang/rust/issues/39016 - return self.MSVCRT_ARGS[self.get_crt_val(crt_val, env)] + return self.MSVCRT_ARGS[self.get_crt_val(crt_val)] def get_colorout_args(self, colortype: str) -> T.List[str]: if colortype in {'always', 'never', 'auto'}: diff --git a/mesonbuild/compilers/swift.py b/mesonbuild/compilers/swift.py index feaa009e0cd1..58ab86c38ac6 100644 --- a/mesonbuild/compilers/swift.py +++ b/mesonbuild/compilers/swift.py @@ -19,6 +19,7 @@ from ..environment import Environment from ..linkers.linkers import DynamicLinker from ..mesonlib import MachineChoice + from ..interpreterbase import SubProject swift_optimization_args: T.Dict[str, T.List[str]] = { 'plain': [], @@ -128,11 +129,18 @@ def get_options(self) -> MutableKeyedOptionDictType: return opts - def get_option_std_args(self, target: build.BuildTarget, subproject: T.Optional[str] = None) -> T.List[str]: + @T.overload + def get_option_std_args(self, target: build.BuildTarget) -> T.List[str]: ... + + @T.overload + def get_option_std_args(self, target: None, subproject: SubProject) -> T.List[str]: ... + + def get_option_std_args(self, target: T.Optional[build.BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: args: T.List[str] = [] + subproject = subproject if subproject is not None else target.subproject - std = self.get_compileropt_value('std', target, subproject) - assert isinstance(std, str) + key = self.form_compileropt_key('std', subproject) + std = self.environment.coredata.optstore.get_option_for_maybe_target(target, key, str) if std != 'none': args += ['-swift-version', std] @@ -145,7 +153,11 @@ def get_option_std_args(self, target: build.BuildTarget, subproject: T.Optional[ c_lang = first(c_langs, lambda x: x in target.compilers) if c_lang is not None: cc = target.compilers[c_lang] - args.extend(arg for c_arg in cc.get_option_std_args(target, subproject) for arg in ['-Xcc', c_arg]) + if target is not None: + cc_std_args = cc.get_option_std_args(target) + else: + cc_std_args = cc.get_option_std_args(target, subproject) + args.extend(arg for c_arg in cc_std_args for arg in ['-Xcc', c_arg]) return args @@ -184,7 +196,7 @@ def _sanity_check_compile_args(self, sourcename: str, binname: str if self.is_cross: args.extend(self.get_compile_only_args()) else: - largs.extend(self.environment.coredata.get_external_link_args(self.for_machine, self.language)) + largs.extend(self.environment.coredata.optstore.get_external_link_args(self.for_machine, self.language)) args.extend(self.get_output_args(binname)) args.append(sourcename) diff --git a/mesonbuild/compilers/vala.py b/mesonbuild/compilers/vala.py index be5c1b0b44a5..625db201a025 100644 --- a/mesonbuild/compilers/vala.py +++ b/mesonbuild/compilers/vala.py @@ -18,6 +18,7 @@ from ..mesonlib import MachineChoice from ..dependencies import Dependency from ..build import BuildTarget + from ..interpreterbase import SubProject class ValaCompiler(Compiler): @@ -153,7 +154,7 @@ def find_library(self, libname: str, extra_dirs: T.List[str], libtype: LibType = if not extra_dirs: code = 'class MesonFindLibrary : Object { }' args: T.List[str] = [] - args += self.environment.coredata.get_external_args(self.for_machine, self.language) + args += self.environment.coredata.optstore.get_external_args(self.for_machine, self.language) vapi_args = ['--pkg', libname] args += vapi_args with self.cached_compile(code, extra_args=args, mode=CompileCheckMode.COMPILE) as p: @@ -173,7 +174,7 @@ def thread_flags(self) -> T.List[str]: def thread_link_flags(self) -> T.List[str]: return [] - def get_option_link_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_link_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: return [] def build_wrapper_args(self, @@ -212,10 +213,10 @@ def build_wrapper_args(self, if mode is CompileCheckMode.COMPILE: # Add DFLAGS from the env - args += self.environment.coredata.get_external_args(self.for_machine, self.language) + args += self.environment.coredata.optstore.get_external_args(self.for_machine, self.language) elif mode is CompileCheckMode.LINK: # Add LDFLAGS from the env - args += self.environment.coredata.get_external_link_args(self.for_machine, self.language) + args += self.environment.coredata.optstore.get_external_link_args(self.for_machine, self.language) # extra_args must override all other arguments, so we add them last args += extra_args return args diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 5f84cb10a893..c378d8e77fc5 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -9,7 +9,6 @@ from . import mlog, options import pickle, os, uuid import sys -from functools import lru_cache from collections import OrderedDict import textwrap @@ -31,8 +30,7 @@ from .mesonlib import FileOrString from .cmake.traceparser import CMakeCacheEntry from .interpreterbase import SubProject - from .options import ElementaryOptionValues, MutableKeyedOptionDictType - from .build import BuildTarget + from .options import MutableKeyedOptionDictType from .cmdline import SharedCMDOptions OptionDictType = T.Dict[str, options.AnyOptionType] @@ -124,8 +122,8 @@ def __init__(self, builtins: options.OptionStore, for_machine: MachineChoice): def __calculate_subkey(self, type_: DependencyCacheType) -> T.Tuple[str, ...]: data: T.Dict[DependencyCacheType, T.List[str]] = { - DependencyCacheType.PKG_CONFIG: T.cast('T.List[str]', self.__builtins.get_value_for(self.__pkg_conf_key)), - DependencyCacheType.CMAKE: T.cast('T.List[str]', self.__builtins.get_value_for(self.__cmake_key)), + DependencyCacheType.PKG_CONFIG: self.__builtins.get_value_for(self.__pkg_conf_key, list), + DependencyCacheType.CMAKE: self.__builtins.get_value_for(self.__cmake_key, list), DependencyCacheType.OTHER: [], } assert type_ in data, 'Someone forgot to update subkey calculations for a new type' @@ -340,28 +338,6 @@ def init_backend_options(self, backend_name: str) -> None: 'Default project to execute in Visual Studio', '')) - def get_option_for_target(self, target: 'BuildTarget', key: T.Union[str, OptionKey]) -> ElementaryOptionValues: - if isinstance(key, str): - assert ':' not in key - newkey = OptionKey(key, target.subproject) - else: - newkey = key - if newkey.subproject != target.subproject: - # FIXME: this should be an error. The caller needs to ensure that - # key and target have the same subproject for consistency. - # Now just do this to get things going. - newkey = newkey.evolve(subproject=target.subproject) - if self.is_cross_build(): - newkey = newkey.evolve(machine=target.for_machine) - option_object, value = self.optstore.get_option_and_value_for(newkey) - override = target.get_override(newkey.name) - if override is not None: - try: - return option_object.validate_value(override) - except MesonException as e: - raise MesonException(f'In override_options for {target}: {e!s}') - return value - def set_from_configure_command(self, options: SharedCMDOptions) -> bool: return self.optstore.set_from_configure_command(options.cmd_line_options) @@ -373,7 +349,7 @@ def clear_cache(self) -> None: def get_nondefault_buildtype_args(self) -> T.List[T.Union[T.Tuple[str, str, str], T.Tuple[str, bool, bool]]]: result: T.List[T.Union[T.Tuple[str, str, str], T.Tuple[str, bool, bool]]] = [] - value = self.optstore.get_value_for('buildtype') + value = self.optstore.get_value_for(OptionKey('buildtype'), str) if value == 'plain': opt = 'plain' debug = False @@ -392,27 +368,14 @@ def get_nondefault_buildtype_args(self) -> T.List[T.Union[T.Tuple[str, str, str] else: assert value == 'custom' return [] - actual_opt = self.optstore.get_value_for('optimization') - actual_debug = self.optstore.get_value_for('debug') - assert isinstance(actual_opt, str) # for mypy - assert isinstance(actual_debug, bool) # for mypy + actual_opt = self.optstore.get_value_for(OptionKey('optimization'), str) + actual_debug = self.optstore.get_value_for(OptionKey('debug'), bool) if actual_opt != opt: result.append(('optimization', actual_opt, opt)) if actual_debug != debug: result.append(('debug', actual_debug, debug)) return result - def get_external_args(self, for_machine: MachineChoice, lang: str) -> T.List[str]: - # mypy cannot analyze type of OptionKey - key = OptionKey(f'{lang}_args', machine=for_machine) - return T.cast('T.List[str]', self.optstore.get_value_for(key)) - - @lru_cache(maxsize=None) - def get_external_link_args(self, for_machine: MachineChoice, lang: str) -> T.List[str]: - # mypy cannot analyze type of OptionKey - linkkey = OptionKey(f'{lang}_link_args', machine=for_machine) - return T.cast('T.List[str]', self.optstore.get_value_for(linkkey)) - def is_cross_build(self, when_building_for: MachineChoice = MachineChoice.HOST) -> bool: if when_building_for == MachineChoice.BUILD: return False @@ -459,7 +422,7 @@ def process_compiler_options(self, lang: Language, comp: Compiler, subproject: s def emit_base_options_warnings(self) -> None: bcodekey = OptionKey('b_bitcode') - if bcodekey in self.optstore and self.optstore.get_value_for(bcodekey): + if bcodekey in self.optstore and self.optstore.get_value_for(bcodekey, bool): msg = textwrap.dedent('''Base option 'b_bitcode' is enabled, which is incompatible with many linker options. Incompatible options such as \'b_asneeded\' have been disabled.' Please see https://mesonbuild.com/Builtin-options.html#Notes_about_Apple_Bitcode_support for more details.''') diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 30aa4a43135d..b5480a33811c 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -431,7 +431,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObje self.silent = kwargs.get('silent', False) static = kwargs.get('static') if static is None: - static = T.cast('bool', self.env.coredata.optstore.get_value_for(OptionKey('prefer_static'))) + static = self.env.coredata.optstore.get_value_for(OptionKey('prefer_static'), bool) self.static = static self.libtype = LibType.STATIC if self.static else LibType.PREFER_SHARED # Is this dependency to be run on the build platform? diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py index 2a86c8264120..33a9ff7947e6 100644 --- a/mesonbuild/dependencies/boost.py +++ b/mesonbuild/dependencies/boost.py @@ -343,8 +343,7 @@ class BoostDependency(SystemDependency): def __init__(self, name: str, environment: Environment, kwargs: DependencyObjectKWs) -> None: kwargs['language'] = 'cpp' super().__init__(name, environment, kwargs) - buildtype = environment.coredata.optstore.get_value_for(OptionKey('buildtype')) - assert isinstance(buildtype, str) + buildtype = environment.coredata.optstore.get_value_for(OptionKey('buildtype'), str) self.debug = buildtype.startswith('debug') self.multithreading = kwargs.get('threading', 'multi') == 'multi' @@ -602,13 +601,11 @@ def detect_lib_dirs(self, root: Path, use_system: bool) -> T.List[Path]: def filter_libraries(self, libs: T.List[BoostLibraryFile], lib_vers: str) -> T.List[BoostLibraryFile]: # MSVC is very picky with the library tags - vscrt = '' try: - crt_val = self.env.coredata.optstore.get_value_for('b_vscrt') - assert isinstance(crt_val, str) - vscrt = self.clib_compiler.get_crt_compile_args(crt_val, self.env)[0] + crt_val = self.env.coredata.optstore.get_value_for(OptionKey('b_vscrt'), str) + vscrt = self.clib_compiler.get_crt_compile_args(crt_val)[0] except (KeyError, IndexError, AttributeError): - pass + vscrt = '' # mlog.debug(' - static: {}'.format(self.static)) # mlog.debug(' - not explicit static: {}'.format(not self.explicit_static)) diff --git a/mesonbuild/dependencies/dub.py b/mesonbuild/dependencies/dub.py index 7b4daf37c26d..b80bb503ed01 100644 --- a/mesonbuild/dependencies/dub.py +++ b/mesonbuild/dependencies/dub.py @@ -124,7 +124,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObje dub_arch = self.compiler.arch # we need to know the build type as well - dub_buildtype = str(environment.coredata.optstore.get_value_for(OptionKey('buildtype'))) + dub_buildtype = environment.coredata.optstore.get_value_for(OptionKey('buildtype'), str) # MESON types: choices=['plain', 'debug', 'debugoptimized', 'release', 'minsize', 'custom'])), # DUB types: debug (default), plain, release, release-debug, release-nobounds, unittest, profile, profile-gc, # docs, ddox, cov, unittest-cov, syntax and custom diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index 1f9f06e97241..770c5255a661 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -578,7 +578,7 @@ def shaderc_factory(env: 'Environment', static = kwargs.get('static') if static is None: - static = T.cast('bool', env.coredata.optstore.get_value_for(OptionKey('prefer_static'))) + static = env.coredata.optstore.get_value_for(OptionKey('prefer_static'), bool) if static: c = [DependencyCandidate.from_dependency(name, PkgConfigDependency, (env, kwargs)) for name in static_libs + shared_libs] diff --git a/mesonbuild/dependencies/mpi.py b/mesonbuild/dependencies/mpi.py index 3258e1e03390..edf4d9d6b97b 100644 --- a/mesonbuild/dependencies/mpi.py +++ b/mesonbuild/dependencies/mpi.py @@ -14,6 +14,7 @@ from .detect import packages from .factory import factory_methods from .pkgconfig import PkgConfigDependency +from ..options import OptionKey if T.TYPE_CHECKING: from .factory import DependencyGenerator @@ -283,8 +284,7 @@ def __init__(self, name: str, env: Environment, kwargs: DependencyObjectKWs): incdir = os.path.join(rootdir, 'include') libdir = os.path.join(rootdir, 'lib') - debug = env.coredata.optstore.get_value_for('debug') - assert isinstance(debug, bool) + debug = env.coredata.optstore.get_value_for(OptionKey('debug'), bool) libdir_post = 'debug' if debug else 'release' for subdirs in (['mpi', libdir_post], [libdir_post]): libdir_buildtype = os.path.join(libdir, *subdirs) diff --git a/mesonbuild/dependencies/pkgconfig.py b/mesonbuild/dependencies/pkgconfig.py index 91f783da2fdd..8d2df9b27842 100644 --- a/mesonbuild/dependencies/pkgconfig.py +++ b/mesonbuild/dependencies/pkgconfig.py @@ -268,9 +268,8 @@ def _check_pkgconfig(self, pkgbin: ExternalProgram) -> T.Optional[str]: def _get_env(self, uninstalled: bool = False) -> EnvironmentVariables: env = EnvironmentVariables() key = OptionKey('pkg_config_path', machine=self.for_machine) - pathlist = self.env.coredata.optstore.get_value_for(key) - assert isinstance(pathlist, list) - extra_paths: T.List[str] = pathlist + self.extra_paths + pathlist = self.env.coredata.optstore.get_value_for(key, list) + extra_paths = pathlist + self.extra_paths if uninstalled: bpath = self.env.get_build_dir() if bpath is not None: @@ -435,7 +434,7 @@ def _search_libs(self, libs_in: ImmutableListProtocol[str], raw_libs_in: Immutab # # Only prefix_libpaths are reordered here because there should not be # too many system_libpaths to cause library version issues. - pkg_config_path: T.List[str] = self.env.coredata.optstore.get_value_for(OptionKey('pkg_config_path', machine=self.for_machine)) # type: ignore[assignment] + pkg_config_path = self.env.coredata.optstore.get_value_for(OptionKey('pkg_config_path', machine=self.for_machine), list) pkg_config_path = self._convert_mingw_paths(pkg_config_path) prefix_libpaths = OrderedSet(sort_libpaths(list(prefix_libpaths), pkg_config_path)) system_libpaths: OrderedSet[str] = OrderedSet() diff --git a/mesonbuild/dependencies/python.py b/mesonbuild/dependencies/python.py index 3b02bad663f9..1d2fa889caf5 100644 --- a/mesonbuild/dependencies/python.py +++ b/mesonbuild/dependencies/python.py @@ -396,16 +396,13 @@ def get_windows_link_args(self, limited_api: bool, environment: 'Environment') - # Python itself (except with pybind11, which has an ugly # hack to work around this) - so emit a warning to explain # the cause of the expected link error. - buildtype = self.env.coredata.optstore.get_value_for(OptionKey('buildtype')) - assert isinstance(buildtype, str) - debug = self.env.coredata.optstore.get_value_for(OptionKey('debug')) + buildtype = self.env.coredata.optstore.get_value_for(OptionKey('buildtype'), str) + debug = self.env.coredata.optstore.get_value_for(OptionKey('debug'), bool) # `debugoptimized` buildtype may not set debug=True currently, see gh-11645 is_debug_build = debug or buildtype == 'debug' - vscrt_debug = False - if OptionKey('b_vscrt') in self.env.coredata.optstore: - vscrt = self.env.coredata.optstore.get_value_for('b_vscrt') - if vscrt in {'mdd', 'mtd', 'from_buildtype', 'static_from_buildtype'}: - vscrt_debug = True + vscrt = self.env.coredata.optstore.get_value_for(OptionKey('b_vscrt'), str, default='sentinal') + vscrt_debug = vscrt in {'mdd', 'mtd', 'from_buildtype', 'static_from_buildtype'} + if is_debug_build and vscrt_debug and not self.variables.get('Py_DEBUG'): mlog.warning(textwrap.dedent('''\ Using a debug build type with MSVC or an MSVC-compatible compiler diff --git a/mesonbuild/dependencies/qt.py b/mesonbuild/dependencies/qt.py index aa321e92cdd7..0d336d9cf72f 100644 --- a/mesonbuild/dependencies/qt.py +++ b/mesonbuild/dependencies/qt.py @@ -20,6 +20,7 @@ from .factory import DependencyFactory from .. import mlog from .. import mesonlib +from ..options import OptionKey if T.TYPE_CHECKING: from ..compilers.compilers import Compiler @@ -168,7 +169,7 @@ def log_details(self) -> str: return f'modules: {", ".join(sorted(self.requested_modules))}' def _get_common_defines(self) -> T.List[str]: - is_debug = self.env.coredata.optstore.get_value_for('debug') + is_debug = self.env.coredata.optstore.get_value_for(OptionKey('debug'), bool) return ['-DQT_DEBUG' if is_debug else '-DQT_NO_DEBUG'] class QtPkgConfigDependency(_QtBase, PkgConfigDependency, metaclass=abc.ABCMeta): @@ -305,10 +306,8 @@ def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs): # Use the buildtype by default, but look at the b_vscrt option if the # compiler supports it. - is_debug = self.env.coredata.optstore.get_value_for('buildtype') == 'debug' - if 'b_vscrt' in self.env.coredata.optstore: - if self.env.coredata.optstore.get_value_for('b_vscrt') in {'mdd', 'mtd'}: - is_debug = True + is_debug = self.env.coredata.optstore.get_value_for(OptionKey('buildtype'), str) == 'debug' + is_debug |= self.env.coredata.optstore.get_value_for(OptionKey('b_vscrt'), str, default='sentinel') in {'mdd', 'mtd'} modules_lib_suffix = _get_modules_lib_suffix(self.version, self.env.machines[self.for_machine], is_debug) for module in self.requested_modules: diff --git a/mesonbuild/dependencies/scalapack.py b/mesonbuild/dependencies/scalapack.py index 92276ce68b6d..97a1f1c68e90 100644 --- a/mesonbuild/dependencies/scalapack.py +++ b/mesonbuild/dependencies/scalapack.py @@ -27,7 +27,9 @@ def scalapack_factory(env: 'Environment', candidates: T.List['DependencyGenerator'] = [] if DependencyMethods.PKGCONFIG in methods: - static_opt = kwargs['static'] if kwargs.get('static') is not None else env.coredata.optstore.get_value_for(OptionKey('prefer_static')) + static_opt = kwargs['static'] + if static_opt is None: + static_opt = env.coredata.optstore.get_value_for(OptionKey('prefer_static'), bool) mkl = 'mkl-static-lp64-iomp' if static_opt else 'mkl-dynamic-lp64-iomp' candidates.append(DependencyCandidate.from_dependency( mkl, MKLPkgConfigDependency, (env, kwargs))) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index de5daa48b4fb..af4f99cda79e 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -48,11 +48,6 @@ build_filename = 'meson.build' -def _as_str(val: object) -> str: - assert isinstance(val, str), 'for mypy' - return val - - def _get_env_var(for_machine: MachineChoice, is_cross: bool, var_name: str) -> T.Optional[str]: """ Returns the exact env var and the value. @@ -488,25 +483,25 @@ def get_static_lib_dir(self) -> str: return self.get_libdir() def get_prefix(self) -> str: - return _as_str(self.coredata.optstore.get_value_for(OptionKey('prefix'))) + return self.coredata.optstore.get_value_for(OptionKey('prefix'), str) def get_libdir(self) -> str: - return _as_str(self.coredata.optstore.get_value_for(OptionKey('libdir'))) + return self.coredata.optstore.get_value_for(OptionKey('libdir'), str) def get_libexecdir(self) -> str: - return _as_str(self.coredata.optstore.get_value_for(OptionKey('libexecdir'))) + return self.coredata.optstore.get_value_for(OptionKey('libexecdir'), str) def get_bindir(self) -> str: - return _as_str(self.coredata.optstore.get_value_for(OptionKey('bindir'))) + return self.coredata.optstore.get_value_for(OptionKey('bindir'), str) def get_includedir(self) -> str: - return _as_str(self.coredata.optstore.get_value_for(OptionKey('includedir'))) + return self.coredata.optstore.get_value_for(OptionKey('includedir'), str) def get_mandir(self) -> str: - return _as_str(self.coredata.optstore.get_value_for(OptionKey('mandir'))) + return self.coredata.optstore.get_value_for(OptionKey('mandir'), str) def get_datadir(self) -> str: - return _as_str(self.coredata.optstore.get_value_for(OptionKey('datadir'))) + return self.coredata.optstore.get_value_for(OptionKey('datadir'), str) def get_compiler_system_lib_dirs(self, for_machine: MachineChoice) -> T.List[str]: for comp in self.coredata.compilers[for_machine].values(): diff --git a/mesonbuild/interpreter/compiler.py b/mesonbuild/interpreter/compiler.py index b0224db1fe9b..9a85794c40e6 100644 --- a/mesonbuild/interpreter/compiler.py +++ b/mesonbuild/interpreter/compiler.py @@ -699,7 +699,7 @@ def find_library_method(self, args: T.Tuple[str], kwargs: 'FindLibraryKW') -> 'd search_dirs = extract_search_dirs(kwargs) - prefer_static = self.environment.coredata.optstore.get_value_for(OptionKey('prefer_static')) + prefer_static = self.environment.coredata.optstore.get_value_for(OptionKey('prefer_static'), bool) if kwargs['static'] is True: libtype = mesonlib.LibType.STATIC elif kwargs['static'] is False: diff --git a/mesonbuild/interpreter/dependencyfallbacks.py b/mesonbuild/interpreter/dependencyfallbacks.py index 1685cc9de70a..d098a75bc39d 100644 --- a/mesonbuild/interpreter/dependencyfallbacks.py +++ b/mesonbuild/interpreter/dependencyfallbacks.py @@ -322,11 +322,9 @@ def lookup(self, kwargs: DependencyObjectKWs, force_fallback: bool = False) -> D required = kwargs.get('required', True) # Check if usage of the subproject fallback is forced - _wm = self.coredata.optstore.get_value_for(OptionKey('wrap_mode')) - assert isinstance(_wm, str), 'for mypy' + _wm = self.coredata.optstore.get_value_for(OptionKey('wrap_mode'), str) wrap_mode = WrapMode.from_string(_wm) - force_fallback_for = self.coredata.optstore.get_value_for(OptionKey('force_fallback_for')) - assert isinstance(force_fallback_for, list), 'for mypy' + force_fallback_for = self.coredata.optstore.get_value_for(OptionKey('force_fallback_for'), list) self.nofallback = wrap_mode == WrapMode.nofallback self.forcefallback = (force_fallback or wrap_mode == WrapMode.forcefallback or diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index a69b50a7d157..09a0c9d137a3 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -1086,7 +1086,7 @@ def func_get_option(self, node: mparser.BaseNode, args: T.Tuple[str], try: optkey = options.OptionKey.from_string(optname).evolve(subproject=self.subproject) - option_object, value = self.coredata.optstore.get_option_and_value_for(optkey) + option_object, value = self.coredata.optstore.get_option_and_value_for_untyped(optkey) except KeyError: if self.coredata.optstore.is_base_option(optkey): # Due to backwards compatibility return the default @@ -1138,10 +1138,10 @@ def set_backend(self) -> None: if OptionKey('genvslite') in self.user_defined_options.cmd_line_options: # Use of the '--genvslite vsxxxx' option ultimately overrides any '--backend xxx' # option the user may specify. - backend_name = self.coredata.optstore.get_value_for(OptionKey('genvslite')) + backend_name = self.coredata.optstore.get_value_for(OptionKey('genvslite'), str) self.backend = backends.get_genvslite_backend(backend_name, self.build) else: - backend_name = self.coredata.optstore.get_value_for(OptionKey('backend')) + backend_name = self.coredata.optstore.get_value_for(OptionKey('backend'), str) self.backend = backends.get_backend_from_name(backend_name, self.build) if self.backend is None: @@ -1227,10 +1227,8 @@ def func_project(self, node: mparser.FunctionNode, args: T.Tuple[str, T.List[str # self.set_backend() otherwise it wouldn't be able to detect which # vs backend version we need. But after setting default_options in case # the project sets vs backend by default. - backend = self.coredata.optstore.get_value_for(OptionKey('backend')) - assert backend is None or isinstance(backend, str), 'for mypy' - vsenv = self.coredata.optstore.get_value_for(OptionKey('vsenv')) - assert isinstance(vsenv, bool), 'for mypy' + backend = self.coredata.optstore.get_value_for(OptionKey('backend'), str) + vsenv = self.coredata.optstore.get_value_for(OptionKey('vsenv'), bool) force_vsenv = vsenv or backend.startswith('vs') mesonlib.setup_vsenv(force_vsenv) self.set_backend() @@ -1295,7 +1293,7 @@ def func_project(self, node: mparser.FunctionNode, args: T.Tuple[str, T.List[str # Load wrap files from this (sub)project. subprojects_dir = os.path.join(self.subdir, spdirname) if not self.is_subproject(): - wrap_mode = WrapMode.from_string(self.coredata.optstore.get_value_for(OptionKey('wrap_mode'))) + wrap_mode = WrapMode.from_string(self.coredata.optstore.get_value_for(OptionKey('wrap_mode'), str)) self.environment.wrap_resolver = wrap.Resolver(self.environment.get_source_dir(), subprojects_dir, self.subproject, wrap_mode) else: assert self.environment.wrap_resolver is not None, 'for mypy' @@ -1720,7 +1718,7 @@ def program_lookup(self, args: T.List[mesonlib.FileOrString], for_machine: Machi return ExternalProgram('meson', self.environment.get_build_command(), silent=True) fallback = None - wrap_mode = WrapMode.from_string(self.coredata.optstore.get_value_for(OptionKey('wrap_mode'))) + wrap_mode = WrapMode.from_string(self.coredata.optstore.get_value_for(OptionKey('wrap_mode'), str)) 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: @@ -3137,14 +3135,14 @@ def check_clang_asan_lundef(self) -> None: return if OptionKey('b_sanitize') not in self.coredata.optstore: return - if (self.coredata.optstore.get_value_for('b_lundef') and - self.coredata.optstore.get_value_for('b_sanitize')): - value = self.coredata.optstore.get_value_for('b_sanitize') - mlog.warning(textwrap.dedent(f'''\ - Trying to use {value} sanitizer on Clang with b_lundef. - This will probably not work. - Try setting b_lundef to false instead.'''), - location=self.current_node) # noqa: E128 + if self.coredata.optstore.get_value_for(OptionKey('b_lundef'), bool): + value = self.coredata.optstore.get_value_for(OptionKey('b_sanitize'), list) + if value: + mlog.warning(textwrap.dedent(f'''\ + Trying to use {value} sanitizer on Clang with b_lundef. + This will probably not work. + Try setting b_lundef to false instead.'''), + location=self.current_node) # noqa: E128 # Check that the indicated file is within the same subproject # as we currently are. This is to stop people doing @@ -3325,9 +3323,9 @@ def add_target(self, name: str, tobj: build.Target) -> None: def build_both_libraries(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType], kwargs: kwtypes.Library) -> build.BothLibraries: shared_lib = self.build_target(node, args, kwargs, build.SharedLibrary, shared_library_only=False) static_lib = self.build_target(node, args, kwargs, build.StaticLibrary) - preferred_library = self.coredata.optstore.get_value_for(OptionKey('default_both_libraries', subproject=self.subproject)) + preferred_library = self.coredata.optstore.get_value_for(OptionKey('default_both_libraries', subproject=self.subproject), str) if preferred_library == 'auto': - preferred_library = self.coredata.optstore.get_value_for(OptionKey('default_library', subproject=self.subproject)) + preferred_library = self.coredata.optstore.get_value_for(OptionKey('default_library', subproject=self.subproject), str) if preferred_library == 'both': preferred_library = 'shared' @@ -3368,8 +3366,7 @@ def build_both_libraries(self, node: mparser.BaseNode, args: T.Tuple[str, Source return build.BothLibraries(shared_lib, static_lib, preferred_library) def build_library(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType], kwargs: kwtypes.Library): - default_library = self.coredata.optstore.get_value_for(OptionKey('default_library', subproject=self.subproject)) - assert isinstance(default_library, str), 'for mypy' + default_library = self.coredata.optstore.get_value_for(OptionKey('default_library', subproject=self.subproject), str) if default_library == 'shared': return self.build_target(node, args, T.cast('kwtypes.SharedLibrary', kwargs), build.SharedLibrary) elif default_library == 'static': diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index 2399fba0f179..ec6c13a6c7b6 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -27,6 +27,7 @@ from ..dependencies import Dependency, ExternalLibrary, InternalDependency from ..programs import ExternalProgram, Program from ..mesonlib import HoldableObject, listify +from ..options import OptionKey import typing as T @@ -1034,7 +1035,7 @@ def extract_objects_method(self, args: T.Tuple[T.List[T.Union[mesonlib.FileOrStr if self.subproject != self.held_object.subproject: raise InterpreterException('Tried to extract objects from a different subproject.') tobj = self._target_object - unity_value = self.interpreter.coredata.get_option_for_target(tobj, "unity") + unity_value = self.interpreter.coredata.optstore.get_option_for_target(tobj, OptionKey("unity"), str) is_unity = (unity_value == 'on' or (unity_value == 'subprojects' and tobj.subproject != '')) return tobj.extract_objects(args[0], is_unity) diff --git a/mesonbuild/interpreter/mesonmain.py b/mesonbuild/interpreter/mesonmain.py index dafabcbcbca5..5eac73e81a44 100644 --- a/mesonbuild/interpreter/mesonmain.py +++ b/mesonbuild/interpreter/mesonmain.py @@ -307,7 +307,7 @@ def get_compiler_method(self, args: T.Tuple[str], kwargs: 'NativeKW') -> 'Compil @noKwargs @InterpreterObject.method('is_unity') def is_unity_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool: - optval = self.interpreter.environment.coredata.optstore.get_value_for(OptionKey('unity')) + optval = self.interpreter.environment.coredata.optstore.get_value_for(OptionKey('unity'), str) return optval == 'on' or (optval == 'subprojects' and self.interpreter.is_subproject()) @noPosargs @@ -363,8 +363,7 @@ def override_dependency_method(self, args: T.Tuple[str, dependencies.Dependency] dep.name = name optkey = OptionKey('default_library', subproject=self.interpreter.subproject) - default_library = self.interpreter.coredata.optstore.get_value_for(optkey) - assert isinstance(default_library, str), 'for mypy' + default_library = self.interpreter.coredata.optstore.get_value_for(optkey, str) static = kwargs['static'] if static is None: # We don't know if dep represents a static or shared library, could diff --git a/mesonbuild/linkers/detect.py b/mesonbuild/linkers/detect.py index cf6803a19418..9e22ba22da34 100644 --- a/mesonbuild/linkers/detect.py +++ b/mesonbuild/linkers/detect.py @@ -55,7 +55,7 @@ def guess_win_linker(env: 'Environment', compiler: T.List[str], comp_class: T.Ty else: # list check_args = comp_class.LINKER_PREFIX + ['/logo'] + comp_class.LINKER_PREFIX + ['--version'] - check_args += env.coredata.get_external_link_args(for_machine, comp_class.language) + check_args += env.coredata.optstore.get_external_link_args(for_machine, comp_class.language) override: T.List[str] = [] value = env.lookup_binary_entry(for_machine, comp_class.language + '_ld') @@ -130,7 +130,7 @@ def guess_nix_linker(env: 'Environment', compiler: T.List[str], comp_class: T.Ty extra_args = extra_args or [] system = env.machines[for_machine].system - ldflags = env.coredata.get_external_link_args(for_machine, comp_class.language) + ldflags = env.coredata.optstore.get_external_link_args(for_machine, comp_class.language) extra_args += comp_class._unix_args_to_native(ldflags, env.machines[for_machine]) if isinstance(comp_class.LINKER_PREFIX, str): @@ -144,7 +144,7 @@ def guess_nix_linker(env: 'Environment', compiler: T.List[str], comp_class: T.Ty override = comp_class.use_linker_args(value[0], comp_version) check_args += override - if env.machines[for_machine].is_os2() and env.coredata.optstore.get_value_for(OptionKey('os2_emxomf')): + if env.machines[for_machine].is_os2() and env.coredata.optstore.get_value_for(OptionKey('os2_emxomf'), bool): check_args += ['-Zomf'] mlog.debug('-----') diff --git a/mesonbuild/linkers/linkers.py b/mesonbuild/linkers/linkers.py index cb8956adf5be..8b5f6473f908 100644 --- a/mesonbuild/linkers/linkers.py +++ b/mesonbuild/linkers/linkers.py @@ -19,6 +19,7 @@ from ..mesonlib import MachineChoice from ..build import BuildTarget from ..compilers import Compiler + from ..interpreterbase import SubProject class StaticLinker: @@ -80,7 +81,7 @@ def thread_flags(self) -> T.List[str]: def openmp_flags(self) -> T.List[str]: return [] - def get_option_link_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_link_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: return [] @classmethod @@ -195,7 +196,7 @@ def get_lib_prefix(self) -> str: def get_option_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]: return [] - def get_option_link_args(self, target: 'BuildTarget', subproject: T.Optional[str] = None) -> T.List[str]: + def get_option_link_args(self, target: T.Optional[BuildTarget], subproject: T.Optional[SubProject] = None) -> T.List[str]: return [] def has_multi_arguments(self, args: T.List[str]) -> T.Tuple[bool, bool]: diff --git a/mesonbuild/mcompile.py b/mesonbuild/mcompile.py index 72219588ceed..2ef4bdceb1f5 100644 --- a/mesonbuild/mcompile.py +++ b/mesonbuild/mcompile.py @@ -355,15 +355,14 @@ def run(options: 'argparse.Namespace') -> int: b = build.load(options.wd) cdata = b.environment.coredata - need_vsenv = T.cast('bool', cdata.optstore.get_value_for(OptionKey('vsenv'))) + need_vsenv = cdata.optstore.get_value_for(OptionKey('vsenv'), bool) if setup_vsenv(need_vsenv): mlog.log(mlog.green('INFO:'), 'automatically activated MSVC compiler environment') cmd: T.List[str] = [] env: T.Optional[T.Dict[str, str]] = None - backend = cdata.optstore.get_value_for(OptionKey('backend')) - assert isinstance(backend, str) + backend = cdata.optstore.get_value_for(OptionKey('backend'), str) mlog.log(mlog.green('INFO:'), 'autodetecting backend as', backend) if backend == 'ninja': cmd, env = get_parsed_args_ninja(options, bdir) diff --git a/mesonbuild/mdevenv.py b/mesonbuild/mdevenv.py index bd1ed134a529..71af361e85b6 100644 --- a/mesonbuild/mdevenv.py +++ b/mesonbuild/mdevenv.py @@ -98,10 +98,8 @@ def bash_completion_files(b: build.Build, install_data: 'InstallData') -> T.List dep = PkgConfigDependency('bash-completion', b.environment, {'required': False, 'silent': True, 'version': ['>=2.10'], 'native': MachineChoice.HOST}) if dep.found(): - prefix = b.environment.coredata.optstore.get_value_for(OptionKey('prefix')) - assert isinstance(prefix, str), 'for mypy' - datadir = b.environment.coredata.optstore.get_value_for(OptionKey('datadir')) - assert isinstance(datadir, str), 'for mypy' + prefix = b.environment.coredata.optstore.get_value_for(OptionKey('prefix'), str) + datadir = b.environment.coredata.optstore.get_value_for(OptionKey('datadir'), str) datadir_abs = os.path.join(prefix, datadir) completionsdir = dep.get_variable(pkgconfig='completionsdir', pkgconfig_define=(('datadir', datadir_abs),)) assert isinstance(completionsdir, str), 'for mypy' @@ -186,7 +184,7 @@ def run(options: argparse.Namespace) -> int: b = build.load(options.builddir) workdir = options.workdir or options.builddir - need_vsenv = T.cast('bool', b.environment.coredata.optstore.get_value_for(OptionKey('vsenv'))) + need_vsenv = b.environment.coredata.optstore.get_value_for(OptionKey('vsenv'), bool) setup_vsenv(need_vsenv) # Call it before get_env to get vsenv vars as well dump_fmt = options.dump_format if options.dump else None devenv, varnames = get_env(b, dump_fmt) diff --git a/mesonbuild/mdist.py b/mesonbuild/mdist.py index 9fcde5bba06a..7006c4d13e4e 100644 --- a/mesonbuild/mdist.py +++ b/mesonbuild/mdist.py @@ -381,7 +381,7 @@ def run(options: argparse.Namespace) -> int: if not buildfile.is_file(): raise MesonException(f'Directory {options.wd!r} does not seem to be a Meson build directory.') b = build.load(options.wd) - need_vsenv = T.cast('bool', b.environment.coredata.optstore.get_value_for(OptionKey('vsenv'))) + need_vsenv = b.environment.coredata.optstore.get_value_for(OptionKey('vsenv'), bool) setup_vsenv(need_vsenv) src_root = b.environment.source_dir bld_root = b.environment.build_dir diff --git a/mesonbuild/minit.py b/mesonbuild/minit.py index 7d0d051ad7d7..b57b264e0be9 100644 --- a/mesonbuild/minit.py +++ b/mesonbuild/minit.py @@ -193,7 +193,7 @@ def run(options: Arguments) -> int: raise SystemExit b = build.load(options.builddir) - need_vsenv = T.cast('bool', b.environment.coredata.optstore.get_value_for(OptionKey('vsenv'))) + need_vsenv = b.environment.coredata.optstore.get_value_for(OptionKey('vsenv'), bool) vsenv_active = mesonlib.setup_vsenv(need_vsenv) if vsenv_active: mlog.log(mlog.green('INFO:'), 'automatically activated MSVC compiler environment') diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py index e9eb9f070eef..4316a08fcdb1 100644 --- a/mesonbuild/minstall.py +++ b/mesonbuild/minstall.py @@ -870,9 +870,9 @@ def run(opts: 'ArgumentType') -> int: sys.exit('Install data not found. Run this command in build directory root.') if not opts.no_rebuild: b = build.load(opts.wd) - need_vsenv = T.cast('bool', b.environment.coredata.optstore.get_value_for(OptionKey('vsenv'))) + need_vsenv = b.environment.coredata.optstore.get_value_for(OptionKey('vsenv'), bool) setup_vsenv(need_vsenv) - backend = T.cast('str', b.environment.coredata.optstore.get_value_for(OptionKey('backend'))) + backend = b.environment.coredata.optstore.get_value_for(OptionKey('backend'), str) if not rebuild_all(opts.wd, backend): sys.exit(-1) os.chdir(opts.wd) diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index e3fcf217ecf6..d569a78c2444 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -166,7 +166,7 @@ def list_install_plan(installdata: backends.InstallData) -> T.Dict[str, T.Dict[s return plan def get_target_dir(coredata: cdata.CoreData, subdir: str) -> str: - if coredata.optstore.get_value_for(OptionKey('layout')) == 'flat': + if coredata.optstore.get_value_for(OptionKey('layout'), str) == 'flat': return 'meson-out' else: return subdir diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py index 45ca2286f9d0..27e24873b773 100644 --- a/mesonbuild/modules/__init__.py +++ b/mesonbuild/modules/__init__.py @@ -23,7 +23,6 @@ from ..interpreterbase import TYPE_var, TYPE_kwargs from ..programs import Program from ..dependencies import Dependency - from ..options import ElementaryOptionValues class ModuleState: """Object passed to all module methods. @@ -159,10 +158,6 @@ def test(self, args: T.Tuple[str, T.Union[build.Executable, build.Jar, Program, # TODO: Use interpreter internal API, but we need to go through @typed_kwargs self._interpreter.func_test(self.current_node, real_args, kwargs) - def get_option(self, name: str, subproject: str = '', - machine: MachineChoice = MachineChoice.HOST) -> ElementaryOptionValues: - return self.environment.coredata.optstore.get_value_for(OptionKey(name, subproject, machine)) - def is_user_defined_option(self, name: str, subproject: str = '', machine: MachineChoice = MachineChoice.HOST, lang: T.Optional[str] = None) -> bool: diff --git a/mesonbuild/modules/cmake.py b/mesonbuild/modules/cmake.py index 2091499c30a3..5769a51d08ff 100644 --- a/mesonbuild/modules/cmake.py +++ b/mesonbuild/modules/cmake.py @@ -307,8 +307,7 @@ def write_basic_package_version_file(self, state: ModuleState, args: TYPE_var, k pkgroot = pkgroot_name = kwargs['install_dir'] if pkgroot is None: - libdir = state.environment.coredata.optstore.get_value_for(OptionKey('libdir')) - assert isinstance(libdir, str), 'for mypy' + libdir = state.environment.coredata.optstore.get_value_for(OptionKey('libdir'), str) pkgroot = os.path.join(libdir, 'cmake', name) pkgroot_name = os.path.join('{libdir}', 'cmake', name) @@ -380,8 +379,7 @@ def configure_package_config_file(self, state: ModuleState, args: TYPE_var, kwar install_dir = kwargs['install_dir'] if install_dir is None: - libdir = state.environment.coredata.optstore.get_value_for(OptionKey('libdir')) - assert isinstance(libdir, str), 'for mypy' + libdir = state.environment.coredata.optstore.get_value_for(OptionKey('libdir'), str) install_dir = os.path.join(libdir, 'cmake', name) conf = kwargs['configuration'] @@ -389,8 +387,7 @@ def configure_package_config_file(self, state: ModuleState, args: TYPE_var, kwar FeatureNew.single_use('cmake.configure_package_config_file dict as configuration', '0.62.0', state.subproject, location=state.current_node) conf = build.ConfigurationData(conf) - prefix = state.environment.coredata.optstore.get_value_for(OptionKey('prefix')) - assert isinstance(prefix, str), 'for mypy' + prefix = state.environment.coredata.optstore.get_value_for(OptionKey('prefix'), str) 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/external_project.py b/mesonbuild/modules/external_project.py index e8d48ceea0a3..e3626345b861 100644 --- a/mesonbuild/modules/external_project.py +++ b/mesonbuild/modules/external_project.py @@ -76,18 +76,10 @@ def __init__(self, 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') - _p = self.env.coredata.optstore.get_value_for(OptionKey('prefix')) - assert isinstance(_p, str), 'for mypy' - self.prefix = Path(_p) - _l = self.env.coredata.optstore.get_value_for(OptionKey('libdir')) - assert isinstance(_l, str), 'for mypy' - self.libdir = Path(_l) - _l = self.env.coredata.optstore.get_value_for(OptionKey('bindir')) - assert isinstance(_l, str), 'for mypy' - self.bindir = Path(_l) - _i = self.env.coredata.optstore.get_value_for(OptionKey('includedir')) - assert isinstance(_i, str), 'for mypy' - self.includedir = Path(_i) + self.prefix = Path(self.env.coredata.optstore.get_value_for(OptionKey('prefix'), str)) + self.libdir = Path(self.env.coredata.optstore.get_value_for(OptionKey('libdir'), str)) + self.bindir = Path(self.env.coredata.optstore.get_value_for(OptionKey('bindir'), str)) + self.includedir = Path(self.env.coredata.optstore.get_value_for(OptionKey('includedir'), str)) self.name = self.src_dir.name self.prefix = self._cygpath_convert(self.prefix) @@ -156,13 +148,13 @@ def _configure(self, state: 'ModuleState') -> None: for lang, compiler in self.env.coredata.compilers[MachineChoice.HOST].items(): if any(lang not in i for i in (ENV_VAR_PROG_MAP, CFLAGS_MAPPING)): continue - cargs = self.env.coredata.get_external_args(MachineChoice.HOST, lang) + cargs = self.env.coredata.optstore.get_external_args(MachineChoice.HOST, lang) assert isinstance(cargs, list), 'for mypy' self.run_env[ENV_VAR_PROG_MAP[lang][0]] = self._quote_and_join(compiler.get_exelist()) self.run_env[CFLAGS_MAPPING[lang]] = self._quote_and_join(cargs) if not link_exelist: link_exelist = compiler.get_linker_exelist() - _l = self.env.coredata.get_external_link_args(MachineChoice.HOST, lang) + _l = self.env.coredata.optstore.get_external_link_args(MachineChoice.HOST, lang) assert isinstance(_l, list), 'for mypy' link_args = _l if link_exelist: diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 6dec8c43ba87..203b08b32e68 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -1,6 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2015-2016 The Meson development team -# Copyright © 2023-2025 Intel Corporation +# Copyright © 2023-2026 Intel Corporation '''This module provides helper functions for Gnome/GLib related functionality such as gobject-introspection, gresources and gtk-doc''' @@ -41,10 +41,10 @@ from . import ModuleState from ..build import BuildTarget - from ..compilers import Compiler + from ..compilers.compilers import Compiler, Language from ..interpreter import Interpreter from ..interpreterbase import TYPE_var, TYPE_kwargs - from ..mesonlib import FileOrString + from ..mesonlib import EnvironmentVariables, FileOrString from ..programs import Program, CommandList, CommandListEntry class PostInstall(TypedDict): @@ -84,6 +84,7 @@ class GenerateGir(TypedDict): build_by_default: bool dependencies: T.List[Dependency] doc_format: T.Optional[str] + env: EnvironmentVariables export_packages: T.List[str] extra_args: T.List[str] fatal_warnings: bool @@ -92,8 +93,10 @@ class GenerateGir(TypedDict): include_directories: T.List[T.Union[build.IncludeDirs, str]] includes: T.List[T.Union[str, GirTarget]] install: bool - install_dir_gir: T.Optional[str] - install_dir_typelib: T.Optional[str] + install_gir: T.Optional[bool] + install_dir_gir: T.Union[str, None, Literal[False]] + install_typelib: T.Optional[bool] + install_dir_typelib: T.Union[str, None, Literal[False]] link_with: T.List[T.Union[build.SharedLibrary, build.StaticLibrary]] namespace: str nsversion: str @@ -522,8 +525,7 @@ def compile_resources(self, state: 'ModuleState', args: T.Tuple[str, 'FileOrStri if gresource: # Only one target for .gresource files return ModuleReturnValue(target_c, [target_c]) - install_dir = kwargs['install_dir'] or state.environment.coredata.optstore.get_value_for(OptionKey('includedir')) - assert isinstance(install_dir, str), 'for mypy' + install_dir = kwargs['install_dir'] or state.environment.coredata.optstore.get_value_for(OptionKey('includedir'), str) target_h = GResourceHeaderTarget( f'{target_name}_h', state.subdir, @@ -833,11 +835,11 @@ def _scan_include(state: 'ModuleState', includes: T.List[T.Union[str, GirTarget] return ret, gir_inc_dirs, depends @staticmethod - def _scan_langs(state: 'ModuleState', langs: T.Iterable[str]) -> T.List[str]: + def _scan_langs(state: 'ModuleState', langs: T.Iterable[Language]) -> T.List[str]: ret: T.List[str] = [] for lang in langs: - link_args = state.environment.coredata.get_external_link_args(MachineChoice.HOST, lang) + link_args = state.environment.coredata.optstore.get_external_link_args(MachineChoice.HOST, lang) for link_arg in link_args: if link_arg.startswith('-L'): ret.append(link_arg) @@ -879,8 +881,8 @@ def _scan_gir_targets(state: 'ModuleState', girtargets: T.Sequence[build.BuildTa return ret @staticmethod - def _get_girtargets_langs_compilers(girtargets: T.Sequence[build.BuildTarget]) -> T.List[T.Tuple[str, 'Compiler']]: - ret: T.List[T.Tuple[str, 'Compiler']] = [] + def _get_girtargets_langs_compilers(girtargets: T.Sequence[build.BuildTarget]) -> T.List[T.Tuple[Language, 'Compiler']]: + ret: T.List[T.Tuple[Language, 'Compiler']] = [] for girtarget in girtargets: for lang, compiler in girtarget.compilers.items(): # XXX: Can you use g-i with any other language? @@ -907,7 +909,7 @@ def _get_gir_targets_inc_dirs(girtargets: T.Sequence[build.BuildTarget]) -> Orde return ret @staticmethod - def _get_langs_compilers_flags(state: 'ModuleState', langs_compilers: T.List[T.Tuple[str, 'Compiler']] + def _get_langs_compilers_flags(state: 'ModuleState', langs_compilers: T.List[T.Tuple[Language, 'Compiler']] ) -> T.Tuple[T.List[str], T.List[str], T.List[str]]: cflags: T.List[str] = [] internal_ldflags: T.List[str] = [] @@ -919,8 +921,7 @@ def _get_langs_compilers_flags(state: 'ModuleState', langs_compilers: T.List[T.T if state.project_args.get(lang): cflags += state.project_args[lang] if OptionKey('b_sanitize') in compiler.base_options: - sanitize = state.environment.coredata.optstore.get_value_for('b_sanitize') - assert isinstance(sanitize, list) + sanitize = state.environment.coredata.optstore.get_value_for(OptionKey('b_sanitize'), list) cflags += compiler.sanitizer_compile_args(None, sanitize) # These must be first in ldflags if 'address' in sanitize: @@ -972,7 +973,7 @@ def _make_gir_target( generated_files: T.Sequence[T.Union[str, mesonlib.File, build.GeneratedTypes]], depends: T.Sequence[T.Union['FileOrString', build.BuildTarget, 'build.GeneratedTypes', build.StructuredSources]], env_flags: T.Sequence[str], - kwargs: T.Dict[str, T.Any]) -> GirTarget: + kwargs: GenerateGir) -> GirTarget: install = kwargs['install_gir'] if install is None: install = kwargs['install'] @@ -1023,7 +1024,7 @@ def _make_gir_target( def _make_typelib_target(state: 'ModuleState', typelib_output: str, typelib_cmd: T.Sequence[T.Union[str, CustomTarget, Program]], generated_files: T.Sequence[T.Union[str, mesonlib.File, build.GeneratedTypes]], - kwargs: T.Dict[str, T.Any]) -> TypelibTarget: + kwargs: GenerateGir) -> TypelibTarget: install = kwargs['install_typelib'] if install is None: install = kwargs['install'] @@ -1091,10 +1092,10 @@ def _gather_typelib_includes_and_update_depends( return typelib_includes, new_depends @staticmethod - def _get_external_args_for_langs(state: 'ModuleState', langs: T.List[str]) -> T.List[str]: + def _get_external_args_for_langs(state: 'ModuleState', langs: T.List[Language]) -> T.List[str]: ret: T.List[str] = [] for lang in langs: - ret += mesonlib.listify(state.environment.coredata.get_external_args(MachineChoice.HOST, lang)) + ret += mesonlib.listify(state.environment.coredata.optstore.get_external_args(MachineChoice.HOST, lang)) return ret @staticmethod @@ -1183,7 +1184,7 @@ def generate_gir(self, state: 'ModuleState', args: T.Tuple[T.List[T.Union[Execut scan_cflags += list(self._get_scanner_cflags(self._get_external_args_for_langs(state, [lc[0] for lc in langs_compilers]))) scan_internal_ldflags = [] scan_external_ldflags = [] - scan_env_ldflags = state.environment.coredata.get_external_link_args(MachineChoice.HOST, 'c') + scan_env_ldflags = state.environment.coredata.optstore.get_external_link_args(MachineChoice.HOST, 'c') for cli_flags, env_flags in (self._get_scanner_ldflags(internal_ldflags), self._get_scanner_ldflags(dep_internal_ldflags)): scan_internal_ldflags += cli_flags scan_env_ldflags += env_flags @@ -1244,9 +1245,8 @@ def generate_gir(self, state: 'ModuleState', args: T.Tuple[T.List[T.Union[Execut generated_files = [f for f in libsources if isinstance(f, (GeneratedList, CustomTarget, CustomTargetIndex))] scan_target = self._make_gir_target( - state, girfile, scan_command, generated_files, depends, scan_env_ldflags, - # We have to cast here because mypy can't figure this out - T.cast('T.Dict[str, T.Any]', kwargs)) + state, girfile, scan_command, generated_files, depends, + scan_env_ldflags, kwargs) typelib_output = f'{ns}-{nsversion}.typelib' typelib_cmd: T.List[T.Union[str, Program, CustomTarget]] @@ -1256,7 +1256,8 @@ def generate_gir(self, state: 'ModuleState', args: T.Tuple[T.List[T.Union[Execut for incdir in typelib_includes: typelib_cmd += ["--includedir=" + incdir] - typelib_target = self._make_typelib_target(state, typelib_output, typelib_cmd, generated_files, T.cast('T.Dict[str, T.Any]', kwargs)) + typelib_target = self._make_typelib_target( + state, typelib_output, typelib_cmd, generated_files, kwargs) self._devenv_prepend('GI_TYPELIB_PATH', os.path.join(state.environment.get_build_dir(), state.subdir)) @@ -1596,8 +1597,8 @@ def _get_build_args(self, c_args: T.List[str], inc_dirs: T.List[T.Union[str, bui ldflags.extend(internal_ldflags) ldflags.extend(external_ldflags) - cflags.extend(state.environment.coredata.get_external_args(MachineChoice.HOST, 'c')) - ldflags.extend(state.environment.coredata.get_external_link_args(MachineChoice.HOST, 'c')) + cflags.extend(state.environment.coredata.optstore.get_external_args(MachineChoice.HOST, 'c')) + ldflags.extend(state.environment.coredata.optstore.get_external_link_args(MachineChoice.HOST, 'c')) compiler = state.environment.coredata.compilers[MachineChoice.HOST]['c'] compiler_flags = self._get_langs_compilers_flags(state, [('c', compiler)]) @@ -1680,8 +1681,7 @@ def gdbus_codegen(self, state: 'ModuleState', args: T.Tuple[str, T.Optional[T.Un targets = [] install_header = kwargs['install_header'] - install_dir = kwargs['install_dir'] or state.environment.coredata.optstore.get_value_for(OptionKey('includedir')) - assert isinstance(install_dir, str), 'for mypy' + install_dir = kwargs['install_dir'] or state.environment.coredata.optstore.get_value_for(OptionKey('includedir'), str) output = namebase + '.c' # Added in https://gitlab.gnome.org/GNOME/glib/commit/e4d68c7b3e8b01ab1a4231bf6da21d045cb5a816 (2.55.2) @@ -2049,13 +2049,12 @@ def _make_mkenum_impl( cmd: T.List[str], *, install: bool = False, - install_dir: T.Optional[T.Sequence[T.Union[str, bool]]] = None, + install_dir: T.Optional[T.Union[str, Literal[False]]] = None, depends: T.Optional[T.Sequence[build.BuildTargetTypes]] = None ) -> build.CustomTarget: real_cmd: CommandList = [self._find_tool(state, 'glib-mkenums')] real_cmd.extend(cmd) - _install_dir = install_dir or state.environment.coredata.optstore.get_value_for(OptionKey('includedir')) - assert isinstance(_install_dir, str), 'for mypy' + _install_dir = install_dir or state.environment.coredata.optstore.get_value_for(OptionKey('includedir'), str) return CustomTarget( output, @@ -2266,8 +2265,7 @@ def generate_vapi(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'Gener cmd.append(gir_file) vapi_output = library + '.vapi' - datadir = state.environment.coredata.optstore.get_value_for(OptionKey('datadir')) - assert isinstance(datadir, str), 'for mypy' + datadir = state.environment.coredata.optstore.get_value_for(OptionKey('datadir'), str) install_dir = kwargs['install_dir'] or os.path.join(datadir, 'vala', 'vapi') if kwargs['install']: diff --git a/mesonbuild/modules/hotdoc.py b/mesonbuild/modules/hotdoc.py index a45fd57ecafd..7f42a11fac4a 100644 --- a/mesonbuild/modules/hotdoc.py +++ b/mesonbuild/modules/hotdoc.py @@ -303,7 +303,7 @@ def make_targets(self) -> T.Tuple[HotdocTarget, mesonlib.ExecutableSerialisation for path in self.include_paths: self.cmd.extend(['--include-path', path]) - if self.state.environment.coredata.optstore.get_value_for(OptionKey('werror', subproject=self.state.subproject)): + if self.state.environment.coredata.optstore.get_value_for(OptionKey('werror', subproject=self.state.subproject), bool): self.cmd.append('--fatal-warnings') self.generate_hotdoc_config() @@ -329,7 +329,9 @@ def make_targets(self) -> T.Tuple[HotdocTarget, mesonlib.ExecutableSerialisation install_script = None if install: - datadir = os.path.join(self.state.get_option('prefix'), self.state.get_option('datadir')) + datadir = os.path.join( + self.state.environment.coredata.optstore.get_value_for(OptionKey('prefix'), str), + self.state.environment.coredata.optstore.get_value_for(OptionKey('datadir'), str)) devhelp = self.kwargs.get('devhelp_activate', False) if not isinstance(devhelp, bool): FeatureDeprecated.single_use('hotdoc.generate_doc() devhelp_activate must be boolean', '1.1.0', self.state.subproject) diff --git a/mesonbuild/modules/i18n.py b/mesonbuild/modules/i18n.py index db728dbeaa69..760a8c0997ca 100644 --- a/mesonbuild/modules/i18n.py +++ b/mesonbuild/modules/i18n.py @@ -412,8 +412,7 @@ def gettext(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'Gettext') - targets.append(pottarget) install = kwargs['install'] - install_dir = kwargs['install_dir'] or state.environment.coredata.optstore.get_value_for(OptionKey('localedir')) - assert isinstance(install_dir, str), 'for mypy' + install_dir = kwargs['install_dir'] or state.environment.coredata.optstore.get_value_for(OptionKey('localedir'), str) if not languages: languages = read_linguas(path.join(state.environment.source_dir, state.subdir)) for l in languages: diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 332ec33c214a..ddf4a8ce7c47 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -75,11 +75,6 @@ class GenerateKw(TypedDict): ) -def _as_str(obj: object) -> str: - assert isinstance(obj, str) - return obj - - @dataclass class MetaData: @@ -545,7 +540,7 @@ def _generate_pkgconfig_file(self, state: ModuleState, deps: DependenciesHelper, else: pure_path_class = state.environment.machines.host.pure_path_class outdir = state.environment.scratch_dir - prefix = pure_path_class(_as_str(coredata.optstore.get_value_for(OptionKey('prefix')))) + prefix = pure_path_class(coredata.optstore.get_value_for(OptionKey('prefix'), str)) if pkgroot: prefix = self._get_relocatable_prefix(pkgroot, prefix, pure_path_class) # relocatable paths will never have a drive letter @@ -558,7 +553,7 @@ def _generate_pkgconfig_file(self, state: ModuleState, deps: DependenciesHelper, if optname == 'prefix': ofile.write('prefix={}\n'.format(self._escape(prefix))) else: - dirpath = PurePath(_as_str(coredata.optstore.get_value_for(OptionKey(optname)))) + dirpath = PurePath(coredata.optstore.get_value_for(OptionKey(optname), str)) ofile.write('{}={}\n'.format(optname, self._escape('${prefix}' / dirpath))) if uninstalled and not dataonly: ofile.write('srcdir={}\n'.format(self._escape(srcdir))) @@ -779,15 +774,15 @@ def parse_variable_list(vardict: T.Dict[str, str]) -> T.List[T.Tuple[str, str]]: if pkgroot is None: m = state.environment.machines.host if m.is_freebsd(): - pkgroot = os.path.join(_as_str(state.environment.coredata.optstore.get_value_for(OptionKey('prefix'))), 'libdata', 'pkgconfig') + pkgroot = os.path.join(state.environment.coredata.optstore.get_value_for(OptionKey('prefix'), str), 'libdata', 'pkgconfig') pkgroot_name = os.path.join('{prefix}', 'libdata', 'pkgconfig') elif m.is_haiku(): - pkgroot = os.path.join(_as_str(state.environment.coredata.optstore.get_value_for(OptionKey('prefix'))), 'develop', 'lib', 'pkgconfig') + pkgroot = os.path.join(state.environment.coredata.optstore.get_value_for(OptionKey('prefix'), str), 'develop', 'lib', 'pkgconfig') pkgroot_name = os.path.join('{prefix}', 'develop', 'lib', 'pkgconfig') else: - pkgroot = os.path.join(_as_str(state.environment.coredata.optstore.get_value_for(OptionKey('libdir'))), 'pkgconfig') + pkgroot = os.path.join(state.environment.coredata.optstore.get_value_for(OptionKey('libdir'), str), 'pkgconfig') pkgroot_name = os.path.join('{libdir}', 'pkgconfig') - relocatable = state.get_option('pkgconfig.relocatable') + relocatable = state.environment.coredata.optstore.get_value_for(OptionKey('pkgconfig.relocatable'), bool) self._generate_pkgconfig_file(state, deps, subdirs, name, description, url, version, license, pcfile, conflicts, variables, unescaped_variables, False, dataonly, diff --git a/mesonbuild/modules/python.py b/mesonbuild/modules/python.py index 881b54e4ca50..c14f464c4fd6 100644 --- a/mesonbuild/modules/python.py +++ b/mesonbuild/modules/python.py @@ -86,13 +86,13 @@ def _get_path(self, state: T.Optional['ModuleState'], key: str) -> str: if not state: # This happens only from run_project_tests.py return rel_path - value = T.cast('str', state.get_option(f'python.{key}dir')) + value = state.environment.coredata.optstore.get_value_for(OptionKey(f'python.{key}dir'), str) if value: if state.is_user_defined_option('python.install_env'): raise mesonlib.MesonException(f'python.{key}dir and python.install_env are mutually exclusive') return value - install_env = state.get_option('python.install_env') + install_env = state.environment.coredata.optstore.get_value_for(OptionKey('python.install_env'), str) if install_env == 'auto': install_env = 'venv' if self.info['is_venv'] else 'system' @@ -116,8 +116,7 @@ class PythonInstallation(ProgramHolder['PythonExternalProgram']): def __init__(self, python: 'PythonExternalProgram', interpreter: 'Interpreter'): ProgramHolder.__init__(self, python, interpreter) info = python.info - prefix = self.interpreter.environment.coredata.optstore.get_value_for(OptionKey('prefix')) - assert isinstance(prefix, str), 'for mypy' + prefix = self.interpreter.environment.coredata.optstore.get_value_for(OptionKey('prefix'), str) if python.build_config: self.version = python.build_config['language']['version'] @@ -178,7 +177,7 @@ def extension_module_method(self, args: T.Tuple[str, T.List[BuildTargetSource]], self.current_node) limited_api_version = kwargs.pop('limited_api') - allow_limited_api = self.interpreter.environment.coredata.optstore.get_value_for(OptionKey('python.allow_limited_api')) + allow_limited_api = self.interpreter.environment.coredata.optstore.get_value_for(OptionKey('python.allow_limited_api'), bool) if limited_api_version != '' and allow_limited_api: target_suffix = self.limited_api_suffix @@ -217,7 +216,7 @@ def extension_module_method(self, args: T.Tuple[str, T.List[BuildTargetSource]], new_link_args = mesonlib.extract_as_list(kwargs, 'link_args') - is_debug = self.interpreter.environment.coredata.optstore.get_value_for('debug') + is_debug = self.interpreter.environment.coredata.optstore.get_value_for(OptionKey('debug'), bool) if is_debug: new_link_args.append(python_windows_debug_link_exception) else: @@ -266,7 +265,7 @@ def _dependency_method_impl(self, kwargs: DependencyObjectKWs) -> Dependency: if dep is not None: return dep - build_config = self.interpreter.environment.coredata.optstore.get_value_for(OptionKey('python.build_config')) + build_config = self.interpreter.environment.coredata.optstore.get_value_for(OptionKey('python.build_config'), str) new_kwargs = kwargs.copy() new_kwargs['required'] = False @@ -402,7 +401,7 @@ def __init__(self, interpreter: 'Interpreter') -> None: def _get_install_scripts(self) -> T.List[mesonlib.ExecutableSerialisation]: backend = self.interpreter.backend ret = [] - optlevel = self.interpreter.environment.coredata.optstore.get_value_for(OptionKey('python.bytecompile')) + optlevel = self.interpreter.environment.coredata.optstore.get_value_for(OptionKey('python.bytecompile'), int) if optlevel == -1: return ret if not any(PythonExternalProgram.run_bytecompile.values()): @@ -469,7 +468,7 @@ def _get_win_pythonpath(name_or_path: str) -> T.Optional[str]: return None def _find_installation_impl(self, state: 'ModuleState', display_name: str, name_or_path: str, required: bool) -> MaybePythonProg: - build_config = self.interpreter.environment.coredata.optstore.get_value_for(OptionKey('python.build_config')) + build_config = self.interpreter.environment.coredata.optstore.get_value_for(OptionKey('python.build_config'), str) if not name_or_path: python = PythonExternalProgram('python3', mesonlib.python_command, build_config_path=build_config) diff --git a/mesonbuild/modules/rust.py b/mesonbuild/modules/rust.py index 4873843c0d9c..16ccd2bc592f 100644 --- a/mesonbuild/modules/rust.py +++ b/mesonbuild/modules/rust.py @@ -27,6 +27,7 @@ from ..interpreter.interpreterobjects import Doctest from ..mesonlib import (is_parent_path, File, MachineChoice, MesonException, PerMachine) from ..programs import ExternalProgram, NonExistingExternalProgram +from ..options import OptionKey if T.TYPE_CHECKING: from . import ModuleState @@ -873,8 +874,7 @@ def bindgen(self, state: ModuleState, args: T.List, kwargs: FuncBindgen) -> Modu raise InterpreterException(f'Unknown file type extension for: {name}') # We only want include directories and defines, other things may not be valid - cargs = state.get_option(f'{language}_args', state.subproject) - assert isinstance(cargs, list), 'for mypy' + cargs = state.environment.coredata.optstore.get_value_for(OptionKey(f'{language}_args', state.subproject), list) for a in itertools.chain(state.global_args.get(language, []), state.project_args.get(language, []), cargs): if a.startswith(('-I', '/I', '-D', '/D', '-U', '/U')): clang_args.append(a) @@ -884,8 +884,7 @@ def bindgen(self, state: ModuleState, args: T.List, kwargs: FuncBindgen) -> Modu # Add the C++ standard to the clang arguments. Attempt to translate VS # extension versions into the nearest standard version - std = state.get_option(f'{language}_std') - assert isinstance(std, str), 'for mypy' + std = state.environment.coredata.optstore.get_value_for(OptionKey(f'{language}_std'), str) if std.startswith('vc++'): if std.endswith('latest'): mlog.warning('Attempting to translate vc++latest into a clang compatible version.', @@ -922,11 +921,7 @@ def bindgen(self, state: ModuleState, args: T.List, kwargs: FuncBindgen) -> Modu if self._bindgen_rust_target and '--rust-target' not in cmd: cmd.extend(['--rust-target', self._bindgen_rust_target]) if self._bindgen_set_std and '--rust-edition' not in cmd: - try: - rust_std = state.environment.coredata.optstore.get_value_for('rust_std') - except KeyError: - rust_std = 'none' - assert isinstance(rust_std, str), 'for mypy' + rust_std = state.environment.coredata.optstore.get_value_for(OptionKey('rust_std'), str, default='none') if rust_std != 'none': cmd.extend(['--rust-edition', rust_std]) cmd.append('--') diff --git a/mesonbuild/modules/snippets.py b/mesonbuild/modules/snippets.py index bfc8d7ab7e09..611e5c66b562 100644 --- a/mesonbuild/modules/snippets.py +++ b/mesonbuild/modules/snippets.py @@ -22,6 +22,7 @@ from ..interpreterbase import KwargInfo, typed_kwargs, typed_pos_args from ..interpreter.type_checking import NoneType from .. import mesonlib +from ..options import OptionKey if T.TYPE_CHECKING: from typing_extensions import TypedDict @@ -63,7 +64,7 @@ def symbol_visibility_header_method(self, state: ModuleState, args: T.Tuple[str] static_compilation = kwargs['static_compilation'] or f'{namespace}_STATIC_COMPILATION' static_only = kwargs['static_only'] if static_only is None: - default_library = state.get_option('default_library') + default_library = state.environment.coredata.optstore.get_value_for(OptionKey('default_library'), str) static_only = default_library == 'static' content = textwrap.dedent('''\ // SPDX-license-identifier: 0BSD OR CC0-1.0 OR WTFPL OR Apache-2.0 OR LGPL-2.0-or-later diff --git a/mesonbuild/msetup.py b/mesonbuild/msetup.py index df06245a394c..e22f3525e2ab 100644 --- a/mesonbuild/msetup.py +++ b/mesonbuild/msetup.py @@ -306,9 +306,9 @@ def _generate(self, env: environment.Environment, capture: bool, vslite_ctx: T.O # collect warnings about unsupported build configurations; must be done after full arg processing # by Interpreter() init, but this is most visible at the end - if env.coredata.optstore.get_value_for('backend') == 'xcode': + if env.coredata.optstore.get_value_for(OptionKey('backend'), str) == 'xcode': mlog.warning('xcode backend is currently unmaintained, patches welcome') - if env.coredata.optstore.get_value_for('layout') == 'flat': + if env.coredata.optstore.get_value_for(OptionKey('layout'), str) == 'flat': mlog.warning('-Dlayout=flat is unsupported and probably broken. It was a failed experiment at ' 'making Windows build artifacts runnable while uninstalled, due to PATH considerations, ' 'but was untested by CI and anyways breaks reasonable use of conflicting targets in different subdirs. ' diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py index aca4e23b41b3..8586b9f45946 100644 --- a/mesonbuild/mtest.py +++ b/mesonbuild/mtest.py @@ -2296,11 +2296,11 @@ def run(options: argparse.Namespace) -> int: return 1 b = build.load(options.wd) - need_vsenv = T.cast('bool', b.environment.coredata.optstore.get_value_for(OptionKey('vsenv'))) + need_vsenv = b.environment.coredata.optstore.get_value_for(OptionKey('vsenv'), bool) setup_vsenv(need_vsenv) if not options.no_rebuild: - backend = b.environment.coredata.optstore.get_value_for(OptionKey('backend')) + backend = b.environment.coredata.optstore.get_value_for(OptionKey('backend'), str) if backend == 'none': # nothing to build... options.no_rebuild = True diff --git a/mesonbuild/munstable_coredata.py b/mesonbuild/munstable_coredata.py index b647dd8fcfb4..fea6c909b9d3 100644 --- a/mesonbuild/munstable_coredata.py +++ b/mesonbuild/munstable_coredata.py @@ -53,7 +53,7 @@ def run(options): print('') coredata = cdata.load(options.builddir) - backend = coredata.optstore.get_value_for(OptionKey('backend')) + backend = coredata.optstore.get_value_for(OptionKey('backend'), str) 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/options.py b/mesonbuild/options.py index 8a831ad520f2..26dbfe6cd3bc 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -4,6 +4,7 @@ from __future__ import annotations from collections import OrderedDict +from functools import lru_cache from itertools import chain import copy import dataclasses @@ -35,6 +36,7 @@ if T.TYPE_CHECKING: from typing_extensions import Literal, Final, TypeAlias + from .build import BuildTarget from .envconfig import MachineInfo from .interpreterbase import SubProject from .compilers.compilers import Language @@ -45,6 +47,7 @@ 'UserIntegerOption', 'UserStdOption', 'UserStringArrayOption', 'UserStringOption', 'UserUmaskOption'] ElementaryOptionValues: TypeAlias = T.Union[str, int, bool, T.List[str]] + ElementaryOptionType = T.TypeVar('ElementaryOptionType', str, int, bool, T.List[str]) MutableKeyedOptionDictType: TypeAlias = T.Dict['OptionKey', AnyOptionType] _OptionKeyTuple: TypeAlias = T.Tuple[T.Optional[str], MachineChoice, str] @@ -858,7 +861,7 @@ def resolve_option(self, key: 'T.Union[OptionKey, str]') -> AnyOptionType: return self.options[parent_key] return potential - def get_option_and_value_for(self, key: OptionKey) -> T.Tuple[AnyOptionType, ElementaryOptionValues]: + def get_option_and_value_for_untyped(self, key: OptionKey) -> T.Tuple[AnyOptionType, ElementaryOptionValues]: assert isinstance(key, OptionKey) key = self.ensure_and_validate_key(key) option_object = self.resolve_option(key) @@ -871,18 +874,81 @@ def get_option_and_value_for(self, key: OptionKey) -> T.Tuple[AnyOptionType, Ele return (option_object, computed_value) def option_has_value(self, key: OptionKey, value: ElementaryOptionValues) -> bool: - option_object, current_value = self.get_option_and_value_for(key) + option_object, current_value = self.get_option_and_value_for_untyped(key) return option_object.validate_value(value) == current_value - def get_value_for(self, name: 'T.Union[OptionKey, str]', subproject: T.Optional[str] = None) -> ElementaryOptionValues: + def get_value_for_untyped(self, name: 'T.Union[OptionKey, str]', subproject: T.Optional[str] = None) -> ElementaryOptionValues: if isinstance(name, str): key = OptionKey(name, subproject) else: assert subproject is None key = name - _, resolved_value = self.get_option_and_value_for(key) + _, resolved_value = self.get_option_and_value_for_untyped(key) return resolved_value + def get_value_for(self, key: OptionKey, type_: T.Type[ElementaryOptionType], + *, default: T.Optional[ElementaryOptionType] = None) -> ElementaryOptionType: + try: + val = self.get_value_for_untyped(key) + except KeyError: + if default is not None: + return default + raise + if not isinstance(val, type_): + raise MesonBugException(f'Expected {key!s} to have type {type_!s}, but had type {type(val)!s}') + return val + + def get_option_for_target_untyped(self, target: 'BuildTarget', key: T.Union[str, OptionKey]) -> ElementaryOptionValues: + if isinstance(key, str): + assert ':' not in key + newkey = OptionKey(key, target.subproject) + else: + newkey = key + if newkey.subproject != target.subproject: + # FIXME: this should be an error. The caller needs to ensure that + # key and target have the same subproject for consistency. + # Now just do this to get things going. + newkey = newkey.evolve(subproject=target.subproject) + if self.is_cross: + newkey = newkey.evolve(machine=target.for_machine) + option_object, value = self.get_option_and_value_for_untyped(newkey) + override = target.get_override(newkey.name) + if override is not None: + try: + return option_object.validate_value(override) + except MesonException as e: + raise MesonException(f'In override_options for {target}: {e!s}') + return value + + def get_option_for_target(self, target: 'BuildTarget', key: OptionKey, + type_: T.Type[ElementaryOptionType], + *, default: T.Optional[ElementaryOptionType] = None) -> ElementaryOptionType: + try: + val = self.get_option_for_target_untyped(target, key) + except KeyError: + if default is not None: + return default + raise + if not isinstance(val, type_): + raise MesonBugException(f'Expected {key!s} to have type {type_!s}, but had type {type(val)!s}') + return val + + def get_option_for_maybe_target(self, target: T.Optional[BuildTarget], key: OptionKey, + type_: T.Type[ElementaryOptionType], + *, default: T.Optional[ElementaryOptionType] = None) -> ElementaryOptionType: + if target is not None: + return self.get_option_for_target(target, key, type_, default=default) + return self.get_value_for(key, type_, default=default) + + def get_external_args(self, for_machine: MachineChoice, lang: Language) -> T.List[str]: + key = OptionKey(f'{lang}_args', machine=for_machine) + return self.get_value_for(key, list) + + @lru_cache(maxsize=None) + def get_external_link_args(self, for_machine: MachineChoice, lang: Language) -> T.List[str]: + linkkey = OptionKey(f'{lang}_link_args', machine=for_machine) + return self.get_value_for(linkkey, list) + def add_system_option(self, key: T.Union[OptionKey, str], valobj: AnyOptionType) -> None: key = self.ensure_and_validate_key(key) if '.' in key.name: @@ -1023,8 +1089,7 @@ def set_option(self, key: OptionKey, new_value: ElementaryOptionValues, first_in assert isinstance(new_value, str), 'for mypy' new_value = self.sanitize_prefix(new_value) elif self.is_builtin_option(key): - prefix = self.get_value_for('prefix') - assert isinstance(prefix, str), 'for mypy' + prefix = self.get_value_for(OptionKey('prefix'), str) new_value = self.sanitize_dir_option_value(prefix, key, new_value) try: diff --git a/mesonbuild/scripts/regen_checker.py b/mesonbuild/scripts/regen_checker.py index 9874607334e6..ff10f9ceb199 100644 --- a/mesonbuild/scripts/regen_checker.py +++ b/mesonbuild/scripts/regen_checker.py @@ -44,8 +44,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.optstore.get_value_for(OptionKey('backend')) - assert isinstance(backend, str) + backend = coredata.optstore.get_value_for(OptionKey('backend'), str) regen_timestamp = os.stat(dumpfile).st_mtime if need_regen(regeninfo, regen_timestamp): regen(regeninfo, coredata.meson_command, backend) diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index 8026d9d95562..404316f62dbd 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -2781,35 +2781,35 @@ def test_command_line(self): out = self.init(testdir, extra_args=['--profile-self', '--fatal-meson-warnings']) self.assertNotIn('[default: true]', out) obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.optstore.get_value_for('default_library'), 'static') - self.assertEqual(obj.optstore.get_value_for('warning_level'), '1') - self.assertEqual(obj.optstore.get_value_for(OptionKey('set_sub_opt', '')), True) - self.assertEqual(obj.optstore.get_value_for(OptionKey('subp_opt', 'subp')), 'default3') + self.assertEqual(obj.optstore.get_value_for_untyped('default_library'), 'static') + self.assertEqual(obj.optstore.get_value_for_untyped('warning_level'), '1') + self.assertEqual(obj.optstore.get_value_for_untyped(OptionKey('set_sub_opt', '')), True) + self.assertEqual(obj.optstore.get_value_for_untyped(OptionKey('subp_opt', 'subp')), '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.optstore.get_value_for('warning_level'), '2') + self.assertEqual(obj.optstore.get_value_for_untyped('warning_level'), '2') self.setconf('--warnlevel=3') obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.optstore.get_value_for('warning_level'), '3') + self.assertEqual(obj.optstore.get_value_for_untyped('warning_level'), '3') self.setconf('--warnlevel=everything') obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.optstore.get_value_for('warning_level'), 'everything') + self.assertEqual(obj.optstore.get_value_for_untyped('warning_level'), 'everything') 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.optstore.get_value_for('warning_level'), '2') + self.assertEqual(obj.optstore.get_value_for_untyped('warning_level'), '2') self.setconf('-Dwarning_level=3') obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.optstore.get_value_for('warning_level'), '3') + self.assertEqual(obj.optstore.get_value_for_untyped('warning_level'), '3') self.setconf('-Dwarning_level=everything') obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.optstore.get_value_for('warning_level'), 'everything') + self.assertEqual(obj.optstore.get_value_for_untyped('warning_level'), 'everything') self.wipe() # Mixing --option and -Doption is forbidden @@ -2833,15 +2833,15 @@ def test_command_line(self): # --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.optstore.get_value_for('default_library'), 'both') + self.assertEqual(obj.optstore.get_value_for_untyped('default_library'), 'both') self.setconf('--default-library=shared') obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.optstore.get_value_for('default_library'), 'shared') + self.assertEqual(obj.optstore.get_value_for_untyped('default_library'), '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.optstore.get_value_for('default_library'), 'shared') + self.assertEqual(obj.optstore.get_value_for_untyped('default_library'), 'shared') self.wipe() # Should fail on unknown options @@ -2878,22 +2878,22 @@ def test_command_line(self): # 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.optstore.get_value_for(OptionKey('subp_opt', 'subp')), 'foo') + self.assertEqual(obj.optstore.get_value_for_untyped(OptionKey('subp_opt', 'subp')), '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.optstore.get_value_for(OptionKey('c_args')), ['-Dfoo', '-Dbar', '-Dthird=one two']) + self.assertEqual(obj.optstore.get_value_for_untyped(OptionKey('c_args')), ['-Dfoo', '-Dbar', '-Dthird=one two']) self.setconf('-Dc_args="foo bar" one two') obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.optstore.get_value_for(OptionKey('c_args')), ['foo bar', 'one', 'two']) + self.assertEqual(obj.optstore.get_value_for_untyped(OptionKey('c_args')), ['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.optstore.get_value_for(OptionKey('set_percent_opt', '')), 'myoption%') + self.assertEqual(obj.optstore.get_value_for_untyped(OptionKey('set_percent_opt', '')), 'myoption%') self.wipe() # Setting a 2nd time the same option should override the first value @@ -2904,19 +2904,19 @@ def test_command_line(self): '-Dc_args=-Dfoo', '-Dc_args=-Dbar', '-Db_lundef=false', '--fatal-meson-warnings']) obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.optstore.get_value_for('bindir'), 'bar') - self.assertEqual(obj.optstore.get_value_for('buildtype'), 'release') - self.assertEqual(obj.optstore.get_value_for('b_sanitize'), ['thread']) - self.assertEqual(obj.optstore.get_value_for(OptionKey('c_args')), ['-Dbar']) + self.assertEqual(obj.optstore.get_value_for_untyped('bindir'), 'bar') + self.assertEqual(obj.optstore.get_value_for_untyped('buildtype'), 'release') + self.assertEqual(obj.optstore.get_value_for_untyped('b_sanitize'), ['thread']) + self.assertEqual(obj.optstore.get_value_for_untyped(OptionKey('c_args')), ['-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.optstore.get_value_for('bindir'), 'foo') - self.assertEqual(obj.optstore.get_value_for('buildtype'), 'plain') - self.assertEqual(obj.optstore.get_value_for('b_sanitize'), ['address']) - self.assertEqual(obj.optstore.get_value_for(OptionKey('c_args')), ['-Dfoo']) + self.assertEqual(obj.optstore.get_value_for_untyped('bindir'), 'foo') + self.assertEqual(obj.optstore.get_value_for_untyped('buildtype'), 'plain') + self.assertEqual(obj.optstore.get_value_for_untyped('b_sanitize'), ['address']) + self.assertEqual(obj.optstore.get_value_for_untyped(OptionKey('c_args')), ['-Dfoo']) self.wipe() except KeyError: # Ignore KeyError, it happens on CI for compilers that does not @@ -2930,25 +2930,25 @@ def test_warning_level_0(self): # Verify default values when passing no args self.init(testdir) obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.optstore.get_value_for('warning_level'), '0') + self.assertEqual(obj.optstore.get_value_for_untyped('warning_level'), '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.optstore.get_value_for('warning_level'), '1') + self.assertEqual(obj.optstore.get_value_for_untyped('warning_level'), '1') self.setconf('--warnlevel=0') obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.optstore.get_value_for('warning_level'), '0') + self.assertEqual(obj.optstore.get_value_for_untyped('warning_level'), '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.optstore.get_value_for('warning_level'), '1') + self.assertEqual(obj.optstore.get_value_for_untyped('warning_level'), '1') self.setconf('-Dwarning_level=0') obj = mesonbuild.coredata.load(self.builddir) - self.assertEqual(obj.optstore.get_value_for('warning_level'), '0') + self.assertEqual(obj.optstore.get_value_for_untyped('warning_level'), '0') self.wipe() def test_feature_check_usage_subprojects(self): @@ -4806,10 +4806,10 @@ def test_env_flags_to_linker(self) -> None: # C does have a separate linking step. It can be done through the compiler # driver or not; act accordingly. if cc.USED_FOR_SEPARATE_LINKING_STEP: - link_args = env.coredata.get_external_link_args(cc.for_machine, cc.language) + link_args = env.coredata.optstore.get_external_link_args(cc.for_machine, cc.language) self.assertEqual(sorted(link_args), sorted(['-DCFLAG', '-flto'])) else: - link_args = env.coredata.get_external_link_args(cc.for_machine, cc.language) + link_args = env.coredata.optstore.get_external_link_args(cc.for_machine, cc.language) self.assertEqual(sorted(link_args), sorted(['-flto'])) def test_install_tag(self) -> None: diff --git a/unittests/datatests.py b/unittests/datatests.py index e529e4e5b8fc..fc6f61ed0f89 100644 --- a/unittests/datatests.py +++ b/unittests/datatests.py @@ -168,9 +168,9 @@ def remove_module_name(key: OptionKey) -> OptionKey: else: raise RuntimeError(f'Invalid debug value {debug!r} in row:\n{m.group()}') env.coredata.optstore.set_option(OptionKey('buildtype'), buildtype) - self.assertEqual(env.coredata.optstore.get_value_for('buildtype'), buildtype) - self.assertEqual(env.coredata.optstore.get_value_for('optimization'), opt) - self.assertEqual(env.coredata.optstore.get_value_for('debug'), debug) + self.assertEqual(env.coredata.optstore.get_value_for_untyped('buildtype'), buildtype) + self.assertEqual(env.coredata.optstore.get_value_for_untyped('optimization'), opt) + self.assertEqual(env.coredata.optstore.get_value_for_untyped('debug'), debug) def test_cpu_families_documented(self): with open("docs/markdown/Reference-tables.md", encoding='utf-8') as f: diff --git a/unittests/linuxliketests.py b/unittests/linuxliketests.py index a79bd6d767ee..6e2b3c33a2d4 100644 --- a/unittests/linuxliketests.py +++ b/unittests/linuxliketests.py @@ -1179,7 +1179,7 @@ def test_pkgconfig_duplicate_path_entries(self): # option, adding the meson-uninstalled directory to it. PkgConfigInterface.setup_env({}, env, MachineChoice.HOST, uninstalled=True) - pkg_config_path = env.coredata.optstore.get_value_for('pkg_config_path') + pkg_config_path = env.coredata.optstore.get_value_for_untyped('pkg_config_path') self.assertEqual(pkg_config_path, [pkg_dir]) def test_pkgconfig_uninstalled_env_added(self): diff --git a/unittests/optiontests.py b/unittests/optiontests.py index 3af71b67c0c4..a1e508254601 100644 --- a/unittests/optiontests.py +++ b/unittests/optiontests.py @@ -3,7 +3,9 @@ from mesonbuild.options import * from mesonbuild.envconfig import MachineInfo +from mesonbuild.build import BuildTarget +from unittest import mock import os import unittest @@ -25,9 +27,9 @@ def test_basic(self): new_value = 'new_value' vo = UserStringOption(name, 'An option of some sort', default_value) optstore.add_system_option(name, vo) - self.assertEqual(optstore.get_value_for(name), default_value) + self.assertEqual(optstore.get_value_for_untyped(name), default_value) optstore.set_option(OptionKey.from_string(name), new_value) - self.assertEqual(optstore.get_value_for(name), new_value) + self.assertEqual(optstore.get_value_for_untyped(name), new_value) def test_toplevel_project(self): optstore = OptionStore(False) @@ -37,9 +39,9 @@ def test_toplevel_project(self): k = OptionKey(name) vo = UserStringOption(k.name, 'An option of some sort', default_value) optstore.add_system_option(k.name, vo) - self.assertEqual(optstore.get_value_for(k), default_value) + self.assertEqual(optstore.get_value_for_untyped(k), default_value) optstore.initialize_from_top_level_project_call({OptionKey('someoption'): new_value}, {}, {}) - self.assertEqual(optstore.get_value_for(k), new_value) + self.assertEqual(optstore.get_value_for_untyped(k), new_value) def test_machine_vs_project(self): optstore = OptionStore(False) @@ -52,10 +54,10 @@ def test_machine_vs_project(self): optstore.add_system_option('prefix', prefix) vo = UserStringOption(k.name, 'You know what this is', default_value) optstore.add_system_option(k.name, vo) - self.assertEqual(optstore.get_value_for(k), default_value) + self.assertEqual(optstore.get_value_for_untyped(k), default_value) optstore.initialize_from_top_level_project_call({OptionKey(name): proj_value}, {}, {OptionKey(name): mfile_value}) - self.assertEqual(optstore.get_value_for(k), mfile_value) + self.assertEqual(optstore.get_value_for_untyped(k), mfile_value) def test_subproject_system_option(self): """Test that subproject system options get their default value from the global @@ -69,7 +71,7 @@ def test_subproject_system_option(self): optstore.initialize_from_top_level_project_call({}, {}, {OptionKey(name): new_value}) vo = UserStringOption(k.name, 'An option of some sort', default_value) optstore.add_system_option(subk, vo) - self.assertEqual(optstore.get_value_for(subk), new_value) + self.assertEqual(optstore.get_value_for_untyped(subk), new_value) def test_parsing(self): with self.subTest('subproject'): @@ -96,7 +98,7 @@ def test_subproject_for_system(self): default_value = 'somevalue' vo = UserStringOption(name, 'An option of some sort', default_value) optstore.add_system_option(name, vo) - self.assertEqual(optstore.get_value_for(name, 'somesubproject'), default_value) + self.assertEqual(optstore.get_value_for_untyped(name, 'somesubproject'), default_value) def test_reset(self): optstore = OptionStore(False) @@ -105,11 +107,11 @@ def test_reset(self): reset_value = 'reset' vo = UserStringOption(name, 'An option set twice', original_value) optstore.add_system_option(name, vo) - self.assertEqual(optstore.get_value_for(name), original_value) + self.assertEqual(optstore.get_value_for_untyped(name), original_value) self.assertEqual(num_options(optstore), 1) vo2 = UserStringOption(name, 'An option set twice', reset_value) optstore.add_system_option(name, vo2) - self.assertEqual(optstore.get_value_for(name), original_value) + self.assertEqual(optstore.get_value_for_untyped(name), original_value) self.assertEqual(num_options(optstore), 1) def test_project_nonyielding(self): @@ -119,12 +121,12 @@ def test_project_nonyielding(self): sub_value = 'sub' vo = UserStringOption(name, 'A top level option', top_value, False) optstore.add_project_option(OptionKey(name, ''), vo) - self.assertEqual(optstore.get_value_for(name, ''), top_value, False) + self.assertEqual(optstore.get_value_for_untyped(name, ''), top_value, False) self.assertEqual(num_options(optstore), 1) vo2 = UserStringOption(name, 'A subproject option', sub_value) optstore.add_project_option(OptionKey(name, 'sub'), vo2) - self.assertEqual(optstore.get_value_for(name, ''), top_value) - self.assertEqual(optstore.get_value_for(name, 'sub'), sub_value) + self.assertEqual(optstore.get_value_for_untyped(name, ''), top_value) + self.assertEqual(optstore.get_value_for_untyped(name, 'sub'), sub_value) self.assertEqual(num_options(optstore), 2) def test_toplevel_project_yielding(self): @@ -133,7 +135,7 @@ def test_toplevel_project_yielding(self): top_value = 'top' vo = UserStringOption(name, 'A top level option', top_value, True) optstore.add_project_option(OptionKey(name, ''), vo) - self.assertEqual(optstore.get_value_for(name, ''), top_value) + self.assertEqual(optstore.get_value_for_untyped(name, ''), top_value) def test_project_yielding(self): optstore = OptionStore(False) @@ -142,12 +144,12 @@ def test_project_yielding(self): sub_value = 'sub' vo = UserStringOption(name, 'A top level option', top_value) optstore.add_project_option(OptionKey(name, ''), vo) - self.assertEqual(optstore.get_value_for(name, ''), top_value) + self.assertEqual(optstore.get_value_for_untyped(name, ''), top_value) self.assertEqual(num_options(optstore), 1) vo2 = UserStringOption(name, 'A subproject option', sub_value, True) optstore.add_project_option(OptionKey(name, 'sub'), vo2) - self.assertEqual(optstore.get_value_for(name, ''), top_value) - self.assertEqual(optstore.get_value_for(name, 'sub'), top_value) + self.assertEqual(optstore.get_value_for_untyped(name, ''), top_value) + self.assertEqual(optstore.get_value_for_untyped(name, 'sub'), top_value) self.assertEqual(num_options(optstore), 2) def test_project_yielding_not_defined_in_top_project(self): @@ -158,12 +160,12 @@ def test_project_yielding_not_defined_in_top_project(self): sub_value = 'sub' vo = UserStringOption(top_name, 'A top level option', top_value) optstore.add_project_option(OptionKey(top_name, ''), vo) - self.assertEqual(optstore.get_value_for(top_name, ''), top_value) + self.assertEqual(optstore.get_value_for_untyped(top_name, ''), top_value) self.assertEqual(num_options(optstore), 1) vo2 = UserStringOption(sub_name, 'A subproject option', sub_value, True) optstore.add_project_option(OptionKey(sub_name, 'sub'), vo2) - self.assertEqual(optstore.get_value_for(top_name, ''), top_value) - self.assertEqual(optstore.get_value_for(sub_name, 'sub'), sub_value) + self.assertEqual(optstore.get_value_for_untyped(top_name, ''), top_value) + self.assertEqual(optstore.get_value_for_untyped(sub_name, 'sub'), sub_value) self.assertEqual(num_options(optstore), 2) def test_project_yielding_initialize(self): @@ -177,18 +179,18 @@ def test_project_yielding_initialize(self): vo = UserStringOption(name, 'A top level option', 'default1') optstore.add_project_option(OptionKey(name, ''), vo) optstore.initialize_from_top_level_project_call({}, cmd_line, {}) - self.assertEqual(optstore.get_value_for(name, ''), top_value) + self.assertEqual(optstore.get_value_for_untyped(name, ''), top_value) self.assertEqual(num_options(optstore), 1) vo2 = UserStringOption(name, 'A subproject option', 'default2', True) optstore.add_project_option(OptionKey(name, 'subp'), vo2) - self.assertEqual(optstore.get_value_for(name, ''), top_value) - self.assertEqual(optstore.get_value_for(name, subp), top_value) + self.assertEqual(optstore.get_value_for_untyped(name, ''), top_value) + self.assertEqual(optstore.get_value_for_untyped(name, subp), top_value) self.assertEqual(num_options(optstore), 2) optstore.initialize_from_subproject_call(subp, {}, {}, cmd_line, {}) - self.assertEqual(optstore.get_value_for(name, ''), top_value) - self.assertEqual(optstore.get_value_for(name, subp), sub_value) + self.assertEqual(optstore.get_value_for_untyped(name, ''), top_value) + self.assertEqual(optstore.get_value_for_untyped(name, subp), sub_value) def test_augments(self): optstore = OptionStore(False) @@ -203,34 +205,34 @@ def test_augments(self): top_value, choices=['c++98', 'c++11', 'c++14', 'c++17', 'c++20', 'c++23']) optstore.add_system_option(name, co) - self.assertEqual(optstore.get_value_for(name), top_value) - self.assertEqual(optstore.get_value_for(name, sub_name), top_value) - self.assertEqual(optstore.get_value_for(name, sub2_name), top_value) + self.assertEqual(optstore.get_value_for_untyped(name), top_value) + self.assertEqual(optstore.get_value_for_untyped(name, sub_name), top_value) + self.assertEqual(optstore.get_value_for_untyped(name, sub2_name), top_value) # First augment a subproject with self.subTest('set subproject override'): optstore.set_from_configure_command({OptionKey.from_string(f'{sub_name}:{name}'): aug_value}) - self.assertEqual(optstore.get_value_for(name), top_value) - self.assertEqual(optstore.get_value_for(name, sub_name), aug_value) - self.assertEqual(optstore.get_value_for(name, sub2_name), top_value) + self.assertEqual(optstore.get_value_for_untyped(name), top_value) + self.assertEqual(optstore.get_value_for_untyped(name, sub_name), aug_value) + self.assertEqual(optstore.get_value_for_untyped(name, sub2_name), top_value) with self.subTest('unset subproject override'): optstore.set_from_configure_command({OptionKey.from_string(f'{sub_name}:{name}'): None}) - self.assertEqual(optstore.get_value_for(name), top_value) - self.assertEqual(optstore.get_value_for(name, sub_name), top_value) - self.assertEqual(optstore.get_value_for(name, sub2_name), top_value) + self.assertEqual(optstore.get_value_for_untyped(name), top_value) + self.assertEqual(optstore.get_value_for_untyped(name, sub_name), top_value) + self.assertEqual(optstore.get_value_for_untyped(name, sub2_name), top_value) # And now augment the top level option optstore.set_from_configure_command({OptionKey.from_string(f':{name}'): aug_value}) - self.assertEqual(optstore.get_value_for(name, None), top_value) - self.assertEqual(optstore.get_value_for(name, ''), aug_value) - self.assertEqual(optstore.get_value_for(name, sub_name), top_value) - self.assertEqual(optstore.get_value_for(name, sub2_name), top_value) + self.assertEqual(optstore.get_value_for_untyped(name, None), top_value) + self.assertEqual(optstore.get_value_for_untyped(name, ''), aug_value) + self.assertEqual(optstore.get_value_for_untyped(name, sub_name), top_value) + self.assertEqual(optstore.get_value_for_untyped(name, sub2_name), top_value) optstore.set_from_configure_command({OptionKey.from_string(f':{name}'): None}) - self.assertEqual(optstore.get_value_for(name), top_value) - self.assertEqual(optstore.get_value_for(name, sub_name), top_value) - self.assertEqual(optstore.get_value_for(name, sub2_name), top_value) + self.assertEqual(optstore.get_value_for_untyped(name), top_value) + self.assertEqual(optstore.get_value_for_untyped(name, sub_name), top_value) + self.assertEqual(optstore.get_value_for_untyped(name, sub2_name), top_value) def test_augment_set_sub(self): optstore = OptionStore(False) @@ -249,8 +251,8 @@ def test_augment_set_sub(self): optstore.add_system_option(name, co) optstore.set_from_configure_command({OptionKey.from_string(f'{sub_name}:{name}'): aug_value}) optstore.set_from_configure_command({OptionKey.from_string(f'{sub_name}:{name}'): set_value}) - self.assertEqual(optstore.get_value_for(name), top_value) - self.assertEqual(optstore.get_value_for(name, sub_name), set_value) + self.assertEqual(optstore.get_value_for_untyped(name), top_value) + self.assertEqual(optstore.get_value_for_untyped(name, sub_name), set_value) def test_build_to_host(self): key = OptionKey('cpp_std') @@ -266,8 +268,8 @@ def test_build_to_host(self): cmd_line = {key: opt_value} optstore.initialize_from_top_level_project_call({}, cmd_line, {}) - self.assertEqual(optstore.get_option_and_value_for(key.as_build())[1], opt_value) - self.assertEqual(optstore.get_value_for(key.as_build()), opt_value) + self.assertEqual(optstore.get_option_and_value_for_untyped(key.as_build())[1], opt_value) + self.assertEqual(optstore.get_value_for_untyped(key.as_build()), opt_value) def test_build_to_host_subproject(self): key = OptionKey('cpp_std') @@ -285,9 +287,9 @@ def test_build_to_host_subproject(self): spcall = {key: opt_value} optstore.initialize_from_top_level_project_call({}, {}, {}) optstore.initialize_from_subproject_call(subp, spcall, {}, {}, {}) - self.assertEqual(optstore.get_option_and_value_for(key.evolve(subproject=subp, + self.assertEqual(optstore.get_option_and_value_for_untyped(key.evolve(subproject=subp, machine=MachineChoice.BUILD))[1], opt_value) - self.assertEqual(optstore.get_value_for(key.evolve(subproject=subp, + self.assertEqual(optstore.get_value_for_untyped(key.evolve(subproject=subp, machine=MachineChoice.BUILD)), opt_value) def test_build_to_host_cross(self): @@ -307,10 +309,10 @@ def test_build_to_host_cross(self): optstore.initialize_from_top_level_project_call({}, cmd_line, {}) print(optstore.options) - self.assertEqual(optstore.get_option_and_value_for(key)[1], opt_value) - self.assertEqual(optstore.get_option_and_value_for(key.as_build())[1], def_value) - self.assertEqual(optstore.get_value_for(key), opt_value) - self.assertEqual(optstore.get_value_for(key.as_build()), def_value) + self.assertEqual(optstore.get_option_and_value_for_untyped(key)[1], opt_value) + self.assertEqual(optstore.get_option_and_value_for_untyped(key.as_build())[1], def_value) + self.assertEqual(optstore.get_value_for_untyped(key), opt_value) + self.assertEqual(optstore.get_value_for_untyped(key.as_build()), def_value) def test_b_nonexistent(self): optstore = OptionStore(False) @@ -349,8 +351,8 @@ def test_subproject_proj_opt_with_same_name(self): optstore.initialize_from_top_level_project_call({}, cmd_line, {}) optstore.initialize_from_subproject_call(subp, spcall, {}, cmd_line, {}) - self.assertEqual(optstore.get_value_for(name, ''), True) - self.assertEqual(optstore.get_value_for(name, subp), False) + self.assertEqual(optstore.get_value_for_untyped(name, ''), True) + self.assertEqual(optstore.get_value_for_untyped(name, subp), False) def test_subproject_cmdline_override_global(self): name = 'optimization' @@ -369,8 +371,8 @@ def test_subproject_cmdline_override_global(self): optstore.initialize_from_top_level_project_call(toplevel_proj_default, cmd_line, {}) optstore.initialize_from_subproject_call(subp, {}, subp_proj_default, cmd_line, {}) - self.assertEqual(optstore.get_value_for(name, subp), new_value) - self.assertEqual(optstore.get_value_for(name), new_value) + self.assertEqual(optstore.get_value_for_untyped(name, subp), new_value) + self.assertEqual(optstore.get_value_for_untyped(name), new_value) def test_subproject_parent_override_subp(self): name = 'optimization' @@ -389,8 +391,8 @@ def test_subproject_parent_override_subp(self): optstore.initialize_from_top_level_project_call(toplevel_proj_default, {}, {}) optstore.initialize_from_subproject_call(subp, {}, subp_proj_default, {}, {}) - self.assertEqual(optstore.get_value_for(name, subp), subp_value) - self.assertEqual(optstore.get_value_for(name), default_value) + self.assertEqual(optstore.get_value_for_untyped(name, subp), subp_value) + self.assertEqual(optstore.get_value_for_untyped(name), default_value) def test_subproject_cmdline_override_global_and_augment(self): name = 'optimization' @@ -410,8 +412,8 @@ def test_subproject_cmdline_override_global_and_augment(self): optstore.initialize_from_top_level_project_call(toplevel_proj_default, cmd_line, {}) optstore.initialize_from_subproject_call(subp, {}, subp_proj_default, cmd_line, {}) - self.assertEqual(optstore.get_value_for(name, subp), new_value) - self.assertEqual(optstore.get_value_for(name), global_value) + self.assertEqual(optstore.get_value_for_untyped(name, subp), new_value) + self.assertEqual(optstore.get_value_for_untyped(name), global_value) def test_subproject_cmdline_override_toplevel(self): name = 'default_library' @@ -431,8 +433,8 @@ def test_subproject_cmdline_override_toplevel(self): optstore.initialize_from_top_level_project_call(toplevel_proj_default, cmd_line, {}) optstore.initialize_from_subproject_call(subp, {}, subp_proj_default, cmd_line, {}) - self.assertEqual(optstore.get_value_for(name, subp), subp_value) - self.assertEqual(optstore.get_value_for(name, ''), toplevel_value) + self.assertEqual(optstore.get_value_for_untyped(name, subp), subp_value) + self.assertEqual(optstore.get_value_for_untyped(name, ''), toplevel_value) def test_subproject_buildtype(self): subp = 'subp' @@ -456,9 +458,9 @@ def test_subproject_buildtype(self): optstore.initialize_from_top_level_project_call(mainopt, {}, {}) optstore.initialize_from_subproject_call(subp, {}, subopt, {}, {}) - self.assertEqual(optstore.get_value_for('buildtype', subp), 'debug') - self.assertEqual(optstore.get_value_for('optimization', subp), '0') - self.assertEqual(optstore.get_value_for('debug', subp), True) + self.assertEqual(optstore.get_value_for_untyped('buildtype', subp), 'debug') + self.assertEqual(optstore.get_value_for_untyped('optimization', subp), '0') + self.assertEqual(optstore.get_value_for_untyped('debug', subp), True) def test_deprecated_nonstring_value(self): # TODO: add a lot more deprecated option tests @@ -468,7 +470,7 @@ def test_deprecated_nonstring_value(self): deprecated={'true': '1'}) optstore.add_system_option(name, do) optstore.set_option(OptionKey(name), True) - value = optstore.get_value_for(name) + value = optstore.get_value_for_untyped(name) self.assertEqual(value, '1') def test_pending_augment_validation(self): @@ -485,7 +487,7 @@ def test_pending_augment_validation(self): bo = UserBooleanOption(name, 'LTO', False) key = OptionKey(name, subproject=subproject) optstore.add_system_option(key, bo) - stored_value = optstore.get_value_for(key) + stored_value = optstore.get_value_for_untyped(key) self.assertIsInstance(stored_value, bool) self.assertTrue(stored_value) @@ -513,7 +515,7 @@ def test_machine_canonicalization_cross(self): build_option_obj = UserStringArrayOption('pkg_config_path', 'Build pkg-config paths', ['/usr/lib64/pkgconfig']) optstore.add_system_option(host_pkg_config, host_option_obj) optstore.add_system_option(build_pkg_config, build_option_obj) - option, value = optstore.get_option_and_value_for(build_pkg_config) + option, value = optstore.get_option_and_value_for_untyped(build_pkg_config) self.assertEqual(value, ['/usr/lib64/pkgconfig']) # Test that non-per-machine BUILD option IS canonicalized to HOST @@ -522,7 +524,7 @@ def test_machine_canonicalization_cross(self): common_option_obj = UserComboOption('optimization', 'Optimization level', '0', choices=['plain', '0', 'g', '1', '2', '3', 's']) optstore.add_system_option(host_opt, common_option_obj) - self.assertEqual(optstore.get_value_for(build_opt), '0') + self.assertEqual(optstore.get_value_for_untyped(build_opt), '0') def test_machine_canonicalization_native(self): """Test that BUILD machine options are canonicalized to HOST when not cross compiling.""" @@ -535,12 +537,12 @@ def test_machine_canonicalization_native(self): # Add per-machine option for HOST only (BUILD will be canonicalized) optstore.add_system_option(host_pkg_config, host_option_obj) - option, value = optstore.get_option_and_value_for(build_pkg_config) + option, value = optstore.get_option_and_value_for_untyped(build_pkg_config) self.assertEqual(value, ['/mingw/lib64/pkgconfig']) # Try again adding build option too, for completeness optstore.add_system_option(build_pkg_config, build_option_obj) - option, value = optstore.get_option_and_value_for(build_pkg_config) + option, value = optstore.get_option_and_value_for_untyped(build_pkg_config) self.assertEqual(value, ['/mingw/lib64/pkgconfig']) def test_sanitize_prefix_windows_host(self): @@ -593,7 +595,7 @@ def test_sanitize_dir_option_cross_to_windows(self): # Set libdir to absolute path inside prefix, should be relativized optstore.set_option(OptionKey('prefix'), 'C:\\Program Files\\MyProg') optstore.set_option(OptionKey('libdir'), 'C:\\Program Files\\MyProg\\lib') - self.assertEqual(optstore.get_value_for('libdir'), 'lib') + self.assertEqual(optstore.get_value_for_untyped('libdir'), 'lib') def test_sanitize_dir_option_cross_to_linux(self): """Test directory option sanitization when cross-compiling to Linux.""" @@ -603,7 +605,7 @@ def test_sanitize_dir_option_cross_to_linux(self): # Set libdir to absolute path inside prefix, should be relativized optstore.set_option(OptionKey('prefix'), '/opt/myapp') optstore.set_option(OptionKey('libdir'), '/opt/myapp/lib64') - self.assertEqual(optstore.get_value_for('libdir'), 'lib64') + self.assertEqual(optstore.get_value_for_untyped('libdir'), 'lib64') def test_sanitize_prefix_native_path(self): """Test that native paths are accepted without set_host_machine().""" @@ -639,3 +641,9 @@ def test_is_host_absolute(self): optstore = OptionStore(False) self.assertTrue(optstore._is_host_absolute(os.sep + 'myprog')) self.assertTrue(optstore._is_host_absolute('/myprog')) + + def test_get_value_default(self) -> None: + optstore = OptionStore(False) + self.assertTrue(optstore.get_value_for(OptionKey('nonexistent'), bool, default=True)) + target = mock.Mock(spec=BuildTarget, subproject='') + self.assertTrue(optstore.get_option_for_target(target, OptionKey('nonexistent'), bool, default=True))