cmake: APPLICATION_CONFIG_DIR support implemented

With this commit a dedicated APPLICATION_CONFIG_DIR is added to the
Zephyr build system.

Currently, the APPLICATION_SOURCE_DIR is identical also the base
location of configuration files.

This is very practical for simple samples, but also has it limitations
for more complex setups.

Introducing a dedicated APPLICATION_CONFIG_DIR allows users more
customization options in Zephyr build system.
Especially in terms of custom build configuration files unknown to
Zephyr itself.

For example, instead of all configuration files being located directly
in the application source folder, a project might prefer to organize
their configuration files on a per board basis, for example:
<app>/boards/custom_board_A/prj.conf
<app>/boards/custom_board_A/app.overlay
<app>/boards/custom_board_A/custom_file.mine
<app>/boards/custom_board_B/prj.conf
<app>/boards/custom_board_B/app.overlay
<app>/boards/custom_board_B/custom_file.mine
...

instead of n-files located in the root of the sample.

If the user / sample specifies APPLICATION_CONFIG_DIR, then this folder
will always be used instead of the default configuration folder.

As part of this extension the behaviour of
`-DCONF_FILE=<relative-path>/prj_<build>.conf` and additional Kconfig
fragments automatic sourcing has been aligned with the default behavior
of `prj.conf`.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
This commit is contained in:
Torsten Rasmussen 2021-09-01 11:26:53 +02:00 committed by Christopher Friedt
commit 1198087440
9 changed files with 116 additions and 23 deletions

View file

@ -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 applications .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 \

View file

@ -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})

View file

@ -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=<path>`` 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

View file

@ -154,18 +154,26 @@ The application configuration can come from the sources below. By default,
:file:`boards/<BOARD>_<build>.conf` is used.
3. Otherwise, :file:`prj_<BOARD>.conf` is used if it exists in the application
directory.
configuration directory.
4. Otherwise, if :file:`boards/<BOARD>.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/<BOARD>_<revision>.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/<BOARD>.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 <application-configuration-directory>`
on how the application configuration directory is defined.
If a symbol is assigned both in :file:`<BOARD>_defconfig` and in the
application configuration, the value set in the application configuration takes

View file

@ -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)

View file

@ -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"

View file

@ -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

View file

@ -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. */
}

View file

@ -0,0 +1,5 @@
tests:
config_dir.user_defined:
platform_allow: native_posix
build_only: true
extra_args: APPLICATION_CONFIG_DIR:PATH=foo