diff options
Diffstat (limited to 'mesonbuild')
| -rw-r--r-- | mesonbuild/cargo/interpreter.py | 2 | ||||
| -rw-r--r-- | mesonbuild/compilers/c.py | 39 | ||||
| -rw-r--r-- | mesonbuild/compilers/compilers.py | 78 | ||||
| -rw-r--r-- | mesonbuild/compilers/cpp.py | 173 | ||||
| -rw-r--r-- | mesonbuild/compilers/cuda.py | 23 | ||||
| -rw-r--r-- | mesonbuild/compilers/cython.py | 27 | ||||
| -rw-r--r-- | mesonbuild/compilers/fortran.py | 18 | ||||
| -rw-r--r-- | mesonbuild/compilers/mixins/emscripten.py | 15 | ||||
| -rw-r--r-- | mesonbuild/compilers/objc.py | 17 | ||||
| -rw-r--r-- | mesonbuild/compilers/objcpp.py | 23 | ||||
| -rw-r--r-- | mesonbuild/compilers/rust.py | 15 | ||||
| -rw-r--r-- | mesonbuild/coredata.py | 91 | ||||
| -rw-r--r-- | mesonbuild/optinterpreter.py | 26 |
13 files changed, 301 insertions, 246 deletions
diff --git a/mesonbuild/cargo/interpreter.py b/mesonbuild/cargo/interpreter.py index f1ed23953..e1b092897 100644 --- a/mesonbuild/cargo/interpreter.py +++ b/mesonbuild/cargo/interpreter.py @@ -716,7 +716,7 @@ def interpret(subp_name: str, subdir: str, env: Environment) -> T.Tuple[mparser. for feature in cargo.features: key = OptionKey(_option_name(feature), subproject=subp_name) enabled = feature == 'default' - options[key] = coredata.UserBooleanOption(f'Cargo {feature} feature', enabled) + options[key] = coredata.UserBooleanOption(key.name, f'Cargo {feature} feature', enabled) ast = _create_project(cargo, build) ast += [build.assign(build.function('import', [build.string('rust')]), 'rust')] diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 048649a32..7e2146111 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -152,12 +152,13 @@ class ClangCCompiler(_ClangCStds, ClangCompiler, CCompiler): def get_options(self) -> 'MutableKeyedOptionDictType': opts = super().get_options() if self.info.is_windows() or self.info.is_cygwin(): - opts.update({ - OptionKey('winlibs', machine=self.for_machine, lang=self.language): coredata.UserArrayOption( - 'Standard Win libraries to link against', - gnu_winlibs, - ), - }) + self.update_options( + opts, + self.create_option(coredata.UserArrayOption, + OptionKey('winlibs', machine=self.for_machine, lang=self.language), + 'Standard Win libraries to link against', + gnu_winlibs), + ) return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: @@ -290,12 +291,13 @@ class GnuCCompiler(GnuCompiler, CCompiler): assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(stds, gnu=True) if self.info.is_windows() or self.info.is_cygwin(): - opts.update({ - key.evolve('winlibs'): coredata.UserArrayOption( - 'Standard Win libraries to link against', - gnu_winlibs, - ), - }) + self.update_options( + opts, + self.create_option(coredata.UserArrayOption, + key.evolve('winlibs'), + 'Standard Win libraries to link against', + gnu_winlibs), + ) return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: @@ -425,15 +427,16 @@ class VisualStudioLikeCCompilerMixin(CompilerMixinBase): """Shared methods that apply to MSVC-like C compilers.""" - def get_options(self) -> 'MutableKeyedOptionDictType': - opts = super().get_options() - opts.update({ - OptionKey('winlibs', machine=self.for_machine, lang=self.language): coredata.UserArrayOption( + def get_options(self) -> MutableKeyedOptionDictType: + return self.update_options( + super().get_options(), + self.create_option( + coredata.UserArrayOption, + OptionKey('winlibs', machine=self.for_machine, lang=self.language), 'Windows libs to link against.', msvc_winlibs, ), - }) - return opts + ) def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: # need a TypeDict to make this work diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 9e99706c0..5854c9e60 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -9,6 +9,7 @@ import contextlib, os.path, re import enum import itertools import typing as T +from dataclasses import dataclass from functools import lru_cache from .. import coredata @@ -34,6 +35,7 @@ if T.TYPE_CHECKING: CompilerType = T.TypeVar('CompilerType', bound='Compiler') _T = T.TypeVar('_T') + UserOptionType = T.TypeVar('UserOptionType', bound=coredata.UserOption) """This file contains the data files of all compilers Meson knows about. To support a new compiler, add its information below. @@ -206,36 +208,46 @@ clike_debug_args: T.Dict[bool, T.List[str]] = { MSCRT_VALS = ['none', 'md', 'mdd', 'mt', 'mtd'] -base_options: 'KeyedOptionDictType' = { - OptionKey('b_pch'): coredata.UserBooleanOption('Use precompiled headers', True), - OptionKey('b_lto'): coredata.UserBooleanOption('Use link time optimization', False), - OptionKey('b_lto_threads'): coredata.UserIntegerOption('Use multiple threads for Link Time Optimization', (None, None, 0)), - OptionKey('b_lto_mode'): coredata.UserComboOption('Select between different LTO modes.', - ['default', 'thin'], - 'default'), - OptionKey('b_thinlto_cache'): coredata.UserBooleanOption('Use LLVM ThinLTO caching for faster incremental builds', False), - OptionKey('b_thinlto_cache_dir'): coredata.UserStringOption('Directory to store ThinLTO cache objects', ''), - OptionKey('b_sanitize'): coredata.UserComboOption('Code sanitizer to use', - ['none', 'address', 'thread', 'undefined', 'memory', 'leak', 'address,undefined'], - 'none'), - OptionKey('b_lundef'): coredata.UserBooleanOption('Use -Wl,--no-undefined when linking', True), - OptionKey('b_asneeded'): coredata.UserBooleanOption('Use -Wl,--as-needed when linking', True), - OptionKey('b_pgo'): coredata.UserComboOption('Use profile guided optimization', - ['off', 'generate', 'use'], - 'off'), - OptionKey('b_coverage'): coredata.UserBooleanOption('Enable coverage tracking.', False), - OptionKey('b_colorout'): coredata.UserComboOption('Use colored output', - ['auto', 'always', 'never'], - 'always'), - OptionKey('b_ndebug'): coredata.UserComboOption('Disable asserts', ['true', 'false', 'if-release'], 'false'), - OptionKey('b_staticpic'): coredata.UserBooleanOption('Build static libraries as position independent', True), - OptionKey('b_pie'): coredata.UserBooleanOption('Build executables as position independent', False), - OptionKey('b_bitcode'): coredata.UserBooleanOption('Generate and embed bitcode (only macOS/iOS/tvOS)', False), - OptionKey('b_vscrt'): coredata.UserComboOption('VS run-time library type to use.', - MSCRT_VALS + ['from_buildtype', 'static_from_buildtype'], - 'from_buildtype'), +@dataclass +class BaseOption(T.Generic[coredata._T, coredata._U]): + opt_type: T.Type[coredata._U] + description: str + default: T.Any = None + choices: T.Any = None + + def init_option(self, name: OptionKey) -> coredata._U: + keywords = {'value': self.default} + if self.choices: + keywords['choices'] = self.choices + return self.opt_type(name.name, self.description, **keywords) + +BASE_OPTIONS: T.Mapping[OptionKey, BaseOption] = { + OptionKey('b_pch'): BaseOption(coredata.UserBooleanOption, 'Use precompiled headers', True), + OptionKey('b_lto'): BaseOption(coredata.UserBooleanOption, 'Use link time optimization', False), + OptionKey('b_lto_threads'): BaseOption(coredata.UserIntegerOption, 'Use multiple threads for Link Time Optimization', (None, None, 0)), + OptionKey('b_lto_mode'): BaseOption(coredata.UserComboOption, 'Select between different LTO modes.', 'default', + choices=['default', 'thin']), + OptionKey('b_thinlto_cache'): BaseOption(coredata.UserBooleanOption, 'Use LLVM ThinLTO caching for faster incremental builds', False), + OptionKey('b_thinlto_cache_dir'): BaseOption(coredata.UserStringOption, 'Directory to store ThinLTO cache objects', ''), + OptionKey('b_sanitize'): BaseOption(coredata.UserComboOption, 'Code sanitizer to use', 'none', + choices=['none', 'address', 'thread', 'undefined', 'memory', 'leak', 'address,undefined']), + OptionKey('b_lundef'): BaseOption(coredata.UserBooleanOption, 'Use -Wl,--no-undefined when linking', True), + OptionKey('b_asneeded'): BaseOption(coredata.UserBooleanOption, 'Use -Wl,--as-needed when linking', True), + OptionKey('b_pgo'): BaseOption(coredata.UserComboOption, 'Use profile guided optimization', 'off', + choices=['off', 'generate', 'use']), + OptionKey('b_coverage'): BaseOption(coredata.UserBooleanOption, 'Enable coverage tracking.', False), + OptionKey('b_colorout'): BaseOption(coredata.UserComboOption, 'Use colored output', 'always', + choices=['auto', 'always', 'never']), + OptionKey('b_ndebug'): BaseOption(coredata.UserComboOption, 'Disable asserts', 'false', choices=['true', 'false', 'if-release']), + OptionKey('b_staticpic'): BaseOption(coredata.UserBooleanOption, 'Build static libraries as position independent', True), + OptionKey('b_pie'): BaseOption(coredata.UserBooleanOption, 'Build executables as position independent', False), + OptionKey('b_bitcode'): BaseOption(coredata.UserBooleanOption, 'Generate and embed bitcode (only macOS/iOS/tvOS)', False), + OptionKey('b_vscrt'): BaseOption(coredata.UserComboOption, 'VS run-time library type to use.', 'from_buildtype', + choices=MSCRT_VALS + ['from_buildtype', 'static_from_buildtype']), } +base_options: KeyedOptionDictType = {key: base_opt.init_option(key) for key, base_opt in BASE_OPTIONS.items()} + def option_enabled(boptions: T.Set[OptionKey], options: 'KeyedOptionDictType', option: OptionKey) -> bool: try: @@ -577,6 +589,14 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta): """ return [] + def create_option(self, option_type: T.Type[UserOptionType], option_key: OptionKey, *args: T.Any, **kwargs: T.Any) -> T.Tuple[OptionKey, UserOptionType]: + return option_key, option_type(f'{self.language}_{option_key.name}', *args, **kwargs) + + @staticmethod + def update_options(options: MutableKeyedOptionDictType, *args: T.Tuple[OptionKey, UserOptionType]) -> MutableKeyedOptionDictType: + options.update(args) + return options + def get_options(self) -> 'MutableKeyedOptionDictType': return {} @@ -1346,10 +1366,12 @@ def get_global_options(lang: str, link_options = env.options.get(largkey, []) cargs = coredata.UserArrayOption( + f'{lang}_{argkey.name}', description + ' compiler', comp_options, split_args=True, allow_dups=True) largs = coredata.UserArrayOption( + f'{lang}_{largkey.name}', description + ' linker', link_options, split_args=True, allow_dups=True) diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index 5e412e7a5..540dedb18 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -237,18 +237,22 @@ class ClangCPPCompiler(_StdCPPLibMixin, ClangCompiler, CPPCompiler): def get_options(self) -> 'MutableKeyedOptionDictType': opts = CPPCompiler.get_options(self) key = OptionKey('key', machine=self.for_machine, lang=self.language) - opts.update({ - key.evolve('debugstl'): coredata.UserBooleanOption( - 'STL debug mode', - False, - ), - key.evolve('eh'): coredata.UserComboOption( - 'C++ exception handling type.', - ['none', 'default', 'a', 's', 'sc'], - 'default', - ), - key.evolve('rtti'): coredata.UserBooleanOption('Enable RTTI', True), - }) + self.update_options( + opts, + self.create_option(coredata.UserComboOption, + key.evolve('eh'), + 'C++ exception handling type.', + ['none', 'default', 'a', 's', 'sc'], + 'default'), + self.create_option(coredata.UserBooleanOption, + key.evolve('rtti'), + 'Enable RTTI', + True), + self.create_option(coredata.UserBooleanOption, + key.evolve('debugstl'), + 'STL debug mode', + False), + ) cppstd_choices = [ 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'c++1z', 'c++2a', 'c++20', ] @@ -260,12 +264,13 @@ class ClangCPPCompiler(_StdCPPLibMixin, ClangCompiler, CPPCompiler): assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(cppstd_choices, gnu=True) if self.info.is_windows() or self.info.is_cygwin(): - opts.update({ - key.evolve('winlibs'): coredata.UserArrayOption( - 'Standard Win libraries to link against', - gnu_winlibs, - ), - }) + self.update_options( + opts, + self.create_option(coredata.UserArrayOption, + key.evolve('winlibs'), + 'Standard Win libraries to link against', + gnu_winlibs), + ) return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: @@ -378,13 +383,14 @@ class ArmclangCPPCompiler(ArmclangCompiler, CPPCompiler): def get_options(self) -> 'MutableKeyedOptionDictType': opts = CPPCompiler.get_options(self) key = OptionKey('std', machine=self.for_machine, lang=self.language) - opts.update({ - key.evolve('eh'): coredata.UserComboOption( - 'C++ exception handling type.', - ['none', 'default', 'a', 's', 'sc'], - 'default', - ), - }) + self.update_options( + opts, + self.create_option(coredata.UserComboOption, + key.evolve('eh'), + 'C++ exception handling type.', + ['none', 'default', 'a', 's', 'sc'], + 'default'), + ) std_opt = opts[key] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(['c++98', 'c++03', 'c++11', 'c++14', 'c++17'], gnu=True) @@ -426,18 +432,22 @@ class GnuCPPCompiler(_StdCPPLibMixin, GnuCompiler, CPPCompiler): def get_options(self) -> 'MutableKeyedOptionDictType': key = OptionKey('std', machine=self.for_machine, lang=self.language) opts = CPPCompiler.get_options(self) - opts.update({ - key.evolve('eh'): coredata.UserComboOption( - 'C++ exception handling type.', - ['none', 'default', 'a', 's', 'sc'], - 'default', - ), - key.evolve('rtti'): coredata.UserBooleanOption('Enable RTTI', True), - key.evolve('debugstl'): coredata.UserBooleanOption( - 'STL debug mode', - False, - ) - }) + self.update_options( + opts, + self.create_option(coredata.UserComboOption, + key.evolve('eh'), + 'C++ exception handling type.', + ['none', 'default', 'a', 's', 'sc'], + 'default'), + self.create_option(coredata.UserBooleanOption, + key.evolve('rtti'), + 'Enable RTTI', + True), + self.create_option(coredata.UserBooleanOption, + key.evolve('debugstl'), + 'STL debug mode', + False), + ) cppstd_choices = [ 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'c++1z', 'c++2a', 'c++20', @@ -450,12 +460,13 @@ class GnuCPPCompiler(_StdCPPLibMixin, GnuCompiler, CPPCompiler): assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(cppstd_choices, gnu=True) if self.info.is_windows() or self.info.is_cygwin(): - opts.update({ - key.evolve('winlibs'): coredata.UserArrayOption( - 'Standard Win libraries to link against', - gnu_winlibs, - ), - }) + self.update_options( + opts, + self.create_option(coredata.UserArrayOption, + key.evolve('winlibs'), + 'Standard Win libraries to link against', + gnu_winlibs), + ) return opts def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: @@ -550,17 +561,18 @@ class ElbrusCPPCompiler(ElbrusCompiler, CPPCompiler): cpp_stds += ['c++20'] key = OptionKey('std', machine=self.for_machine, lang=self.language) - opts.update({ - key.evolve('eh'): coredata.UserComboOption( - 'C++ exception handling type.', - ['none', 'default', 'a', 's', 'sc'], - 'default', - ), - key.evolve('debugstl'): coredata.UserBooleanOption( - 'STL debug mode', - False, - ), - }) + self.update_options( + opts, + self.create_option(coredata.UserComboOption, + key.evolve('eh'), + 'C++ exception handling type.', + ['none', 'default', 'a', 's', 'sc'], + 'default'), + self.create_option(coredata.UserBooleanOption, + key.evolve('debugstl'), + 'STL debug mode', + False), + ) std_opt = opts[key] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(cpp_stds, gnu=True) @@ -628,15 +640,22 @@ class IntelCPPCompiler(IntelGnuLikeCompiler, CPPCompiler): g_stds += ['gnu++2a'] key = OptionKey('std', machine=self.for_machine, lang=self.language) - opts.update({ - key.evolve('eh'): coredata.UserComboOption( - 'C++ exception handling type.', - ['none', 'default', 'a', 's', 'sc'], - 'default', - ), - key.evolve('rtti'): coredata.UserBooleanOption('Enable RTTI', True), - key.evolve('debugstl'): coredata.UserBooleanOption('STL debug mode', False), - }) + self.update_options( + opts, + self.create_option(coredata.UserComboOption, + key.evolve('eh'), + 'C++ exception handling type.', + ['none', 'default', 'a', 's', 'sc'], + 'default'), + self.create_option(coredata.UserBooleanOption, + key.evolve('rtti'), + 'Enable RTTI', + True), + self.create_option(coredata.UserBooleanOption, + key.evolve('debugstl'), + 'STL debug mode', + False), + ) std_opt = opts[key] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(c_stds + g_stds) @@ -694,18 +713,22 @@ class VisualStudioLikeCPPCompilerMixin(CompilerMixinBase): def _get_options_impl(self, opts: 'MutableKeyedOptionDictType', cpp_stds: T.List[str]) -> 'MutableKeyedOptionDictType': key = OptionKey('std', machine=self.for_machine, lang=self.language) - opts.update({ - key.evolve('eh'): coredata.UserComboOption( - 'C++ exception handling type.', - ['none', 'default', 'a', 's', 'sc'], - 'default', - ), - key.evolve('rtti'): coredata.UserBooleanOption('Enable RTTI', True), - key.evolve('winlibs'): coredata.UserArrayOption( - 'Windows libs to link against.', - msvc_winlibs, - ), - }) + self.update_options( + opts, + self.create_option(coredata.UserComboOption, + key.evolve('eh'), + 'C++ exception handling type.', + ['none', 'default', 'a', 's', 'sc'], + 'default'), + self.create_option(coredata.UserBooleanOption, + key.evolve('rtti'), + 'Enable RTTI', + True), + self.create_option(coredata.UserArrayOption, + key.evolve('winlibs'), + 'Windows libs to link against.', + msvc_winlibs), + ) std_opt = opts[key] assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' std_opt.set_versions(cpp_stds) diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py index 391107f84..ab4810798 100644 --- a/mesonbuild/compilers/cuda.py +++ b/mesonbuild/compilers/cuda.py @@ -630,10 +630,6 @@ class CudaCompiler(Compiler): _CPP20_VERSION = '>=12.0' def get_options(self) -> 'MutableKeyedOptionDictType': - opts = super().get_options() - std_key = OptionKey('std', machine=self.for_machine, lang=self.language) - ccbindir_key = OptionKey('ccbindir', machine=self.for_machine, lang=self.language) - cpp_stds = ['none', 'c++03', 'c++11'] if version_compare(self.version, self._CPP14_VERSION): cpp_stds += ['c++14'] @@ -642,13 +638,18 @@ class CudaCompiler(Compiler): if version_compare(self.version, self._CPP20_VERSION): cpp_stds += ['c++20'] - opts.update({ - std_key: coredata.UserComboOption('C++ language standard to use with CUDA', - cpp_stds, 'none'), - ccbindir_key: coredata.UserStringOption('CUDA non-default toolchain directory to use (-ccbin)', - ''), - }) - return opts + return self.update_options( + super().get_options(), + self.create_option(coredata.UserComboOption, + OptionKey('std', machine=self.for_machine, lang=self.language), + 'C++ language standard to use with CUDA', + cpp_stds, + 'none'), + self.create_option(coredata.UserStringOption, + OptionKey('ccbindir', machine=self.for_machine, lang=self.language), + 'CUDA non-default toolchain directory to use (-ccbin)', + ''), + ) def _to_host_compiler_options(self, options: 'KeyedOptionDictType') -> 'KeyedOptionDictType': """ diff --git a/mesonbuild/compilers/cython.py b/mesonbuild/compilers/cython.py index a58b3a814..30cec81e3 100644 --- a/mesonbuild/compilers/cython.py +++ b/mesonbuild/compilers/cython.py @@ -67,20 +67,19 @@ class CythonCompiler(Compiler): return new def get_options(self) -> 'MutableKeyedOptionDictType': - opts = super().get_options() - opts.update({ - OptionKey('version', machine=self.for_machine, lang=self.language): coredata.UserComboOption( - 'Python version to target', - ['2', '3'], - '3', - ), - OptionKey('language', machine=self.for_machine, lang=self.language): coredata.UserComboOption( - 'Output C or C++ files', - ['c', 'cpp'], - 'c', - ) - }) - return opts + return self.update_options( + super().get_options(), + self.create_option(coredata.UserComboOption, + OptionKey('version', machine=self.for_machine, lang=self.language), + 'Python version to target', + ['2', '3'], + '3'), + self.create_option(coredata.UserComboOption, + OptionKey('language', machine=self.for_machine, lang=self.language), + 'Output C or C++ files', + ['c', 'cpp'], + 'c'), + ) def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]: args: T.List[str] = [] diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index 3a7365046..2cdff36de 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -112,16 +112,14 @@ class FortranCompiler(CLikeCompiler, Compiler): return self._has_multi_link_arguments(args, env, 'stop; end program') def get_options(self) -> 'MutableKeyedOptionDictType': - opts = super().get_options() - key = OptionKey('std', machine=self.for_machine, lang=self.language) - opts.update({ - key: coredata.UserComboOption( - 'Fortran language standard to use', - ['none'], - 'none', - ), - }) - return opts + return self.update_options( + super().get_options(), + self.create_option(coredata.UserComboOption, + OptionKey('std', machine=self.for_machine, lang=self.language), + 'Fortran language standard to use', + ['none'], + 'none'), + ) class GnuFortranCompiler(GnuCompiler, FortranCompiler): diff --git a/mesonbuild/compilers/mixins/emscripten.py b/mesonbuild/compilers/mixins/emscripten.py index d10c49987..bb8a52054 100644 --- a/mesonbuild/compilers/mixins/emscripten.py +++ b/mesonbuild/compilers/mixins/emscripten.py @@ -55,17 +55,16 @@ class EmscriptenMixin(Compiler): args.append(f'-sPTHREAD_POOL_SIZE={count}') return args - def get_options(self) -> 'coredata.MutableKeyedOptionDictType': - opts = super().get_options() - key = OptionKey('thread_count', machine=self.for_machine, lang=self.language) - opts.update({ - key: coredata.UserIntegerOption( + def get_options(self) -> coredata.MutableKeyedOptionDictType: + return self.update_options( + super().get_options(), + self.create_option( + coredata.UserIntegerOption, + OptionKey('thread_count', machine=self.for_machine, lang=self.language), 'Number of threads to use in web assembly, set to 0 to disable', (0, None, 4), # Default was picked at random ), - }) - - return opts + ) @classmethod def native_args_to_unix(cls, args: T.List[str]) -> T.List[str]: diff --git a/mesonbuild/compilers/objc.py b/mesonbuild/compilers/objc.py index f805bd6be..7c19c1b7d 100644 --- a/mesonbuild/compilers/objc.py +++ b/mesonbuild/compilers/objc.py @@ -78,15 +78,14 @@ class ClangObjCCompiler(ClangCompiler, ObjCCompiler): 'everything': ['-Weverything']} def get_options(self) -> 'coredata.MutableKeyedOptionDictType': - opts = super().get_options() - opts.update({ - OptionKey('std', machine=self.for_machine, lang='c'): coredata.UserComboOption( - 'C language standard to use', - ['none', 'c89', 'c99', 'c11', 'c17', 'gnu89', 'gnu99', 'gnu11', 'gnu17'], - 'none', - ) - }) - return opts + return self.update_options( + super().get_options(), + self.create_option(coredata.UserComboOption, + OptionKey('std', machine=self.for_machine, lang='c'), + 'C language standard to use', + ['none', 'c89', 'c99', 'c11', 'c17', 'gnu89', 'gnu99', 'gnu11', 'gnu17'], + 'none'), + ) def get_option_compile_args(self, options: 'coredata.KeyedOptionDictType') -> T.List[str]: args = [] diff --git a/mesonbuild/compilers/objcpp.py b/mesonbuild/compilers/objcpp.py index baf4fb5ca..46eaa5049 100644 --- a/mesonbuild/compilers/objcpp.py +++ b/mesonbuild/compilers/objcpp.py @@ -77,18 +77,17 @@ class ClangObjCPPCompiler(ClangCompiler, ObjCPPCompiler): '3': default_warn_args + ['-Wextra', '-Wpedantic'], 'everything': ['-Weverything']} - def get_options(self) -> 'coredata.MutableKeyedOptionDictType': - opts = super().get_options() - opts.update({ - OptionKey('std', machine=self.for_machine, lang='cpp'): coredata.UserComboOption( - 'C++ language standard to use', - ['none', 'c++98', 'c++11', 'c++14', 'c++17', 'c++20', 'c++2b', - 'gnu++98', 'gnu++11', 'gnu++14', 'gnu++17', 'gnu++20', - 'gnu++2b'], - 'none', - ) - }) - return opts + def get_options(self) -> coredata.MutableKeyedOptionDictType: + return self.update_options( + super().get_options(), + self.create_option(coredata.UserComboOption, + OptionKey('std', machine=self.for_machine, lang='cpp'), + 'C++ language standard to use', + ['none', 'c++98', 'c++11', 'c++14', 'c++17', 'c++20', 'c++2b', + 'gnu++98', 'gnu++11', 'gnu++14', 'gnu++17', 'gnu++20', + 'gnu++2b'], + 'none'), + ) def get_option_compile_args(self, options: 'coredata.KeyedOptionDictType') -> T.List[str]: args = [] diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py index 65f4ac1b1..05e8b2b27 100644 --- a/mesonbuild/compilers/rust.py +++ b/mesonbuild/compilers/rust.py @@ -156,15 +156,12 @@ class RustCompiler(Compiler): # C compiler for dynamic linking, as such we invoke the C compiler's # use_linker_args method instead. - def get_options(self) -> 'MutableKeyedOptionDictType': - key = OptionKey('std', machine=self.for_machine, lang=self.language) - return { - key: coredata.UserComboOption( - 'Rust edition to use', - ['none', '2015', '2018', '2021'], - 'none', - ), - } + def get_options(self) -> MutableKeyedOptionDictType: + return dict((self.create_option(coredata.UserComboOption, + OptionKey('std', machine=self.for_machine, lang=self.language), + 'Rust edition to use', + ['none', '2015', '2018', '2021'], + 'none'),)) def get_dependency_compile_args(self, dep: 'Dependency') -> T.List[str]: # Rust doesn't have dependency compile arguments so simply return diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 112310745..df575981a 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -109,10 +109,11 @@ class MesonVersionMismatchException(MesonException): class UserOption(T.Generic[_T], HoldableObject): - def __init__(self, description: str, choices: T.Optional[T.Union[str, T.List[_T]]], + def __init__(self, name: str, description: str, choices: T.Optional[T.Union[str, T.List[_T]]], yielding: bool, deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False): super().__init__() + self.name = name self.choices = choices self.description = description if not isinstance(yielding, bool): @@ -140,20 +141,20 @@ class UserOption(T.Generic[_T], HoldableObject): return self.value != oldvalue class UserStringOption(UserOption[str]): - def __init__(self, description: str, value: T.Any, yielding: bool = DEFAULT_YIELDING, + def __init__(self, name: str, description: str, value: T.Any, yielding: bool = DEFAULT_YIELDING, deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False): - super().__init__(description, None, yielding, deprecated) + super().__init__(name, description, None, yielding, deprecated) self.set_value(value) def validate_value(self, value: T.Any) -> str: if not isinstance(value, str): - raise MesonException('Value "%s" for string option is not a string.' % str(value)) + raise MesonException(f'The value of option "{self.name}" is "{value}", which is not a string.') return value class UserBooleanOption(UserOption[bool]): - def __init__(self, description: str, value: bool, yielding: bool = DEFAULT_YIELDING, + def __init__(self, name: str, description: str, value: bool, yielding: bool = DEFAULT_YIELDING, deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False): - super().__init__(description, [True, False], yielding, deprecated) + super().__init__(name, description, [True, False], yielding, deprecated) self.set_value(value) def __bool__(self) -> bool: @@ -163,15 +164,15 @@ class UserBooleanOption(UserOption[bool]): if isinstance(value, bool): return value if not isinstance(value, str): - raise MesonException(f'Value {value} cannot be converted to a boolean') + raise MesonException(f'Option "{self.name}" value {value} cannot be converted to a boolean') if value.lower() == 'true': return True if value.lower() == 'false': return False - raise MesonException('Value %s is not boolean (true or false).' % value) + raise MesonException(f'Option "{self.name}" value {value} is not boolean (true or false).') class UserIntegerOption(UserOption[int]): - def __init__(self, description: str, value: T.Any, yielding: bool = DEFAULT_YIELDING, + def __init__(self, name: str, description: str, value: T.Any, yielding: bool = DEFAULT_YIELDING, deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False): min_value, max_value, default_value = value self.min_value = min_value @@ -182,25 +183,25 @@ class UserIntegerOption(UserOption[int]): if max_value is not None: c.append('<=' + str(max_value)) choices = ', '.join(c) - super().__init__(description, choices, yielding, deprecated) + super().__init__(name, description, choices, yielding, deprecated) self.set_value(default_value) def validate_value(self, value: T.Any) -> int: if isinstance(value, str): value = self.toint(value) if not isinstance(value, int): - raise MesonException('New value for integer option is not an integer.') + raise MesonException(f'Value {value!r} for option "{self.name}" is not an integer.') if self.min_value is not None and value < self.min_value: - raise MesonException('New value %d is less than minimum value %d.' % (value, self.min_value)) + raise MesonException(f'Value {value} for option "{self.name}" is less than minimum value {self.min_value}.') if self.max_value is not None and value > self.max_value: - raise MesonException('New value %d is more than maximum value %d.' % (value, self.max_value)) + raise MesonException(f'Value {value} for option "{self.name}" is more than maximum value {self.max_value}.') return value def toint(self, valuestring: str) -> int: try: return int(valuestring) except ValueError: - raise MesonException('Value string "%s" is not convertible to an integer.' % valuestring) + raise MesonException(f'Value string "{valuestring}" for option "{self.name}" is not convertible to an integer.') class OctalInt(int): # NinjaBackend.get_user_option_args uses str() to converts it to a command line option @@ -210,9 +211,9 @@ class OctalInt(int): return oct(int(self)) class UserUmaskOption(UserIntegerOption, UserOption[T.Union[str, OctalInt]]): - def __init__(self, description: str, value: T.Any, yielding: bool = DEFAULT_YIELDING, + def __init__(self, name: str, description: str, value: T.Any, yielding: bool = DEFAULT_YIELDING, deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False): - super().__init__(description, (0, 0o777, value), yielding, deprecated) + super().__init__(name, description, (0, 0o777, value), yielding, deprecated) self.choices = ['preserve', '0000-0777'] def printable_value(self) -> str: @@ -229,18 +230,18 @@ class UserUmaskOption(UserIntegerOption, UserOption[T.Union[str, OctalInt]]): try: return int(valuestring, 8) except ValueError as e: - raise MesonException(f'Invalid mode: {e}') + raise MesonException(f'Invalid mode for option "{self.name}" {e}') class UserComboOption(UserOption[str]): - def __init__(self, description: str, choices: T.List[str], value: T.Any, + def __init__(self, name: str, description: str, choices: T.List[str], value: T.Any, yielding: bool = DEFAULT_YIELDING, deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False): - super().__init__(description, choices, yielding, deprecated) + super().__init__(name, description, choices, yielding, deprecated) if not isinstance(self.choices, list): - raise MesonException('Combo choices must be an array.') + raise MesonException(f'Combo choices for option "{self.name}" must be an array.') for i in self.choices: if not isinstance(i, str): - raise MesonException('Combo choice elements must be strings.') + raise MesonException(f'Combo choice elements for option "{self.name}" must be strings.') self.set_value(value) def validate_value(self, value: T.Any) -> str: @@ -252,24 +253,27 @@ class UserComboOption(UserOption[str]): else: _type = 'string' optionsstring = ', '.join([f'"{item}"' for item in self.choices]) - raise MesonException('Value "{}" (of type "{}") for combo option "{}" is not one of the choices.' + raise MesonException('Value "{}" (of type "{}") for option "{}" is not one of the choices.' ' Possible choices are (as string): {}.'.format( - value, _type, self.description, optionsstring)) + value, _type, self.name, optionsstring)) return value class UserArrayOption(UserOption[T.List[str]]): - def __init__(self, description: str, value: T.Union[str, T.List[str]], + def __init__(self, name: str, description: str, value: T.Union[str, T.List[str]], split_args: bool = False, allow_dups: bool = False, yielding: bool = DEFAULT_YIELDING, choices: T.Optional[T.List[str]] = None, deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False): - super().__init__(description, choices if choices is not None else [], yielding, deprecated) + super().__init__(name, description, choices if choices is not None else [], yielding, deprecated) self.split_args = split_args self.allow_dups = allow_dups self.set_value(value) def listify(self, value: T.Any) -> T.List[T.Any]: - return listify_array_value(value, self.split_args) + try: + return listify_array_value(value, self.split_args) + except MesonException as e: + raise MesonException(f'error in option "{self.name}": {e!s}') def validate_value(self, value: T.Union[str, T.List[str]]) -> T.List[str]: newvalue = self.listify(value) @@ -280,12 +284,17 @@ class UserArrayOption(UserOption[T.List[str]]): mlog.deprecation(msg) for i in newvalue: if not isinstance(i, str): - raise MesonException(f'String array element "{newvalue!s}" is not a string.') + raise MesonException(f'String array element "{newvalue!s}" for option "{self.name}" is not a string.') if self.choices: bad = [x for x in newvalue if x not in self.choices] if bad: - raise MesonException('Options "{}" are not in allowed choices: "{}"'.format( - ', '.join(bad), ', '.join(self.choices))) + raise MesonException('Value{} "{}" for option "{}" {} not in allowed choices: "{}"'.format( + '' if len(bad) == 1 else 's', + ', '.join(bad), + self.name, + 'is' if len(bad) == 1 else 'are', + ', '.join(self.choices)) + ) return newvalue def extend_value(self, value: T.Union[str, T.List[str]]) -> None: @@ -297,9 +306,9 @@ class UserArrayOption(UserOption[T.List[str]]): class UserFeatureOption(UserComboOption): static_choices = ['enabled', 'disabled', 'auto'] - def __init__(self, description: str, value: T.Any, yielding: bool = DEFAULT_YIELDING, + def __init__(self, name: str, description: str, value: T.Any, yielding: bool = DEFAULT_YIELDING, deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False): - super().__init__(description, self.static_choices, value, yielding, deprecated) + super().__init__(name, description, self.static_choices, value, yielding, deprecated) self.name: T.Optional[str] = None # TODO: Refactor options to all store their name def is_enabled(self) -> bool: @@ -330,7 +339,8 @@ class UserStdOption(UserComboOption): self.all_stds = ['none'] + all_stds # Map a deprecated std to its replacement. e.g. gnu11 -> c11. self.deprecated_stds: T.Dict[str, str] = {} - super().__init__(f'{lang} language standard to use', ['none'], 'none') + opt_name = 'cpp_std' if lang == 'c++' else f'{lang}_std' + super().__init__(opt_name, f'{lang} language standard to use', ['none'], 'none') def set_versions(self, versions: T.List[str], gnu: bool = False, gnu_deprecated: bool = False) -> None: assert all(std in self.all_stds for std in versions) @@ -343,10 +353,13 @@ class UserStdOption(UserComboOption): self.choices += gnu_stds_map.keys() def validate_value(self, value: T.Union[str, T.List[str]]) -> str: - candidates = listify_array_value(value) - unknown = [std for std in candidates if std not in self.all_stds] + try: + candidates = listify_array_value(value) + except MesonException as e: + raise MesonException(f'error in option "{self.name}": {e!s}') + unknown = ','.join(std for std in candidates if std not in self.all_stds) if unknown: - raise MesonException(f'Unknown {self.lang.upper()} std {unknown}. Possible values are {self.all_stds}.') + raise MesonException(f'Unknown option "{self.name}" value {unknown}. Possible values are {self.all_stds}.') # Check first if any of the candidates are not deprecated for std in candidates: if std in self.choices: @@ -360,10 +373,10 @@ class UserStdOption(UserComboOption): f'However, the deprecated {std} std currently falls back to {newstd}.\n' + 'This will be an error in the future.\n' + 'If the project supports both GNU and MSVC compilers, a value such as\n' + - '"c_std=gnu11,c11" specifies that GNU is prefered but it can safely fallback to plain c11.') + '"c_std=gnu11,c11" specifies that GNU is preferred but it can safely fallback to plain c11.') return newstd raise MesonException(f'None of values {candidates} are supported by the {self.lang.upper()} compiler. ' + - f'Possible values are {self.choices}') + f'Possible values for option "{self.name}" are {self.choices}') @dataclass class OptionsView(abc.Mapping): @@ -720,11 +733,13 @@ class CoreData: def init_backend_options(self, backend_name: str) -> None: if backend_name == 'ninja': self.options[OptionKey('backend_max_links')] = UserIntegerOption( + 'backend_max_links', 'Maximum number of linker processes to run or 0 for no ' 'limit', (0, None, 0)) elif backend_name.startswith('vs'): self.options[OptionKey('backend_startup_project')] = UserStringOption( + 'backend_startup_project', 'Default project to execute in Visual Studio', '') @@ -1294,7 +1309,7 @@ class BuiltinOption(T.Generic[_T, _U]): keywords = {'yielding': self.yielding, 'value': value} if self.choices: keywords['choices'] = self.choices - o = self.opt_type(self.description, **keywords) + o = self.opt_type(name.name, self.description, **keywords) o.readonly = self.readonly return o diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py index e9c201eec..9da355a51 100644 --- a/mesonbuild/optinterpreter.py +++ b/mesonbuild/optinterpreter.py @@ -196,7 +196,7 @@ class OptionInterpreter: n_kwargs = {k: v for k, v in kwargs.items() if k not in {'type', 'description', 'deprecated', 'yield'}} - opt = parser(description, (kwargs['yield'], kwargs['deprecated']), n_kwargs) + opt = parser(opt_name, description, (kwargs['yield'], kwargs['deprecated']), n_kwargs) if key in self.options: mlog.deprecation(f'Option {opt_name} already exists.') self.options[key] = opt @@ -205,8 +205,8 @@ class OptionInterpreter: 'string option', KwargInfo('value', str, default=''), ) - def string_parser(self, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: StringArgs) -> coredata.UserOption: - return coredata.UserStringOption(description, kwargs['value'], *args) + def string_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: StringArgs) -> coredata.UserOption: + return coredata.UserStringOption(name, description, kwargs['value'], *args) @typed_kwargs( 'boolean option', @@ -218,20 +218,20 @@ class OptionInterpreter: deprecated_values={str: ('1.1.0', 'use a boolean, not a string')}, ), ) - def boolean_parser(self, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: BooleanArgs) -> coredata.UserOption: - return coredata.UserBooleanOption(description, kwargs['value'], *args) + def boolean_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: BooleanArgs) -> coredata.UserOption: + return coredata.UserBooleanOption(name, description, kwargs['value'], *args) @typed_kwargs( 'combo option', KwargInfo('value', (str, NoneType)), KwargInfo('choices', ContainerTypeInfo(list, str, allow_empty=False), required=True), ) - def combo_parser(self, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: ComboArgs) -> coredata.UserOption: + def combo_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: ComboArgs) -> coredata.UserOption: choices = kwargs['choices'] value = kwargs['value'] if value is None: value = kwargs['choices'][0] - return coredata.UserComboOption(description, choices, value, *args) + return coredata.UserComboOption(name, description, choices, value, *args) @typed_kwargs( 'integer option', @@ -245,17 +245,17 @@ class OptionInterpreter: KwargInfo('min', (int, NoneType)), KwargInfo('max', (int, NoneType)), ) - def integer_parser(self, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: IntegerArgs) -> coredata.UserOption: + def integer_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: IntegerArgs) -> coredata.UserOption: value = kwargs['value'] inttuple = (kwargs['min'], kwargs['max'], value) - return coredata.UserIntegerOption(description, inttuple, *args) + return coredata.UserIntegerOption(name, description, inttuple, *args) @typed_kwargs( 'string array option', KwargInfo('value', (ContainerTypeInfo(list, str), str, NoneType)), KwargInfo('choices', ContainerTypeInfo(list, str), default=[]), ) - def string_array_parser(self, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: StringArrayArgs) -> coredata.UserOption: + def string_array_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: StringArrayArgs) -> coredata.UserOption: choices = kwargs['choices'] value = kwargs['value'] if kwargs['value'] is not None else choices if isinstance(value, str): @@ -263,7 +263,7 @@ class OptionInterpreter: FeatureDeprecated('String value for array option', '1.3.0').use(self.subproject) else: raise mesonlib.MesonException('Value does not define an array: ' + value) - return coredata.UserArrayOption(description, value, + return coredata.UserArrayOption(name, description, value, choices=choices, yielding=args[0], deprecated=args[1]) @@ -272,5 +272,5 @@ class OptionInterpreter: 'feature option', KwargInfo('value', str, default='auto', validator=in_set_validator({'auto', 'enabled', 'disabled'})), ) - def feature_parser(self, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: FeatureArgs) -> coredata.UserOption: - return coredata.UserFeatureOption(description, kwargs['value'], *args) + def feature_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: FeatureArgs) -> coredata.UserOption: + return coredata.UserFeatureOption(name, description, kwargs['value'], *args) |
