diff --git a/Kconfig.zephyr b/Kconfig.zephyr index 7a5bfee963501..c57c0d8cf54f9 100644 --- a/Kconfig.zephyr +++ b/Kconfig.zephyr @@ -10,6 +10,14 @@ config KERNELVERSION string option env="KERNELVERSION" +config ENV_VAR_SYM_BOARD_DIR + string + option env="ENV_VAR_BOARD_DIR" + +config ENV_VAR_SYM_ARCH + string + option env="ENV_VAR_ARCH" + source "arch/Kconfig" source "kernel/Kconfig" @@ -37,5 +45,5 @@ source "tests/Kconfig" # Board defaults should be parsed after SoC defaults # because board usually overrides SoC values. # -source "arch/*/soc/*/Kconfig.defconfig" -source "boards/*/*/Kconfig.defconfig" +source "arch/$ENV_VAR_SYM_ARCH/soc/*/Kconfig.defconfig" +source "$ENV_VAR_SYM_BOARD_DIR/Kconfig.defconfig" diff --git a/arch/Kconfig b/arch/Kconfig index 51a5886de3f8b..4c49d8431fee0 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -298,6 +298,6 @@ config BOARD arch//soc// -source "arch/*/Kconfig" +source "arch/$ENV_VAR_SYM_ARCH/Kconfig" source "boards/Kconfig" diff --git a/boards/Kconfig b/boards/Kconfig index 08533c543596d..e4391da726221 100644 --- a/boards/Kconfig +++ b/boards/Kconfig @@ -16,10 +16,10 @@ config QEMU_TARGET choice prompt "Board Selection" -source "boards/*/*/Kconfig.board" +source "$ENV_VAR_SYM_BOARD_DIR/Kconfig.board" endchoice menu "Board Options" -source "boards/*/*/Kconfig" +source "$ENV_VAR_SYM_BOARD_DIR/Kconfig" endmenu diff --git a/cmake/host-tools.cmake b/cmake/host-tools.cmake index b8230f41f033d..8d454be607bb2 100644 --- a/cmake/host-tools.cmake +++ b/cmake/host-tools.cmake @@ -12,12 +12,14 @@ if(${DTC} STREQUAL DTC-NOTFOUND) message(FATAL_ERROR "Unable to find dtc") endif() -find_program( - KCONFIG_CONF - conf - ) -if(${KCONFIG_CONF} STREQUAL KCONFIG_CONF-NOTFOUND) - message(FATAL_ERROR "Unable to find the Kconfig program 'conf'") +if (NOT WIN32) + find_program( + KCONFIG_CONF + conf + ) + if(${KCONFIG_CONF} STREQUAL KCONFIG_CONF-NOTFOUND) + message(FATAL_ERROR "Unable to find the Kconfig program 'conf'") + endif() endif() find_program( diff --git a/cmake/kconfig.cmake b/cmake/kconfig.cmake index ca374b873a458..50543b6908c73 100644 --- a/cmake/kconfig.cmake +++ b/cmake/kconfig.cmake @@ -37,17 +37,34 @@ set(COMMAND_FOR_menuconfig ${KCONFIG_MCONF} ${KCONFIG_ROOT}) set(COMMAND_FOR_oldconfig ${KCONFIG_CONF} --oldconfig ${KCONFIG_ROOT}) set(COMMAND_FOR_xconfig qconf ${KCONFIG_ROOT}) +# 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}) - add_custom_target( - ${kconfig_target} - ${CMAKE_COMMAND} -E env - srctree=${PROJECT_SOURCE_DIR} - KERNELVERSION=${PROJECT_VERSION} - KCONFIG_CONFIG=${DOTCONFIG} - ${COMMAND_FOR_${kconfig_target}} - WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/kconfig - USES_TERMINAL - ) + if (NOT WIN32) + add_custom_target( + ${kconfig_target} + ${CMAKE_COMMAND} -E env + srctree=${PROJECT_SOURCE_DIR} + 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; @@ -81,80 +98,27 @@ foreach(f ${merge_config_files_with_absolute_paths}) 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) - execute_process( - COMMAND - ${PROJECT_SOURCE_DIR}/scripts/kconfig/merge_config.sh - -m - -q - -O ${PROJECT_BINARY_DIR} - ${merge_config_files} - 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() - - execute_process( - COMMAND ${KCONFIG_CONF} - --olddefconfig - ${KCONFIG_ROOT} - WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/kconfig - RESULT_VARIABLE ret - ) - if(NOT "${ret}" STREQUAL "0") - message(FATAL_ERROR "command failed with return code: ${ret}") - endif() - - 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() -message(STATUS "Generating zephyr/include/generated/autoconf.h") execute_process( - COMMAND ${KCONFIG_CONF} - --silentoldconfig - ${KCONFIG_ROOT} - WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/kconfig -) + COMMAND + ${PYTHON_EXECUTABLE} + ${PROJECT_SOURCE_DIR}/scripts/kconfig/kconfig.py + ${KCONFIG_ROOT} + ${PROJECT_BINARY_DIR}/.config + ${PROJECT_BINARY_DIR}/include/generated/autoconf.h + ${merge_config_files} + 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() add_custom_target(config-sanitycheck DEPENDS ${DOTCONFIG}) diff --git a/scripts/kconfig/kconfig.py b/scripts/kconfig/kconfig.py new file mode 100755 index 0000000000000..de831655634c9 --- /dev/null +++ b/scripts/kconfig/kconfig.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# Modified from: https://github.com/ulfalizer/Kconfiglib/blob/master/examples/merge_config.py +from kconfiglib import Kconfig, Symbol, BOOL, STRING, TRISTATE, TRI_TO_STR +import sys + +if len(sys.argv) < 5: + print('usage: {} Kconfig dotconfig autoconf conf1 [conf2 ...]' + .format(sys.argv[0])) + sys.exit(1) + +print("Parsing Kconfig tree in {}".format(sys.argv[1])) +kconf = Kconfig(sys.argv[1]) + +# Enable warnings for assignments to undefined symbols +kconf.enable_undef_warnings() + +# (This script uses alldefconfig as the base. Other starting states could be +# set up here as well. The approach in examples/allnoconfig_simpler.py could +# provide an allnoconfig starting state for example.) + +print("Using {} as base".format(sys.argv[4])) +for config in sys.argv[5:]: + print("Merging {}".format(config)) +# Create a merged configuration by loading the fragments with replace=False +for config in sys.argv[4:]: + kconf.load_config(config, replace=False) + +# Write the merged configuration +kconf.write_config(sys.argv[2]) + +# Output autoconf +kconf.write_autoconf(sys.argv[3]) + +# Print warnings for symbols whose actual value doesn't match the assigned +# value +for sym in kconf.defined_syms: + # Was the symbol assigned to? + #print('name: {} value: {}'.format(sym.name, sym.str_value)) + if sym.user_value is not None: + # Tristate values are represented as 0, 1, 2. Having them as + # "n", "m", "y" is more convenient here, so convert. + if sym.type in (BOOL, TRISTATE): + user_value = TRI_TO_STR[sym.user_value] + else: + user_value = sym.user_value + if user_value != sym.str_value: + print('warning: {} was assigned the value "{}" but got the ' + 'value "{}" -- check dependencies' + .format(sym.name, user_value, sym.str_value)) + diff --git a/scripts/kconfig/kconfiglib.py b/scripts/kconfig/kconfiglib.py new file mode 100644 index 0000000000000..fdaa7a2b1b89a --- /dev/null +++ b/scripts/kconfig/kconfiglib.py @@ -0,0 +1,4296 @@ +# Copyright (c) 2011-2017, Ulf Magnusson +# SPDX-License-Identifier: ISC + +""" +Overview +======== + +Kconfiglib is a Python 2/3 library for scripting and extracting information +from Kconfig configuration systems. It can be used for the following, among +other things: + + - Programmatically get and set symbol values + + allnoconfig.py and allyesconfig.py examples are provided, automatically + verified to produce identical output to the standard 'make allnoconfig' and + 'make allyesconfig'. + + - Read and write .config files + + The generated .config files are character-for-character identical to what + the C implementation would generate (except for the header comment). The + test suite relies on this, as it compares the generated files. + + - Inspect symbols + + Printing a symbol gives output which could be fed back into a Kconfig parser + to redefine it***. The printing function (__str__()) is implemented with + public APIs, meaning you can fetch just whatever information you need as + well. + + A helpful __repr__() is implemented on all objects too, also implemented + with public APIs. + + ***Choice symbols get their parent choice as a dependency, which shows up as + e.g. 'prompt "choice symbol" if ' when printing the symbol. This + could easily be worked around if 100% reparsable output is needed. + + - Inspect expressions + + Expressions use a simple tuple-based format that can be processed manually + if needed. Expression printing and evaluation functions are provided, + implemented with public APIs. + + - Inspect the menu tree + + The underlying menu tree is exposed, including submenus created implicitly + from symbols depending on preceding symbols. This can be used e.g. to + implement menuconfig-like functionality. See the menuconfig.py example. + + +Here are some other features: + + - Single-file implementation + + The entire library is contained in this file. + + - Runs unmodified under both Python 2 and Python 3 + + The code mostly uses basic Python features and has no third-party + dependencies. The most advanced things used are probably @property and + __slots__. + + - Robust and highly compatible with the standard Kconfig C tools + + The test suite automatically compares output from Kconfiglib and the C tools + by diffing the generated .config files for the real kernel Kconfig and + defconfig files, for all ARCHes. + + This currently involves comparing the output for 36 ARCHes and 498 defconfig + files (or over 18000 ARCH/defconfig combinations in "obsessive" test suite + mode). All tests are expected to pass. + + - Not horribly slow despite being a pure Python implementation + + The allyesconfig.py example currently runs in about 1.6 seconds on a Core i7 + 2600K (with a warm file cache), where half a second is overhead from 'make + scriptconfig' (see below). + + For long-running jobs, PyPy gives a big performance boost. CPython is faster + for short-running jobs as PyPy needs some time to warm up. + + - Internals that (mostly) mirror the C implementation + + While being simpler to understand. + + +Using Kconfiglib on the Linux kernel with the Makefile targets +============================================================== + +For the Linux kernel, a handy interface is provided by the +scripts/kconfig/Makefile patch. Apply it with either 'git am' or the 'patch' +utility: + + $ wget -qO- https://raw.githubusercontent.com/ulfalizer/Kconfiglib/master/makefile.patch | git am + $ wget -qO- https://raw.githubusercontent.com/ulfalizer/Kconfiglib/master/makefile.patch | patch -p1 + +Warning: Not passing -p1 to patch will cause the wrong file to be patched. + +Please tell me if the patch does not apply. It should be trivial to apply +manually, as it's just a block of text that needs to be inserted near the other +*conf: targets in scripts/kconfig/Makefile. + +If you do not wish to install Kconfiglib via pip, the Makefile patch is set up +so that you can also just clone Kconfiglib into the kernel root: + + $ git clone git://github.com/ulfalizer/Kconfiglib.git + $ git am Kconfiglib/makefile.patch (or 'patch -p1 < Kconfiglib/makefile.patch') + +Warning: The directory name Kconfiglib/ is significant in this case, because +it's added to PYTHONPATH by the new targets in makefile.patch. + +Look further down for a motivation for the Makefile patch and for instructions +on how you can use Kconfiglib without it. + +The Makefile patch adds the following targets: + + +make [ARCH=] iscriptconfig +-------------------------------- + +This target gives an interactive Python prompt where a Kconfig instance has +been preloaded and is available in 'kconf'. To change the Python interpreter +used, pass PYTHONCMD= to make. The default is "python". + +To get a feel for the API, try evaluating and printing the symbols in +kconf.defined_syms, and explore the MenuNode menu tree starting at +kconf.top_node by following 'next' and 'list' pointers. + +The item contained in a menu node is found in MenuNode.item (note that this can +be one of the constants MENU and COMMENT), and all symbols and choices have a +'nodes' attribute containing their menu nodes (usually only one). Printing a +menu node will print its item, in Kconfig format. + +If you want to look up a symbol by name, use the kconf.syms dictionary. + + +make scriptconfig SCRIPT=