use OptionKey for builtin and base options

I would have prefered to do these seperatately, but they are combined in
some cases, so it was much easier to convert them together.

this eliminates the builtins_per_machine dict, as it's duplicated with
the OptionKey's machine parameter.
pull/8080/head
Dylan Baker 4 years ago
parent f9b19e73a5
commit 71db6b04a3
  1. 29
      mesonbuild/backend/backends.py
  2. 39
      mesonbuild/backend/ninjabackend.py
  3. 8
      mesonbuild/backend/vs2010backend.py
  4. 35
      mesonbuild/build.py
  5. 4
      mesonbuild/cmake/executor.py
  6. 2
      mesonbuild/cmake/interpreter.py
  7. 106
      mesonbuild/compilers/compilers.py
  8. 2
      mesonbuild/compilers/cpp.py
  9. 12
      mesonbuild/compilers/d.py
  10. 7
      mesonbuild/compilers/mixins/arm.py
  11. 7
      mesonbuild/compilers/mixins/clang.py
  12. 7
      mesonbuild/compilers/mixins/clike.py
  13. 6
      mesonbuild/compilers/mixins/elbrus.py
  14. 2
      mesonbuild/compilers/mixins/emscripten.py
  15. 14
      mesonbuild/compilers/mixins/gnu.py
  16. 5
      mesonbuild/compilers/mixins/intel.py
  17. 3
      mesonbuild/compilers/mixins/pgi.py
  18. 2
      mesonbuild/compilers/mixins/visualstudio.py
  19. 4
      mesonbuild/compilers/rust.py
  20. 4
      mesonbuild/compilers/vala.py
  21. 244
      mesonbuild/coredata.py
  22. 11
      mesonbuild/dependencies/base.py
  23. 4
      mesonbuild/dependencies/boost.py
  24. 4
      mesonbuild/dependencies/ui.py
  25. 43
      mesonbuild/interpreter.py
  26. 60
      mesonbuild/mconf.py
  27. 78
      mesonbuild/mesonlib.py
  28. 38
      mesonbuild/mintro.py
  29. 14
      mesonbuild/modules/gnome.py
  30. 2
      mesonbuild/msetup.py
  31. 6
      mesonbuild/rewriter.py
  32. 73
      run_unittests.py

