diff --git a/cmake/app/boilerplate.cmake b/cmake/app/boilerplate.cmake index f69c628cc74..2ccc8c3515c 100644 --- a/cmake/app/boilerplate.cmake +++ b/cmake/app/boilerplate.cmake @@ -424,6 +424,17 @@ please check your installation. ARCH roots searched: \n\ ${ARCH_ROOT}") endif() +if(DEFINED APPLICATION_CONFIG_DIR) + string(CONFIGURE ${APPLICATION_CONFIG_DIR} APPLICATION_CONFIG_DIR) + if(NOT IS_ABSOLUTE ${APPLICATION_CONFIG_DIR}) + get_filename_component(APPLICATION_CONFIG_DIR ${APPLICATION_CONFIG_DIR} ABSOLUTE) + endif() +else() + # Application config dir is not set, so we default to the application + # source directory as configuration directory. + set(APPLICATION_CONFIG_DIR ${APPLICATION_SOURCE_DIR}) +endif() + if(DEFINED CONF_FILE) # This ensures that CACHE{CONF_FILE} will be set correctly to current scope # variable CONF_FILE. An already current scope variable will stay the same. @@ -441,14 +452,9 @@ if(DEFINED CONF_FILE) # Need the file name to look for match. # Need path in order to check if it is absolute. get_filename_component(CONF_FILE_NAME ${CONF_FILE} NAME) - get_filename_component(CONF_FILE_DIR ${CONF_FILE} DIRECTORY) if(${CONF_FILE_NAME} MATCHES "prj_(.*).conf") set(CONF_FILE_BUILD_TYPE ${CMAKE_MATCH_1}) set(CONF_FILE_INCLUDE_FRAGMENTS true) - - if(NOT IS_ABSOLUTE ${CONF_FILE_DIR}) - set(CONF_FILE_DIR ${APPLICATION_SOURCE_DIR}/${CONF_FILE_DIR}) - endif() endif() endif() elseif(CACHED_CONF_FILE) @@ -459,21 +465,19 @@ elseif(CACHED_CONF_FILE) elseif(DEFINED ENV{CONF_FILE}) set(CONF_FILE $ENV{CONF_FILE}) -elseif(EXISTS ${APPLICATION_SOURCE_DIR}/prj_${BOARD}.conf) - set(CONF_FILE ${APPLICATION_SOURCE_DIR}/prj_${BOARD}.conf) +elseif(EXISTS ${APPLICATION_CONFIG_DIR}/prj_${BOARD}.conf) + set(CONF_FILE ${APPLICATION_CONFIG_DIR}/prj_${BOARD}.conf) -elseif(EXISTS ${APPLICATION_SOURCE_DIR}/prj.conf) - set(CONF_FILE ${APPLICATION_SOURCE_DIR}/prj.conf) +elseif(EXISTS ${APPLICATION_CONFIG_DIR}/prj.conf) + set(CONF_FILE ${APPLICATION_CONFIG_DIR}/prj.conf) set(CONF_FILE_INCLUDE_FRAGMENTS true) endif() if(CONF_FILE_INCLUDE_FRAGMENTS) - if(NOT CONF_FILE_DIR) - set(CONF_FILE_DIR ${APPLICATION_SOURCE_DIR}) - endif() - zephyr_file(CONF_FILES ${CONF_FILE_DIR}/boards KCONF CONF_FILE BUILD ${CONF_FILE_BUILD_TYPE}) + zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR}/boards KCONF CONF_FILE BUILD ${CONF_FILE_BUILD_TYPE}) endif() +set(APPLICATION_CONFIG_DIR ${APPLICATION_CONFIG_DIR} CACHE INTERNAL "The application configuration folder") set(CACHED_CONF_FILE ${CONF_FILE} CACHE STRING "If desired, you can build the application using\ the configuration settings specified in an alternate .conf file using this parameter. \ These settings will override the settings in the application’s .config file or its default .conf file.\ @@ -482,7 +486,7 @@ The CACHED_CONF_FILE is internal Zephyr variable used between CMake runs. \ To change CONF_FILE, use the CONF_FILE variable.") unset(CONF_FILE CACHE) -zephyr_file(CONF_FILES ${APPLICATION_SOURCE_DIR}/boards DTS APP_BOARD_DTS) +zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR}/boards DTS APP_BOARD_DTS) # The CONF_FILE variable is now set to its final value. zephyr_boilerplate_watch(CONF_FILE) @@ -492,10 +496,10 @@ if(DTC_OVERLAY_FILE) # in the CMakeCache.txt. elseif(APP_BOARD_DTS) set(DTC_OVERLAY_FILE ${APP_BOARD_DTS}) -elseif(EXISTS ${APPLICATION_SOURCE_DIR}/${BOARD}.overlay) - set(DTC_OVERLAY_FILE ${APPLICATION_SOURCE_DIR}/${BOARD}.overlay) -elseif(EXISTS ${APPLICATION_SOURCE_DIR}/app.overlay) - set(DTC_OVERLAY_FILE ${APPLICATION_SOURCE_DIR}/app.overlay) +elseif(EXISTS ${APPLICATION_CONFIG_DIR}/${BOARD}.overlay) + set(DTC_OVERLAY_FILE ${APPLICATION_CONFIG_DIR}/${BOARD}.overlay) +elseif(EXISTS ${APPLICATION_CONFIG_DIR}/app.overlay) + set(DTC_OVERLAY_FILE ${APPLICATION_CONFIG_DIR}/app.overlay) endif() set(DTC_OVERLAY_FILE ${DTC_OVERLAY_FILE} CACHE STRING "If desired, you can \ diff --git a/cmake/kconfig.cmake b/cmake/kconfig.cmake index 1aac82f0dea..a3de2156f96 100644 --- a/cmake/kconfig.cmake +++ b/cmake/kconfig.cmake @@ -199,7 +199,7 @@ foreach(f ${merge_config_files}) if(IS_ABSOLUTE ${f}) set(path ${f}) else() - set(path ${APPLICATION_SOURCE_DIR}/${f}) + set(path ${APPLICATION_CONFIG_DIR}/${f}) endif() list(APPEND merge_config_files_with_absolute_paths ${path}) diff --git a/doc/application/index.rst b/doc/application/index.rst index bb59b8c18ac..a8ee20b3dab 100644 --- a/doc/application/index.rst +++ b/doc/application/index.rst @@ -587,6 +587,29 @@ documentation `runningcmake`_ . Application Configuration ************************* +.. _application-configuration-directory: + +Application Configuration Directory +=================================== + +Zephyr will use configuration files from the application's configuration +directory except for files with an absolute path provided by the arguments +described earlier, for example ``CONF_FILE``, ``OVERLAY_CONFIG``, and +``DTC_OVERLAY_FILE``. + +The application configuration directory is defined by the +``APPLICATION_CONFIG_DIR`` variable. + +``APPLICATION_CONFIG_DIR`` will be set by one of the sources below with the +highest priority listed first. + +1. If ``APPLICATION_CONFIG_DIR`` is specified by the user with + ``-DAPPLICATION_CONFIG_DIR=`` or in a CMake file before + ``find_package(Zephyr)`` then this folder is used a the application's + configuration directory. + +2. The application's source directory. + .. _application-kconfig: Kconfig Configuration diff --git a/doc/guides/build/kconfig/setting.rst b/doc/guides/build/kconfig/setting.rst index 41ed19c0bd0..fa919f62566 100644 --- a/doc/guides/build/kconfig/setting.rst +++ b/doc/guides/build/kconfig/setting.rst @@ -154,18 +154,26 @@ The application configuration can come from the sources below. By default, :file:`boards/_.conf` is used. 3. Otherwise, :file:`prj_.conf` is used if it exists in the application - directory. + configuration directory. 4. Otherwise, if :file:`boards/.conf` exists in the application - directory, the result of merging it with :file:`prj.conf` is used. + configuration directory, the result of merging it with :file:`prj.conf` is + used. 5. Otherwise, if board revisions are used and :file:`boards/_.conf` exists in the application - directory, the result of merging it with :file:`prj.conf` and + configuration directory, the result of merging it with :file:`prj.conf` and :file:`boards/.conf` is used. 6. Otherwise, :file:`prj.conf` is used if it exists in the application - directory + configuration directory + +All configuration files will be taken from the application's configuration +directory except for files with an absolute path that are given with the +``CONF_FILE`` argument. + +See :ref:`Application Configuration Directory ` +on how the application configuration directory is defined. If a symbol is assigned both in :file:`_defconfig` and in the application configuration, the value set in the application configuration takes diff --git a/tests/cmake/config_dir/CMakeLists.txt b/tests/cmake/config_dir/CMakeLists.txt new file mode 100644 index 00000000000..6078e3074d3 --- /dev/null +++ b/tests/cmake/config_dir/CMakeLists.txt @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +if(DEFINED APPLICATION_CONFIG_DIR) + # Has been specified as relative on CMake invocation, convert to absolute + # and keep reference to see it's identical when Zephyr boilerplate returns. + get_filename_component(EXPECTED_APPLICATION_CONFIG_DIR ${APPLICATION_CONFIG_DIR} ABSOLUTE) +else() + # We expect a board config setup + set(EXPECTED_APPLICATION_CONFIG_DIR ${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD}) +endif() + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(app_config_dir_test) + +if(CONFIG_FAIL_TEST) + message(FATAL_ERROR "Test failed, " + "actual CONFIG_FAIL_TEST=${CONFIG_FAIL_TEST}, " + "expected CONFIG_FAIL_TEST=n" + ) +endif() + +if(NOT "${APPLICATION_CONFIG_DIR}" STREQUAL "${EXPECTED_APPLICATION_CONFIG_DIR}") + message(FATAL_ERROR "Test failed, " + "actual APPLICATION_CONFIG_DIR=${APPLICATION_CONFIG_DIR}, " + "expected APPLICATION_CONFIG_DIR=${EXPECTED_APPLICATION_CONFIG_DIR}" + ) +endif() + +target_sources(app PRIVATE src/main.c) diff --git a/tests/cmake/config_dir/Kconfig b/tests/cmake/config_dir/Kconfig new file mode 100644 index 00000000000..184d3065257 --- /dev/null +++ b/tests/cmake/config_dir/Kconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2021 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config FAIL_TEST + bool "Fail the test" + default y + +source "Kconfig.zephyr" diff --git a/tests/cmake/config_dir/foo/prj.conf b/tests/cmake/config_dir/foo/prj.conf new file mode 100644 index 00000000000..8ed5d32820d --- /dev/null +++ b/tests/cmake/config_dir/foo/prj.conf @@ -0,0 +1,3 @@ +# If this config is loaded, then the test will pass and specifying a custom +# configuration dir worked correctly. +CONFIG_FAIL_TEST=n diff --git a/tests/cmake/config_dir/src/main.c b/tests/cmake/config_dir/src/main.c new file mode 100644 index 00000000000..22ed2438dcc --- /dev/null +++ b/tests/cmake/config_dir/src/main.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +void test_main(void) +{ + /* Intentionally left empty, we are testing CMake. */ +} diff --git a/tests/cmake/config_dir/testcase.yaml b/tests/cmake/config_dir/testcase.yaml new file mode 100644 index 00000000000..b553882293f --- /dev/null +++ b/tests/cmake/config_dir/testcase.yaml @@ -0,0 +1,5 @@ +tests: + config_dir.user_defined: + platform_allow: native_posix + build_only: true + extra_args: APPLICATION_CONFIG_DIR:PATH=foo