mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 03:00:34 +03:00
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>
65 lines
1.8 KiB
Python
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())
|