Skip to content

Commit

Permalink
compilers: Remove the BaseOption type
Browse files Browse the repository at this point in the history
This class only served one purpose, to avoid typing the name of the
option twice. Unfortunately the way it was implemented made getting the
type checking right difficult, and required storing the same data twice.
This patch replaces this approach with a simple function helper that
reads the UserOption and generates the OptionKey from that data, so we
can initialize a single dictionary once, avoid typing the name twice,
delete lines of code, and get better type safety.

As an added bonus, it means that the exported data from the module can
be marked module constant, ie, ALL_CAPS.
  • Loading branch information
dcbaker committed Feb 28, 2025
1 parent cc7a75e commit a90ab0f
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 45 deletions.
4 changes: 2 additions & 2 deletions mesonbuild/compilers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
'RunResult',

'all_languages',
'base_options',
'BASE_OPTIONS',
'clib_langs',
'clink_langs',
'c_suffixes',
Expand Down Expand Up @@ -48,7 +48,7 @@
Compiler,
RunResult,
all_languages,
base_options,
BASE_OPTIONS,
clib_langs,
clink_langs,
c_suffixes,
Expand Down
70 changes: 30 additions & 40 deletions mesonbuild/compilers/compilers.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,46 +215,36 @@ class CompileCheckMode(enum.Enum):
MSCRT_VALS = ['none', 'md', 'mdd', 'mt', 'mtd']


@dataclass
class BaseOption(T.Generic[_T]):
opt_type: T.Type[options.UserOption[_T]]
description: str
default: T.Any = None
choices: T.Any = None

def init_option(self, name: OptionKey) -> options.UserOption[_T]:
keywords = {}
if self.choices:
keywords['choices'] = self.choices
return self.opt_type(name.name, self.description, self.default, **keywords)


BASE_OPTIONS: T.Mapping[OptionKey, BaseOption] = {
OptionKey('b_pch'): BaseOption(options.UserBooleanOption, 'Use precompiled headers', True),
OptionKey('b_lto'): BaseOption(options.UserBooleanOption, 'Use link time optimization', False),
OptionKey('b_lto_threads'): BaseOption(options.UserIntegerOption, 'Use multiple threads for Link Time Optimization', 0),
OptionKey('b_lto_mode'): BaseOption(options.UserComboOption, 'Select between different LTO modes.', 'default',
choices=['default', 'thin']),
OptionKey('b_thinlto_cache'): BaseOption(options.UserBooleanOption, 'Use LLVM ThinLTO caching for faster incremental builds', False),
OptionKey('b_thinlto_cache_dir'): BaseOption(options.UserStringOption, 'Directory to store ThinLTO cache objects', ''),
OptionKey('b_sanitize'): BaseOption(options.UserComboOption, 'Code sanitizer to use', 'none',
choices=['none', 'address', 'thread', 'undefined', 'memory', 'leak', 'address,undefined']),
OptionKey('b_lundef'): BaseOption(options.UserBooleanOption, 'Use -Wl,--no-undefined when linking', True),
OptionKey('b_asneeded'): BaseOption(options.UserBooleanOption, 'Use -Wl,--as-needed when linking', True),
OptionKey('b_pgo'): BaseOption(options.UserComboOption, 'Use profile guided optimization', 'off',
choices=['off', 'generate', 'use']),
OptionKey('b_coverage'): BaseOption(options.UserBooleanOption, 'Enable coverage tracking.', False),
OptionKey('b_colorout'): BaseOption(options.UserComboOption, 'Use colored output', 'always',
choices=['auto', 'always', 'never']),
OptionKey('b_ndebug'): BaseOption(options.UserComboOption, 'Disable asserts', 'false', choices=['true', 'false', 'if-release']),
OptionKey('b_staticpic'): BaseOption(options.UserBooleanOption, 'Build static libraries as position independent', True),
OptionKey('b_pie'): BaseOption(options.UserBooleanOption, 'Build executables as position independent', False),
OptionKey('b_bitcode'): BaseOption(options.UserBooleanOption, 'Generate and embed bitcode (only macOS/iOS/tvOS)', False),
OptionKey('b_vscrt'): BaseOption(options.UserComboOption, 'VS run-time library type to use.', 'from_buildtype',
choices=MSCRT_VALS + ['from_buildtype', 'static_from_buildtype']),
}

