mirror of
https://github.com/mesonbuild/meson.git
synced 2026-11-06 05:16:42 +00:00
mintro: include per-subproject options in buildoptions
The configured-builddir path called the option listing without the set of subprojects, so the per-subproject replication of non-yielding builtin options only happened for source-only introspection and no sub: rows were emitted at all. Augments (per-subproject values such as -Dsub:c_args=...) were additionally never consulted, so even the source-only rows reported the parent project's value. Pass coredata.initialized_subprojects on the configured path, add per-subproject rows for base and compiler options that have an augment set, and resolve replicated keys through the option store so augments and yielding are reflected in the reported value. Project options keep their stored value as before. Fixes #15993.
This commit is contained in:
1 parent
0102669f6c
commit
e6c4e8d040
7 files changed
+59
-11
No files matched your search
@@ -0,0 +1,8 @@
|
||||
## Per-subproject options are included in buildoptions introspection
|
||||
|
||||
`meson introspect --buildoptions` and `meson-info/intro-buildoptions.json`
|
||||
now contain rows for per-subproject options in configured build
|
||||
directories: non-yielding builtin options get one row per subproject
|
||||
(e.g. `sub:warning_level`), and options with a per-subproject value set
|
||||
(e.g. via `-Dsub:c_args=...`) are reported with the value in effect for
|
||||
that subproject.
|
||||
+26
-8
@@ -208,7 +208,7 @@ def list_targets(coredata: cdata.CoreData, builddata: build.Build, backend: back
|
||||
return tlist
|
||||
|
||||
def list_buildoptions(coredata: cdata.CoreData, builddata: build.Build, backend: backends.Backend) -> T.List[T.Dict[str, T.Union[str, bool, int, T.List[str]]]]:
|
||||
return _list_buildoptions(coredata)
|
||||
return _list_buildoptions(coredata, sorted(coredata.initialized_subprojects - {''}))
|
||||
|
||||
def list_buildoptions_from_source(intr: IntrospectionInterpreter) -> T.List[T.Dict[str, T.Union[str, bool, int, T.List[str]]]]:
|
||||
subprojects = [i['name'] for i in intr.project_data['subprojects']]
|
||||
@@ -216,7 +216,20 @@ def list_buildoptions_from_source(intr: IntrospectionInterpreter) -> T.List[T.Di
|
||||
|
||||
def _list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[str]] = None) -> T.List[T.Dict[str, T.Union[str, bool, int, T.List[str]]]]:
|
||||
optlist: T.List[T.Dict[str, T.Union[str, bool, int, T.List[str]]]] = []
|
||||
subprojects = subprojects or []
|
||||
subprojects = sorted(subprojects or [])
|
||||
|
||||
def add_subproject_keys(opts: options.MutableKeyedOptionDictType,
|
||||
replicate_non_yielding: bool = False) -> options.MutableKeyedOptionDictType:
|
||||
# Add a row per subproject for options that can differ from the
|
||||
# top-level value there: non-yielding ones (if requested) and any
|
||||
# with a per-subproject value (augment) actually set.
|
||||
ret = dict(opts)
|
||||
for k, v in opts.items():
|
||||
for s in subprojects:
|
||||
sk = k.evolve(subproject=s)
|
||||
if (replicate_non_yielding and not v.yielding) or sk in coredata.optstore.augments:
|
||||
ret[sk] = v
|
||||
return ret
|
||||
|
||||
dir_option_names = set(options.BUILTIN_DIR_OPTIONS)
|
||||
test_option_names = {OptionKey('errorlogs'),
|
||||
@@ -232,13 +245,18 @@ def _list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[
|
||||
test_options[k] = v
|
||||
elif coredata.optstore.is_builtin_option(k):
|
||||
core_options[k] = v
|
||||
if not v.yielding:
|
||||
for s in subprojects:
|
||||
core_options[k.evolve(subproject=s)] = v
|
||||
core_options = add_subproject_keys(core_options, replicate_non_yielding=True)
|
||||
|
||||
def add_keys(opts: T.Union[options.MutableKeyedOptionDictType, options.OptionStore], section: str) -> None:
|
||||
for key, opt in sorted(opts.items()):
|
||||
optdict = {'name': str(key), 'value': opt.value, 'section': section,
|
||||
# Replicated per-subproject keys resolve through augments and
|
||||
# yielding to report the value in effect for that subproject.
|
||||
# Project options keep their stored value as before.
|
||||
if key.subproject and not coredata.optstore.is_project_option(key):
|
||||
value = coredata.optstore.get_value_for(key)
|
||||
else:
|
||||
value = opt.value
|
||||
optdict = {'name': str(key), 'value': value, 'section': section,
|
||||
'machine': key.machine.get_lower_case_name() if coredata.optstore.is_per_machine_option(key) else 'any'}
|
||||
if isinstance(opt, options.UserStringOption):
|
||||
typestr = 'string'
|
||||
@@ -269,9 +287,9 @@ def _list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[
|
||||
|
||||
add_keys(core_options, 'core')
|
||||
add_keys({k: v for k, v in coredata.optstore.items() if coredata.optstore.is_backend_option(k)}, 'backend')
|
||||
add_keys({k: v for k, v in coredata.optstore.items() if coredata.optstore.is_base_option(k)}, 'base')
|
||||
add_keys(add_subproject_keys({k: v for k, v in coredata.optstore.items() if coredata.optstore.is_base_option(k)}), 'base')
|
||||
add_keys(
|
||||
{k: v for k, v in sorted(coredata.optstore.items(), key=lambda i: i[0].machine) if coredata.optstore.is_compiler_option(k)},
|
||||
add_subproject_keys({k: v for k, v in sorted(coredata.optstore.items(), key=lambda i: i[0].machine) if coredata.optstore.is_compiler_option(k)}),
|
||||
'compiler',
|
||||
)
|
||||
add_keys(dir_options, 'directory')
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
0fd8007dd44a1a5eb5c01af4c138f0993c6cb44da194b36db04484212eff591b
|
||||
@@ -0,0 +1,3 @@
|
||||
project('subsubsub')
|
||||
|
||||
meson.override_dependency('subsubsub', declare_dependency())
|
||||
@@ -0,0 +1,2 @@
|
||||
[wrap-redirect]
|
||||
filename = sub_implicit/subprojects/subsub/subprojects/subsubsub.wrap
|
||||
@@ -3781,6 +3781,24 @@ class AllPlatformTests(BasePlatformTests):
|
||||
self.assertIn('c_args', optnames)
|
||||
self.assertNotIn('build.c_args', optnames)
|
||||
|
||||
def test_introspect_buildoptions_subproject_augments(self):
|
||||
testdir = os.path.join(self.unit_test_dir, '47 reconfigure')
|
||||
self.init(testdir, extra_args=['-Dsub1:c_args=-DAUG', '-Dsub1:werror=true'])
|
||||
res = self.introspect('--buildoptions')
|
||||
opts = {o['name']: o for o in res}
|
||||
self.assertEqual(opts['sub1:c_args']['value'], ['-DAUG'])
|
||||
self.assertEqual(opts['sub1:werror']['value'], True)
|
||||
# Non-yielding builtins get a row per subproject.
|
||||
self.assertIn('sub1:warning_level', opts)
|
||||
# The generated intro file matches the introspect command.
|
||||
infofile = os.path.join(self.builddir, 'meson-info', 'intro-buildoptions.json')
|
||||
with open(infofile, encoding='utf-8') as fp:
|
||||
self.assertListEqual(json.load(fp), res)
|
||||
# Source-only introspection takes the same path and must not crash.
|
||||
testfile = os.path.join(testdir, 'meson.build')
|
||||
res_nb = self.introspect_directory(testfile, ['--buildoptions'] + self.meson_args)
|
||||
self.assertIn('sub1:warning_level', {o['name'] for o in res_nb})
|
||||
|
||||
def test_introspect_json_flat(self):
|
||||
testdir = os.path.join(self.unit_test_dir, '56 introspection')
|
||||
self.init(testdir, extra_args=['-Dlayout=flat'])
|
||||
|
||||
@@ -583,9 +583,7 @@ class NativeFileTests(BasePlatformTests):
|
||||
elif each['name'] == 'sub:default_library':
|
||||
self.assertEqual(each['value'], 'static')
|
||||
found += 1
|
||||
# FIXME: check that the subproject option has beeb added
|
||||
# into augments.
|
||||
self.assertEqual(found, 2, 'Did not find all two sections')
|
||||
self.assertEqual(found, 3, 'Did not find all three sections')
|
||||
|
||||
def test_builtin_options_machinefile_overrides_subproject(self):
|
||||
# The buildfile says subproject(... default_library: static), the machinefile overrides it
|
||||
|
||||
Reference in new issue
Block a user