feat(cmakev2): Added multi_config example for cmakev2

This commit updates the examples/build_system/cmake/multi_config
example for the new build system and adds the newly created example at
examples/build_system/cmakev2/features/multi_config.
This commit is contained in:
Sudeep Mohanty
2026-02-24 11:21:19 +01:00
parent d9aa6adbfc
commit 1580f7695b
14 changed files with 300 additions and 0 deletions
+15
View File
@@ -130,6 +130,21 @@ Demonstrates importing a prebuilt static library in the ESP-IDF build system wit
---
### multi_config
**Location:** [multi_config/](./features/multi_config/)
Demonstrates building multiple configurations of a single application.
**Key Concepts:** CMake presets, multiple `sdkconfig` files, conditional compilation based on configuration
**When to use:** When building binaries for multiple products from a single codebase or different hardware variants.
**Features:**
- Development and production configurations
- Product-specific settings via `sdkconfig.defaults.*` files
- CMake presets for easy configuration switching
- Separate build directories for side-by-side builds
## Build System v2 API Quick Reference
### Project Setup
@@ -0,0 +1,2 @@
build_prod1/
build_prod2/
@@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 3.22)
# In this example, sdkconfig file is placed into the build directory.
# This allows building development and production configs side by side,
# without having them influence each other.
set(SDKCONFIG "${CMAKE_BINARY_DIR}/sdkconfig")
include($ENV{IDF_PATH}/tools/cmakev2/idf.cmake)
project(multi_config C CXX ASM)
idf_project_default()
@@ -0,0 +1,34 @@
{
"version": 3,
"configurePresets": [
{
"name": "default",
"binaryDir": "build/default",
"displayName": "Default (development)",
"description": "Development configuration",
"cacheVariables": {
"SDKCONFIG": "./build/default/sdkconfig"
}
},
{
"name": "prod1",
"binaryDir": "build/prod1",
"displayName": "Product 1",
"description": "Production configuration for product 1",
"cacheVariables": {
"SDKCONFIG_DEFAULTS": "sdkconfig.defaults.prod_common;sdkconfig.defaults.prod1",
"SDKCONFIG": "./build/prod1/sdkconfig"
}
},
{
"name": "prod2",
"binaryDir": "build/prod2",
"displayName": "Product 2",
"description": "Production configuration for product 2",
"cacheVariables": {
"SDKCONFIG_DEFAULTS": "sdkconfig.defaults.prod_common;sdkconfig.defaults.prod2",
"SDKCONFIG": "./build/prod2/sdkconfig"
}
}
]
}
@@ -0,0 +1,132 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- |
# Multiple Build Configurations Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example demonstrates how to build multiple configurations of a single application. This can be useful in the following cases:
* Building binaries for multiple similar products from single codebase
* Building the application for development or production hardware
* Optimizing the application differently for development and production
This example contains three build configurations:
* Development configuration, described by `sdkconfig.defaults` file. This configuration is used by default if the application is built using `idf.py build`.
* Production configuration for product 1 ("Blinky Smart Light"), described in `sdkconfig.prod1` file. This configuration is not built by default, however it can be built as shown in the next section. It is used together `sdkconfig.prod_common`, common configuration file for all products.
* Production configuration for product 2 ("Blinky Smart Switch"), described in `sdkconfig.prod2` file. Differs from `prod1` configuration only in product name.
For each configuration, a few configuration options are set:
* Project-specific Kconfig options, `CONFIG_EXAMPLE_PRODUCT_NAME` and `CONFIG_EXAMPLE_FUNC_IMPL`. These options are declared in [component Kconfig.projbuild](main/Kconfig.projbuild). These are used to demonstrate how to create and set project-specific options. These options are set differently in `sdkconfig.defaults` and `sdkconfig.prod_common` files.
- `CONFIG_EXAMPLE_PRODUCT_NAME` is a simple `string` option. It is used to set the product name.
- `CONFIG_EXAMPLE_FUNC_IMPL` is a `choice` option. It is used to select which of the two source files, [func_dev.c](main/func_dev.c) or [func_prod.c](main/func_prod.c), is compiled and linked. See [component CMakeLists.txt file](main/CMakeLists.txt) for related logic.
* ESP-IDF configuration options, `CONFIG_COMPILER_OPTIMIZATION_SIZE`, `CONFIG_BOOTLOADER_LOG_LEVEL_NONE`, `CONFIG_LOG_DEFAULT_LEVEL_NONE` are set in `sdkconfig.prod_common` to illustrate a typical production configuration where log messages are disabled and optimization for size is used.
## How to Use Example
### Development build
To build the development configuration (specified in `sdkconfig.defaults`), specify it using --preset argument:
```
idf.py --preset default build
```
To flash the project and see the output, run:
```
idf.py --preset default -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
### Production build
To build one of the Production configurations, specify the name using idf.py --preset argument:
```
idf.py --preset prod1 build
```
To flash the project and see the output, run:
```
idf.py --preset prod1 -p PORT flash monitor
```
To build and run the app with `prod2` configuration, repeat the steps above, replacing `prod1` with `prod2`.
### Specifying the preset for multiple commands
To avoid having to specify `--preset` argument every time you run `idf.py`, you can set `IDF_PRESET` environment variable:
For UNIX-like systems (Linux, macOS):
```shell
export IDF_PRESET=prod1
```
For Windows (PowerShell):
```powershell
$ENV:IDF_PRESET='prod1'
```
For Windows (cmd.exe):
```shell
set IDF_PRESET=prod1
```
Then subsequent commands will work with `prod1` configuration:
```shell
idf.py build
idf.py flash monitor
```
### Combining multiple files in `SDKCONFIG_DEFAULTS`
`SDKCONFIG_DEFAULTS` build system variable selects the file which contains the default app configuration, used when no `sdkconfig` file is present. If not specified, `SDKCONFIG_DEFAULTS` is set to `"sdkconfig.defaults"`.
`SDKCONFIG_DEFAULTS` can be set to a different name from the command line, using `-D` flag of `idf.py`, as shown above. It can also be set from the project CMakeLists.txt file, before `project.cmake` is included.
It is possible to specify multiple files in this variable, separating them with semicolons. In the example given in the previous section, this is used to create a common config file for production builds and product-specific config files:
* product 1: `sdkconfig.prod_common;sdkconfig.prod1`
* product 2: `sdkconfig.prod_common;sdkconfig.prod2`
This way the common options do not need to be repeated in each of `sdkconfig.prodN` files.
### Generated `sdkconfig` file
In this example, `sdkconfig` file is placed into the build directory, instead of the project root directory as it is done by default. This allows development and production builds to exist side by side. The location of `sdkconfig` file is set using `SDKCONFIG` variable in [project CMakeLists.txt](CMakeLists.txt) file.
## Example Output
### Development build output
```
I (310) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
This app is built for running on: Blinky Development Board
func() from func_dev.c (Development) called.
See README.md for building and running other app configurations.
```
### Production build output
When building with `-DSDKCONFIG_DEFAULTS="sdkconfig.prod_common;sdkconfig.prod1"` option:
```
This app is built for running on: Blinky Smart Light
func() from func_prod.c (Production) called.
See README.md for building and running other app configurations.
```
When building with `-DSDKCONFIG_DEFAULTS="sdkconfig.prod_common;sdkconfig.prod2"` option:
```
This app is built for running on: Blinky Smart Switch
func() from func_prod.c (Production) called.
See README.md for building and running other app configurations.
```
@@ -0,0 +1,8 @@
idf_component_register(SRCS "multi_config_example_main.c"
INCLUDE_DIRS ".")
if(CONFIG_EXAMPLE_FUNC_IMPL_DEV)
target_sources(${COMPONENT_LIB} PRIVATE "func_dev.c")
elseif(CONFIG_EXAMPLE_FUNC_IMPL_PROD)
target_sources(${COMPONENT_LIB} PRIVATE "func_prod.c")
endif()
@@ -0,0 +1,20 @@
menu "Example Product Configuration"
config EXAMPLE_PRODUCT_NAME
string "Product name"
default "Not set"
help
Product name used in the example
choice EXAMPLE_FUNC_IMPL
prompt "Implementation of function 'func'"
help
Select one of the implementations of 'func' to be used in the app.
This setting is used in component CMakeLists.txt.
config EXAMPLE_FUNC_IMPL_DEV
bool "Development (func_dev.c)"
config EXAMPLE_FUNC_IMPL_PROD
bool "Production (func_prod.c)"
endchoice
endmenu
@@ -0,0 +1,23 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief This function has different implementations depending on the product type.
*
* See func_dev.c and func_prod.c. Which of the files is compiled is determined in
* CMakeLists.txt,
*/
void func(void);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,13 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include "func.h"
void func(void)
{
printf("func() from func_dev.c (Development) called.\n");
}
@@ -0,0 +1,13 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include "func.h"
void func(void)
{
printf("func() from func_prod.c (Production) called.\n");
}
@@ -0,0 +1,20 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include "sdkconfig.h"
#include "func.h"
void app_main(void)
{
printf("This app is built for running on: " CONFIG_EXAMPLE_PRODUCT_NAME "\n");
/* This will call func() either from func_dev.c or func_prod.c, depending on
* the build configuration.
*/
func();
printf("See README.md for building and running other app configurations.\n");
}
@@ -0,0 +1,6 @@
# In this example, the default build (obtained with 'idf.py build')
# targets a hypothetical development platform.
CONFIG_EXAMPLE_PRODUCT_NAME="Blinky Development Board"
# This selects 'func_dev.c' file to be compiled and linked, see CMakeLists.txt.
CONFIG_EXAMPLE_FUNC_IMPL_DEV=y
@@ -0,0 +1,2 @@
# This build configuration is for a specific product:
CONFIG_EXAMPLE_PRODUCT_NAME="Blinky Smart Light"
@@ -0,0 +1,2 @@
# This build configuration is for a specific product:
CONFIG_EXAMPLE_PRODUCT_NAME="Blinky Smart Switch"