Files
esp-idf/tools/kconfig_new/menuconfig_dispatcher.py
T
Frantisek Hrbata 5aca23352a feat(cmakev2): add menuconfig dispatcher for sub-projects with own configuration
Sub-projects that grow their own configuration (e.g. the ULP cmakev2
flow, where the sub-project runs its own kconfgen and writes its own
sdkconfig) need a way to expose that configuration via `idf.py
menuconfig` without forcing every caller to know per-sub-project target
names.

Add a small registration + dispatcher mechanism in cmakev2:

* `idf_register_menuconfig(NAME <label> TARGET <cmake-target>)` records
  a menuconfig target with the build. It is intentionally decoupled
  from `idf_create_menuconfig` so that any custom target may be
  registered, including the parent-side proxy targets that sub-projects
  add via `externalproject_add` (e.g. ULP's `menuconfig-<app_name>`).
* `__finalize_menuconfig()` at project finalization creates the
  user-facing `menuconfig` target:
  - With a single registration, `menuconfig` is a thin alias for that
    target. Behaviour is identical to before for all existing single
    -menuconfig projects (bootloader/TEE share the main configuration,
    so they do not register).
  - With two or more registrations, `menuconfig` runs a small Python
    dispatcher (`tools/kconfig_new/menuconfig_dispatcher.py`) that
    lists the registered configurations and re-invokes the selected
    target. The prompt surfaces the direct target name (e.g.
    `idf.py menuconfig-ulp_app`) so users learn the per-sub-project
    target after first use.

`__project_default()` is updated to register the main application as
`menuconfig-app` and then call `__finalize_menuconfig`. The component
side change is one line in `components/ulp/project_include.cmake`,
registering the existing `menuconfig-<app_name>` proxy target.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2026-07-14 16:54:58 +09:00

65 lines
1.8 KiB
Python

#!/usr/bin/env python
#
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import subprocess
import sys
from pathlib import Path
def _read_entries(entries_file: Path) -> list[tuple[str, str]]:
entries: list[tuple[str, str]] = []
for line in entries_file.read_text().splitlines():
line = line.strip()
if not line:
continue
name, _, target = line.partition('|')
entries.append((name, target))
return entries
def _prompt(entries: list[tuple[str, str]]) -> str | None:
width = max(len(name) for name, _ in entries)
print('\nMultiple menuconfig configurations available:\n')
for i, (name, target) in enumerate(entries, 1):
print(f' [{i}] {name:<{width}} (idf.py {target})')
print()
while True:
try:
choice = input(f'Select [1-{len(entries)}, q to quit]: ').strip().lower()
except EOFError:
return None
if choice in ('q', 'quit', ''):
return None
if choice.isdigit():
idx = int(choice)
if 1 <= idx <= len(entries):
return entries[idx - 1][1]
print('Invalid choice.')
def main() -> int:
if len(sys.argv) != 3:
print(f'Usage: {sys.argv[0]} <entries_file> <build_dir>', file=sys.stderr)
return 2
entries_file = Path(sys.argv[1])
build_dir = sys.argv[2]
entries = _read_entries(entries_file)
if not entries:
print(f'No menuconfig entries registered in {entries_file}', file=sys.stderr)
return 1
target = _prompt(entries)
if target is None:
return 0
return subprocess.run(['cmake', '--build', build_dir, '--target', target]).returncode
if __name__ == '__main__':
sys.exit(main())