base_options = {key: base_opt.init_option(key) for key, base_opt in BASE_OPTIONS.items()}
def _make_option_key(opt: options.AnyOptionType) -> T.Tuple[OptionKey, options.AnyOptionType]:
return OptionKey(opt.name), opt


BASE_OPTIONS: T.Mapping[OptionKey, options.AnyOptionType] = dict([
_make_option_key(options.UserBooleanOption('b_pch', 'Use precompiled headers', True)),
_make_option_key(options.UserBooleanOption('b_lto', 'Use link time optimization', False)),
_make_option_key(options.UserIntegerOption('b_lto_threads', 'Use multiple threads for Link Time Optimization', 0)),
_make_option_key(options.UserComboOption('b_lto_mode', 'Select between different LTO modes.', 'default', choices=['default', 'thin'])),
_make_option_key(options.UserBooleanOption('b_thinlto_cache', 'Use LLVM ThinLTO caching for faster incremental builds', False)),
_make_option_key(options.UserStringOption('b_thinlto_cache_dir', 'Directory to store ThinLTO cache objects', '')),
_make_option_key(options.UserComboOption(
'b_sanitize', 'Code sanitizer to use', 'none',
choices=['none', 'address', 'thread', 'undefined', 'memory', 'leak', 'address,undefined'])),
_make_option_key(options.UserBooleanOption('b_lundef', 'Use -Wl,--no-undefined when linking', True)),
_make_option_key(options.UserBooleanOption('b_asneeded', 'Use -Wl,--as-needed when linking', True)),
_make_option_key(options.UserComboOption(
'b_pgo', 'Use profile guided optimization', 'off', choices=['off', 'generate', 'use'])),
_make_option_key(options.UserBooleanOption('b_coverage', 'Enable coverage tracking.', False)),
_make_option_key(options.UserComboOption(
'b_colorout', 'Use colored output', 'always', choices=['auto', 'always', 'never'])),
_make_option_key(options.UserComboOption(
'b_ndebug', 'Disable asserts', 'false', choices=['true', 'false', 'if-release'])),
_make_option_key(options.UserBooleanOption('b_staticpic', 'Build static libraries as position independent', True)),
_make_option_key(options.UserBooleanOption('b_pie', 'Build executables as position independent', False)),
_make_option_key(options.UserBooleanOption('b_bitcode', 'Generate and embed bitcode (only macOS/iOS/tvOS)', False)),
_make_option_key(options.UserComboOption(
'b_vscrt', 'VS run-time library type to use.', 'from_buildtype',
choices=MSCRT_VALS + ['from_buildtype', 'static_from_buildtype'])),
])

def option_enabled(boptions: T.Set[OptionKey],
target: 'BuildTarget',
Expand Down
6 changes: 3 additions & 3 deletions mesonbuild/coredata.py
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,7 @@ def remove_sp_options(self, U_args) -> bool:
return dirty

def set_default_options(self, default_options: T.MutableMapping[OptionKey, str], subproject: str, env: 'Environment') -> None:
from .compilers import base_options
from .compilers import BASE_OPTIONS

# Main project can set default options on subprojects, but subprojects
# can only set default options on themselves.
Expand Down Expand Up @@ -696,7 +696,7 @@ def set_default_options(self, default_options: T.MutableMapping[OptionKey, str],
# adding languages and setting backend.
if self.optstore.is_compiler_option(k) or self.optstore.is_backend_option(k):
continue
if self.optstore.is_base_option(k) and k.as_root() in base_options:
if self.optstore.is_base_option(k) and k.as_root() in BASE_OPTIONS:
# set_options will report unknown base options
continue
options[k] = v
Expand Down Expand Up @@ -744,7 +744,7 @@ def process_compiler_options(self, lang: str, comp: Compiler, env: Environment,
else:
skey = key
if skey not in self.optstore:
self.optstore.add_system_option(skey, copy.deepcopy(compilers.base_options[key]))
self.optstore.add_system_option(skey, copy.deepcopy(compilers.BASE_OPTIONS[key]))
if skey in env.options:
self.optstore.set_value(skey, env.options[skey])
elif subproject and key in env.options:
Expand Down

0 comments on commit a90ab0f

Please sign in to comment.