73549ad852
This commit adds a Kconfiglib-based menuconfig implementation, built with the standard Python 'curses' module. A new 'pymenuconfig' target is added to run it. The C tools are kept for now. Removing them separately allows testing of pymenuconfig alongside the C tools, and keeps changes small and focused. A feature is planned for later that shows all symbols -- including those that aren't currently visible -- along with a search and "jump to" feature. Loading of arbitrary .config files will be supported later as well (as opposed to always loading .config/KCONFIG_CONFIG). Those features are all connected implementation-wise. For Windows, the wheels at https://www.lfd.uci.edu/~gohlke/pythonlibs/#curses provide the curses implementation. They use the standard Python curses module (_cursesmodule.c), linked against PDCurses. Running 'python -VV' gives the Python version and bitness, to know which wheel to install. User documentation will be added once the C tools are removed and the 'pymenuconfig' target is moved over to 'menuconfig'. The CMake parts are originally by Sebastian Bøe. Description, taken from the menuconfig.py docstring: Overview ======== A curses-based menuconfig implementation. The interface should feel familiar to people used to mconf ('make menuconfig'). Supports the same keys as mconf, and also supports a set of keybindings inspired by Vi: J/K : Down/Up L : Enter menu/Toggle item H : Leave menu Ctrl-D/U: Page Down/Page Down G/End : Jump to end of list g/Home : Jump to beginning of list The mconf feature where pressing a key jumps to a menu entry with that character in it in the current menu isn't supported. A search feature with a "jump to" function for jumping directly to a particular symbol regardless of where it is defined will be added later instead. Space and Enter are "smart" and try to do what you'd expect for the given menu entry. Running ======= menuconfig.py can be run either as a standalone executable or by calling the menu.menuconfig() function with an existing Kconfig instance. The second option is a bit inflexible in that it will still load and save .config, etc. When run in standalone mode, the top-level Kconfig file to load can be passed as a command-line argument. With no argument, it defaults to "Kconfig". The KCONFIG_CONFIG environment variable specifies the .config file to load (if it exists) and save. If KCONFIG_CONFIG is unset, ".config" is used. $srctree is supported through Kconfiglib. Other features ============== - Seamless terminal resizing - No dependencies on *nix, as the 'curses' module is in the Python standard library - Unicode text entry - Improved information screen compared to mconf: * Expressions are split up by their top-level &&/|| operands to improve readability * Undefined symbols in expressions are pointed out * Menus and comments have information displays * Kconfig definitions are printed Limitations =========== - Python 3 only This is mostly due to Python 2 not having curses.get_wch(), which is needed for Unicode support. - Doesn't work out of the box on Windows Has been tested to work with the wheels provided at https://www.lfd.uci.edu/~gohlke/pythonlibs/#curses though. Signed-off-by: Ulf Magnusson <ulfalizer@gmail.com>
168 lines
5.2 KiB
CMake
168 lines
5.2 KiB
CMake
# Folders needed for conf/mconf files (kconfig has no method of redirecting all output files).
|
|
# conf/mconf needs to be run from a different directory because of: GH-3408
|
|
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/kconfig/include/generated)
|
|
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/kconfig/include/config)
|
|
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/include/generated)
|
|
|
|
set_ifndef(KCONFIG_ROOT ${ZEPHYR_BASE}/Kconfig)
|
|
|
|
set(BOARD_DEFCONFIG ${BOARD_DIR}/${BOARD}_defconfig)
|
|
set(DOTCONFIG ${PROJECT_BINARY_DIR}/.config)
|
|
|
|
if(CONF_FILE)
|
|
string(REPLACE " " ";" CONF_FILE_AS_LIST ${CONF_FILE})
|
|
endif()
|
|
|
|
set(ENV{srctree} ${ZEPHYR_BASE})
|
|
set(ENV{KERNELVERSION} ${PROJECT_VERSION})
|
|
set(ENV{KCONFIG_CONFIG} ${DOTCONFIG})
|
|
set(ENV{KCONFIG_AUTOHEADER} ${AUTOCONF_H})
|
|
|
|
set(kconfig_target_list
|
|
config
|
|
gconfig
|
|
menuconfig
|
|
pymenuconfig
|
|
oldconfig
|
|
xconfig
|
|
)
|
|
|
|
set(COMMAND_FOR_config ${KCONFIG_CONF} --oldaskconfig ${KCONFIG_ROOT})
|
|
set(COMMAND_FOR_gconfig gconf ${KCONFIG_ROOT})
|
|
set(COMMAND_FOR_menuconfig ${KCONFIG_MCONF} ${KCONFIG_ROOT})
|
|
set(COMMAND_FOR_pymenuconfig ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/kconfig/menuconfig.py ${KCONFIG_ROOT})
|
|
set(COMMAND_FOR_oldconfig ${KCONFIG_CONF} --oldconfig ${KCONFIG_ROOT})
|
|
set(COMMAND_FOR_xconfig qconf ${KCONFIG_ROOT})
|
|
|
|
set(COMMAND_RUNS_ON_WIN_pymenuconfig 1)
|
|
|
|
# Set environment variables so that Kconfig can prune Kconfig source
|
|
# files for other architectures
|
|
set(ENV{ENV_VAR_ARCH} ${ARCH})
|
|
set(ENV{ENV_VAR_BOARD_DIR} ${BOARD_DIR})
|
|
|
|
foreach(kconfig_target ${kconfig_target_list})
|
|
if ((NOT WIN32) OR (DEFINED COMMAND_RUNS_ON_WIN_${kconfig_target}))
|
|
add_custom_target(
|
|
${kconfig_target}
|
|
${CMAKE_COMMAND} -E env
|
|
srctree=${ZEPHYR_BASE}
|
|
KERNELVERSION=${PROJECT_VERSION}
|
|
KCONFIG_CONFIG=${DOTCONFIG}
|
|
ENV_VAR_ARCH=$ENV{ENV_VAR_ARCH}
|
|
ENV_VAR_BOARD_DIR=$ENV{ENV_VAR_BOARD_DIR}
|
|
${COMMAND_FOR_${kconfig_target}}
|
|
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/kconfig
|
|
USES_TERMINAL
|
|
)
|
|
else()
|
|
add_custom_target(
|
|
${kconfig_target}
|
|
${CMAKE_COMMAND} -E echo
|
|
"========================================="
|
|
"Reconfiguration not supported on Windows."
|
|
"========================================="
|
|
)
|
|
endif()
|
|
endforeach()
|
|
|
|
# Bring in extra configuration files dropped in by the user or anyone else;
|
|
# make sure they are set at the end so we can override any other setting
|
|
file(GLOB config_files ${APPLICATION_BINARY_DIR}/*.conf)
|
|
list(SORT config_files)
|
|
set(
|
|
merge_config_files
|
|
${BOARD_DEFCONFIG}
|
|
${CONF_FILE_AS_LIST}
|
|
${OVERLAY_CONFIG}
|
|
${config_files}
|
|
)
|
|
|
|
# Create a list of absolute paths to the .config sources from
|
|
# merge_config_files, which is a mix of absolute and relative paths.
|
|
set(merge_config_files_with_absolute_paths "")
|
|
foreach(f ${merge_config_files})
|
|
if(IS_ABSOLUTE ${f})
|
|
set(path ${f})
|
|
else()
|
|
set(path ${APPLICATION_SOURCE_DIR}/${f})
|
|
endif()
|
|
|
|
list(APPEND merge_config_files_with_absolute_paths ${path})
|
|
endforeach()
|
|
|
|
foreach(f ${merge_config_files_with_absolute_paths})
|
|
if(NOT EXISTS ${f} OR IS_DIRECTORY ${f})
|
|
message(FATAL_ERROR "File not found: ${f}")
|
|
endif()
|
|
endforeach()
|
|
|
|
# Calculate a checksum of merge_config_files to determine if we need
|
|
# to re-generate .config
|
|
set(merge_config_files_checksum "")
|
|
foreach(f ${merge_config_files_with_absolute_paths})
|
|
file(MD5 ${f} checksum)
|
|
set(merge_config_files_checksum "${merge_config_files_checksum}${checksum}")
|
|
endforeach()
|
|
|
|
# Create a new .config if it does not exists, or if the checksum of
|
|
# the dependencies has changed
|
|
set(merge_config_files_checksum_file ${PROJECT_BINARY_DIR}/.cmake.dotconfig.checksum)
|
|
set(CREATE_NEW_DOTCONFIG "")
|
|
if(NOT EXISTS ${DOTCONFIG})
|
|
set(CREATE_NEW_DOTCONFIG 1)
|
|
else()
|
|
# Read out what the checksum was previously
|
|
file(READ
|
|
${merge_config_files_checksum_file}
|
|
merge_config_files_checksum_prev
|
|
)
|
|
set(CREATE_NEW_DOTCONFIG 1)
|
|
if(
|
|
${merge_config_files_checksum} STREQUAL
|
|
${merge_config_files_checksum_prev}
|
|
)
|
|
set(CREATE_NEW_DOTCONFIG 0)
|
|
endif()
|
|
endif()
|
|
|
|
if(CREATE_NEW_DOTCONFIG)
|
|
set(merge_fragments ${merge_config_files})
|
|
else()
|
|
set(merge_fragments ${DOTCONFIG})
|
|
endif()
|
|
|
|
execute_process(
|
|
COMMAND
|
|
${PYTHON_EXECUTABLE}
|
|
${ZEPHYR_BASE}/scripts/kconfig/kconfig.py
|
|
${KCONFIG_ROOT}
|
|
${PROJECT_BINARY_DIR}/.config
|
|
${PROJECT_BINARY_DIR}/include/generated/autoconf.h
|
|
${merge_fragments}
|
|
WORKING_DIRECTORY ${APPLICATION_SOURCE_DIR}
|
|
# The working directory is set to the app dir such that the user
|
|
# can use relative paths in CONF_FILE, e.g. CONF_FILE=nrf5.conf
|
|
RESULT_VARIABLE ret
|
|
)
|
|
if(NOT "${ret}" STREQUAL "0")
|
|
message(FATAL_ERROR "command failed with return code: ${ret}")
|
|
endif()
|
|
|
|
if(CREATE_NEW_DOTCONFIG)
|
|
file(WRITE
|
|
${merge_config_files_checksum_file}
|
|
${merge_config_files_checksum}
|
|
)
|
|
endif()
|
|
|
|
# Force CMAKE configure when the configuration files changes.
|
|
foreach(merge_config_input ${merge_config_files} ${DOTCONFIG})
|
|
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${merge_config_input})
|
|
endforeach()
|
|
|
|
add_custom_target(config-sanitycheck DEPENDS ${DOTCONFIG})
|
|
|
|
# Parse the lines prefixed with CONFIG_ in the .config file from Kconfig
|
|
import_kconfig(${DOTCONFIG})
|