@ -32,7 +32,7 @@ from .. import mlog
from ..compilers import languages_using_ldflags from ..compilers import languages_using_ldflags
from ..mesonlib import ( from ..mesonlib import (
File, MachineChoice, MesonException, OrderedSet, OptionOverrideProxy, File, MachineChoice, MesonException, OrderedSet, OptionOverrideProxy,
classify_unity_sources, unholder classify_unity_sources, unholder, OptionKey
) )
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
@ -211,21 +211,21 @@ class Backend:
def get_target_filename_abs(self, target): def get_target_filename_abs(self, target):
return os.path.join(self.environment.get_build_dir(), self.get_target_filename(target)) return os.path.join(self.environment.get_build_dir(), self.get_target_filename(target))
def get_base_options_for_target(self, target): def get_base_options_for_target(self, target: build.BuildTarget) -> OptionOverrideProxy:
return OptionOverrideProxy(target.option_overrides_base, return OptionOverrideProxy(target.option_overrides_base,
self.environment.coredata.builtins, self.environment.coredata.builtins,
self.environment.coredata.base_options) {k: v for k, v in self.environment.coredata.base_options.items()})
def get_compiler_options_for_target(self, target: build.BuildTarget) -> OptionOverrideProxy: def get_compiler_options_for_target(self, target: build.BuildTarget) -> OptionOverrideProxy:
comp_reg = self.environment.coredata.compiler_options comp_reg = self.environment.coredata.compiler_options
comp_override = target.option_overrides_compiler comp_override = target.option_overrides_compiler
return OptionOverrideProxy(comp_override, comp_reg) return OptionOverrideProxy(comp_override, comp_reg)
def get_option_for_target(self, option_name, target): def get_option_for_target(self, option_name: 'OptionKey', target: build.BuildTarget):
if option_name in target.option_overrides_base: if option_name in target.option_overrides_base:
override = target.option_overrides_base[option_name] override = target.option_overrides_base[option_name]
return self.environment.coredata.validate_option_value(option_name, override) return self.environment.coredata.validate_option_value(option_name, override)
return self.environment.coredata.get_builtin_option(option_name, target.subproject) return self.environment.coredata.get_builtin_option(str(option_name), target.subproject)
def get_target_filename_for_linking(self, target): def get_target_filename_for_linking(self, target):
# On some platforms (msvc for instance), the file that is used for # On some platforms (msvc for instance), the file that is used for
@ -299,7 +299,7 @@ class Backend:
abs_files = [] abs_files = []
result = [] result = []
compsrcs = classify_unity_sources(target.compilers.values(), unity_src) compsrcs = classify_unity_sources(target.compilers.values(), unity_src)
unity_size = self.get_option_for_target('unity_size', target) unity_size = self.get_option_for_target(OptionKey('unity_size'), target)
def init_language_file(suffix, unity_file_number): def init_language_file(suffix, unity_file_number):
unity_src = self.get_unity_source_file(target, suffix, unity_file_number) unity_src = self.get_unity_source_file(target, suffix, unity_file_number)
@ -620,7 +620,8 @@ class Backend:
if self.is_unity(extobj.target): if self.is_unity(extobj.target):
compsrcs = classify_unity_sources(extobj.target.compilers.values(), sources) compsrcs = classify_unity_sources(extobj.target.compilers.values(), sources)
sources = [] sources = []
unity_size = self.get_option_for_target('unity_size', extobj.target) unity_size = self.get_option_for_target(OptionKey('unity_size'), extobj.target)
for comp, srcs in compsrcs.items(): for comp, srcs in compsrcs.items():
for i in range(len(srcs) // unity_size + 1): for i in range(len(srcs) // unity_size + 1):
osrc = self.get_unity_source_file(extobj.target, osrc = self.get_unity_source_file(extobj.target,
@ -689,20 +690,20 @@ class Backend:
if no_warn_args: if no_warn_args:
commands += compiler.get_no_warn_args() commands += compiler.get_no_warn_args()
else: else:
commands += compiler.get_warn_args(self.get_option_for_target('warning_level', target)) commands += compiler.get_warn_args(self.get_option_for_target(OptionKey('warning_level'), target))
# Add -Werror if werror=true is set in the build options set on the # 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 # 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 # action to be done for warnings if/when they are emitted, so it's ok
# to set it after get_no_warn_args() or get_warn_args(). # to set it after get_no_warn_args() or get_warn_args().
if self.get_option_for_target('werror', target): if self.get_option_for_target(OptionKey('werror'), target):
commands += compiler.get_werror_args() commands += compiler.get_werror_args()
# Add compile args for c_* or cpp_* build options set on the # Add compile args for c_* or cpp_* build options set on the
# command-line or default_options inside project(). # command-line or default_options inside project().
commands += compiler.get_option_compile_args(copt_proxy) commands += compiler.get_option_compile_args(copt_proxy)
# Add buildtype args: optimization level, debugging, etc. # Add buildtype args: optimization level, debugging, etc.
commands += compiler.get_buildtype_args(self.get_option_for_target('buildtype', target)) commands += compiler.get_buildtype_args(self.get_option_for_target(OptionKey('buildtype'), target))
commands += compiler.get_optimization_args(self.get_option_for_target('optimization', target)) commands += compiler.get_optimization_args(self.get_option_for_target(OptionKey('optimization'), target))
commands += compiler.get_debug_args(self.get_option_for_target('debug', target)) commands += compiler.get_debug_args(self.get_option_for_target(OptionKey('debug'), target))
# MSVC debug builds have /ZI argument by default and /Zi is added with debug flag # MSVC debug builds have /ZI argument by default and /Zi is added with debug flag
# /ZI needs to be removed in that case to avoid cl's warning to that effect (D9025 : overriding '/ZI' with '/Zi') # /ZI needs to be removed in that case to avoid cl's warning to that effect (D9025 : overriding '/ZI' with '/Zi')
if ('/ZI' in commands) and ('/Zi' in commands): if ('/ZI' in commands) and ('/Zi' in commands):
@ -1021,7 +1022,7 @@ class Backend:
return libs return libs
def is_unity(self, target): def is_unity(self, target):
optval = self.get_option_for_target('unity', target) optval = self.get_option_for_target(OptionKey('unity'), target)
if optval == 'on' or (optval == 'subprojects' and target.subproject != ''): if optval == 'on' or (optval == 'subprojects' and target.subproject != ''):
return True return True
return False return False
@ -1227,7 +1228,7 @@ class Backend:
# #
# TODO: Create GNUStrip/AppleStrip/etc. hierarchy for more # TODO: Create GNUStrip/AppleStrip/etc. hierarchy for more
# fine-grained stripping of static archives. # fine-grained stripping of static archives.
should_strip = not isinstance(t, build.StaticLibrary) and self.get_option_for_target('strip', t) should_strip = not isinstance(t, build.StaticLibrary) and self.get_option_for_target(OptionKey('strip'), t)
# Install primary build output (library/executable/jar, etc) # Install primary build output (library/executable/jar, etc)
# Done separately because of strip/aliases/rpath # Done separately because of strip/aliases/rpath
if outdirs[0] is not False: if outdirs[0] is not False:

@ -537,8 +537,9 @@ int dummy;
self.add_build_comment(NinjaComment('Install rules')) self.add_build_comment(NinjaComment('Install rules'))
self.generate_install() self.generate_install()
self.generate_dist() self.generate_dist()
if 'b_coverage' in self.environment.coredata.base_options and \ key = OptionKey('b_coverage')
self.environment.coredata.base_options['b_coverage'].value: if (key in self.environment.coredata.base_options and
self.environment.coredata.base_options[key].value):
self.add_build_comment(NinjaComment('Coverage rules')) self.add_build_comment(NinjaComment('Coverage rules'))
self.generate_coverage_rules() self.generate_coverage_rules()
self.add_build_comment(NinjaComment('Suffix')) self.add_build_comment(NinjaComment('Suffix'))
@ -814,7 +815,7 @@ int dummy;
source2object[s] = o source2object[s] = o
obj_list.append(o) obj_list.append(o)
use_pch = self.environment.coredata.base_options.get('b_pch', False) use_pch = self.environment.coredata.base_options.get(OptionKey('b_pch'))
if use_pch and target.has_pch(): if use_pch and target.has_pch():
pch_objects = self.generate_pch(target, header_deps=header_deps) pch_objects = self.generate_pch(target, header_deps=header_deps)
else: else:
@ -1297,8 +1298,8 @@ int dummy;
args.append(a) args.append(a)
return args, deps return args, deps
def generate_cs_target(self, target): def generate_cs_target(self, target: build.BuildTarget):
buildtype = self.get_option_for_target('buildtype', target) buildtype = self.get_option_for_target(OptionKey('buildtype'), target)
fname = target.get_filename() fname = target.get_filename()
outname_rel = os.path.join(self.get_target_dir(target), fname) outname_rel = os.path.join(self.get_target_dir(target), fname)
src_list = target.get_sources() src_list = target.get_sources()
@ -1307,8 +1308,8 @@ int dummy;
deps = [] deps = []
commands = compiler.compiler_args(target.extra_args.get('cs', [])) commands = compiler.compiler_args(target.extra_args.get('cs', []))
commands += compiler.get_buildtype_args(buildtype) commands += compiler.get_buildtype_args(buildtype)
commands += compiler.get_optimization_args(self.get_option_for_target('optimization', target)) commands += compiler.get_optimization_args(self.get_option_for_target(OptionKey('optimization'), target))
commands += compiler.get_debug_args(self.get_option_for_target('debug', target)) commands += compiler.get_debug_args(self.get_option_for_target(OptionKey('debug'), target))
if isinstance(target, build.Executable): if isinstance(target, build.Executable):
commands.append('-target:exe') commands.append('-target:exe')
elif isinstance(target, build.SharedLibrary): elif isinstance(target, build.SharedLibrary):
@ -1349,7 +1350,7 @@ int dummy;
def determine_single_java_compile_args(self, target, compiler): def determine_single_java_compile_args(self, target, compiler):
args = [] args = []
args += compiler.get_buildtype_args(self.get_option_for_target('buildtype', target)) args += compiler.get_buildtype_args(self.get_option_for_target(OptionKey('buildtype'), target))
args += self.build.get_global_args(compiler, target.for_machine) args += self.build.get_global_args(compiler, target.for_machine)
args += self.build.get_project_args(compiler, target.subproject, target.for_machine) args += self.build.get_project_args(compiler, target.subproject, target.for_machine)
args += target.get_java_args() args += target.get_java_args()
@ -1512,7 +1513,7 @@ int dummy;
valac_outputs.append(vala_c_file) valac_outputs.append(vala_c_file)
args = self.generate_basic_compiler_args(target, valac) args = self.generate_basic_compiler_args(target, valac)
args += valac.get_colorout_args(self.environment.coredata.base_options.get('b_colorout').value) args += valac.get_colorout_args(self.environment.coredata.base_options.get(OptionKey('b_colorout')).value)
# Tell Valac to output everything in our private directory. Sadly this # Tell Valac to output everything in our private directory. Sadly this
# means it will also preserve the directory components of Vala sources # means it will also preserve the directory components of Vala sources
# found inside the build tree (generated sources). # found inside the build tree (generated sources).
@ -1619,9 +1620,9 @@ int dummy;
opt_proxy = self.get_compiler_options_for_target(target) opt_proxy = self.get_compiler_options_for_target(target)
args += ['--crate-name', target.name] args += ['--crate-name', target.name]
args += rustc.get_buildtype_args(self.get_option_for_target('buildtype', target)) args += rustc.get_buildtype_args(self.get_option_for_target(OptionKey('buildtype'), target))
args += rustc.get_debug_args(self.get_option_for_target('debug', target)) args += rustc.get_debug_args(self.get_option_for_target(OptionKey('debug'), target))
args += rustc.get_optimization_args(self.get_option_for_target('optimization', target)) args += rustc.get_optimization_args(self.get_option_for_target(OptionKey('optimization'), target))
args += rustc.get_option_compile_args(opt_proxy) args += rustc.get_option_compile_args(opt_proxy)
args += self.build.get_global_args(rustc, target.for_machine) args += self.build.get_global_args(rustc, target.for_machine)
args += self.build.get_project_args(rustc, target.subproject, target.for_machine) args += self.build.get_project_args(rustc, target.subproject, target.for_machine)
@ -1772,8 +1773,8 @@ int dummy;
raise InvalidArguments('Swift target {} contains a non-swift source file.'.format(target.get_basename())) raise InvalidArguments('Swift target {} contains a non-swift source file.'.format(target.get_basename()))
os.makedirs(self.get_target_private_dir_abs(target), exist_ok=True) os.makedirs(self.get_target_private_dir_abs(target), exist_ok=True)
compile_args = swiftc.get_compile_only_args() compile_args = swiftc.get_compile_only_args()
compile_args += swiftc.get_optimization_args(self.get_option_for_target('optimization', target)) compile_args += swiftc.get_optimization_args(self.get_option_for_target(OptionKey('optimization'), target))
compile_args += swiftc.get_debug_args(self.get_option_for_target('debug', target)) compile_args += swiftc.get_debug_args(self.get_option_for_target(OptionKey('debug'), target))
compile_args += swiftc.get_module_args(module_name) compile_args += swiftc.get_module_args(module_name)
compile_args += self.build.get_project_args(swiftc, target.subproject, target.for_machine) compile_args += self.build.get_project_args(swiftc, target.subproject, target.for_machine)
compile_args += self.build.get_global_args(swiftc, target.for_machine) compile_args += self.build.get_global_args(swiftc, target.for_machine)
@ -2498,7 +2499,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
commands += self.get_compile_debugfile_args(compiler, target, rel_obj) commands += self.get_compile_debugfile_args(compiler, target, rel_obj)
# PCH handling # PCH handling
if self.environment.coredata.base_options.get('b_pch', False): if self.environment.coredata.base_options.get(OptionKey('b_pch')):
commands += self.get_pch_include_args(compiler, target) commands += self.get_pch_include_args(compiler, target)
pchlist = target.get_pch(compiler.language) pchlist = target.get_pch(compiler.language)
else: else:
@ -2869,9 +2870,9 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
# Add things like /NOLOGO; usually can't be overridden # Add things like /NOLOGO; usually can't be overridden
commands += linker.get_linker_always_args() commands += linker.get_linker_always_args()
# Add buildtype linker args: optimization level, etc. # Add buildtype linker args: optimization level, etc.
commands += linker.get_buildtype_linker_args(self.get_option_for_target('buildtype', target)) commands += linker.get_buildtype_linker_args(self.get_option_for_target(OptionKey('buildtype'), target))
# Add /DEBUG and the pdb filename when using MSVC # Add /DEBUG and the pdb filename when using MSVC
if self.get_option_for_target('debug', target): if self.get_option_for_target(OptionKey('debug'), target):
commands += self.get_link_debugfile_args(linker, target, outname) commands += self.get_link_debugfile_args(linker, target, outname)
debugfile = self.get_link_debugfile_name(linker, target, outname) debugfile = self.get_link_debugfile_name(linker, target, outname)
if debugfile is not None: if debugfile is not None:
@ -3155,8 +3156,8 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
if ctlist: if ctlist:
elem.add_dep(self.generate_custom_target_clean(ctlist)) elem.add_dep(self.generate_custom_target_clean(ctlist))
if 'b_coverage' in self.environment.coredata.base_options and \ if OptionKey('b_coverage') in self.environment.coredata.base_options and \
self.environment.coredata.base_options['b_coverage'].value: self.environment.coredata.base_options[OptionKey('b_coverage')].value:
self.generate_gcov_clean() self.generate_gcov_clean()
elem.add_dep('clean-gcda') elem.add_dep('clean-gcda')
elem.add_dep('clean-gcno') elem.add_dep('clean-gcno')

@ -785,7 +785,7 @@ class Vs2010Backend(backends.Backend):
build_args += compiler.get_optimization_args(self.optimization) build_args += compiler.get_optimization_args(self.optimization)
build_args += compiler.get_debug_args(self.debug) build_args += compiler.get_debug_args(self.debug)
buildtype_link_args = compiler.get_buildtype_linker_args(self.buildtype) buildtype_link_args = compiler.get_buildtype_linker_args(self.buildtype)
vscrt_type = self.environment.coredata.base_options['b_vscrt'] vscrt_type = self.environment.coredata.base_options[OptionKey('b_vscrt')]
project_name = target.name project_name = target.name
target_name = target.name target_name = target.name
root = ET.Element('Project', {'DefaultTargets': "Build", root = ET.Element('Project', {'DefaultTargets': "Build",
@ -1048,9 +1048,9 @@ class Vs2010Backend(backends.Backend):
ET.SubElement(clconf, 'PreprocessorDefinitions').text = ';'.join(target_defines) ET.SubElement(clconf, 'PreprocessorDefinitions').text = ';'.join(target_defines)
ET.SubElement(clconf, 'FunctionLevelLinking').text = 'true' ET.SubElement(clconf, 'FunctionLevelLinking').text = 'true'
# Warning level # Warning level
warning_level = self.get_option_for_target('warning_level', target) warning_level = self.get_option_for_target(OptionKey('warning_level'), target)
ET.SubElement(clconf, 'WarningLevel').text = 'Level' + str(1 + int(warning_level)) ET.SubElement(clconf, 'WarningLevel').text = 'Level' + str(1 + int(warning_level))
if self.get_option_for_target('werror', target): if self.get_option_for_target(OptionKey('werror'), target):
ET.SubElement(clconf, 'TreatWarningAsError').text = 'true' ET.SubElement(clconf, 'TreatWarningAsError').text = 'true'
# Optimization flags # Optimization flags
o_flags = split_o_flags_args(build_args) o_flags = split_o_flags_args(build_args)
@ -1075,7 +1075,7 @@ class Vs2010Backend(backends.Backend):
ET.SubElement(clconf, 'FavorSizeOrSpeed').text = 'Speed' ET.SubElement(clconf, 'FavorSizeOrSpeed').text = 'Speed'
# Note: SuppressStartupBanner is /NOLOGO and is 'true' by default # Note: SuppressStartupBanner is /NOLOGO and is 'true' by default
pch_sources = {} pch_sources = {}
if self.environment.coredata.base_options.get('b_pch', False): if self.environment.coredata.base_options.get(OptionKey('b_pch')):
for lang in ['c', 'cpp']: for lang in ['c', 'cpp']:
pch = target.get_pch(lang) pch = target.get_pch(lang)
if not pch: if not pch:

@ -404,7 +404,7 @@ class EnvironmentVariables:
return env return env
class Target: class Target:
def __init__(self, name, subdir, subproject, build_by_default, for_machine: MachineChoice): def __init__(self, name, subdir, subproject, build_by_default: bool, for_machine: MachineChoice):
if has_path_sep(name): if has_path_sep(name):
# Fix failing test 53 when this becomes an error. # Fix failing test 53 when this becomes an error.
mlog.warning('''Target "{}" has a path separator in its name. mlog.warning('''Target "{}" has a path separator in its name.
@ -417,7 +417,7 @@ a hard error in the future.'''.format(name))
self.for_machine = for_machine self.for_machine = for_machine
self.install = False self.install = False
self.build_always_stale = False self.build_always_stale = False
self.option_overrides_base: 'OptionDictType' = {} self.option_overrides_base: T.Dict[OptionKey, str] = {}
self.option_overrides_compiler: 'KeyedOptionDictType' = {} self.option_overrides_compiler: 'KeyedOptionDictType' = {}
self.extra_files = [] # type: T.List[File] self.extra_files = [] # type: T.List[File]
if not hasattr(self, 'typename'): if not hasattr(self, 'typename'):
@ -499,7 +499,7 @@ a hard error in the future.'''.format(name))
return self.construct_id_from_path( return self.construct_id_from_path(
self.subdir, self.name, self.type_suffix()) self.subdir, self.name, self.type_suffix())
def process_kwargs_base(self, kwargs): def process_kwargs_base(self, kwargs: T.Dict[str, T.Any]) -> None:
if 'build_by_default' in kwargs: if 'build_by_default' in kwargs:
self.build_by_default = kwargs['build_by_default'] self.build_by_default = kwargs['build_by_default']
if not isinstance(self.build_by_default, bool): if not isinstance(self.build_by_default, bool):
@ -512,23 +512,22 @@ a hard error in the future.'''.format(name))
option_overrides = self.parse_overrides(kwargs) option_overrides = self.parse_overrides(kwargs)
for k, v in option_overrides.items(): for k, v in option_overrides.items():
if '_' in k: if k.lang:
key = OptionKey.from_string(k) self.option_overrides_compiler[k.evolve(machine=self.for_machine)] = v
if key.lang: continue
self.option_overrides_compiler[key.evolve(machine=self.for_machine)] = v
continue
self.option_overrides_base[k] = v self.option_overrides_base[k] = v
def parse_overrides(self, kwargs) -> dict: @staticmethod
result = {} def parse_overrides(kwargs: T.Dict[str, T.Any]) -> T.Dict[OptionKey, str]:
result: T.Dict[OptionKey, str] = {}
overrides = stringlistify(kwargs.get('override_options', [])) overrides = stringlistify(kwargs.get('override_options', []))
for o in overrides: for o in overrides:
if '=' not in o: if '=' not in o:
raise InvalidArguments('Overrides must be of form "key=value"') raise InvalidArguments('Overrides must be of form "key=value"')
k, v = o.split('=', 1) k, v = o.split('=', 1)
k = k.strip() key = OptionKey.from_string(k.strip())
v = v.strip() v = v.strip()
result[k] = v result[key] = v
return result return result
def is_linkable_target(self) -> bool: def is_linkable_target(self) -> bool:
@ -1066,17 +1065,18 @@ This will become a hard error in a future Meson release.''')
raise InvalidArguments('Invalid value for win_subsystem: {}.'.format(value)) raise InvalidArguments('Invalid value for win_subsystem: {}.'.format(value))
return value return value
def _extract_pic_pie(self, kwargs, arg, environment, option): def _extract_pic_pie(self, kwargs, arg: str, environment, option: str):
# Check if we have -fPIC, -fpic, -fPIE, or -fpie in cflags # Check if we have -fPIC, -fpic, -fPIE, or -fpie in cflags
all_flags = self.extra_args['c'] + self.extra_args['cpp'] all_flags = self.extra_args['c'] + self.extra_args['cpp']
if '-f' + arg.lower() in all_flags or '-f' + arg.upper() in all_flags: if '-f' + arg.lower() in all_flags or '-f' + arg.upper() in all_flags:
mlog.warning("Use the '{}' kwarg instead of passing '{}' manually to {!r}".format(arg, '-f' + arg, self.name)) mlog.warning("Use the '{}' kwarg instead of passing '{}' manually to {!r}".format(arg, '-f' + arg, self.name))
return True return True
k = OptionKey(option)
if arg in kwargs: if arg in kwargs:
val = kwargs[arg] val = kwargs[arg]
elif option in environment.coredata.base_options: elif k in environment.coredata.base_options:
val = environment.coredata.base_options[option].value val = environment.coredata.base_options[k].value
else: else:
val = False val = False
@ -1597,8 +1597,9 @@ class Executable(BuildTarget):
def __init__(self, name: str, subdir: str, subproject: str, for_machine: MachineChoice, def __init__(self, name: str, subdir: str, subproject: str, for_machine: MachineChoice,
sources: T.List[File], objects, environment: environment.Environment, kwargs): sources: T.List[File], objects, environment: environment.Environment, kwargs):
self.typename = 'executable' self.typename = 'executable'
if 'pie' not in kwargs and 'b_pie' in environment.coredata.base_options: key = OptionKey('b_pie')
kwargs['pie'] = environment.coredata.base_options['b_pie'].value if 'pie' not in kwargs and key in environment.coredata.base_options:
kwargs['pie'] = environment.coredata.base_options[key].value
super().__init__(name, subdir, subproject, for_machine, sources, objects, environment, kwargs) super().__init__(name, subdir, subproject, for_machine, sources, objects, environment, kwargs)
# Unless overridden, executables have no suffix or prefix. Except on # Unless overridden, executables have no suffix or prefix. Except on
# Windows and with C#/Mono executables where the suffix is 'exe' # Windows and with C#/Mono executables where the suffix is 'exe'

@ -23,7 +23,7 @@ import re
import os import os
from .. import mlog from .. import mlog
from ..mesonlib import PerMachine, Popen_safe, version_compare, MachineChoice, is_windows from ..mesonlib import PerMachine, Popen_safe, version_compare, MachineChoice, is_windows, OptionKey
from ..envconfig import get_env_var from ..envconfig import get_env_var
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
@ -62,7 +62,7 @@ class CMakeExecutor:
self.cmakebin = None self.cmakebin = None
return return
self.prefix_paths = self.environment.coredata.builtins_per_machine[self.for_machine]['cmake_prefix_path'].value self.prefix_paths = self.environment.coredata.builtins[OptionKey('cmake_prefix_path', machine=self.for_machine)].value
env_pref_path_raw = get_env_var( env_pref_path_raw = get_env_var(
self.for_machine, self.for_machine,
self.environment.is_cross_build(), self.environment.is_cross_build(),

@ -578,7 +578,7 @@ class ConverterTarget:
@lru_cache(maxsize=None) @lru_cache(maxsize=None)
def _all_lang_stds(self, lang: str) -> T.List[str]: def _all_lang_stds(self, lang: str) -> T.List[str]:
try: try:
res = self.env.coredata.compiler_options[OptionKey('std', machine=MachineChoice.BUILD, lang=lang)].choices # type: ignore res = self.env.coredata.compiler_options[OptionKey('std', machine=MachineChoice.BUILD, lang=lang)].choices
except KeyError: except KeyError:
return [] return []

@ -265,36 +265,32 @@ cuda_debug_args = {False: [],
clike_debug_args = {False: [], clike_debug_args = {False: [],
True: ['-g']} # type: T.Dict[bool, T.List[str]] True: ['-g']} # type: T.Dict[bool, T.List[str]]
base_options = {'b_pch': coredata.UserBooleanOption('Use precompiled headers', True), base_options: 'KeyedOptionDictType' = {
'b_lto': coredata.UserBooleanOption('Use link time optimization', False), OptionKey('b_pch'): coredata.UserBooleanOption('Use precompiled headers', True),
'b_sanitize': coredata.UserComboOption('Code sanitizer to use', OptionKey('b_lto'): coredata.UserBooleanOption('Use link time optimization', False),
['none', 'address', 'thread', 'undefined', 'memory', 'address,undefined'], OptionKey('b_sanitize'): coredata.UserComboOption('Code sanitizer to use',
'none'), ['none', 'address', 'thread', 'undefined', 'memory', 'address,undefined'],
'b_lundef': coredata.UserBooleanOption('Use -Wl,--no-undefined when linking', True), 'none'),
'b_asneeded': coredata.UserBooleanOption('Use -Wl,--as-needed when linking', True), OptionKey('b_lundef'): coredata.UserBooleanOption('Use -Wl,--no-undefined when linking', True),
'b_pgo': coredata.UserComboOption('Use profile guided optimization', OptionKey('b_asneeded'): coredata.UserBooleanOption('Use -Wl,--as-needed when linking', True),
['off', 'generate', 'use'], OptionKey('b_pgo'): coredata.UserComboOption('Use profile guided optimization',
'off'), ['off', 'generate', 'use'],
'b_coverage': coredata.UserBooleanOption('Enable coverage tracking.', 'off'),
False), OptionKey('b_coverage'): coredata.UserBooleanOption('Enable coverage tracking.', False),
'b_colorout': coredata.UserComboOption('Use colored output', OptionKey('b_colorout'): coredata.UserComboOption('Use colored output',
['auto', 'always', 'never'], ['auto', 'always', 'never'],
'always'), 'always'),
'b_ndebug': coredata.UserComboOption('Disable asserts', OptionKey('b_ndebug'): coredata.UserComboOption('Disable asserts', ['true', 'false', 'if-release'], 'false'),
['true', 'false', 'if-release'], 'false'), OptionKey('b_staticpic'): coredata.UserBooleanOption('Build static libraries as position independent', True),
'b_staticpic': coredata.UserBooleanOption('Build static libraries as position independent', OptionKey('b_pie'): coredata.UserBooleanOption('Build executables as position independent', False),
True), OptionKey('b_bitcode'): coredata.UserBooleanOption('Generate and embed bitcode (only macOS/iOS/tvOS)', False),
'b_pie': coredata.UserBooleanOption('Build executables as position independent', OptionKey('b_vscrt'): coredata.UserComboOption('VS run-time library type to use.',
False), ['none', 'md', 'mdd', 'mt', 'mtd', 'from_buildtype', 'static_from_buildtype'],
'b_bitcode': coredata.UserBooleanOption('Generate and embed bitcode (only macOS/iOS/tvOS)', 'from_buildtype'),
False), }
'b_vscrt': coredata.UserComboOption('VS run-time library type to use.',
['none', 'md', 'mdd', 'mt', 'mtd', 'from_buildtype', 'static_from_buildtype'], def option_enabled(boptions: T.Set[OptionKey], options: 'KeyedOptionDictType',
'from_buildtype'), option: OptionKey) -> bool:
} # type: OptionDictType
def option_enabled(boptions: T.List[str], options: 'OptionDictType',
option: str) -> bool:
try: try:
if option not in boptions: if option not in boptions:
return False return False
@ -304,23 +300,23 @@ def option_enabled(boptions: T.List[str], options: 'OptionDictType',
except KeyError: except KeyError:
return False return False
def get_base_compile_args(options: 'OptionDictType', compiler: 'Compiler') -> T.List[str]: def get_base_compile_args(options: 'KeyedOptionDictType', compiler: 'Compiler') -> T.List[str]:
args = [] # type T.List[str] args = [] # type T.List[str]
try: try:
if options['b_lto'].value: if options[OptionKey('b_lto')].value:
args.extend(compiler.get_lto_compile_args()) args.extend(compiler.get_lto_compile_args())
except KeyError: except KeyError:
pass pass
try: try:
args += compiler.get_colorout_args(options['b_colorout'].value) args += compiler.get_colorout_args(options[OptionKey('b_colorout')].value)
except KeyError: except KeyError:
pass pass
try: try:
args += compiler.sanitizer_compile_args(options['b_sanitize'].value) args += compiler.sanitizer_compile_args(options[OptionKey('b_sanitize')].value)
except KeyError: except KeyError:
pass pass
try: try:
pgo_val = options['b_pgo'].value pgo_val = options[OptionKey('b_pgo')].value
if pgo_val == 'generate': if pgo_val == 'generate':
args.extend(compiler.get_profile_generate_args()) args.extend(compiler.get_profile_generate_args())
elif pgo_val == 'use': elif pgo_val == 'use':
@ -328,23 +324,23 @@ def get_base_compile_args(options: 'OptionDictType', compiler: 'Compiler') -> T.
except KeyError: except KeyError:
pass pass
try: try:
if options['b_coverage'].value: if options[OptionKey('b_coverage')].value:
args += compiler.get_coverage_args() args += compiler.get_coverage_args()
except KeyError: except KeyError:
pass pass
try: try:
if (options['b_ndebug'].value == 'true' or if (options[OptionKey('b_ndebug')].value == 'true' or
(options['b_ndebug'].value == 'if-release' and (options[OptionKey('b_ndebug')].value == 'if-release' and
options['buildtype'].value in {'release', 'plain'})): options[OptionKey('buildtype')].value in {'release', 'plain'})):
args += compiler.get_disable_assert_args() args += compiler.get_disable_assert_args()
except KeyError: except KeyError:
pass pass
# This does not need a try...except # This does not need a try...except
if option_enabled(compiler.base_options, options, 'b_bitcode'): if option_enabled(compiler.base_options, options, OptionKey('b_bitcode')):
args.append('-fembed-bitcode') args.append('-fembed-bitcode')
try: try:
crt_val = options['b_vscrt'].value crt_val = options[OptionKey('b_vscrt')].value
buildtype = options['buildtype'].value buildtype = options[OptionKey('buildtype')].value
try: try:
args += compiler.get_crt_compile_args(crt_val, buildtype) args += compiler.get_crt_compile_args(crt_val, buildtype)
except AttributeError: except AttributeError:
@ -353,20 +349,20 @@ def get_base_compile_args(options: 'OptionDictType', compiler: 'Compiler') -> T.
pass pass
return args return args
def get_base_link_args(options: 'OptionDictType', linker: 'Compiler', def get_base_link_args(options: 'KeyedOptionDictType', linker: 'Compiler',
is_shared_module: bool) -> T.List[str]: is_shared_module: bool) -> T.List[str]:
args = [] # type: T.List[str] args = [] # type: T.List[str]
try: try:
if options['b_lto'].value: if options[OptionKey('b_lto')].value:
args.extend(linker.get_lto_link_args()) args.extend(linker.get_lto_link_args())
except KeyError: except KeyError:
pass pass
try: try:
args += linker.sanitizer_link_args(options['b_sanitize'].value) args += linker.sanitizer_link_args(options[OptionKey('b_sanitize')].value)
except KeyError: except KeyError:
pass pass
try: try:
pgo_val = options['b_pgo'].value pgo_val = options[OptionKey('b_pgo')].value
if pgo_val == 'generate': if pgo_val == 'generate':
args.extend(linker.get_profile_generate_args()) args.extend(linker.get_profile_generate_args())
elif pgo_val == 'use': elif pgo_val == 'use':
@ -374,13 +370,13 @@ def get_base_link_args(options: 'OptionDictType', linker: 'Compiler',
except KeyError: except KeyError:
pass pass
try: try:
if options['b_coverage'].value: if options[OptionKey('b_coverage')].value:
args += linker.get_coverage_link_args() args += linker.get_coverage_link_args()
except KeyError: except KeyError:
pass pass
as_needed = option_enabled(linker.base_options, options, 'b_asneeded') as_needed = option_enabled(linker.base_options, options, OptionKey('b_asneeded'))
bitcode = option_enabled(linker.base_options, options, 'b_bitcode') bitcode = option_enabled(linker.base_options, options, OptionKey('b_bitcode'))
# Shared modules cannot be built with bitcode_bundle because # Shared modules cannot be built with bitcode_bundle because
# -bitcode_bundle is incompatible with -undefined and -bundle # -bitcode_bundle is incompatible with -undefined and -bundle
if bitcode and not is_shared_module: if bitcode and not is_shared_module:
@ -394,14 +390,14 @@ def get_base_link_args(options: 'OptionDictType', linker: 'Compiler',
if not bitcode: if not bitcode:
args.extend(linker.headerpad_args()) args.extend(linker.headerpad_args())
if (not is_shared_module and if (not is_shared_module and
option_enabled(linker.base_options, options, 'b_lundef')): option_enabled(linker.base_options, options, OptionKey('b_lundef'))):
args.extend(linker.no_undefined_link_args()) args.extend(linker.no_undefined_link_args())
else: else:
args.extend(linker.get_allow_undefined_link_args()) args.extend(linker.get_allow_undefined_link_args())
try: try:
crt_val = options['b_vscrt'].value crt_val = options[OptionKey('b_vscrt')].value
buildtype = options['buildtype'].value buildtype = options[OptionKey('buildtype')].value
try: try:
args += linker.get_crt_link_args(crt_val, buildtype) args += linker.get_crt_link_args(crt_val, buildtype)
except AttributeError: except AttributeError:
@ -477,7 +473,7 @@ class Compiler(metaclass=abc.ABCMeta):
self.version = version self.version = version
self.full_version = full_version self.full_version = full_version
self.for_machine = for_machine self.for_machine = for_machine
self.base_options = [] # type: T.List[str] self.base_options: T.Set[OptionKey] = set()
self.linker = linker self.linker = linker
self.info = info self.info = info
self.is_cross = is_cross self.is_cross = is_cross
@ -1248,14 +1244,14 @@ def get_global_options(lang: str,
description = 'Extra arguments passed to the {}'.format(lang) description = 'Extra arguments passed to the {}'.format(lang)
argkey = OptionKey('args', lang=lang, machine=for_machine) argkey = OptionKey('args', lang=lang, machine=for_machine)
largkey = argkey.evolve('link_args') largkey = argkey.evolve('link_args')
opts = { opts: 'KeyedOptionDictType' = {
argkey: coredata.UserArrayOption( argkey: coredata.UserArrayOption(
description + ' compiler', description + ' compiler',
[], split_args=True, user_input=True, allow_dups=True), [], split_args=True, user_input=True, allow_dups=True),
largkey: coredata.UserArrayOption( largkey: coredata.UserArrayOption(
description + ' linker', description + ' linker',
[], split_args=True, user_input=True, allow_dups=True), [], split_args=True, user_input=True, allow_dups=True),
} # type: OptionDictType }
# Get from env vars. # Get from env vars.
compile_args, link_args = get_args_from_envvars( compile_args, link_args = get_args_from_envvars(

@ -664,7 +664,7 @@ class VisualStudioCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixi
CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, CPPCompiler.__init__(self, exelist, version, for_machine, is_cross,
info, exe_wrapper, linker=linker, full_version=full_version) info, exe_wrapper, linker=linker, full_version=full_version)
MSVCCompiler.__init__(self, target) MSVCCompiler.__init__(self, target)
self.base_options = ['b_pch', 'b_vscrt', 'b_ndebug'] # FIXME add lto, pgo and the like self.base_options = {OptionKey(o) for o in ['b_pch', 'b_vscrt', 'b_ndebug']} # FIXME add lto, pgo and the like
self.id = 'msvc' self.id = 'msvc'
def get_options(self) -> 'KeyedOptionDictType': def get_options(self) -> 'KeyedOptionDictType':

@ -18,7 +18,7 @@ import subprocess
import typing as T import typing as T
from ..mesonlib import ( from ..mesonlib import (
EnvironmentException, MachineChoice, version_compare, EnvironmentException, MachineChoice, version_compare, OptionKey,
) )
from ..arglist import CompilerArgs from ..arglist import CompilerArgs
@ -653,8 +653,10 @@ class GnuDCompiler(GnuCompiler, DCompiler):
'1': default_warn_args, '1': default_warn_args,
'2': default_warn_args + ['-Wextra'], '2': default_warn_args + ['-Wextra'],
'3': default_warn_args + ['-Wextra', '-Wpedantic']} '3': default_warn_args + ['-Wextra', '-Wpedantic']}
self.base_options = ['b_colorout', 'b_sanitize', 'b_staticpic', self.base_options = {
'b_vscrt', 'b_coverage', 'b_pgo', 'b_ndebug'] OptionKey(o) for o in [
'b_colorout', 'b_sanitize', 'b_staticpic', 'b_vscrt',
'b_coverage', 'b_pgo', 'b_ndebug']}
self._has_color_support = version_compare(self.version, '>=4.9') self._has_color_support = version_compare(self.version, '>=4.9')
# dependencies were implemented before, but broken - support was fixed in GCC 7.1+ # dependencies were implemented before, but broken - support was fixed in GCC 7.1+
@ -724,7 +726,7 @@ class LLVMDCompiler(DmdLikeCompilerMixin, DCompiler):
full_version=full_version, is_cross=is_cross) full_version=full_version, is_cross=is_cross)
DmdLikeCompilerMixin.__init__(self, dmd_frontend_version=find_ldc_dmd_frontend_version(version_output)) DmdLikeCompilerMixin.__init__(self, dmd_frontend_version=find_ldc_dmd_frontend_version(version_output))
self.id = 'llvm' self.id = 'llvm'
self.base_options = ['b_coverage', 'b_colorout', 'b_vscrt', 'b_ndebug'] self.base_options = {OptionKey(o) for o in ['b_coverage', 'b_colorout', 'b_vscrt', 'b_ndebug']}
def get_colorout_args(self, colortype: str) -> T.List[str]: def get_colorout_args(self, colortype: str) -> T.List[str]:
if colortype == 'always': if colortype == 'always':
@ -782,7 +784,7 @@ class DmdDCompiler(DmdLikeCompilerMixin, DCompiler):
full_version=full_version, is_cross=is_cross) full_version=full_version, is_cross=is_cross)
DmdLikeCompilerMixin.__init__(self, version) DmdLikeCompilerMixin.__init__(self, version)
self.id = 'dmd' self.id = 'dmd'
self.base_options = ['b_coverage', 'b_colorout', 'b_vscrt', 'b_ndebug'] self.base_options = {OptionKey(o) for o in ['b_coverage', 'b_colorout', 'b_vscrt', 'b_ndebug']}
def get_colorout_args(self, colortype: str) -> T.List[str]: def get_colorout_args(self, colortype: str) -> T.List[str]:
if colortype == 'always': if colortype == 'always':

@ -19,6 +19,7 @@ import typing as T
from ... import mesonlib from ... import mesonlib
from ...linkers import ArmClangDynamicLinker from ...linkers import ArmClangDynamicLinker
from ...mesonlib import OptionKey
from ..compilers import clike_debug_args from ..compilers import clike_debug_args
from .clang import clang_color_args from .clang import clang_color_args
@ -145,8 +146,10 @@ class ArmclangCompiler(Compiler):
if not mesonlib.version_compare(self.version, '==' + self.linker.version): if not mesonlib.version_compare(self.version, '==' + self.linker.version):
raise mesonlib.EnvironmentException('armlink version does not match with compiler version') raise mesonlib.EnvironmentException('armlink version does not match with compiler version')
self.id = 'armclang' self.id = 'armclang'
self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage', self.base_options = {
'b_ndebug', 'b_staticpic', 'b_colorout'] OptionKey(o) for o in
['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage',
'b_ndebug', 'b_staticpic', 'b_colorout']}
# Assembly # Assembly
self.can_compile_suffixes.add('s') self.can_compile_suffixes.add('s')

@ -20,6 +20,7 @@ import typing as T
from ... import mesonlib from ... import mesonlib
from ...linkers import AppleDynamicLinker from ...linkers import AppleDynamicLinker
from ...mesonlib import OptionKey
from ..compilers import CompileCheckMode from ..compilers import CompileCheckMode
from .gnu import GnuLikeCompiler from .gnu import GnuLikeCompiler
@ -48,11 +49,11 @@ class ClangCompiler(GnuLikeCompiler):
super().__init__() super().__init__()
self.id = 'clang' self.id = 'clang'
self.defines = defines or {} self.defines = defines or {}
self.base_options.append('b_colorout') self.base_options.add(OptionKey('b_colorout'))
# TODO: this really should be part of the linker base_options, but # TODO: this really should be part of the linker base_options, but
# linkers don't have base_options. # linkers don't have base_options.
if isinstance(self.linker, AppleDynamicLinker): if isinstance(self.linker, AppleDynamicLinker):
self.base_options.append('b_bitcode') self.base_options.add(OptionKey('b_bitcode'))
# All Clang backends can also do LLVM IR # All Clang backends can also do LLVM IR
self.can_compile_suffixes.add('ll') self.can_compile_suffixes.add('ll')
@ -108,7 +109,7 @@ class ClangCompiler(GnuLikeCompiler):
else: else:
# Shouldn't work, but it'll be checked explicitly in the OpenMP dependency. # Shouldn't work, but it'll be checked explicitly in the OpenMP dependency.
return [] return []
@classmethod @classmethod
def use_linker_args(cls, linker: str) -> T.List[str]: def use_linker_args(cls, linker: str) -> T.List[str]:
# Clang additionally can use a linker specified as a path, which GCC # Clang additionally can use a linker specified as a path, which GCC

@ -35,6 +35,7 @@ from ... import mesonlib
from ... import mlog from ... import mlog
from ...linkers import GnuLikeDynamicLinkerMixin, SolarisDynamicLinker, CompCertDynamicLinker from ...linkers import GnuLikeDynamicLinkerMixin, SolarisDynamicLinker, CompCertDynamicLinker
from ...mesonlib import LibType from ...mesonlib import LibType
from ...coredata import OptionKey
from .. import compilers from .. import compilers
from ..compilers import CompileCheckMode from ..compilers import CompileCheckMode
from .visualstudio import VisualStudioLikeCompiler from .visualstudio import VisualStudioLikeCompiler
@ -393,14 +394,16 @@ class CLikeCompiler(Compiler):
# linking with static libraries since MSVC won't select a CRT for # 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. # us in that case and will error out asking us to pick one.
try: try:
crt_val = env.coredata.base_options['b_vscrt'].value crt_val = env.coredata.base_options[OptionKey('b_vscrt')].value
buildtype = env.coredata.builtins['buildtype'].value buildtype = env.coredata.builtins[OptionKey('buildtype')].value
cargs += self.get_crt_compile_args(crt_val, buildtype) cargs += self.get_crt_compile_args(crt_val, buildtype)
except (KeyError, AttributeError): except (KeyError, AttributeError):
pass pass
# Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS and CPPFLAGS from the env # Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS and CPPFLAGS from the env
sys_args = env.coredata.get_external_args(self.for_machine, self.language) sys_args = env.coredata.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 # Apparently it is a thing to inject linker flags both
# via CFLAGS _and_ LDFLAGS, even though the former are # via CFLAGS _and_ LDFLAGS, even though the former are
# also used during linking. These flags can break # also used during linking. These flags can break

@ -21,7 +21,7 @@ import re
from .gnu import GnuLikeCompiler from .gnu import GnuLikeCompiler
from .gnu import gnu_optimization_args from .gnu import gnu_optimization_args
from ...mesonlib import Popen_safe from ...mesonlib import Popen_safe, OptionKey
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
from ...environment import Environment from ...environment import Environment
@ -34,9 +34,7 @@ class ElbrusCompiler(GnuLikeCompiler):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
self.id = 'lcc' self.id = 'lcc'
self.base_options = ['b_pgo', 'b_coverage', self.base_options = {OptionKey(o) for o in ['b_pgo', 'b_coverage', 'b_ndebug', 'b_staticpic', 'b_lundef', 'b_asneeded']}
'b_ndebug', 'b_staticpic',
'b_lundef', 'b_asneeded']
# FIXME: use _build_wrapper to call this so that linker flags from the env # FIXME: use _build_wrapper to call this so that linker flags from the env
# get applied # get applied

@ -51,7 +51,7 @@ class EmscriptenMixin(Compiler):
def thread_link_flags(self, env: 'Environment') -> T.List[str]: def thread_link_flags(self, env: 'Environment') -> T.List[str]:
args = ['-s', 'USE_PTHREADS=1'] args = ['-s', 'USE_PTHREADS=1']
count: int = env.coredata.compiler_options[OptionKey('thread_count', lang=self.language, machine=self.for_machine)].value # type: ignore count: int = env.coredata.compiler_options[OptionKey('thread_count', lang=self.language, machine=self.for_machine)].value
if count: if count:
args.extend(['-s', 'PTHREAD_POOL_SIZE={}'.format(count)]) args.extend(['-s', 'PTHREAD_POOL_SIZE={}'.format(count)])
return args return args

@ -24,6 +24,7 @@ import typing as T
from ... import mesonlib from ... import mesonlib
from ... import mlog from ... import mlog
from ...mesonlib import OptionKey
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
from ...environment import Environment from ...environment import Environment
@ -146,14 +147,15 @@ class GnuLikeCompiler(Compiler, metaclass=abc.ABCMeta):
LINKER_PREFIX = '-Wl,' LINKER_PREFIX = '-Wl,'
def __init__(self) -> None: def __init__(self) -> None:
self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_coverage', self.base_options = {
'b_ndebug', 'b_staticpic', 'b_pie'] OptionKey(o) for o in ['b_pch', 'b_lto', 'b_pgo', 'b_coverage',
'b_ndebug', 'b_staticpic', 'b_pie']}
if not (self.info.is_windows() or self.info.is_cygwin() or self.info.is_openbsd()): if not (self.info.is_windows() or self.info.is_cygwin() or self.info.is_openbsd()):
self.base_options.append('b_lundef') self.base_options.add(OptionKey('b_lundef'))
if not self.info.is_windows() or self.info.is_cygwin(): if not self.info.is_windows() or self.info.is_cygwin():
self.base_options.append('b_asneeded') self.base_options.add(OptionKey('b_asneeded'))
if not self.info.is_hurd(): if not self.info.is_hurd():
self.base_options.append('b_sanitize') self.base_options.add(OptionKey('b_sanitize'))
# All GCC-like backends can do assembly # All GCC-like backends can do assembly
self.can_compile_suffixes.add('s') self.can_compile_suffixes.add('s')
@ -328,7 +330,7 @@ class GnuCompiler(GnuLikeCompiler):
super().__init__() super().__init__()
self.id = 'gcc' self.id = 'gcc'
self.defines = defines or {} self.defines = defines or {}
self.base_options.append('b_colorout') self.base_options.add(OptionKey('b_colorout'))
def get_colorout_args(self, colortype: str) -> T.List[str]: def get_colorout_args(self, colortype: str) -> T.List[str]:
if mesonlib.version_compare(self.version, '>=4.9.0'): if mesonlib.version_compare(self.version, '>=4.9.0'):

@ -79,8 +79,9 @@ class IntelGnuLikeCompiler(GnuLikeCompiler):
# It does have IPO, which serves much the same purpose as LOT, but # It does have IPO, which serves much the same purpose as LOT, but
# there is an unfortunate rule for using IPO (you can't control the # there is an unfortunate rule for using IPO (you can't control the
# name of the output file) which break assumptions meson makes # name of the output file) which break assumptions meson makes
self.base_options = ['b_pch', 'b_lundef', 'b_asneeded', 'b_pgo', self.base_options = {mesonlib.OptionKey(o) for o in [
'b_coverage', 'b_ndebug', 'b_staticpic', 'b_pie'] 'b_pch', 'b_lundef', 'b_asneeded', 'b_pgo', 'b_coverage',
'b_ndebug', 'b_staticpic', 'b_pie']}
self.id = 'intel' self.id = 'intel'
self.lang_header = 'none' self.lang_header = 'none'

@ -19,6 +19,7 @@ import os
from pathlib import Path from pathlib import Path
from ..compilers import clike_debug_args, clike_optimization_args from ..compilers import clike_debug_args, clike_optimization_args
from ...mesonlib import OptionKey
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
from ...environment import Environment from ...environment import Environment
@ -43,7 +44,7 @@ pgi_buildtype_args = {
class PGICompiler(Compiler): class PGICompiler(Compiler):
def __init__(self) -> None: def __init__(self) -> None:
self.base_options = ['b_pch'] self.base_options = {OptionKey('b_pch')}
self.id = 'pgi' self.id = 'pgi'
default_warn_args = ['-Minform=inform'] default_warn_args = ['-Minform=inform']

@ -129,7 +129,7 @@ class VisualStudioLikeCompiler(Compiler, metaclass=abc.ABCMeta):
INVOKES_LINKER = False INVOKES_LINKER = False
def __init__(self, target: str): def __init__(self, target: str):
self.base_options = ['b_pch', 'b_ndebug', 'b_vscrt'] # FIXME add lto, pgo and the like self.base_options = {mesonlib.OptionKey(o) for o in ['b_pch', 'b_ndebug', 'b_vscrt']} # FIXME add lto, pgo and the like
self.target = target self.target = target
self.is_64 = ('x64' in target) or ('x86_64' in target) self.is_64 = ('x64' in target) or ('x86_64' in target)
# do some canonicalization of target machine # do some canonicalization of target machine

@ -55,9 +55,9 @@ class RustCompiler(Compiler):
linker=linker) linker=linker)
self.exe_wrapper = exe_wrapper self.exe_wrapper = exe_wrapper
self.id = 'rustc' self.id = 'rustc'
self.base_options.append('b_colorout') self.base_options.add(OptionKey('b_colorout'))
if 'link' in self.linker.id: if 'link' in self.linker.id:
self.base_options.append('b_vscrt') self.base_options.add(OptionKey('b_vscrt'))
def needs_static_linker(self) -> bool: def needs_static_linker(self) -> bool:
return False return False

@ -16,7 +16,7 @@ import os.path
import typing as T import typing as T
from .. import mlog from .. import mlog
from ..mesonlib import EnvironmentException, MachineChoice, version_compare from ..mesonlib import EnvironmentException, MachineChoice, version_compare, OptionKey
from .compilers import Compiler, LibType from .compilers import Compiler, LibType
@ -33,7 +33,7 @@ class ValaCompiler(Compiler):
super().__init__(exelist, version, for_machine, info, is_cross=is_cross) super().__init__(exelist, version, for_machine, info, is_cross=is_cross)
self.version = version self.version = version
self.id = 'valac' self.id = 'valac'
self.base_options = ['b_colorout'] self.base_options = {OptionKey('b_colorout')}
def needs_static_linker(self) -> bool: def needs_static_linker(self) -> bool:
return False # Because compiles into C. return False # Because compiles into C.

@ -21,7 +21,7 @@ from collections import OrderedDict, defaultdict
from .mesonlib import ( from .mesonlib import (
MesonException, EnvironmentException, MachineChoice, PerMachine, MesonException, EnvironmentException, MachineChoice, PerMachine,
default_libdir, default_libexecdir, default_prefix, split_args, default_libdir, default_libexecdir, default_prefix, split_args,
OptionKey, OptionKey, OptionType,
) )
from .wrap import WrapMode from .wrap import WrapMode
import ast import ast
@ -301,16 +301,17 @@ class DependencyCache:
successfully lookup by providing a simple get/put interface. successfully lookup by providing a simple get/put interface.
""" """
def __init__(self, builtins_per_machine: PerMachine[T.Dict[str, UserOption[T.Any]]], for_machine: MachineChoice): def __init__(self, builtins: 'KeyedOptionDictType', for_machine: MachineChoice):
self.__cache = OrderedDict() # type: T.MutableMapping[CacheKeyType, DependencySubCache] self.__cache = OrderedDict() # type: T.MutableMapping[CacheKeyType, DependencySubCache]
self.__builtins_per_machine = builtins_per_machine self.__builtins = builtins
self.__for_machine = for_machine self.__pkg_conf_key = OptionKey('pkg_config_path', machine=for_machine)
self.__cmake_key = OptionKey('cmake_prefix_path', machine=for_machine)
def __calculate_subkey(self, type_: DependencyCacheType) -> T.Tuple[T.Any, ...]: def __calculate_subkey(self, type_: DependencyCacheType) -> T.Tuple[T.Any, ...]:
if type_ is DependencyCacheType.PKG_CONFIG: if type_ is DependencyCacheType.PKG_CONFIG:
return tuple(self.__builtins_per_machine[self.__for_machine]['pkg_config_path'].value) return tuple(self.__builtins[self.__pkg_conf_key].value)
elif type_ is DependencyCacheType.CMAKE: elif type_ is DependencyCacheType.CMAKE:
return tuple(self.__builtins_per_machine[self.__for_machine]['cmake_prefix_path'].value) return tuple(self.__builtins[self.__cmake_key].value)
assert type_ is DependencyCacheType.OTHER, 'Someone forgot to update subkey calculations for a new type' assert type_ is DependencyCacheType.OTHER, 'Someone forgot to update subkey calculations for a new type'
return tuple() return tuple()
@ -384,17 +385,16 @@ class CoreData:
self.meson_command = meson_command self.meson_command = meson_command
self.target_guids = {} self.target_guids = {}
self.version = version self.version = version
self.builtins = {} # type: OptionDictType self.builtins: 'KeyedOptionDictType' = {}
self.builtins_per_machine: PerMachine['OptionDictType'] = PerMachine({}, {})
self.backend_options: 'KeyedOptionDictType' = {} self.backend_options: 'KeyedOptionDictType' = {}
self.user_options: 'KeyedOptionDictType' = {} self.user_options: 'KeyedOptionDictType' = {}
self.compiler_options: 'KeyedOptionDictType' = {} self.compiler_options: 'KeyedOptionDictType' = {}
self.base_options = {} # type: OptionDictType self.base_options: 'KeyedOptionDictType' = {}
self.cross_files = self.__load_config_files(options, scratch_dir, 'cross') self.cross_files = self.__load_config_files(options, scratch_dir, 'cross')
self.compilers = PerMachine(OrderedDict(), OrderedDict()) # type: PerMachine[T.Dict[str, Compiler]] self.compilers = PerMachine(OrderedDict(), OrderedDict()) # type: PerMachine[T.Dict[str, Compiler]]
build_cache = DependencyCache(self.builtins_per_machine, MachineChoice.BUILD) build_cache = DependencyCache(self.builtins, MachineChoice.BUILD)
host_cache = DependencyCache(self.builtins_per_machine, MachineChoice.BUILD) host_cache = DependencyCache(self.builtins, MachineChoice.BUILD)
self.deps = PerMachine(build_cache, host_cache) # type: PerMachine[DependencyCache] self.deps = PerMachine(build_cache, host_cache) # type: PerMachine[DependencyCache]
self.compiler_check_cache = OrderedDict() # type: T.Dict[CompilerCheckCacheKey, compiler.CompileResult] self.compiler_check_cache = OrderedDict() # type: T.Dict[CompilerCheckCacheKey, compiler.CompileResult]
@ -466,7 +466,7 @@ class CoreData:
# getting the "system default" is always wrong on multiarch # getting the "system default" is always wrong on multiarch
# platforms as it gets a value like lib/x86_64-linux-gnu. # platforms as it gets a value like lib/x86_64-linux-gnu.
if self.cross_files: if self.cross_files:
BUILTIN_OPTIONS['libdir'].default = 'lib' BUILTIN_OPTIONS[OptionKey('libdir')].default = 'lib'
def sanitize_prefix(self, prefix): def sanitize_prefix(self, prefix):
prefix = os.path.expanduser(prefix) prefix = os.path.expanduser(prefix)
@ -486,7 +486,7 @@ class CoreData:
prefix = prefix[:-1] prefix = prefix[:-1]
return prefix return prefix
def sanitize_dir_option_value(self, prefix: str, option: str, value: T.Any) -> T.Any: def sanitize_dir_option_value(self, prefix: str, option: OptionKey, value: T.Any) -> T.Any:
''' '''
If the option is an installation directory option and the value is an If the option is an installation directory option and the value is an
absolute path, check that it resides within prefix and return the value absolute path, check that it resides within prefix and return the value
@ -501,13 +501,13 @@ class CoreData:
value = PurePath(value) value = PurePath(value)
except TypeError: except TypeError:
return value return value
if option.endswith('dir') and value.is_absolute() and \ if option.name.endswith('dir') and value.is_absolute() and \
option not in builtin_dir_noprefix_options: option not in BULITIN_DIR_NOPREFIX_OPTIONS:
# Value must be a subdir of the prefix # Value must be a subdir of the prefix
# commonpath will always return a path in the native format, so we # commonpath will always return a path in the native format, so we
# must use pathlib.PurePath to do the same conversion before # must use pathlib.PurePath to do the same conversion before
# comparing. # comparing.
msg = ('The value of the {!r} option is \'{!s}\' which must be a ' msg = ('The value of the \'{!s}\' option is \'{!s}\' which must be a '
'subdir of the prefix {!r}.\nNote that if you pass a ' 'subdir of the prefix {!r}.\nNote that if you pass a '
'relative path, it is assumed to be a subdir of prefix.') 'relative path, it is assumed to be a subdir of prefix.')
# os.path.commonpath doesn't understand case-insensitive filesystems, # os.path.commonpath doesn't understand case-insensitive filesystems,
@ -520,25 +520,25 @@ class CoreData:
raise MesonException(msg.format(option, value, prefix)) raise MesonException(msg.format(option, value, prefix))
return value.as_posix() return value.as_posix()
def init_builtins(self, subproject: str): def init_builtins(self, subproject: str) -> None:
# Create builtin options with default values # Create builtin options with default values
for key, opt in BUILTIN_OPTIONS.items(): for key, opt in BUILTIN_OPTIONS.items():
self.add_builtin_option(self.builtins, key, opt, subproject) self.add_builtin_option(self.builtins, key.evolve(subproject=subproject), opt)
for for_machine in iter(MachineChoice): for for_machine in iter(MachineChoice):
for key, opt in BUILTIN_OPTIONS_PER_MACHINE.items(): for key, opt in BUILTIN_OPTIONS_PER_MACHINE.items():
self.add_builtin_option(self.builtins_per_machine[for_machine], key, opt, subproject) self.add_builtin_option(self.builtins, key.evolve(subproject=subproject, machine=for_machine), opt)
def add_builtin_option(self, opts_map, key, opt, subproject): @staticmethod
if subproject: def add_builtin_option(opts_map: 'KeyedOptionDictType', key: OptionKey,
opt: 'BuiltinOption') -> None:
if key.subproject:
if opt.yielding: if opt.yielding:
# This option is global and not per-subproject # This option is global and not per-subproject
return return
optname = subproject + ':' + key value = opts_map[key.as_root()].value
value = opts_map[key].value
else: else:
optname = key
value = None value = None
opts_map[optname] = opt.init_option(key, value, default_prefix()) opts_map[key] = opt.init_option(key, value, default_prefix())
def init_backend_options(self, backend_name: str) -> None: def init_backend_options(self, backend_name: str) -> None:
if backend_name == 'ninja': if backend_name == 'ninja':
@ -552,45 +552,43 @@ class CoreData:
'') '')
def get_builtin_option(self, optname: str, subproject: str = '') -> T.Union[str, int, bool]: def get_builtin_option(self, optname: str, subproject: str = '') -> T.Union[str, int, bool]:
raw_optname = optname key = OptionKey.from_string(optname).evolve(subproject=subproject)
if subproject:
optname = subproject + ':' + optname
for opts in self._get_all_builtin_options(): for opts in self._get_all_builtin_options():
v = opts.get(optname) v = opts.get(str(key))
if v is None or v.yielding: if v is None or v.yielding:
v = opts.get(raw_optname) v = opts.get(str(key.as_root()))
if v is None: if v is None:
continue continue
if raw_optname == 'wrap_mode': if key.name == 'wrap_mode':
return WrapMode.from_string(v.value) return WrapMode.from_string(v.value)
return v.value return v.value
raise RuntimeError('Tried to get unknown builtin option %s.' % raw_optname) raise RuntimeError(f'Tried to get unknown builtin option {key.name}.')
def _try_set_builtin_option(self, optname, value): def _try_set_builtin_option(self, key: OptionKey, value) -> bool:
for opts in self._get_all_builtin_options(): for opts in self._get_all_builtin_options():
opt = opts.get(optname) opt = opts.get(str(key))
if opt is None: if opt is None:
continue continue
if optname == 'prefix': if key.name == 'prefix':
value = self.sanitize_prefix(value) value = self.sanitize_prefix(value)
else: else:
prefix = self.builtins['prefix'].value prefix = self.builtins[OptionKey('prefix')].value
value = self.sanitize_dir_option_value(prefix, optname, value) value = self.sanitize_dir_option_value(prefix, key, value)
break break
else: else:
return False return False
opt.set_value(value) opt.set_value(value)
# Make sure that buildtype matches other settings. # Make sure that buildtype matches other settings.
if optname == 'buildtype': if key.name == 'buildtype':
self.set_others_from_buildtype(value) self.set_others_from_buildtype(value)
else: else:
self.set_buildtype_from_others() self.set_buildtype_from_others()
return True return True
def set_builtin_option(self, optname, value): def set_builtin_option(self, optname: OptionKey, value) -> None:
res = self._try_set_builtin_option(optname, value) res = self._try_set_builtin_option(optname, value)
if not res: if not res:
raise RuntimeError('Tried to set unknown builtin option %s.' % optname) raise RuntimeError(f'Tried to set unknown builtin option {str(optname)}')
def set_others_from_buildtype(self, value): def set_others_from_buildtype(self, value):
if value == 'plain': if value == 'plain':
@ -611,12 +609,12 @@ class CoreData:
else: else:
assert(value == 'custom') assert(value == 'custom')
return return
self.builtins['optimization'].set_value(opt) self.builtins[OptionKey('optimization')].set_value(opt)
self.builtins['debug'].set_value(debug) self.builtins[OptionKey('debug')].set_value(debug)
def set_buildtype_from_others(self): def set_buildtype_from_others(self):
opt = self.builtins['optimization'].value opt = self.builtins[OptionKey('optimization')].value
debug = self.builtins['debug'].value debug = self.builtins[OptionKey('debug')].value
if opt == '0' and not debug: if opt == '0' and not debug:
mode = 'plain' mode = 'plain'
elif opt == '0' and debug: elif opt == '0' and debug:
@ -629,7 +627,7 @@ class CoreData:
mode = 'minsize' mode = 'minsize'
else: else:
mode = 'custom' mode = 'custom'
self.builtins['buildtype'].set_value(mode) self.builtins[OptionKey('buildtype')].set_value(mode)
@classmethod @classmethod
def get_prefixed_options_per_machine( def get_prefixed_options_per_machine(
@ -666,19 +664,18 @@ class CoreData:
yield {str(k): v for k, v in self.backend_options.items()} yield {str(k): v for k, v in self.backend_options.items()}
yield {str(k): v for k, v in self.user_options.items()} yield {str(k): v for k, v in self.user_options.items()}
yield {str(k): v for k, v in self.compiler_options.items()} yield {str(k): v for k, v in self.compiler_options.items()}
yield self.base_options yield {str(k): v for k, v in self.base_options.items()}
def _get_all_builtin_options(self) -> T.Iterable[T.Dict[str, UserOption]]: def _get_all_builtin_options(self) -> T.Iterable[T.Dict[str, UserOption]]:
yield dict(self.get_prefixed_options_per_machine(self.builtins_per_machine)) yield {str(k): v for k, v in self.builtins.items()}
yield self.builtins
def get_all_options(self) -> T.Iterable[T.Dict[str, UserOption]]: def get_all_options(self) -> T.Iterable[T.Dict[str, UserOption]]:
yield from self._get_all_nonbuiltin_options() yield from self._get_all_nonbuiltin_options()
yield from self._get_all_builtin_options() yield from self._get_all_builtin_options()
def validate_option_value(self, option_name, override_value): def validate_option_value(self, option_name: OptionKey, override_value):
for opts in self.get_all_options(): for opts in self.get_all_options():
opt = opts.get(option_name) opt = opts.get(str(option_name))
if opt is not None: if opt is not None:
try: try:
return opt.validate_value(override_value) return opt.validate_value(override_value)
@ -718,10 +715,11 @@ class CoreData:
return False return False
return len(self.cross_files) > 0 return len(self.cross_files) > 0
def copy_build_options_from_regular_ones(self): def copy_build_options_from_regular_ones(self) -> None:
assert not self.is_cross_build() assert not self.is_cross_build()
for k, o in self.builtins_per_machine.host.items(): for k in BUILTIN_OPTIONS_PER_MACHINE:
self.builtins_per_machine.build[k].set_value(o.value) o = self.builtins[k]
self.builtins[k.as_build()].set_value(o.value)
for bk, bv in self.compiler_options.items(): for bk, bv in self.compiler_options.items():
if bk.machine is MachineChoice.BUILD: if bk.machine is MachineChoice.BUILD:
hk = bk.as_host() hk = bk.as_host()
@ -738,8 +736,8 @@ class CoreData:
pfk = OptionKey('prefix') pfk = OptionKey('prefix')
if pfk in options: if pfk in options:
prefix = self.sanitize_prefix(options[pfk]) prefix = self.sanitize_prefix(options[pfk])
self.builtins['prefix'].set_value(prefix) self.builtins[OptionKey('prefix')].set_value(prefix)
for key in builtin_dir_noprefix_options: for key in BULITIN_DIR_NOPREFIX_OPTIONS:
if key not in options: if key not in options:
self.builtins[key].set_value(BUILTIN_OPTIONS[key].prefixed_default(key, prefix)) self.builtins[key].set_value(BUILTIN_OPTIONS[key].prefixed_default(key, prefix))
@ -747,7 +745,7 @@ class CoreData:
for k, v in options.items(): for k, v in options.items():
if k == pfk: if k == pfk:
continue continue
if self._try_set_builtin_option(str(k), v): if self._try_set_builtin_option(k, v):
continue continue
for opts in self._get_all_nonbuiltin_options(): for opts in self._get_all_nonbuiltin_options():
tgt = opts.get(str(k)) tgt = opts.get(str(k))
@ -783,15 +781,13 @@ class CoreData:
# to know which backend we'll use). # to know which backend we'll use).
options: T.MutableMapping[OptionKey, T.Any] = OrderedDict() options: T.MutableMapping[OptionKey, T.Any] = OrderedDict()
from . import optinterpreter
for k, v in chain(default_options.items(), env.options.items()): for k, v in chain(default_options.items(), env.options.items()):
# Subproject: skip options for other subprojects # Subproject: skip options for other subprojects
if k.subproject and k.subproject != subproject: if k.subproject and k.subproject != subproject:
continue continue
# Skip base, compiler, and backend options, they are handled when # Skip base, compiler, and backend options, they are handled when
# adding languages and setting backend. # adding languages and setting backend.
if (k.name not in self.builtins and k.name not in self.builtins_per_machine[k.machine] and if k.type in {OptionType.COMPILER, OptionType.BACKEND, OptionType.BASE}:
optinterpreter.is_invalid_name(str(k), log=False)):
continue continue
options[k] = v options[k] = v
@ -818,20 +814,19 @@ class CoreData:
self.compilers[comp.for_machine][lang] = comp self.compilers[comp.for_machine][lang] = comp
self.add_compiler_options(comp.get_options(), lang, comp.for_machine, env) self.add_compiler_options(comp.get_options(), lang, comp.for_machine, env)
enabled_opts = [] enabled_opts: T.List[OptionKey] = []
for optname in comp.base_options: for key in comp.base_options:
if optname in self.base_options: if key in self.base_options:
continue continue
oobj = compilers.base_options[optname] oobj = compilers.base_options[key]
key = OptionKey(optname, machine=comp.for_machine)
if key in env.options: if key in env.options:
oobj.set_value(env.options[key]) oobj.set_value(env.options[key])
enabled_opts.append(optname) enabled_opts.append(key)
self.base_options[optname] = oobj self.base_options[key] = oobj
self.emit_base_options_warnings(enabled_opts) self.emit_base_options_warnings(enabled_opts)
def emit_base_options_warnings(self, enabled_opts: list): def emit_base_options_warnings(self, enabled_opts: T.List[OptionKey]) -> None:
if 'b_bitcode' in enabled_opts: if OptionKey('b_bitcode') in enabled_opts:
mlog.warning('Base option \'b_bitcode\' is enabled, which is incompatible with many linker options. Incompatible options such as \'b_asneeded\' have been disabled.', fatal=False) mlog.warning('Base option \'b_bitcode\' is enabled, which is incompatible with many linker options. Incompatible options such as \'b_asneeded\' have been disabled.', fatal=False)
mlog.warning('Please see https://mesonbuild.com/Builtin-options.html#Notes_about_Apple_Bitcode_support for more details.', fatal=False) mlog.warning('Please see https://mesonbuild.com/Builtin-options.html#Notes_about_Apple_Bitcode_support for more details.', fatal=False)
@ -1007,10 +1002,10 @@ def save(obj: CoreData, build_dir: str) -> str:
def register_builtin_arguments(parser: argparse.ArgumentParser) -> None: def register_builtin_arguments(parser: argparse.ArgumentParser) -> None:
for n, b in BUILTIN_OPTIONS.items(): for n, b in BUILTIN_OPTIONS.items():
b.add_to_argparse(n, parser, '', '') b.add_to_argparse(str(n), parser, '')
for n, b in BUILTIN_OPTIONS_PER_MACHINE.items(): for n, b in BUILTIN_OPTIONS_PER_MACHINE.items():
b.add_to_argparse(n, parser, '', ' (just for host machine)') b.add_to_argparse(str(n), parser, ' (just for host machine)')
b.add_to_argparse(n, parser, 'build.', ' (just for build machine)') b.add_to_argparse(str(n.as_build()), parser, ' (just for build machine)')
parser.add_argument('-D', action='append', dest='projectoptions', default=[], metavar="option", parser.add_argument('-D', action='append', dest='projectoptions', default=[], metavar="option",
help='Set the value of an option, can be used several times to set multiple options.') help='Set the value of an option, can be used several times to set multiple options.')
@ -1031,14 +1026,14 @@ def parse_cmd_line_options(args: argparse.Namespace) -> None:
args.cmd_line_options = create_options_dict(args.projectoptions) args.cmd_line_options = create_options_dict(args.projectoptions)
# Merge builtin options set with --option into the dict. # Merge builtin options set with --option into the dict.
for name in chain( for key in chain(
BUILTIN_OPTIONS.keys(), BUILTIN_OPTIONS.keys(),
('build.' + k for k in BUILTIN_OPTIONS_PER_MACHINE.keys()), (k.as_build() for k in BUILTIN_OPTIONS_PER_MACHINE.keys()),
BUILTIN_OPTIONS_PER_MACHINE.keys(), BUILTIN_OPTIONS_PER_MACHINE.keys(),
): ):
name = str(key)
value = getattr(args, name, None) value = getattr(args, name, None)
if value is not None: if value is not None:
key = OptionKey.from_string(name)
if key in args.cmd_line_options: if key in args.cmd_line_options:
cmdline_name = BuiltinOption.argparse_name_to_arg(name) cmdline_name = BuiltinOption.argparse_name_to_arg(name)
raise MesonException( raise MesonException(
@ -1064,7 +1059,7 @@ class BuiltinOption(T.Generic[_T, _U]):
self.choices = choices self.choices = choices
self.yielding = yielding self.yielding = yielding
def init_option(self, name: str, value: T.Optional[T.Any], prefix: str) -> _U: def init_option(self, name: 'OptionKey', value: T.Optional[T.Any], prefix: str) -> _U:
"""Create an instance of opt_type and return it.""" """Create an instance of opt_type and return it."""
if value is None: if value is None:
value = self.prefixed_default(name, prefix) value = self.prefixed_default(name, prefix)
@ -1095,16 +1090,16 @@ class BuiltinOption(T.Generic[_T, _U]):
else: else:
return '--' + name.replace('_', '-') return '--' + name.replace('_', '-')
def prefixed_default(self, name: str, prefix: str = '') -> T.Any: def prefixed_default(self, name: 'OptionKey', prefix: str = '') -> T.Any:
if self.opt_type in [UserComboOption, UserIntegerOption]: if self.opt_type in [UserComboOption, UserIntegerOption]:
return self.default return self.default
try: try:
return builtin_dir_noprefix_options[name][prefix] return BULITIN_DIR_NOPREFIX_OPTIONS[name][prefix]
except KeyError: except KeyError:
pass pass
return self.default return self.default
def add_to_argparse(self, name: str, parser: argparse.ArgumentParser, prefix: str, help_suffix: str) -> None: def add_to_argparse(self, name: str, parser: argparse.ArgumentParser, help_suffix: str) -> None:
kwargs = OrderedDict() kwargs = OrderedDict()
c = self._argparse_choices() c = self._argparse_choices()
@ -1117,64 +1112,65 @@ class BuiltinOption(T.Generic[_T, _U]):
if c and not b: if c and not b:
kwargs['choices'] = c kwargs['choices'] = c
kwargs['default'] = argparse.SUPPRESS kwargs['default'] = argparse.SUPPRESS
kwargs['dest'] = prefix + name kwargs['dest'] = name
cmdline_name = self.argparse_name_to_arg(prefix + name) cmdline_name = self.argparse_name_to_arg(name)
parser.add_argument(cmdline_name, help=h + help_suffix, **kwargs) parser.add_argument(cmdline_name, help=h + help_suffix, **kwargs)
# Update `docs/markdown/Builtin-options.md` after changing the options below # Update `docs/markdown/Builtin-options.md` after changing the options below
BUILTIN_DIR_OPTIONS = OrderedDict([ # Also update mesonlib._BUILTIN_NAMES. See the comment there for why this is required.
('prefix', BuiltinOption(UserStringOption, 'Installation prefix', default_prefix())), BUILTIN_DIR_OPTIONS: 'KeyedOptionDictType' = OrderedDict([
('bindir', BuiltinOption(UserStringOption, 'Executable directory', 'bin')), (OptionKey('prefix'), BuiltinOption(UserStringOption, 'Installation prefix', default_prefix())),
('datadir', BuiltinOption(UserStringOption, 'Data file directory', 'share')), (OptionKey('bindir'), BuiltinOption(UserStringOption, 'Executable directory', 'bin')),
('includedir', BuiltinOption(UserStringOption, 'Header file directory', 'include')), (OptionKey('datadir'), BuiltinOption(UserStringOption, 'Data file directory', 'share')),
('infodir', BuiltinOption(UserStringOption, 'Info page directory', 'share/info')), (OptionKey('includedir'), BuiltinOption(UserStringOption, 'Header file directory', 'include')),
('libdir', BuiltinOption(UserStringOption, 'Library directory', default_libdir())), (OptionKey('infodir'), BuiltinOption(UserStringOption, 'Info page directory', 'share/info')),
('libexecdir', BuiltinOption(UserStringOption, 'Library executable directory', default_libexecdir())), (OptionKey('libdir'), BuiltinOption(UserStringOption, 'Library directory', default_libdir())),
('localedir', BuiltinOption(UserStringOption, 'Locale data directory', 'share/locale')), (OptionKey('libexecdir'), BuiltinOption(UserStringOption, 'Library executable directory', default_libexecdir())),
('localstatedir', BuiltinOption(UserStringOption, 'Localstate data directory', 'var')), (OptionKey('localedir'), BuiltinOption(UserStringOption, 'Locale data directory', 'share/locale')),
('mandir', BuiltinOption(UserStringOption, 'Manual page directory', 'share/man')), (OptionKey('localstatedir'), BuiltinOption(UserStringOption, 'Localstate data directory', 'var')),
('sbindir', BuiltinOption(UserStringOption, 'System executable directory', 'sbin')), (OptionKey('mandir'), BuiltinOption(UserStringOption, 'Manual page directory', 'share/man')),
('sharedstatedir', BuiltinOption(UserStringOption, 'Architecture-independent data directory', 'com')), (OptionKey('sbindir'), BuiltinOption(UserStringOption, 'System executable directory', 'sbin')),
('sysconfdir', BuiltinOption(UserStringOption, 'Sysconf data directory', 'etc')), (OptionKey('sharedstatedir'), BuiltinOption(UserStringOption, 'Architecture-independent data directory', 'com')),
]) # type: OptionDictType (OptionKey('sysconfdir'), BuiltinOption(UserStringOption, 'Sysconf data directory', 'etc')),
])
BUILTIN_CORE_OPTIONS = OrderedDict([
('auto_features', BuiltinOption(UserFeatureOption, "Override value of all 'auto' features", 'auto')), BUILTIN_CORE_OPTIONS: 'KeyedOptionDictType' = OrderedDict([
('backend', BuiltinOption(UserComboOption, 'Backend to use', 'ninja', choices=backendlist)), (OptionKey('auto_features'), BuiltinOption(UserFeatureOption, "Override value of all 'auto' features", 'auto')),
('buildtype', BuiltinOption(UserComboOption, 'Build type to use', 'debug', (OptionKey('backend'), BuiltinOption(UserComboOption, 'Backend to use', 'ninja', choices=backendlist)),
choices=['plain', 'debug', 'debugoptimized', 'release', 'minsize', 'custom'])), (OptionKey('buildtype'), BuiltinOption(UserComboOption, 'Build type to use', 'debug',
('debug', BuiltinOption(UserBooleanOption, 'Debug', True)), choices=['plain', 'debug', 'debugoptimized', 'release', 'minsize', 'custom'])),
('default_library', BuiltinOption(UserComboOption, 'Default library type', 'shared', choices=['shared', 'static', 'both'], (OptionKey('debug'), BuiltinOption(UserBooleanOption, 'Debug', True)),
yielding=False)), (OptionKey('default_library'), BuiltinOption(UserComboOption, 'Default library type', 'shared', choices=['shared', 'static', 'both'],
('errorlogs', BuiltinOption(UserBooleanOption, "Whether to print the logs from failing tests", True)), yielding=False)),
('install_umask', BuiltinOption(UserUmaskOption, 'Default umask to apply on permissions of installed files', '022')), (OptionKey('errorlogs'), BuiltinOption(UserBooleanOption, "Whether to print the logs from failing tests", True)),
('layout', BuiltinOption(UserComboOption, 'Build directory layout', 'mirror', choices=['mirror', 'flat'])), (OptionKey('install_umask'), BuiltinOption(UserUmaskOption, 'Default umask to apply on permissions of installed files', '022')),
('optimization', BuiltinOption(UserComboOption, 'Optimization level', '0', choices=['0', 'g', '1', '2', '3', 's'])), (OptionKey('layout'), BuiltinOption(UserComboOption, 'Build directory layout', 'mirror', choices=['mirror', 'flat'])),
('stdsplit', BuiltinOption(UserBooleanOption, 'Split stdout and stderr in test logs', True)), (OptionKey('optimization'), BuiltinOption(UserComboOption, 'Optimization level', '0', choices=['0', 'g', '1', '2', '3', 's'])),
('strip', BuiltinOption(UserBooleanOption, 'Strip targets on install', False)), (OptionKey('stdsplit'), BuiltinOption(UserBooleanOption, 'Split stdout and stderr in test logs', True)),
('unity', BuiltinOption(UserComboOption, 'Unity build', 'off', choices=['on', 'off', 'subprojects'])), (OptionKey('strip'), BuiltinOption(UserBooleanOption, 'Strip targets on install', False)),
('unity_size', BuiltinOption(UserIntegerOption, 'Unity block size', (2, None, 4))), (OptionKey('unity'), BuiltinOption(UserComboOption, 'Unity build', 'off', choices=['on', 'off', 'subprojects'])),
('warning_level', BuiltinOption(UserComboOption, 'Compiler warning level to use', '1', choices=['0', '1', '2', '3'], yielding=False)), (OptionKey('unity_size'), BuiltinOption(UserIntegerOption, 'Unity block size', (2, None, 4))),
('werror', BuiltinOption(UserBooleanOption, 'Treat warnings as errors', False, yielding=False)), (OptionKey('warning_level'), BuiltinOption(UserComboOption, 'Compiler warning level to use', '1', choices=['0', '1', '2', '3'], yielding=False)),
('wrap_mode', BuiltinOption(UserComboOption, 'Wrap mode', 'default', choices=['default', 'nofallback', 'nodownload', 'forcefallback'])), (OptionKey('werror'), BuiltinOption(UserBooleanOption, 'Treat warnings as errors', False, yielding=False)),
('force_fallback_for', BuiltinOption(UserArrayOption, 'Force fallback for those subprojects', [])), (OptionKey('wrap_mode'), BuiltinOption(UserComboOption, 'Wrap mode', 'default', choices=['default', 'nofallback', 'nodownload', 'forcefallback'])),
]) # type: OptionDictType (OptionKey('force_fallback_for'), BuiltinOption(UserArrayOption, 'Force fallback for those subprojects', [])),
])
BUILTIN_OPTIONS = OrderedDict(chain(BUILTIN_DIR_OPTIONS.items(), BUILTIN_CORE_OPTIONS.items())) BUILTIN_OPTIONS = OrderedDict(chain(BUILTIN_DIR_OPTIONS.items(), BUILTIN_CORE_OPTIONS.items()))
BUILTIN_OPTIONS_PER_MACHINE = OrderedDict([ BUILTIN_OPTIONS_PER_MACHINE: 'KeyedOptionDictType' = OrderedDict([
('pkg_config_path', BuiltinOption(UserArrayOption, 'List of additional paths for pkg-config to search', [])), (OptionKey('pkg_config_path'), BuiltinOption(UserArrayOption, 'List of additional paths for pkg-config to search', [])),
('cmake_prefix_path', BuiltinOption(UserArrayOption, 'List of additional prefixes for cmake to search', [])), (OptionKey('cmake_prefix_path'), BuiltinOption(UserArrayOption, 'List of additional prefixes for cmake to search', [])),
]) ])
# Special prefix-dependent defaults for installation directories that reside in # Special prefix-dependent defaults for installation directories that reside in
# a path outside of the prefix in FHS and common usage. # a path outside of the prefix in FHS and common usage.
builtin_dir_noprefix_options = { BULITIN_DIR_NOPREFIX_OPTIONS: T.Dict[OptionKey, T.Dict[str, str]] = {
'sysconfdir': {'/usr': '/etc'}, OptionKey('sysconfdir'): {'/usr': '/etc'},
'localstatedir': {'/usr': '/var', '/usr/local': '/var/local'}, OptionKey('localstatedir'): {'/usr': '/var', '/usr/local': '/var/local'},
'sharedstatedir': {'/usr': '/var/lib', '/usr/local': '/var/local/lib'}, OptionKey('sharedstatedir'): {'/usr': '/var/lib', '/usr/local': '/var/local/lib'},
} }
FORBIDDEN_TARGET_NAMES = {'clean': None, FORBIDDEN_TARGET_NAMES = {'clean': None,

@ -37,7 +37,7 @@ from ..environment import Environment, MachineInfo
from ..cmake import CMakeExecutor, CMakeTraceParser, CMakeException, CMakeToolchain, CMakeExecScope, check_cmake_args from ..cmake import CMakeExecutor, CMakeTraceParser, CMakeException, CMakeToolchain, CMakeExecScope, check_cmake_args
from ..mesonlib import MachineChoice, MesonException, OrderedSet, PerMachine from ..mesonlib import MachineChoice, MesonException, OrderedSet, PerMachine
from ..mesonlib import Popen_safe, version_compare_many, version_compare, listify, stringlistify, extract_as_list, split_args from ..mesonlib import Popen_safe, version_compare_many, version_compare, listify, stringlistify, extract_as_list, split_args
from ..mesonlib import Version, LibType from ..mesonlib import Version, LibType, OptionKey
from ..mesondata import mesondata from ..mesondata import mesondata
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
@ -656,8 +656,9 @@ class PkgConfigDependency(ExternalDependency):
return rc, out, err return rc, out, err
@staticmethod @staticmethod
def setup_env(env, environment, for_machine, extra_path=None): def setup_env(env: T.MutableMapping[str, str], environment: 'Environment', for_machine: MachineChoice,
extra_paths = environment.coredata.builtins_per_machine[for_machine]['pkg_config_path'].value extra_path: T.Optional[str] = None) -> None:
extra_paths: T.List[str] = environment.coredata.builtins[OptionKey('pkg_config_path', machine=for_machine)].value
if extra_path: if extra_path:
extra_paths.append(extra_path) extra_paths.append(extra_path)
sysroot = environment.properties[for_machine].get_sys_root() sysroot = environment.properties[for_machine].get_sys_root()
@ -1484,9 +1485,9 @@ class CMakeDependency(ExternalDependency):
cfgs = [x for x in tgt.properties['IMPORTED_CONFIGURATIONS'] if x] cfgs = [x for x in tgt.properties['IMPORTED_CONFIGURATIONS'] if x]
cfg = cfgs[0] cfg = cfgs[0]
if 'b_vscrt' in self.env.coredata.base_options: if OptionKey('b_vscrt') in self.env.coredata.base_options:
is_debug = self.env.coredata.get_builtin_option('buildtype') == 'debug' is_debug = self.env.coredata.get_builtin_option('buildtype') == 'debug'
if self.env.coredata.base_options['b_vscrt'].value in ('mdd', 'mtd'): if self.env.coredata.base_options[OptionKey('b_vscrt')].value in {'mdd', 'mtd'}:
is_debug = True is_debug = True
else: else:
is_debug = self.env.coredata.get_builtin_option('debug') is_debug = self.env.coredata.get_builtin_option('debug')

@ -616,8 +616,8 @@ class BoostDependency(ExternalDependency):
# MSVC is very picky with the library tags # MSVC is very picky with the library tags
vscrt = '' vscrt = ''
try: try:
crt_val = self.env.coredata.base_options['b_vscrt'].value crt_val = self.env.coredata.base_options[mesonlib.OptionKey('b_vscrt')].value
buildtype = self.env.coredata.builtins['buildtype'].value buildtype = self.env.coredata.builtins[mesonlib.OptionKey('buildtype')].value
vscrt = self.clib_compiler.get_crt_compile_args(crt_val, buildtype)[0] vscrt = self.clib_compiler.get_crt_compile_args(crt_val, buildtype)[0]
except (KeyError, IndexError, AttributeError): except (KeyError, IndexError, AttributeError):
pass pass

@ -383,8 +383,8 @@ class QtBaseDependency(ExternalDependency):
# Use the buildtype by default, but look at the b_vscrt option if the # Use the buildtype by default, but look at the b_vscrt option if the
# compiler supports it. # compiler supports it.
is_debug = self.env.coredata.get_builtin_option('buildtype') == 'debug' is_debug = self.env.coredata.get_builtin_option('buildtype') == 'debug'
if 'b_vscrt' in self.env.coredata.base_options: if mesonlib.OptionKey('b_vscrt') in self.env.coredata.base_options:
if self.env.coredata.base_options['b_vscrt'].value in ('mdd', 'mtd'): if self.env.coredata.base_options[mesonlib.OptionKey('b_vscrt')].value in {'mdd', 'mtd'}:
is_debug = True is_debug = True
modules_lib_suffix = self._get_modules_lib_suffix(is_debug) modules_lib_suffix = self._get_modules_lib_suffix(is_debug)

@ -11,7 +11,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import pdb
from . import mparser from . import mparser
from . import environment from . import environment
from . import coredata from . import coredata
@ -22,7 +21,7 @@ from . import optinterpreter
from . import compilers from . import compilers
from .wrap import wrap, WrapMode from .wrap import wrap, WrapMode
from . import mesonlib from . import mesonlib
from .mesonlib import FileMode, MachineChoice, Popen_safe, listify, extract_as_list, has_path_sep, unholder from .mesonlib import FileMode, MachineChoice, OptionKey, Popen_safe, listify, extract_as_list, has_path_sep, unholder
from .dependencies import ExternalProgram from .dependencies import ExternalProgram
from .dependencies import InternalDependency, Dependency, NotFoundDependency, DependencyException from .dependencies import InternalDependency, Dependency, NotFoundDependency, DependencyException
from .depfile import DepFile from .depfile import DepFile
@ -83,7 +82,7 @@ class FeatureOptionHolder(InterpreterObject, ObjectHolder):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
ObjectHolder.__init__(self, option) ObjectHolder.__init__(self, option)
if option.is_auto(): if option.is_auto():
self.held_object = env.coredata.builtins['auto_features'] self.held_object = env.coredata.builtins[OptionKey('auto_features')]
self.name = name self.name = name
self.methods.update({'enabled': self.enabled_method, self.methods.update({'enabled': self.enabled_method,
'disabled': self.disabled_method, 'disabled': self.disabled_method,
@ -3010,7 +3009,7 @@ external dependencies (including libraries) must go to "dependencies".''')
def _do_subproject_cmake(self, subp_name, subdir, subdir_abs, default_options, kwargs): def _do_subproject_cmake(self, subp_name, subdir, subdir_abs, default_options, kwargs):
with mlog.nested(): with mlog.nested():
new_build = self.build.copy() new_build = self.build.copy()
prefix = self.coredata.builtins['prefix'].value prefix = self.coredata.builtins[OptionKey('prefix')].value
from .modules.cmake import CMakeSubprojectOptions from .modules.cmake import CMakeSubprojectOptions
options = kwargs.get('options', CMakeSubprojectOptions()) options = kwargs.get('options', CMakeSubprojectOptions())
@ -3052,23 +3051,10 @@ external dependencies (including libraries) must go to "dependencies".''')
return result return result
def get_option_internal(self, optname: str): def get_option_internal(self, optname: str):
raw_optname = optname # TODO: this optname may be a compiler option
if self.is_subproject(): key = OptionKey.from_string(optname).evolve(subproject=self.subproject)
optname = self.subproject + ':' + optname
for opts in [
self.coredata.base_options, compilers.base_options, self.coredata.builtins,
dict(self.coredata.get_prefixed_options_per_machine(self.coredata.builtins_per_machine)),
]:
v = opts.get(optname)
if v is None or v.yielding:
v = opts.get(raw_optname)
if v is not None:
return v
key = mesonlib.OptionKey.from_string(optname) for opts in [self.coredata.builtins, self.coredata.base_options, compilers.base_options, self.coredata.compiler_options]:
for opts in [self.coredata.compiler_options]:
v = opts.get(key) v = opts.get(key)
if v is None or v.yielding: if v is None or v.yielding:
v = opts.get(key.as_root()) v = opts.get(key.as_root())
@ -3090,7 +3076,7 @@ external dependencies (including libraries) must go to "dependencies".''')
mlog.warning('Option {0!r} of type {1!r} in subproject {2!r} cannot yield ' mlog.warning('Option {0!r} of type {1!r} in subproject {2!r} cannot yield '
'to parent option of type {3!r}, ignoring parent value. ' 'to parent option of type {3!r}, ignoring parent value. '
'Use -D{2}:{0}=value to set the value for this option manually' 'Use -D{2}:{0}=value to set the value for this option manually'
'.'.format(raw_optname, opt_type, self.subproject, popt_type), '.'.format(optname, opt_type, self.subproject, popt_type),
location=self.current_node) location=self.current_node)
return opt return opt
except KeyError: except KeyError:
@ -4786,15 +4772,15 @@ different subdirectory.
break break
def check_clang_asan_lundef(self) -> None: def check_clang_asan_lundef(self) -> None:
if 'b_lundef' not in self.coredata.base_options: if OptionKey('b_lundef') not in self.coredata.base_options:
return return
if 'b_sanitize' not in self.coredata.base_options: if OptionKey('b_sanitize') not in self.coredata.base_options:
return return
if (self.coredata.base_options['b_lundef'].value and if (self.coredata.base_options[OptionKey('b_lundef')].value and
self.coredata.base_options['b_sanitize'].value != 'none'): self.coredata.base_options[OptionKey('b_sanitize')].value != 'none'):
mlog.warning('''Trying to use {} sanitizer on Clang with b_lundef. mlog.warning('''Trying to use {} sanitizer on Clang with b_lundef.
This will probably not work. This will probably not work.
Try setting b_lundef to false instead.'''.format(self.coredata.base_options['b_sanitize'].value), Try setting b_lundef to false instead.'''.format(self.coredata.base_options[OptionKey('b_sanitize')].value),
location=self.current_node) location=self.current_node)
def evaluate_subproject_info(self, path_from_source_root, subproject_dir): def evaluate_subproject_info(self, path_from_source_root, subproject_dir):
@ -4889,10 +4875,11 @@ Try setting b_lundef to false instead.'''.format(self.coredata.base_options['b_s
# Check if user forces non-PIC static library. # Check if user forces non-PIC static library.
pic = True pic = True
key = OptionKey('b_staticpic')
if 'pic' in kwargs: if 'pic' in kwargs:
pic = kwargs['pic'] pic = kwargs['pic']
elif 'b_staticpic' in self.environment.coredata.base_options: elif key in self.environment.coredata.base_options:
pic = self.environment.coredata.base_options['b_staticpic'].value pic = self.environment.coredata.base_options[key].value
if pic: if pic:
# Exclude sources from args and kwargs to avoid building them twice # Exclude sources from args and kwargs to avoid building them twice

@ -17,12 +17,11 @@ from . import coredata, environment, mesonlib, build, mintro, mlog
from .ast import AstIDGenerator from .ast import AstIDGenerator
import typing as T import typing as T
from .mesonlib import MachineChoice from .mesonlib import MachineChoice, OptionKey
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
import argparse import argparse
from .coredata import UserOption from .coredata import UserOption
from .mesonlib import OptionKey
def add_arguments(parser: 'argparse.ArgumentParser') -> None: def add_arguments(parser: 'argparse.ArgumentParser') -> None:
coredata.register_builtin_arguments(parser) coredata.register_builtin_arguments(parser)
@ -30,7 +29,6 @@ def add_arguments(parser: 'argparse.ArgumentParser') -> None:
parser.add_argument('--clearcache', action='store_true', default=False, parser.add_argument('--clearcache', action='store_true', default=False,
help='Clear cached state (e.g. found dependencies)') help='Clear cached state (e.g. found dependencies)')
def make_lower_case(val: T.Any) -> T.Union[str, T.List[T.Any]]: # T.Any because of recursion... def make_lower_case(val: T.Any) -> T.Union[str, T.List[T.Any]]: # T.Any because of recursion...
if isinstance(val, bool): if isinstance(val, bool):
return str(val).lower() return str(val).lower()
@ -39,12 +37,6 @@ def make_lower_case(val: T.Any) -> T.Union[str, T.List[T.Any]]: # T.Any because
else: else:
return str(val) return str(val)
def insert_build_prefix(k: str) -> str:
idx = k.find(':')
if idx < 0:
return 'build.' + k
return k[:idx + 1] + 'build.' + k[idx + 1:]
class ConfException(mesonlib.MesonException): class ConfException(mesonlib.MesonException):
pass pass
@ -62,8 +54,8 @@ class Conf:
self.choices_col = [] self.choices_col = []
self.descr_col = [] self.descr_col = []
self.has_choices = False self.has_choices = False
self.all_subprojects = set() self.all_subprojects: T.Set[str] = set()
self.yielding_options = set() self.yielding_options: T.Set[OptionKey] = set()
if os.path.isdir(os.path.join(self.build_dir, 'meson-private')): if os.path.isdir(os.path.join(self.build_dir, 'meson-private')):
self.build = build.load(self.build_dir) self.build = build.load(self.build_dir)
@ -111,20 +103,8 @@ class Conf:
else: else:
print('{0:{width[0]}} {1:{width[1]}} {3}'.format(*line, width=col_widths)) print('{0:{width[0]}} {1:{width[1]}} {3}'.format(*line, width=col_widths))
def split_options_per_subproject(self, options: T.Dict[str, 'UserOption']) -> T.Dict[str, T.Dict[str, 'UserOption']]: def split_options_per_subproject(self, options: 'coredata.KeyedOptionDictType') -> T.Dict[str, T.Dict[str, 'UserOption']]:
result = {} result: T.Dict[str, T.Dict[str, 'UserOption']] = {}
for k, o in options.items():
subproject = ''
if ':' in k:
subproject, optname = k.split(':')
if o.yielding and optname in options:
self.yielding_options.add(k)
self.all_subprojects.add(subproject)
result.setdefault(subproject, {})[k] = o
return result
def split_options_per_subproject2(self, options: 'coredata.KeyedOptionDictType') -> T.Dict[str, T.Dict[str, 'UserOption']]:
result = {}
for k, o in options.items(): for k, o in options.items():
subproject = k.subproject subproject = k.subproject
if k.subproject: if k.subproject:
@ -135,8 +115,8 @@ class Conf:
result.setdefault(subproject, {})[str(k)] = o result.setdefault(subproject, {})[str(k)] = o
return result return result
def _add_line(self, name, value, choices, descr): def _add_line(self, name: OptionKey, value, choices, descr) -> None:
self.name_col.append(' ' * self.print_margin + name) self.name_col.append(' ' * self.print_margin + str(name))
self.value_col.append(value) self.value_col.append(value)
self.choices_col.append(choices) self.choices_col.append(choices)
self.descr_col.append(descr) self.descr_col.append(descr)
@ -185,7 +165,7 @@ class Conf:
self._add_line(section + ':', '', '', '') self._add_line(section + ':', '', '', '')
self.print_margin = 2 self.print_margin = 2
def print_options(self, title: str, options: 'coredata.OptionDictType') -> None: def print_options(self, title: str, options: 'coredata.KeyedOptionDictType') -> None:
if not options: if not options:
return return
if title: if title:
@ -210,28 +190,28 @@ class Conf:
if not self.default_values_only: if not self.default_values_only:
print(' Build dir ', self.build_dir) print(' Build dir ', self.build_dir)
dir_option_names = list(coredata.BUILTIN_DIR_OPTIONS) dir_option_names = set(coredata.BUILTIN_DIR_OPTIONS)
test_option_names = ['errorlogs', test_option_names = {OptionKey('errorlogs'),
'stdsplit'] OptionKey('stdsplit')}
core_option_names = [k for k in self.coredata.builtins if k not in dir_option_names + test_option_names] core_option_names = [k for k in self.coredata.builtins if k not in dir_option_names | test_option_names]
dir_options = {k: o for k, o in self.coredata.builtins.items() if k in dir_option_names} dir_options = {k: o for k, o in self.coredata.builtins.items() if k in dir_option_names}
test_options = {k: o for k, o in self.coredata.builtins.items() if k in test_option_names} test_options = {k: o for k, o in self.coredata.builtins.items() if k in test_option_names}
core_options = {k: o for k, o in self.coredata.builtins.items() if k in core_option_names} core_options = {k: o for k, o in self.coredata.builtins.items() if k in core_option_names}
core_options = self.split_options_per_subproject(core_options) host_core_options = self.split_options_per_subproject({k: v for k, v in self.coredata.builtins.items() if k.machine is MachineChoice.HOST})
host_compiler_options = self.split_options_per_subproject2({k: v for k, v in self.coredata.compiler_options.items() if k.machine is MachineChoice.HOST}) build_core_options = self.split_options_per_subproject({k: v for k, v in self.coredata.builtins.items() if k.machine is MachineChoice.BUILD})
build_compiler_options = self.split_options_per_subproject2({k: v for k, v in self.coredata.compiler_options.items() if k.machine is MachineChoice.BUILD}) host_compiler_options = self.split_options_per_subproject({k: v for k, v in self.coredata.compiler_options.items() if k.machine is MachineChoice.HOST})
project_options = self.split_options_per_subproject2(self.coredata.user_options) build_compiler_options = self.split_options_per_subproject({k: v for k, v in self.coredata.compiler_options.items() if k.machine is MachineChoice.BUILD})
project_options = self.split_options_per_subproject(self.coredata.user_options)
show_build_options = self.default_values_only or self.build.environment.is_cross_build() show_build_options = self.default_values_only or self.build.environment.is_cross_build()
self.add_section('Main project options') self.add_section('Main project options')
self.print_options('Core options', core_options['']) self.print_options('Core options', host_core_options[''])
self.print_options('', self.coredata.builtins_per_machine.host)
if show_build_options: if show_build_options:
self.print_options('', {insert_build_prefix(k): o for k, o in self.coredata.builtins_per_machine.build.items()}) self.print_options('', build_core_options[''])
self.print_options('Backend options', {str(k): v for k, v in self.coredata.backend_options.items()}) self.print_options('Backend options', {str(k): v for k, v in self.coredata.backend_options.items()})
self.print_options('Base options', self.coredata.base_options) self.print_options('Base options', {str(k): v for k, v in self.coredata.base_options.items()})
self.print_options('Compiler options', host_compiler_options.get('', {})) self.print_options('Compiler options', host_compiler_options.get('', {}))
if show_build_options: if show_build_options:
self.print_options('', build_compiler_options.get('', {})) self.print_options('', build_compiler_options.get('', {}))

@ -32,7 +32,7 @@ from mesonbuild import mlog
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
from .build import ConfigurationData from .build import ConfigurationData
from .coredata import OptionDictType, UserOption from .coredata import KeyedOptionDictType, UserOption
from .compilers.compilers import CompilerType from .compilers.compilers import CompilerType
from .interpreterbase import ObjectHolder from .interpreterbase import ObjectHolder
@ -1743,6 +1743,10 @@ class OptionProxy(T.Generic[_T]):
self.value = value self.value = value
self.choices = choices self.choices = choices
def set_value(self, v: _T) -> None:
# XXX: should this be an error
self.value = v
class OptionOverrideProxy(collections.abc.MutableMapping): class OptionOverrideProxy(collections.abc.MutableMapping):
@ -1753,13 +1757,13 @@ class OptionOverrideProxy(collections.abc.MutableMapping):
# TODO: the typing here could be made more explicit using a TypeDict from # TODO: the typing here could be made more explicit using a TypeDict from
# python 3.8 or typing_extensions # python 3.8 or typing_extensions
def __init__(self, overrides: T.Dict[str, T.Any], *options: 'OptionDictType'): def __init__(self, overrides: T.Dict['OptionKey', T.Any], *options: 'KeyedOptionDictType'):
self.overrides = overrides.copy() self.overrides = overrides.copy()
self.options = {} # type: T.Dict[str, UserOption] self.options: T.Dict['OptionKey', UserOption] = {}
for o in options: for o in options:
self.options.update(o) self.options.update(o)
def __getitem__(self, key: str) -> T.Union['UserOption', OptionProxy]: def __getitem__(self, key: 'OptionKey') -> T.Union['UserOption', OptionProxy]:
if key in self.options: if key in self.options:
opt = self.options[key] opt = self.options[key]
if key in self.overrides: if key in self.overrides:
@ -1767,13 +1771,13 @@ class OptionOverrideProxy(collections.abc.MutableMapping):
return opt return opt
raise KeyError('Option not found', key) raise KeyError('Option not found', key)
def __setitem__(self, key: str, value: T.Union['UserOption', OptionProxy]) -> None: def __setitem__(self, key: 'OptionKey', value: T.Union['UserOption', OptionProxy]) -> None:
self.overrides[key] = value.value self.overrides[key] = value.value
def __delitem__(self, key: str) -> None: def __delitem__(self, key: 'OptionKey') -> None:
del self.overrides[key] del self.overrides[key]
def __iter__(self) -> T.Iterator[str]: def __iter__(self) -> T.Iterator['OptionKey']:
return iter(self.options) return iter(self.options)
def __len__(self) -> int: def __len__(self) -> int:
@ -1793,20 +1797,54 @@ class OptionType(enum.Enum):
PROJECT = 3 PROJECT = 3
BACKEND = 4 BACKEND = 4
# This is copied from coredata. There is no way to share this, because this
# is used in the OptionKey constructor, and the coredata lists are
# OptionKeys...
_BUILTIN_NAMES = {
'prefix',
'bindir',
'datadir',
'includedir',
'infodir',
'libdir',
'libexecdir',
'localedir',
'localstatedir',
'mandir',
'sbindir',
'sharedstatedir',
'sysconfdir',
'auto_features',
'backend',
'buildtype',
'debug',
'default_library',
'errorlogs',
'install_umask',
'layout',
'optimization',
'stdsplit',
'strip',
'unity',
'unity_size',
'warning_level',
'werror',
'wrap_mode',
'force_fallback_for',
'pkg_config_path',
'cmake_prefix_path',
}
def _classify_argument(key: 'OptionKey') -> OptionType: def _classify_argument(key: 'OptionKey') -> OptionType:
"""Classify arguments into groups so we know which dict to assign them to.""" """Classify arguments into groups so we know which dict to assign them to."""
from .compilers import base_options if key.name.startswith('b_'):
from .coredata import BUILTIN_OPTIONS, BUILTIN_OPTIONS_PER_MACHINE, builtin_dir_noprefix_options
all_builtins = set(BUILTIN_OPTIONS) | set(BUILTIN_OPTIONS_PER_MACHINE) | set(builtin_dir_noprefix_options)
if key.name in base_options:
assert key.machine is MachineChoice.HOST, str(key) assert key.machine is MachineChoice.HOST, str(key)
return OptionType.BASE return OptionType.BASE
elif key.lang is not None: elif key.lang is not None:
return OptionType.COMPILER return OptionType.COMPILER
elif key.name in all_builtins: elif key.name in _BUILTIN_NAMES:
return OptionType.BUILTIN return OptionType.BUILTIN
elif key.name.startswith('backend_'): elif key.name.startswith('backend_'):
assert key.machine is MachineChoice.HOST, str(key) assert key.machine is MachineChoice.HOST, str(key)
@ -1868,9 +1906,10 @@ class OptionKey:
This is very clever. __init__ is not a constructor, it's an This is very clever. __init__ is not a constructor, it's an
initializer, therefore it's safe to call more than once. We create a initializer, therefore it's safe to call more than once. We create a
state in the custom __getstate__ method, which is valid to pass state in the custom __getstate__ method, which is valid to pass
unsplatted to the initializer. splatted to the initializer.
""" """
self.__init__(**state) # Mypy doesn't like this, because it's so clever.
self.__init__(**state) # type: ignore
def __hash__(self) -> int: def __hash__(self) -> int:
return self._hash return self._hash
@ -1884,6 +1923,15 @@ class OptionKey:
self.lang == other.lang) self.lang == other.lang)
return NotImplemented return NotImplemented
def __lt__(self, other: object) -> bool:
if isinstance(other, OptionKey):
return (
self.name < other.name and
self.subproject < other.subproject and
self.machine < other.machine and
self.lang < other.lang)
return NotImplemented
def __str__(self) -> str: def __str__(self) -> str:
out = self.name out = self.name
if self.lang: if self.lang:

@ -33,7 +33,7 @@ import typing as T
import os import os
import argparse import argparse
from .mesonlib import MachineChoice from .mesonlib import MachineChoice, OptionKey
def get_meson_info_file(info_dir: str) -> str: def get_meson_info_file(info_dir: str) -> str:
return os.path.join(info_dir, 'meson-info.json') return os.path.join(info_dir, 'meson-info.json')
@ -213,24 +213,16 @@ def list_buildoptions_from_source(intr: IntrospectionInterpreter) -> T.List[T.Di
def list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[str]] = None) -> T.List[T.Dict[str, T.Union[str, bool, int, T.List[str]]]]: def list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[str]] = None) -> T.List[T.Dict[str, T.Union[str, bool, int, T.List[str]]]]:
optlist = [] # type: T.List[T.Dict[str, T.Union[str, bool, int, T.List[str]]]] optlist = [] # type: T.List[T.Dict[str, T.Union[str, bool, int, T.List[str]]]]
dir_option_names = list(cdata.BUILTIN_DIR_OPTIONS) dir_option_names = set(cdata.BUILTIN_DIR_OPTIONS)
test_option_names = ['errorlogs', test_option_names = {OptionKey('errorlogs'),
'stdsplit'] OptionKey('stdsplit')}
core_option_names = [k for k in coredata.builtins if k not in dir_option_names + test_option_names] core_option_names = {k for k in coredata.builtins if k not in dir_option_names | test_option_names}
dir_options = {k: o for k, o in coredata.builtins.items() if k in dir_option_names} dir_options = {str(k): o for k, o in coredata.builtins.items() if k in dir_option_names}
test_options = {k: o for k, o in coredata.builtins.items() if k in test_option_names} test_options = {str(k): o for k, o in coredata.builtins.items() if k in test_option_names}
core_options = {k: o for k, o in coredata.builtins.items() if k in core_option_names} core_options = {str(k): o for k, o in coredata.builtins.items() if k in core_option_names}
for s in subprojects or []:
if subprojects: core_options.update({str(k.evolve(subproject=s)): v for k, v in coredata.builtins.items() if not v.yielding})
# Add per subproject built-in options
sub_core_options = {}
for sub in subprojects:
for k, o in core_options.items():
if o.yielding:
continue
sub_core_options[sub + ':' + k] = o
core_options.update(sub_core_options)
def add_keys(options: 'cdata.OptionDictType', section: str, machine: str = 'any') -> None: def add_keys(options: 'cdata.OptionDictType', section: str, machine: str = 'any') -> None:
for key, opt in sorted(options.items()): for key, opt in sorted(options.items()):
@ -253,14 +245,8 @@ def list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[s
optlist.append(optdict) optlist.append(optdict)
add_keys(core_options, 'core') add_keys(core_options, 'core')
add_keys(coredata.builtins_per_machine.host, 'core', machine='host')
add_keys(
{'build.' + k: o for k, o in coredata.builtins_per_machine.build.items()},
'core',
machine='build',
)
add_keys({str(k): v for k, v in coredata.backend_options.items()}, 'backend') add_keys({str(k): v for k, v in coredata.backend_options.items()}, 'backend')
add_keys(coredata.base_options, 'base') add_keys({str(k): v for k, v in coredata.base_options.items()}, 'base')
add_keys( add_keys(
{str(k): v for k, v in coredata.compiler_options.items() if k.machine is MachineChoice.HOST}, {str(k): v for k, v in coredata.compiler_options.items() if k.machine is MachineChoice.HOST},
'compiler', 'compiler',

@ -19,6 +19,7 @@ import os
import copy import copy
import subprocess import subprocess
import functools import functools
import typing as T
from .. import build from .. import build
from .. import mlog from .. import mlog
@ -35,6 +36,9 @@ from ..mesonlib import (
from ..dependencies import Dependency, PkgConfigDependency, InternalDependency, ExternalProgram from ..dependencies import Dependency, PkgConfigDependency, InternalDependency, ExternalProgram
from ..interpreterbase import noKwargs, permittedKwargs, FeatureNew, FeatureNewKwargs, FeatureDeprecatedKwargs from ..interpreterbase import noKwargs, permittedKwargs, FeatureNew, FeatureNewKwargs, FeatureDeprecatedKwargs
if T.TYPE_CHECKING:
from ..compilers import Compiler
# gresource compilation is broken due to the way # gresource compilation is broken due to the way
# the resource compiler and Ninja clash about it # the resource compiler and Ninja clash about it
# #
@ -574,8 +578,8 @@ class GnomeModule(ExtensionModule):
return ret return ret
def _get_girtargets_langs_compilers(self, girtargets): def _get_girtargets_langs_compilers(self, girtargets: T.List[GirTarget]) -> T.List[T.Tuple[str, 'Compiler']]:
ret = [] ret: T.List[T.Tuple[str, 'Compiler']] = []
for girtarget in girtargets: for girtarget in girtargets:
for lang, compiler in girtarget.compilers.items(): for lang, compiler in girtarget.compilers.items():
# XXX: Can you use g-i with any other language? # XXX: Can you use g-i with any other language?
@ -598,7 +602,7 @@ class GnomeModule(ExtensionModule):
ret += girtarget.get_include_dirs() ret += girtarget.get_include_dirs()
return ret return ret
def _get_langs_compilers_flags(self, state, langs_compilers): def _get_langs_compilers_flags(self, state, langs_compilers: T.List[T.Tuple[str, 'Compiler']]):
cflags = [] cflags = []
internal_ldflags = [] internal_ldflags = []
external_ldflags = [] external_ldflags = []
@ -608,8 +612,8 @@ class GnomeModule(ExtensionModule):
cflags += state.global_args[lang] cflags += state.global_args[lang]
if state.project_args.get(lang): if state.project_args.get(lang):
cflags += state.project_args[lang] cflags += state.project_args[lang]
if 'b_sanitize' in compiler.base_options: if mesonlib.OptionKey('b_sanitize') in compiler.base_options:
sanitize = state.environment.coredata.base_options['b_sanitize'].value sanitize = state.environment.coredata.base_options[mesonlib.OptionKey('b_sanitize')].value
cflags += compiler.sanitizer_compile_args(sanitize) cflags += compiler.sanitizer_compile_args(sanitize)
sanitize = sanitize.split(',') sanitize = sanitize.split(',')
# These must be first in ldflags # These must be first in ldflags

@ -177,7 +177,7 @@ class MesonApp:
mlog.initialize(env.get_log_dir(), self.options.fatal_warnings) mlog.initialize(env.get_log_dir(), self.options.fatal_warnings)
if self.options.profile: if self.options.profile:
mlog.set_timestamp_start(time.monotonic()) mlog.set_timestamp_start(time.monotonic())
if env.coredata.builtins['backend'].value == 'xcode': if env.coredata.builtins[mesonlib.OptionKey('backend')].value == 'xcode':
mlog.warning('xcode backend is currently unmaintained, patches welcome') mlog.warning('xcode backend is currently unmaintained, patches welcome')
with mesonlib.BuildDirLock(self.build_dir): with mesonlib.BuildDirLock(self.build_dir):
self._generate(env) self._generate(env)

@ -464,11 +464,9 @@ class Rewriter:
cdata = self.interpreter.coredata cdata = self.interpreter.coredata
options = { options = {
**cdata.builtins, **{str(k): v for k, v in cdata.builtins.items()},
**cdata.builtins_per_machine.host,
**{'build.' + k: o for k, o in cdata.builtins_per_machine.build.items()},
**{str(k): v for k, v in cdata.backend_options.items()}, **{str(k): v for k, v in cdata.backend_options.items()},
**cdata.base_options, **{str(k): v for k, v in cdata.base_options.items()},
**{str(k): v for k, v in cdata.compiler_options.items()}, **{str(k): v for k, v in cdata.compiler_options.items()},
**{str(k): v for k, v in cdata.user_options.items()}, **{str(k): v for k, v in cdata.user_options.items()},
} }

@ -263,7 +263,8 @@ def skip_if_not_base_option(feature):
def wrapped(*args, **kwargs): def wrapped(*args, **kwargs):
env = get_fake_env() env = get_fake_env()
cc = env.detect_c_compiler(MachineChoice.HOST) cc = env.detect_c_compiler(MachineChoice.HOST)
if feature not in cc.base_options: key = OptionKey(feature)
if key not in cc.base_options:
raise unittest.SkipTest( raise unittest.SkipTest(
'{} not available with {}'.format(feature, cc.id)) '{} not available with {}'.format(feature, cc.id))
return f(*args, **kwargs) return f(*args, **kwargs)
@ -1390,8 +1391,8 @@ class DataTests(unittest.TestCase):
found_entries |= options found_entries |= options
self.assertEqual(found_entries, set([ self.assertEqual(found_entries, set([
*mesonbuild.coredata.BUILTIN_OPTIONS.keys(), *[str(k) for k in mesonbuild.coredata.BUILTIN_OPTIONS],
*mesonbuild.coredata.BUILTIN_OPTIONS_PER_MACHINE.keys() *[str(k) for k in mesonbuild.coredata.BUILTIN_OPTIONS_PER_MACHINE],
])) ]))
# Check that `buildtype` table inside `Core options` matches how # Check that `buildtype` table inside `Core options` matches how
@ -1412,10 +1413,10 @@ class DataTests(unittest.TestCase):
debug = False debug = False
else: else:
raise RuntimeError('Invalid debug value {!r} in row:\n{}'.format(debug, m.group())) raise RuntimeError('Invalid debug value {!r} in row:\n{}'.format(debug, m.group()))
env.coredata.set_builtin_option('buildtype', buildtype) env.coredata.set_builtin_option(OptionKey('buildtype'), buildtype)
self.assertEqual(env.coredata.builtins['buildtype'].value, buildtype) self.assertEqual(env.coredata.builtins[OptionKey('buildtype')].value, buildtype)
self.assertEqual(env.coredata.builtins['optimization'].value, opt) self.assertEqual(env.coredata.builtins[OptionKey('optimization')].value, opt)
self.assertEqual(env.coredata.builtins['debug'].value, debug) self.assertEqual(env.coredata.builtins[OptionKey('debug')].value, debug)
def test_cpu_families_documented(self): def test_cpu_families_documented(self):
with open("docs/markdown/Reference-tables.md", encoding='utf-8') as f: with open("docs/markdown/Reference-tables.md", encoding='utf-8') as f:
@ -1903,11 +1904,14 @@ class AllPlatformTests(BasePlatformTests):
https://github.com/mesonbuild/meson/issues/1349 https://github.com/mesonbuild/meson/issues/1349
''' '''
testdir = os.path.join(self.common_test_dir, '88 default options') testdir = os.path.join(self.common_test_dir, '88 default options')
self.init(testdir, default_args=False) self.init(testdir, default_args=False, inprocess=True)
opts = self.introspect('--buildoptions') opts = self.introspect('--buildoptions')
for opt in opts: for opt in opts:
if opt['name'] == 'prefix': if opt['name'] == 'prefix':
prefix = opt['value'] prefix = opt['value']
break
else:
raise self.fail('Did not find option "prefix"')
self.assertEqual(prefix, '/absoluteprefix') self.assertEqual(prefix, '/absoluteprefix')
def test_do_conf_file_preserve_newlines(self): def test_do_conf_file_preserve_newlines(self):
@ -3679,35 +3683,34 @@ class AllPlatformTests(BasePlatformTests):
def test_command_line(self): def test_command_line(self):
testdir = os.path.join(self.unit_test_dir, '34 command line') testdir = os.path.join(self.unit_test_dir, '34 command line')
K = OptionKey
# Verify default values when passing no args that affect the # Verify default values when passing no args that affect the
# configuration, and as a bonus, test that --profile-self works. # configuration, and as a bonus, test that --profile-self works.
self.init(testdir, extra_args=['--profile-self', '--fatal-meson-warnings']) self.init(testdir, extra_args=['--profile-self', '--fatal-meson-warnings'])
obj = mesonbuild.coredata.load(self.builddir) obj = mesonbuild.coredata.load(self.builddir)
self.assertEqual(obj.builtins['default_library'].value, 'static') self.assertEqual(obj.builtins[OptionKey('default_library')].value, 'static')
self.assertEqual(obj.builtins['warning_level'].value, '1') self.assertEqual(obj.builtins[OptionKey('warning_level')].value, '1')
self.assertEqual(obj.user_options[K('set_sub_opt')].value, True) self.assertEqual(obj.user_options[OptionKey('set_sub_opt')].value, True)
self.assertEqual(obj.user_options[K('subp_opt', 'subp')].value, 'default3') self.assertEqual(obj.user_options[OptionKey('subp_opt', 'subp')].value, 'default3')
self.wipe() self.wipe()
# warning_level is special, it's --warnlevel instead of --warning-level # warning_level is special, it's --warnlevel instead of --warning-level
# for historical reasons # for historical reasons
self.init(testdir, extra_args=['--warnlevel=2', '--fatal-meson-warnings']) self.init(testdir, extra_args=['--warnlevel=2', '--fatal-meson-warnings'])
obj = mesonbuild.coredata.load(self.builddir) obj = mesonbuild.coredata.load(self.builddir)
self.assertEqual(obj.builtins['warning_level'].value, '2') self.assertEqual(obj.builtins[OptionKey('warning_level')].value, '2')
self.setconf('--warnlevel=3') self.setconf('--warnlevel=3')
obj = mesonbuild.coredata.load(self.builddir) obj = mesonbuild.coredata.load(self.builddir)
self.assertEqual(obj.builtins['warning_level'].value, '3') self.assertEqual(obj.builtins[OptionKey('warning_level')].value, '3')
self.wipe() self.wipe()
# But when using -D syntax, it should be 'warning_level' # But when using -D syntax, it should be 'warning_level'
self.init(testdir, extra_args=['-Dwarning_level=2', '--fatal-meson-warnings']) self.init(testdir, extra_args=['-Dwarning_level=2', '--fatal-meson-warnings'])
obj = mesonbuild.coredata.load(self.builddir) obj = mesonbuild.coredata.load(self.builddir)
self.assertEqual(obj.builtins['warning_level'].value, '2') self.assertEqual(obj.builtins[OptionKey('warning_level')].value, '2')
self.setconf('-Dwarning_level=3') self.setconf('-Dwarning_level=3')
obj = mesonbuild.coredata.load(self.builddir) obj = mesonbuild.coredata.load(self.builddir)
self.assertEqual(obj.builtins['warning_level'].value, '3') self.assertEqual(obj.builtins[OptionKey('warning_level')].value, '3')
self.wipe() self.wipe()
# Mixing --option and -Doption is forbidden # Mixing --option and -Doption is forbidden
@ -3731,15 +3734,15 @@ class AllPlatformTests(BasePlatformTests):
# --default-library should override default value from project() # --default-library should override default value from project()
self.init(testdir, extra_args=['--default-library=both', '--fatal-meson-warnings']) self.init(testdir, extra_args=['--default-library=both', '--fatal-meson-warnings'])
obj = mesonbuild.coredata.load(self.builddir) obj = mesonbuild.coredata.load(self.builddir)
self.assertEqual(obj.builtins['default_library'].value, 'both') self.assertEqual(obj.builtins[OptionKey('default_library')].value, 'both')
self.setconf('--default-library=shared') self.setconf('--default-library=shared')
obj = mesonbuild.coredata.load(self.builddir) obj = mesonbuild.coredata.load(self.builddir)
self.assertEqual(obj.builtins['default_library'].value, 'shared') self.assertEqual(obj.builtins[OptionKey('default_library')].value, 'shared')
if self.backend is Backend.ninja: if self.backend is Backend.ninja:
# reconfigure target works only with ninja backend # reconfigure target works only with ninja backend
self.build('reconfigure') self.build('reconfigure')
obj = mesonbuild.coredata.load(self.builddir) obj = mesonbuild.coredata.load(self.builddir)
self.assertEqual(obj.builtins['default_library'].value, 'shared') self.assertEqual(obj.builtins[OptionKey('default_library')].value, 'shared')
self.wipe() self.wipe()
# Should warn on unknown options # Should warn on unknown options
@ -3774,7 +3777,7 @@ class AllPlatformTests(BasePlatformTests):
# Test we can set subproject option # Test we can set subproject option
self.init(testdir, extra_args=['-Dsubp:subp_opt=foo', '--fatal-meson-warnings']) self.init(testdir, extra_args=['-Dsubp:subp_opt=foo', '--fatal-meson-warnings'])
obj = mesonbuild.coredata.load(self.builddir) obj = mesonbuild.coredata.load(self.builddir)
self.assertEqual(obj.user_options[K('subp_opt', 'subp')].value, 'foo') self.assertEqual(obj.user_options[OptionKey('subp_opt', 'subp')].value, 'foo')
self.wipe() self.wipe()
# c_args value should be parsed with split_args # c_args value should be parsed with split_args
@ -3789,7 +3792,7 @@ class AllPlatformTests(BasePlatformTests):
self.init(testdir, extra_args=['-Dset_percent_opt=myoption%', '--fatal-meson-warnings']) self.init(testdir, extra_args=['-Dset_percent_opt=myoption%', '--fatal-meson-warnings'])
obj = mesonbuild.coredata.load(self.builddir) obj = mesonbuild.coredata.load(self.builddir)
self.assertEqual(obj.user_options[K('set_percent_opt')].value, 'myoption%') self.assertEqual(obj.user_options[OptionKey('set_percent_opt')].value, 'myoption%')
self.wipe() self.wipe()
# Setting a 2nd time the same option should override the first value # Setting a 2nd time the same option should override the first value
@ -3800,18 +3803,18 @@ class AllPlatformTests(BasePlatformTests):
'-Dc_args=-Dfoo', '-Dc_args=-Dbar', '-Dc_args=-Dfoo', '-Dc_args=-Dbar',
'-Db_lundef=false', '--fatal-meson-warnings']) '-Db_lundef=false', '--fatal-meson-warnings'])
obj = mesonbuild.coredata.load(self.builddir) obj = mesonbuild.coredata.load(self.builddir)
self.assertEqual(obj.builtins['bindir'].value, 'bar') self.assertEqual(obj.builtins[OptionKey('bindir')].value, 'bar')
self.assertEqual(obj.builtins['buildtype'].value, 'release') self.assertEqual(obj.builtins[OptionKey('buildtype')].value, 'release')
self.assertEqual(obj.base_options['b_sanitize'].value, 'thread') self.assertEqual(obj.base_options[OptionKey('b_sanitize')].value, 'thread')
self.assertEqual(obj.compiler_options[OptionKey('args', lang='c')].value, ['-Dbar']) self.assertEqual(obj.compiler_options[OptionKey('args', lang='c')].value, ['-Dbar'])
self.setconf(['--bindir=bar', '--bindir=foo', self.setconf(['--bindir=bar', '--bindir=foo',
'-Dbuildtype=release', '-Dbuildtype=plain', '-Dbuildtype=release', '-Dbuildtype=plain',
'-Db_sanitize=thread', '-Db_sanitize=address', '-Db_sanitize=thread', '-Db_sanitize=address',
'-Dc_args=-Dbar', '-Dc_args=-Dfoo']) '-Dc_args=-Dbar', '-Dc_args=-Dfoo'])
obj = mesonbuild.coredata.load(self.builddir) obj = mesonbuild.coredata.load(self.builddir)
self.assertEqual(obj.builtins['bindir'].value, 'foo') self.assertEqual(obj.builtins[OptionKey('bindir')].value, 'foo')
self.assertEqual(obj.builtins['buildtype'].value, 'plain') self.assertEqual(obj.builtins[OptionKey('buildtype')].value, 'plain')
self.assertEqual(obj.base_options['b_sanitize'].value, 'address') self.assertEqual(obj.base_options[OptionKey('b_sanitize')].value, 'address')
self.assertEqual(obj.compiler_options[OptionKey('args', lang='c')].value, ['-Dfoo']) self.assertEqual(obj.compiler_options[OptionKey('args', lang='c')].value, ['-Dfoo'])
self.wipe() self.wipe()
except KeyError: except KeyError:
@ -3826,25 +3829,25 @@ class AllPlatformTests(BasePlatformTests):
# Verify default values when passing no args # Verify default values when passing no args
self.init(testdir) self.init(testdir)
obj = mesonbuild.coredata.load(self.builddir) obj = mesonbuild.coredata.load(self.builddir)
self.assertEqual(obj.builtins['warning_level'].value, '0') self.assertEqual(obj.builtins[OptionKey('warning_level')].value, '0')
self.wipe() self.wipe()
# verify we can override w/ --warnlevel # verify we can override w/ --warnlevel
self.init(testdir, extra_args=['--warnlevel=1']) self.init(testdir, extra_args=['--warnlevel=1'])
obj = mesonbuild.coredata.load(self.builddir) obj = mesonbuild.coredata.load(self.builddir)
self.assertEqual(obj.builtins['warning_level'].value, '1') self.assertEqual(obj.builtins[OptionKey('warning_level')].value, '1')
self.setconf('--warnlevel=0') self.setconf('--warnlevel=0')
obj = mesonbuild.coredata.load(self.builddir) obj = mesonbuild.coredata.load(self.builddir)
self.assertEqual(obj.builtins['warning_level'].value, '0') self.assertEqual(obj.builtins[OptionKey('warning_level')].value, '0')
self.wipe() self.wipe()
# verify we can override w/ -Dwarning_level # verify we can override w/ -Dwarning_level
self.init(testdir, extra_args=['-Dwarning_level=1']) self.init(testdir, extra_args=['-Dwarning_level=1'])
obj = mesonbuild.coredata.load(self.builddir) obj = mesonbuild.coredata.load(self.builddir)
self.assertEqual(obj.builtins['warning_level'].value, '1') self.assertEqual(obj.builtins[OptionKey('warning_level')].value, '1')
self.setconf('-Dwarning_level=0') self.setconf('-Dwarning_level=0')
obj = mesonbuild.coredata.load(self.builddir) obj = mesonbuild.coredata.load(self.builddir)
self.assertEqual(obj.builtins['warning_level'].value, '0') self.assertEqual(obj.builtins[OptionKey('warning_level')].value, '0')
self.wipe() self.wipe()
def test_feature_check_usage_subprojects(self): def test_feature_check_usage_subprojects(self):
@ -5771,7 +5774,7 @@ class WindowsTests(BasePlatformTests):
# Verify that the `b_vscrt` option is available # Verify that the `b_vscrt` option is available
env = get_fake_env() env = get_fake_env()
cc = env.detect_c_compiler(MachineChoice.HOST) cc = env.detect_c_compiler(MachineChoice.HOST)
if 'b_vscrt' not in cc.base_options: if OptionKey('b_vscrt') not in cc.base_options:
raise unittest.SkipTest('Compiler does not support setting the VS CRT') raise unittest.SkipTest('Compiler does not support setting the VS CRT')
# Verify that qmake is for Qt5 # Verify that qmake is for Qt5
if not shutil.which('qmake-qt5'): if not shutil.which('qmake-qt5'):
@ -5797,7 +5800,7 @@ class WindowsTests(BasePlatformTests):
# Verify that the `b_vscrt` option is available # Verify that the `b_vscrt` option is available
env = get_fake_env() env = get_fake_env()
cc = env.detect_c_compiler(MachineChoice.HOST) cc = env.detect_c_compiler(MachineChoice.HOST)
if 'b_vscrt' not in cc.base_options: if OptionKey('b_vscrt') not in cc.base_options:
raise unittest.SkipTest('Compiler does not support setting the VS CRT') raise unittest.SkipTest('Compiler does not support setting the VS CRT')
def sanitycheck_vscrt(vscrt): def sanitycheck_vscrt(vscrt):

Loading…
Cancel
Save