Build System
Build System
中文]
[
This document explains the implementation of the ESP-IDF build system and the concept of "components".
Read this document if you want to know how to organize and build a new ESP-IDF project or component.
Overview
An ESP-IDF project can be seen as an amalgamation of a number of components. For example, for a web
server that shows the current humidity, there could be:
ESP-IDF makes these components explicit and configurable. To do that, when a project is compiled, the build
system will look up all the components in the ESP-IDF directories, the project directories and (optionally) in
additional custom component directories. It then allows the user to configure the ESP-IDF project using a
text-based menu system to customize each component. After the components in the project are configured,
the build system will compile the project.
Concepts
A project is a directory that contains all the files and configuration to build a single app (executable), as
well as additional supporting elements such as a partition table, data partitions or filesystem partitions,
and a bootloader.
Project configuration is held in a single file called sdkconfig in the root directory of the project. This
configuration file is modified via [Link] menuconfig to customize the configuration of the project. A
single project contains exactly one project configuration.
An app is an executable that is built by ESP-IDF. A single project will usually build two apps - a "project
app" (the main executable, ie your custom firmware) and a "bootloader app" (the initial bootloader
program which launches the project app).
Components are modular pieces of standalone code that are compiled into static libraries (.a files) and
linked to an app. Some are provided by ESP-IDF itself, others may be sourced from other places.
Target is the hardware for which an application is built. A full list of supported targets in your version of
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
Some things are not part of the project:
ESP-IDF is not part of the project. Instead, it is standalone, and linked to the project via the IDF_PATH
environment variable which holds the path of the esp-idf directory. This allows the ESP-IDF framework
to be decoupled from your project.
The toolchain for compilation is not part of the project. The toolchain should be installed in the system
command line PATH.
Using the Build System
[Link]
The [Link] command-line tool provides a front-end for easily managing your project builds. It manages the
following tools:
For more details about configuring the build system using [Link] , please refer to IDF Frontend.
[Link] is a wrapper around CMake for convenience. However, you can also invoke CMake directly.
When [Link] does something, it prints each command that it runs for easy reference. For example, the
[Link] build command is the same as running these commands in a bash shell (or similar commands for
Windows Command Prompt):
mkdir -p build
cd build
cmake .. -G Ninja # or 'Unix Makefiles'
ninja
In the above list, the cmake command configures the project and generates build files for use with the final
build tool. In this case, the final build tool is Ninja: running ninja actually builds the project.
It's not necessary to run cmake more than once. After the first build, you only need to run ninja each time.
ninja will automatically re-invoke cmake if the project needs reconfiguration.
If using CMake with ninja or make , there are also targets for more of the [Link] sub-commands. For
example, running make menuconfig or ninja menuconfig in the build directory will work the same as [Link]
menuconfig .
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
Note
If you're already familiar with CMake, you may find the ESP-IDF CMake-based build system unusual
because it wraps a lot of CMake's functionality to reduce boilerplate. See writing pure CMake
components for some information about writing more "CMake style" components.
It's possible to build and flash directly from ninja or make by running a target like:
ninja flash
Or:
make app-flash
Available targets are: flash , app-flash (app only), bootloader-flash (bootloader only).
When flashing this way, optionally set the ESPPORT and ESPBAUD environment variables to specify the serial
port and baud rate. You can set environment variables in your operating system or IDE project. Alternatively,
set them directly on the command line:
Note
Providing environment variables at the start of the command like this is Bash shell Syntax. It will work on
Linux and macOS. It won't work when using Windows Command Prompt, but it will work when using
Bash-like shells on Windows.
Or:
Note
Providing variables at the end of the command line is make syntax, and works for make on all platforms.
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
You can also use an IDE with CMake integration. The IDE will want to know the path to the project's
[Link] file. IDEs with CMake integration often provide their own build tools (CMake calls these
"generators") to build the source files as part of the IDE.
When adding custom non-build steps like "flash" to the IDE, it is recommended to execute [Link] for these
"special" commands.
For more detailed information about integrating ESP-IDF with CMake into an IDE, see Build System
Metadata.
Setting up the Python Interpreter
[Link] and other Python scripts will run with the default Python interpreter, i.e., python . You can switch to
a different one like python3 $IDF_PATH/tools/[Link] ... , or you can set up a shell alias or another script to
simplify the command.
If using CMake directly, running cmake -D PYTHON=python3 ... will cause CMake to override the default
Python interpreter.
If using an IDE with CMake, setting the PYTHON value as a CMake cache override in the IDE UI will override
the default Python interpreter.
To manage the Python version more generally via the command line, check out the tools pyenv or virtualenv.
These let you change the default Python version.
Example Project
- myProject/
- [Link]
- sdkconfig
- [Link]
- bootloader_components/ - boot_component/ - [Link]
- Kconfig
- src1.c
- components/ - component1/ - [Link]
- Kconfig
- src1.c
- component2/ - [Link]
- Kconfig
- src1.c
- include/ - component2.h
- managed_components/ - namespace__component-name/ - [Link]
- src1.c
- idf_component.yml
- include/ - src1.h
- main/ - [Link]
- src1.c
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
- src2.c
- idf_component.yml
- build/
A top-level project [Link] file. This is the primary file which CMake uses to learn how to build the
project; and may set project-wide CMake variables. It includes the file /tools/cmake/[Link] which
implements the rest of the build system. Finally, it sets the project name and defines the project.
"sdkconfig" project configuration file. This file is created/updated when [Link] menuconfig runs, and
holds the configuration for all of the components in the project (including ESP-IDF itself). The sdkconfig
file may or may not be added to the source control system of the project. More information about this file
can be found in the sdkconfig file section in the Configuration Guide.
"[Link]" file contains the list of all managed components, and their versions, that are
currently in used in the project. The [Link] file is generated or updated automatically when
IDF Component Manager is used to add or update project components. So this file should never be
edited manually! If the project does not have idf_component.yml files in any of its components,
[Link] will not be created.
Optional "idf_component.yml" file contains metadata about the component and its dependencies. It is
used by the IDF Component Manager to download and resolve these dependencies. More information
about this file can be found in the idf_component.yml section.
Optional "bootloader_components" directory contains components that need to be compiled and linked
inside the bootloader project. A project does not have to contain custom bootloader components of this
kind, but it can be useful in case the bootloader needs to be modified to embed new features.
Optional "components" directory contains components that are part of the project. A project does not
have to contain custom components of this kind, but it can be useful for structuring reusable code or
including third-party components that aren't part of ESP-IDF. Alternatively, EXTRA_COMPONENT_DIRS can be
set in the top-level [Link] to look for components in other places.
"main" directory is a special component that contains source code for the project itself. "main" is a default
name, the CMake variable COMPONENT_DIRS includes this component but you can modify this variable. See
the renaming main section for more info. If you have a lot of source files in your project, we recommend
grouping most into components instead of putting them all in "main".
"build" directory is where the build output is created. This directory is created by [Link] if it doesn't
already exist. CMake configures the project and generates interim build files in this directory. Then, after
the main build process is run, this directory will also contain interim object files and libraries as well as
final binary output files. This directory is usually not added to source control or distributed with the
project source code.
"managed_components" directory is created by the IDF Component Manager to store components
managed by this tool. Each managed component typically includes a idf_component.yml manifest file
defining the component's metadata, such as version and dependencies. However, for components
sourced from Git repositories, the manifest file is optional. Users should avoid manually modifying the
contents of the "managed_components" directory. If alterations are needed, the component can be
copied to the components directory. The "managed_components" directory is usually not versioned in Git
and not distributed with the project source code.
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
Component directories each contain a component [Link] file. This file contains variable definitions
to control the build process of the component, and its integration into the overall project. See Component
CMakeLists Files for more details.
Each component may also include a Kconfig file defining the component configuration options that can be
set via menuconfig . Some components may also include [Link] and project_include.cmake
files, which are special files for overriding parts of the project.
Project CMakeLists File
Each project has a single top-level [Link] file that contains build settings for the entire project. By
default, the project CMakeLists can be quite minimal.
Minimal project:
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/[Link])
project(myProject)
Mandatory Parts
The inclusion of these three lines, in the order shown above, is necessary for every project:
cmake_minimum_required(VERSION 3.16) tells CMake the minimum version that is required to build the
project. ESP-IDF is designed to work with CMake 3.16 or newer. This line must be the first line in the
[Link] file.
include($ENV{IDF_PATH}/tools/cmake/[Link]) pulls in the rest of the CMake functionality to
for the final binary output files of the app - ie [Link] , [Link] . Only one project can be
defined per CMakeLists file.
These variables all have default values that can be overridden for custom behavior. Look in
/tools/cmake/[Link] for all of the implementation details.
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
COMPONENTS : A list of component names to build into the project. Defaults to all components found in the
COMPONENT_DIRS directories. Use this variable to "trim down" the project for faster build times. Note that
any component which "requires" another component via the REQUIRES or PRIV_REQUIRES arguments
on component registration will automatically have it added to this list, so the COMPONENTS list can be very
short. The MINIMAL_BUILD build property can be used as an alternative to specifying only the main
component in COMPONENTS .
BOOTLOADER_IGNORE_EXTRA_COMPONENT : Optional list of components, placed in bootloader_components/ , that
should be ignored by the bootloader compilation. Use this variable if a bootloader component needs to
be included conditionally inside the project.
BOOTLOADER_EXTRA_COMPONENT_DIRS : Optional list of additional directories to search for components to be
compiled as part of the bootloader. Please note that this is a build property.
Any paths in these variables can be absolute paths, or set relative to the project directory.
To set these variables, use the cmake set command ie set(VARIABLE "VALUE") . The set() commands should
be placed after the cmake_minimum(...) line but before the include(...) line.
Renaming main Component
The build system provides special treatment to the main component. It is a component that gets
automatically added to the build provided that it is in the expected location, PROJECT_DIR/main. All other
components in the build are also added as its dependencies, saving the user from hunting down
dependencies and providing a build that works right out of the box. Renaming the main component causes
the loss of these behind-the-scenes heavy lifting, requiring the user to specify the location of the newly
renamed component and manually specify its dependencies. Specifically, the steps to renaming main are as
follows:
The build sets some global build specifications (compile flags, definitions, etc.) that gets used in compiling all
sources from all components.
For example, one of the default build specifications set is the compile option -Wextra . Suppose a user wants
to use override this with -Wno-extra , it should be done after project() :
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/[Link])
project(myProject)
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
idf_build_set_property(COMPILE_OPTIONS "-Wno-error" APPEND)
This ensures that the compile options set by the user won't be overridden by the default build specifications,
since the latter are set inside project() .
Each project contains one or more components. Components can be part of ESP-IDF, part of the project's
own components directory, or added from custom component directories (see above).
A component is any directory in the COMPONENT_DIRS list which contains a [Link] file.
The list of directories in COMPONENT_DIRS is searched for the project's components. Directories in this list can
either be components themselves (ie they contain a [Link] file), or they can be top-level directories
whose sub-directories are components.
When CMake runs to configure the project, it logs the components included in the build. This list can be
useful for debugging the inclusion/exclusion of certain components.
When ESP-IDF is collecting all the components to compile, the search precedence is as follows (from highest
to lowest):
Project components
Components from EXTRA_COMPONENT_DIRS
If two or more of these directories contain component sub-directories with the same name, the component
with higher precedence is used. This allows, for example, overriding ESP-IDF components with a modified
version by copying that component from the ESP-IDF components directory to the project components
directory and then modifying it there. If used in this way, the ESP-IDF directory itself can remain untouched.
Note
If a component is overridden in an existing project by moving it to a new location, the project will not
automatically see the new component path. Run [Link] reconfigure (or delete the project build folder)
and then build again.
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
Minimal Component CMakeLists
The minimal component [Link] file simply registers the component to the build system using
idf_component_register :
SRCS is a list of source files ( *.c , *.cpp , *.cc , *.S ). These source files will be compiled into the
component library.
INCLUDE_DIRS is a list of directories to add to the global include search path for any component which
requires this component, and also the main source files.
REQUIRES is not actually required, but it is very often required to declare what other components this
A library with the name of the component will be built and linked to the final app.
Directories are usually specified relative to the [Link] file itself, although they can be absolute.
There are other arguments that can be passed to idf_component_register . These arguments are discussed
here.
See example component requirements and example component CMakeLists for more complete component
[Link] examples.
Preset Component Variables
The following component-specific variables are available for use inside component CMakeLists, but should
not be modified:
COMPONENT_DIR : The component directory. Evaluates to the absolute path of the directory containing
[Link] . The component path cannot contain spaces. This is the same as the
CMAKE_CURRENT_SOURCE_DIR variable.
COMPONENT_NAME : Name of the component. Same as the name of the component directory.
COMPONENT_ALIAS : Alias of the library created internally by the build system for the component.
COMPONENT_LIB : Name of the library created internally by the build system for the component.
COMPONENT_VERSION : Component version specified by idf_component.yml and set by IDF Component
Manager.
The following variables are set at the project level, but available for use in component CMakeLists:
CONFIG_* : Each value in the project configuration has a corresponding variable available in cmake. All
names begin with CONFIG_ . More information on how the project configuration works, please visit
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
Project Configuration Guide.
ESP_PLATFORM : Set to 1 when the CMake file is processed within the ESP-IDF build system.
Build/Project Variables
The following are some project/build variables that are available as build properties and whose values can be
queried using idf_build_get_property from the component [Link]:
variable. v4.0-dev-* , v4.0-beta1 , v4.0-rc1 and v4.0 will all have the same values of IDF_VERSION_*
VERSION x.y.z.w ) then it will be used as PROJECT_VER . The VERSION argument must be compliant
with the cmake standard.
Else, if the project is located inside a Git repository, the output of git description will be used.
Otherwise, PROJECT_VER will be "1".
EXTRA_PARTITION_SUBTYPES : CMake list of extra partition subtypes. Each subtype description is a comma-
separated string with type_name, subtype_name, numeric_value format. Components may add new
subtypes by appending them to this list.
To pass compiler options when compiling source files belonging to a particular component, use the
target_compile_options function:
To apply the compilation flags to a single source file, use the CMake set_source_files_properties command:
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
set_source_files_properties(mysrc.c
PROPERTIES COMPILE_FLAGS
-Wno-unused-variable
)
Note
CMake set_source_files_properties command is not applicable when the source files have been
populated with help of the SRC_DIRS variable in idf_component_register . See File Globbing &
Incremental Builds for more details.
When using these commands, place them after the call to idf_component_register in the component
CMakeLists file.
Component Configuration
Each component can also have a Kconfig file, alongside [Link] . This contains configuration
settings to add to the configuration menu for this component.
These settings are found under the "Component Settings" menu when menuconfig is run.
To create a component Kconfig file, it is easiest to start with one of the Kconfig files distributed with ESP-
IDF.
For an example, see Adding conditional configuration. For a more detailed guide, see Component
Configuration Guide.
Preprocessor Definitions
The ESP-IDF build system adds the following C preprocessor definitions on the command line:
Component Requirements
When compiling each component, the ESP-IDF build system recursively evaluates its dependencies. This
means each component needs to declare the components that it depends on ("requires").
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
idf_component_register(...
REQUIRES mbedtls
PRIV_REQUIRES console spiffs)
REQUIRES should be set to all components whose header files are #included from the public header files
of this component.
PRIV_REQUIRES should be set to all components whose header files are #included from any source files in
this component, unless already listed in REQUIRES . Also, any component which is required to be linked in
order for this component to function correctly.
The values of REQUIRES and PRIV_REQUIRES should not depend on any configuration options
( CONFIG_xxx macros). This is because requirements are expanded before the configuration is loaded.
Other component variables (like include paths or source files) can depend on configuration options.
Not setting either or both REQUIRES variables is fine. If the component has no requirements except for
the Common component requirements needed for RTOS, libc, etc.
If a component only supports some target chips (values of IDF_TARGET ) then it can specify
REQUIRED_IDF_TARGETS in the idf_component_register call to express these requirements. In this case, the
build system will generate an error if the component is included in the build, but does not support the
selected target.
Note
In CMake terms, REQUIRES & PRIV_REQUIRES are approximate wrappers around the CMake functions
target_link_libraries(... PUBLIC ...) and target_link_libraries(... PRIVATE ...) .
Imagine there is a car component, which uses the engine component, which uses the spark_plug
component:
- autoProject/
- [Link]
- components/ - car/ - [Link]
- car.c
- car.h
- engine/ - [Link]
- engine.c
- include/ - engine.h
- spark_plug/ - [Link]
- spark_plug.c
- spark_plug.h
Car Component
The car.h header file is the public interface for the car component. This header includes engine.h
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
/* car.h */
#include "engine.h"
#ifdef ENGINE_IS_HYBRID
#define CAR_MODEL "Hybrid"
#endif
/* car.c */
#include "car.h"
This means the car/[Link] file needs to declare that car requires engine :
idf_component_register(SRCS "car.c"
INCLUDE_DIRS "."
REQUIRES engine)
The engine component also has a public header file include/engine.h , but this header is simpler:
/* engine.h */
#define ENGINE_IS_HYBRID
void engine_start(void);
/* engine.c */
#include "engine.h"
#include "spark_plug.h"
...
In this component, engine depends on spark_plug but this is a private dependency. spark_plug.h is
needed to compile engine.c , but not needed to include engine.h .
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
This means that the engine/[Link] file can use PRIV_REQUIRES :
idf_component_register(SRCS "engine.c"
INCLUDE_DIRS "include"
PRIV_REQUIRES spark_plug)
As a result, source files in the car component don't need the spark_plug include directories added to their
compiler search path. This can speed up compilation, and stops compiler command lines from becoming
longer than necessary.
Spark Plug Component
The spark_plug component doesn't depend on anything else. It has a public header file spark_plug.h , but
this doesn't include headers from any other components.
This means that the spark_plug/[Link] file doesn't need any REQUIRES or PRIV_REQUIRES clauses:
idf_component_register(SRCS "spark_plug.c"
INCLUDE_DIRS ".")
Each component's source file is compiled with these include path directories, as specified in the passed
arguments to idf_component_register :
idf_component_register(..
INCLUDE_DIRS "include"
PRIV_INCLUDE_DIRS "other")
parameters (ie all the current component's public and private dependencies).
Recursively, all of the INCLUDE_DIRS of those components REQUIRES lists (ie all public dependencies of
this component's dependencies, recursively expanded).
The component named main is special because it automatically requires all other components in the build.
So it's not necessary to pass REQUIRES or PRIV_REQUIRES to this component. See renaming main for a
description of what needs to be changed if no longer using the main component.
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
To avoid duplication, every component automatically requires some "common" IDF components even if they
are not mentioned explicitly. Headers from these components can always be included.
The list of common components is: cxx, newlib, freertos, esp_hw_support, heap, log, soc, hal, esp_rom,
esp_common, esp_system, xtensa/riscv.
Including Components in the Build
Note
Certain features and configurations, such as those provided by esp_psram or espcoredump components,
may not be available to your project by default if the minimal list of components is used. When using the
COMPONENTS variable, ensure that all necessary components are included. Similarly, when using the
MINIMAL_BUILD build property, ensure that all required components are specified in the REQUIRES or
PRIV_REQUIRES argument during component registration.
Circular Dependencies
It's possible for a project to contain Component A that requires ( REQUIRES or PRIV_REQUIRES ) Component B,
and Component B that requires Component A. This is known as a dependency cycle or a circular
dependency.
CMake will usually handle circular dependencies automatically by repeating the component library names
twice on the linker command line. However this strategy doesn't always work, and the build may fail with a
linker error about "Undefined reference to ...", referencing a symbol defined by one of the components inside
the circular dependency. This is particularly likely if there is a large circular dependency, i.e., A > B > C > D >
A.
The best solution is to restructure the components to remove the circular dependency. In most cases, a
software architecture without circular dependencies has desirable properties of modularity and clean
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
layering and will be more maintainable in the long term. However, removing circular dependencies is not
always possible.
To bypass a linker error caused by a circular dependency, the simplest workaround is to increase the CMake
LINK_INTERFACE_MULTIPLICITY property of one of the component libraries. This causes CMake to repeat
this library and its dependencies more than two times on the linker command line.
For example:
This line should be placed after idf_component_register in the component [Link] file.
If possible, place this line in the component that creates the circular dependency by depending on a lot of
other components. However, the line can be placed inside any component that is part of the cycle.
Choosing the component that owns the source file shown in the linker error message, or the component
that defines the symbol(s) mentioned in the linker error message, is a good place to start.
Usually increasing the value to 3 (default is 2) is enough, but if this doesn't work then try increasing the
number further.
Adding this option will make the linker command line longer, and the linking stage slower.
If only one or two symbols are causing a circular dependency, and all other dependencies are linear, then
there is an alternative method to avoid linker errors: Specify the specific symbols required for the "reverse"
dependency as undefined symbols at link time.
For example, if component A depends on component B but component B also needs to reference
reverse_ops from component A (but nothing else), then you can add a line like the following to the
component B [Link] to resolve the cycle at link time:
The -u argument means that the linker will always include this symbol in the link, regardless of
dependency ordering.
This line should be placed after idf_component_register in the component [Link] file.
If 'Component B' doesn't need to access any headers of 'Component A', only link to a few symbol(s), then
this line can be used instead of any REQUIRES from B to A. This further simplifies the component
structure in the build system.
See the target_link_libraries documentation for more information about this CMake function.
Requirements in the Build System Implementation
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
Very early in the CMake configuration process, the script expand_requirements.cmake is run. This script
does a partial evaluation of all component [Link] files and builds a graph of component
requirements (this graph may have cycles). The graph is used to generate a file component_depends.cmake
in the build directory.
The main CMake process then includes this file and uses it to determine the list of components to include
in the build (internal BUILD_COMPONENTS variable). The BUILD_COMPONENTS variable is sorted so
dependencies are listed first, however, as the component dependency graph has cycles this cannot be
guaranteed for all components. The order should be deterministic given the same set of components and
component dependencies.
The value of BUILD_COMPONENTS is logged by CMake as "Component names: "
Configuration is then evaluated for the components included in the build.
Each component is included in the build normally and the [Link] file is evaluated again to add
the component libraries to the build.
The order of components in the BUILD_COMPONENTS variable determines other orderings during the build:
idf_component_add_link_dependency(FROM other_component)
Project_include.cmake
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
For components that have build requirements that must be evaluated before any component CMakeLists
files are evaluated, you can create a file called project_include.cmake in the component directory. This
CMake file is included when [Link] is evaluating the entire project.
project_include.cmake files are used inside ESP-IDF, for defining project-wide build features such as
[Link] command line arguments and the bootloader "special app".
Unlike component [Link] files, when including a project_include.cmake file the current source
directory ( CMAKE_CURRENT_SOURCE_DIR and working directory) is the project directory. Use the variable
COMPONENT_DIR for the absolute directory of the component.
Note that project_include.cmake isn't necessary for the most common component uses, such as adding
include directories to the project, or LDFLAGS to the final linking step. These values can be customized via
the [Link] file itself. See Optional Project Variables for details.
project_include.cmake files are included in the order given in BUILD_COMPONENTS variable (as logged by
CMake). This means that a component's project_include.cmake file will be included after it's all
dependencies' project_include.cmake files, unless both components are part of a dependency cycle. This is
important if a project_include.cmake file relies on variables set by another component. See also above.
Take great care when setting variables or targets in a project_include.cmake file. As the values are included
in the top-level project CMake pass, they can influence or break functionality across all components!
[Link]
This is an equivalent to project_include.cmake for Component Configuration Kconfig files. If you want to
include configuration options at the top level of menuconfig, rather than inside the "Component
Configuration" sub-menu, then these can be defined in the [Link] file alongside the
[Link] file.
Take care when adding configuration values in this file, as they will be included across the entire project
configuration. Where possible, it's generally better to create a Kconfig file for Component Configuration.
For more information, see Kconfig Files section in the Configuration Guide.
Thanks to the linker's wrap feature, it is possible to redefine or extend the behavior of an existing ESP-IDF
function. To do so, you will need to provide the following CMake declaration in your project's
[Link] file:
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
Where function_to_redefine is the name of the function to redefine or extend. This option will let the linker
replace all the calls to function_to_redefine functions in the binary libraries with calls to
__wrap_function_to_redefine function. Thus, you must define this new symbol in your application.
The linker will provide a new symbol named __real_function_to_redefine which points to the former
implementation of the function to redefine. It can be called from the new implementation, making it an
extension of the former one.
Thanks to the optional bootloader_components directory present in your ESP-IDF project, it is possible to
override the default ESP-IDF bootloader. To do so, a new bootloader_components/main component should be
defined, which will make the project directory tree look like the following:
myProject/
[Link]
sdkconfig
bootloader_components/ - main/ - [Link]
Kconfig
my_bootloader.c
main/ - [Link]
app_main.c
build/
Here, the my_bootloader.c file becomes source code for the new bootloader, which means that it will need
to perform all the required operations to set up and load the main application from flash.
It is also possible to conditionally replace the bootloader depending on a certain condition, such as the target
for example. This can be achieved thanks to the BOOTLOADER_IGNORE_EXTRA_COMPONENT CMake variable. This list
can be used to tell the ESP-IDF bootloader project to ignore and not compile the given components present
in bootloader_components . For example, if one wants to use the default bootloader for ESP32 target, then
myProject/[Link] should look like the following:
include($ENV{IDF_PATH}/tools/cmake/[Link])
project(main)
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
It is important to note that this can also be used for any other bootloader components than main . In all
cases, the prefix bootloader_component must not be specified.
include($ENV{IDF_PATH}/tools/cmake/[Link])
idf_build_set_property(BOOTLOADER_EXTRA_COMPONENT_DIRS "/path/to/extra/component/"
APPEND)
project(main)
Debugging CMake
For full details about CMake and CMake commands, see the CMake v3.16 documentation.
When CMake runs, it prints quite a lot of diagnostic information including lists of components and
component paths.
Running cmake -DDEBUG=1 will produce more verbose diagnostic output from the IDF build system.
Running cmake with the --trace or --trace-expand options will give a lot of information about control
flow. See the cmake command line documentation.
When included from a project CMakeLists file, the [Link] file defines some utility modules and
global variables and then sets IDF_PATH if it was not set in the system environment.
It also defines an overridden custom version of the built-in CMake project function. This function is
overridden to add all of the ESP-IDF specific project functionality.
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
Warning On Undefined Variables
To enable this function, we can pass the --warn-uninitialized flag to CMake or pass the --cmake-warn-
uninitialized flag to [Link] so it will print a warning if an undefined variable is referenced in the build. This
can be very useful to find buggy CMake files.
Browse the /tools/cmake/[Link] file and supporting functions in /tools/cmake/ for more details.
The configuration system can be used to conditionally compile some files depending on the options selected
in the project configuration.
Kconfig :
config FOO_ENABLE_BAR
bool "Enable the BAR feature."
help
This enables the BAR feature of the FOO component.
[Link] :
if(CONFIG_FOO_ENABLE_BAR)
list(APPEND srcs "bar.c")
endif()
idf_component_register(SRCS "${srcs}"
...)
This example makes use of the CMake if function and list APPEND function.
Kconfig :
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
config ENABLE_LCD_OUTPUT
bool "Enable LCD output."
help
Select this if your board has an LCD.
config ENABLE_LCD_CONSOLE
bool "Output console text to LCD"
depends on ENABLE_LCD_OUTPUT
help
Select this to output debugging output to the LCD
config ENABLE_LCD_PLOT
bool "Output temperature plots to LCD"
depends on ENABLE_LCD_OUTPUT
help
Select this to output temperature plots
[Link] :
if(CONFIG_ENABLE_LCD_OUTPUT)
set(srcs lcd-real.c lcd-spi.c)
else()
set(srcs lcd-dummy.c)
endif()
idf_component_register(SRCS "${srcs}"
...)
In addition to that, if target xyz is used ( IDF_TARGET=xyz ), then Kconfig variable CONFIG_IDF_TARGET_XYZ will
be set.
Note that component dependencies may depend on IDF_TARGET variable, but not on Kconfig variables. Also
one can not use Kconfig variables in include statements in CMake files, but IDF_TARGET can be used in
such context.
Some components will have a situation where a source file isn't supplied with the component itself but has
to be generated from another file. Say our component has a header file that consists of the converted binary
data of a BMP file, converted using a hypothetical tool called bmp2h. The header file is then included in as C
source file called graphics_lib.c:
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
add_custom_command(OUTPUT logo.h
COMMAND bmp2h -i ${COMPONENT_DIR}/[Link] -o log.h
DEPENDS ${COMPONENT_DIR}/[Link]
VERBATIM)
This answer is adapted from the CMake FAQ entry, which contains some other examples that will also work
with ESP-IDF builds.
In this example, logo.h will be generated in the current directory (the build directory) while [Link] comes
with the component and resides under the component path. Because logo.h is a generated file, it should be
cleaned when the project is cleaned. For this reason, it is added to the ADDITIONAL_CLEAN_FILES
property.
Note
If generating files as part of the project [Link] file, not a component [Link], then use
build property PROJECT_DIR instead of ${COMPONENT_DIR} and ${PROJECT_NAME}.elf instead of
${COMPONENT_LIB} .)
If a a source file from another component included logo.h , then add_dependencies would need to be called
to add a dependency between the two components, to ensure that the component source files were always
compiled in the correct order.
Embedding Binary Data
Sometimes you have a file with some binary or text data that you'd like to make available to your component,
but you don't want to reformat the file as a C source.
You can specify argument EMBED_FILES in the component registration, giving space-delimited names of the
files to embed:
idf_component_register(...
EMBED_FILES server_root_cert.der)
Or if the file is a string, you can use the variable EMBED_TXTFILES . This will embed the contents of the text file
as a null-terminated string:
idf_component_register(...
EMBED_TXTFILES server_root_cert.pem)
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
The file's contents will be added to the .rodata section in flash, and are available via symbol names as
follows:
The names are generated from the full name of the file, as given in EMBED_FILES . Characters /, ., etc. are
replaced with underscores. The _binary prefix in the symbol name is added by objcopy and is the same for
both text and binary files.
To embed a file into a project, rather than a component, you can call the function target_add_binary_data
like this:
Place this line after the project() line in your project [Link] file. Replace [Link] with your
project name. The final argument can be TEXT to embed a null-terminated string, or BINARY to embed the
content as-is.
For an example of using this technique, see the "main" component of the file_serving example
protocols/http_server/file_serving/main/[Link] - two files are loaded at build time and linked into
the firmware.
add_custom_command(OUTPUT my_processed_file.bin
COMMAND my_process_file_cmd my_unprocessed_file.bin)
target_add_binary_data(my_target "my_processed_file.bin" BINARY)
The DEPENDS argument to target_add_binary_data ensures that the target executes first.
Code and Data Placements
ESP-IDF has a feature called linker script generation that enables components to define where its code and
data will be placed in memory through linker fragment files. These files are processed by the build system,
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
and is used to augment the linker script used for linking app binary. See Linker Script Generation for a quick
start guide as well as a detailed discussion of the mechanism.
Fully Overriding the Component Build Process
Obviously, there are cases where all these recipes are insufficient for a certain component, for example when
the component is basically a wrapper around another third-party component not originally intended to be
compiled under this build system. In that case, it's possible to forego the ESP-IDF build system entirely by
using a CMake feature called ExternalProject. Example component CMakeLists:
(The above [Link] can be used to create a component named quirc that builds the quirc project
using its own Makefile.)
The second set of commands adds a library target, which points to the "imported" library file built by the
external system. Some properties need to be set in order to add include directories and tell CMake where
this file is.
Finally, the generated library is added to ADDITIONAL_CLEAN_FILES. This means make clean will delete
this library. (Note that the other object files from the build won't be deleted.)
Note
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
When using an external build process with PSRAM, remember to add -mfix-esp32-psram-cache-issue to
the C compiler arguments. See CONFIG_SPIRAM_CACHE_WORKAROUND for details of this flag.
ADDITIONAL_CLEAN_FILES only works when "make" or "ninja" is used as the build system. If an IDE
build system is used, it won't delete these files when cleaning.
However, the ExternalProject configure & build commands will always be re-run after a clean is run.
Therefore, there are two alternative recommended ways to configure the external build command:
1. Have the external BUILD_COMMAND run a full clean compile of all sources. The build command will
be run if any of the dependencies passed to externalproject_add with DEPENDS have changed, or
if this is a clean build (ie any of [Link] clean , ninja clean , or make clean was run.)
2. Have the external BUILD_COMMAND be an incremental build command. Pass the parameter
BUILD_ALWAYS 1 to externalproject_add . This means the external project will be built each time a
build is run, regardless of dependencies. This is only recommended if the external project has
correct incremental build behavior, and doesn't take too long to run.
The best of these approaches for building an external project will depend on the project itself, its build
system, and whether you anticipate needing to frequently recompile the project.
Custom Sdkconfig Defaults
Note
For more detailed information about [Link] file, please visit [Link] file in Project
Configuration section.
For example projects or other projects where you don't want to specify a full sdkconfig configuration, but
you do want to override some key values from the ESP-IDF defaults, it is possible to create a file
[Link] in the project directory. This file will be used when creating a new config from scratch,
or when any new config value hasn't yet been set in the sdkconfig file.
To override the name of this file or to specify multiple files, set the SDKCONFIG_DEFAULTS environment variable
or set SDKCONFIG_DEFAULTS in top-level [Link] . File names that are not specified as full paths are
resolved relative to current project's directory.
When specifying multiple files, use a semicolon as the list separator. Files listed first will be applied first. If a
particular key is defined in multiple files, the definition in the latter file will override definitions from former
files.
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
Some of the IDF examples include a [Link] file. This is part of the continuous integration (CI) test
framework and is ignored by the normal build process.
If and only if an [Link] file exists, the build system will also attempt to load defaults from an
[Link].TARGET_NAME file, where TARGET_NAME is the value of IDF_TARGET . For example, for
esp32 target, default settings will be taken from [Link] first, and then from
[Link].esp32 . If there are no generic default settings, an empty [Link] still needs
to be created if the build system should recognize any additional target-dependent
[Link].TARGET_NAME files.
If SDKCONFIG_DEFAULTS is used to override the name of defaults file/files, the name of target-specific defaults
file will be derived from SDKCONFIG_DEFAULTS value/values using the rule above. When there are multiple files
in SDKCONFIG_DEFAULTS , target-specific file will be applied right after the file bringing it in, before all latter files
in SDKCONFIG_DEFAULTS
You can find more detailed information on how the project configuration works in the Project Configuration
Guide. In the Configuration Files Structure and Relationships, you can find lower-level information about the
configuration files.
Flash Arguments
There are some scenarios that we want to flash the target board without IDF. For this case we want to save
the built binaries, [Link] and esptool write_flash arguments. It's simple to write a script to save binaries
and [Link].
After running a project build, the build directory contains binary output files ( .bin files) for the project and
also the following flashing data files:
flash_project_args contains arguments to flash the entire project (app, bootloader, partition table, PHY
data if this is configured).
flash_app_args contains arguments to flash only the app.
You can pass any of these flasher argument files to [Link] as follows:
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
Alternatively, it is possible to manually copy the parameters from the argument file and pass them on the
command line.
The build directory also contains a generated file flasher_args.json which contains project flash
information, in JSON format. This file is used by [Link] and can also be used by other tools which need
information about the project build.
Building the Bootloader
The bootloader is a special "subproject" inside /components/bootloader/subproject. It has its own project
[Link] file and builds separate .ELF and .BIN files to the main project. However, it shares its
configuration and build directory with the main project.
The subproject is inserted as an external project from the top-level project, by the file
/components/bootloader/project_include.cmake. The main build process runs CMake for the subproject,
which includes discovering components (a subset of the main components) and generating a bootloader-
specific config (derived from the main sdkconfig ).
However, underneath the concept of "components" is a full CMake build system. It is also possible to make a
component which is pure CMake.
Here is an example minimal "pure CMake" component CMakeLists file for a component named json :
add_library(json STATIC
cJSON/cJSON.c
cJSON/cJSON_Utils.c)
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
projects, sometimes even without modification! This allows for users to be able to get functionality that may
not yet be provided by a component, or use another library for the same functionality.
Importing a library might look like this for a hypothetical library foo to be used in the main component:
For an actual example, take a look at build_system/cmake/import_lib. Take note that what needs to be done
in order to import the library may vary. It is recommended to read up on the library's documentation for
instructions on how to import it from other projects. Studying the library's [Link] and build
structure can also be helpful.
It is also possible to wrap a third-party library to be used as a component in this manner. For example, the
mbedtls component is a wrapper for Espressif's fork of mbedtls. See its component [Link] .
The CMake variable ESP_PLATFORM is set to 1 whenever the ESP-IDF build system is being used. Tests such
as if (ESP_PLATFORM) can be used in generic CMake code if special IDF-specific logic is required.
The above example assumes that the external library foo (or tinyxml in the case of the import_lib
example) doesn't need to use any ESP-IDF APIs apart from common APIs such as libc, libstdc++, etc. If the
external library needs to use APIs provided by other ESP-IDF components, this needs to be specified in the
external [Link] file by adding a dependency on the library target idf::<componentname> .
if(ESP_PLATFORM)
# On ESP-IDF, bar.c needs to include esp_flash.h from the spi_flash component
target_link_libraries(foo PRIVATE idf::spi_flash)
endif()
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
The ESP-IDF build system provides a utility function add_prebuilt_library for users to be able to easily
import and use prebuilt libraries:
add_prebuilt_library(target_name lib_path [REQUIRES req1 req2 ...] [PRIV_REQUIRES req1 req2 ...])
where:
target_name - name that can be used to reference the imported library, such as when linking to other
targets
lib_path - path to prebuilt library; may be an absolute or relative path to the component directory
Optional arguments REQUIRES and PRIV_REQUIRES specify dependency on other components. These have
the same meaning as the arguments for idf_component_register .
Take note that the prebuilt library must have been compiled for the same target as the consuming project.
Configuration relevant to the prebuilt library must also match. If not paid attention to, these two factors may
contribute to subtle bugs in the app.
ESP-IDF provides a template CMake project for easily creating an application. However, in some instances
the user might already have an existing CMake project or may want to create a custom one. In these cases it
is desirable to be able to consume IDF components as libraries to be linked to the user's targets
(libraries/executables).
It is possible to do so by using the build system APIs provided by tools/cmake/[Link]. For example:
cmake_minimum_required(VERSION 3.16)
project(my_custom_app C)
# Include CMake file that provides ESP-IDF CMake build system APIs.
include($ENV{IDF_PATH}/tools/cmake/[Link])
# Create the project executable and plainly link the newlib component to it using
# its alias, idf::newlib.
add_executable(${CMAKE_PROJECT_NAME}.elf main.c)
target_link_libraries(${CMAKE_PROJECT_NAME}.elf idf::newlib)
# Let the build system know what the project executable is to attach more targets, dependencies, etc.
idf_build_executable(${CMAKE_PROJECT_NAME}.elf)
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
The example in build_system/cmake/idf_as_lib demonstrates the creation of an application equivalent to
hello world application using a custom CMake project.
Note
The IDF build system can only set compiler flags for source files that it builds. When an external
[Link] file is used and PSRAM is enabled, remember to add -mfix-esp32-psram-cache-issue to
the C compiler arguments. See CONFIG_SPIRAM_CACHE_WORKAROUND for details of this flag.
Idf-build-commands
Retrieve a build property property and store it in var accessible from the current scope. Specifying
GENERATOR_EXPRESSION will retrieve the generator expression string for that property, instead of the
actual value, which can be used with CMake commands that support generator expressions.
Set a build property property with value val. Specifying APPEND will append the specified value to the
current value of the property. If the property does not previously exist or it is currently empty, the specified
value becomes the first element/member instead.
idf_build_component(component_dir [component_source])
Present a directory component_dir that contains a component to the build system. Relative paths are
converted to absolute paths with respect to current directory.
An optional component_source argument can be specified to indicate the source of the component. (default:
"project_components")
This argument determines the overriding priority for components with the same name. For detailed
information, see Multiple Components with the Same Name.
This argument supports the following values (from highest to lowest priority):
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
"idf_components" - ESP-IDF built-in components, typically under /components
For instance, if a component named "json" is present as both "idf_components", and "project_components",
the component as "project_components" takes precedence over the one as "idf_components".
Warning
All calls to this command must be performed before idf_build_process. This command does not guarantee
that the component will be processed during build (see the COMPONENTS argument description for
idf_build_process).
idf_build_process(target
[PROJECT_DIR project_dir]
[PROJECT_VER project_ver]
[PROJECT_NAME project_name]
[SDKCONFIG sdkconfig]
[SDKCONFIG_DEFAULTS sdkconfig_defaults]
[BUILD_DIR build_dir]
[COMPONENTS component1 component2 ...])
Performs the bulk of the behind-the-scenes magic for including ESP-IDF components such as component
configuration, libraries creation, dependency expansion and resolution. Among these functions, perhaps the
most important from a user's perspective is the libraries creation by calling each component's
idf_component_register . This command creates the libraries for each component, which are accessible using
aliases in the form idf::component_name. These aliases can be used to link the components to the user's own
targets, either libraries or executables.
The call requires the target chip to be specified with target argument. Optional arguments for the call
include:
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
idf_build_executable(executable)
Specify the executable executable for ESP-IDF build. This attaches additional targets such as dependencies
related to flashing, generating additional binary files, etc. Should be called after idf_build_process .
Get the value of the specified config. Much like build properties, specifying GENERATOR_EXPRESSION will
retrieve the generator expression string for that config, instead of the actual value, which can be used with
CMake commands that support generator expressions. Actual config values are only known after call to
idf_build_process , however.
Idf-build-properties
These are properties that describe the build. Values of build properties can be retrieved by using the build
command idf_build_get_property . For example, to get the Python interpreter used for the build:
idf_build_get_property(python PYTHON)
message(STATUS "The Python interpreter is: ${python}")
IDF_TARGET - target chip for the build; set from the required target argument for idf_build_process
IDF_VER - ESP-IDF version; set from either a version file or the Git revision of the IDF_PATH repository
INCLUDE_DIRECTORIES - include directories for all component source files
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
KCONFIGS - list of Kconfig files found in components in build; set by idf_build_process
MINIMAL_BUILD - perform a minimal build by including only the "common" components required by all
other components, along with the components that are direct or transitive dependencies only of the
main component. By default, this property is disabled (set to OFF ), but it can be enabled by setting it to
ON .
PROJECT_NAME - name of the project; set from idf_build_process PROJECT_NAME argument
PROJECT_DIR - directory of the project; set from idf_build_process PROJECT_DIR argument
PROJECT_VER - version of the project; set from idf_build_process PROJECT_VER argument
PYTHON - Python interpreter used for the build; set from PYTHON environment variable if available, if
not "python" is used
SDKCONFIG - full path to output config file; set from idf_build_process SDKCONFIG argument
SDKCONFIG_DEFAULTS - list of files containing default config to use in the build; set from
idf_build_process SDKCONFIG_DEFAULTS argument
SDKCONFIG_HEADER - full path to C/C++ header file containing component configuration; set by
idf_build_process
SDKCONFIG_JSON_MENUS - full path to JSON file containing config menus; set by idf_build_process
Idf-component-commands
Retrieve a specified component's component property, property and store it in var accessible from the current
scope. Specifying GENERATOR_EXPRESSION will retrieve the generator expression string for that property,
instead of the actual value, which can be used with CMake commands that support generator expressions.
Set a specified component's component property, property with value val. Specifying APPEND will append the
specified value to the current value of the property. If the property does not previously exist or it is currently
empty, the specified value becomes the first element/member instead.
idf_component_register([[SRCS src1 src2 ...] | [[SRC_DIRS dir1 dir2 ...] [EXCLUDE_SRCS src1 src2 ...]]
[INCLUDE_DIRS dir1 dir2 ...]
[PRIV_INCLUDE_DIRS dir1 dir2 ...]
[REQUIRES component1 component2 ...]
[PRIV_REQUIRES component1 component2 ...]
[LDFRAGMENTS ldfragment1 ldfragment2 ...]
[REQUIRED_IDF_TARGETS target1 target2 ...]
[EMBED_FILES file1 file2 ...]
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
[EMBED_TXTFILES file1 file2 ...]
[KCONFIG kconfig]
[KCONFIG_PROJBUILD kconfig_projbuild]
[WHOLE_ARCHIVE])
Register a component to the build system. Much like the project() CMake command, this should be called
from the component's [Link] directly (not through a function or macro) and is recommended to be
called before any other command. Here are some guidelines on what commands can not be called before
idf_component_register :
Commands that set and operate on variables are generally okay to call before idf_component_register .
SRCS - component source files used for creating a static library for the component; if not specified,
component is a treated as a config-only component and an interface library is created instead.
SRC_DIRS, EXCLUDE_SRCS - used to glob source files (.c, .cpp, .S) by specifying directories, instead of
specifying source files manually via SRCS. Note that this is subject to the limitations of globbing in
CMake. Source files specified in EXCLUDE_SRCS are removed from the globbed files.
INCLUDE_DIRS - paths, relative to the component directory, which will be added to the include
search path for all other components which require the current component
PRIV_INCLUDE_DIRS - directory paths, must be relative to the component directory, which will be
added to the include search path for this component's source files only
REQUIRES - public component requirements for the component
PRIV_REQUIRES - private component requirements for the component; ignored on config-only
components
LDFRAGMENTS - component linker fragment files
REQUIRED_IDF_TARGETS - specify the only target the component supports
KCONFIG - override the default Kconfig file
KCONFIG_PROJBUILD - override the default [Link] file
WHOLE_ARCHIVE - if specified, the component library is surrounded by -Wl,--whole-archive , -Wl,-
-no-whole-archive when linked. This has the same effect as setting WHOLE_ARCHIVE component
property.
The following are used for embedding data into the component, and is considered as source files when
determining if a component is config-only. This means that even if the component does not specify source
files, a static library is still created internally for the component if it specifies either:
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
Idf-component-properties
These are properties that describe a component. Values of component properties can be retrieved by using
the build command idf_component_get_property . For example, to get the directory of the freertos
component:
COMPONENT_ALIAS - alias for COMPONENT_LIB used for linking the component to external targets;
set by idf_build_component and alias library itself is created by idf_component_register
COMPONENT_DIR - component directory; set by idf_build_component
EMBED_TXTFILES argument
INCLUDE_DIRS - list of component include directories; set from idf_component_register
INCLUDE_DIRS argument
KCONFIG - component Kconfig file; set by idf_build_component
LDFRAGMENTS argument
MANAGED_PRIV_REQUIRES - list of private component dependencies added by the IDF component
manager from dependencies in idf_component.yml manifest file
MANAGED_REQUIRES - list of public component dependencies added by the IDF component manager
from dependencies in idf_component.yml manifest file
PRIV_INCLUDE_DIRS - list of component private include directories; set from idf_component_register
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
REQUIRED_IDF_TARGETS - list of targets the component supports; set from idf_component_register
REQUIRED_IDF_TARGETS argument
REQUIRES - list of public component dependencies; set from value of idf_component_register
WHOLE_ARCHIVE - if this property is set to TRUE (or any boolean "true" CMake value: 1, ON , YES , Y ),
the component library is surrounded by -Wl,--whole-archive , -Wl,--no-whole-archive when linked. This
can be used to force the linker to include every object file into the executable, even if the object file
doesn't resolve any references from the rest of the application. This is commonly used when a
component contains plugins or modules which rely on link-time registration. This property is FALSE by
default. It can be set to TRUE from the component [Link] file.
This preference reflects the CMake best practice of manually listing source files. This could, however, be
inconvenient when there are lots of source files to add to the build. The ESP-IDF build system provides an
alternative way for specifying source files using SRC_DIRS :
This uses globbing behind the scenes to find source files in the specified directories. Be aware, however, that
if a new source file is added and this method is used, then CMake won't know to automatically re-run and
this file won't be added to the build.
The trade-off is acceptable when you're adding the file yourself, because you can trigger a clean build or run
[Link] reconfigure to manually re-run CMake. However, the problem gets harder when you share your
project with others who may check out a new version using a source control tool like Git...
For components which are part of ESP-IDF, we use a third party Git CMake integration module
(/tools/cmake/third_party/[Link]) which automatically re-runs CMake any time
the repository commit changes. This means if you check out a new ESP-IDF version, CMake will
automatically rerun.
For project components (not part of ESP-IDF), there are a few different options:
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
If keeping your project file in Git, ESP-IDF will automatically track the Git revision and re-run CMake if
the revision changes.
If some components are kept in a third git repository (not the project repository or ESP-IDF repository),
you can add a call to the git_describe function in a component CMakeLists file in order to automatically
trigger re-runs of CMake when the Git revision changes.
If not using Git, remember to manually run [Link] reconfigure whenever a source file may change.
To avoid this problem entirely, use SRCS argument to idf_component_register to list all source files in
project components.
The best option will depend on your particular project and its users.
Build System Metadata
For integration into IDEs and other build systems, when CMake runs the build process generates a number
of metadata files in the build/ directory. To regenerate these files, run cmake or [Link] reconfigure (or
any other [Link] build command).
compile_commands.json is a standard format JSON file which describes every source file which is
compiled in the project. A CMake feature generates this file, and many IDEs know how to parse it.
project_description.json contains some general information about the ESP-IDF project, configured
paths, etc.
flasher_args.json contains [Link] arguments to flash the project's binary files. There are also
flash_*_args files which can be used directly with [Link]. See Flash arguments.
[Link] is the CMake cache file which contains other information about the CMake process,
toolchain, etc.
config/[Link] is a JSON-formatted version of the project configuration values.
config/kconfig_menus.json is a JSON-formatted version of the menus shown in menuconfig, for use in
external IDE UIs.
A tool called kconfserver is provided to allow IDEs to easily integrate with the configuration system logic.
kconfserver is designed to run in the background and interact with a calling process by reading and writing
JSON over process stdin & stdout.
You can run kconfserver from a project via [Link] confserver or ninja kconfserver , or a similar target
triggered from a different build generator.
Build Scripts
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
The listfiles for the ESP-IDF build system reside in /tools/cmake. The modules which implement core build
system functionality are as follows:
[Link] - Build related commands i.e., build initialization, retrieving/setting build properties,
build processing.
[Link] - Component related commands i.e., adding components, retrieving/setting
component properties, registering components.
[Link] - Generation of configuration files (sdkconfig, sdkconfig.h, [Link], etc.)
from Kconfig files.
[Link] - Generation of final linker script from linker fragment files.
[Link] - Setting build target and toolchain file.
[Link] - Miscellaneous helper commands.
Aside from these files, there are two other important CMake scripts in /tools/cmake:
[Link] - Sets up the build and includes the core modules listed above. Included in CMake
projects in order to access ESP-IDF build system functionality.
[Link] - Includes [Link] and provides a custom project() command that takes care
of all the heavy lifting of building an executable. Included in the top-level [Link] of
standard ESP-IDF projects.
The rest of the files in /tools/cmake are support or third-party scripts used in the build process.
Build Process
This section describes the standard ESP-IDF application build process. The build process can be broken
down roughly into four phases:
Initialization
Set IDF_PATH from environment variable or inferred from path to [Link] included
in the top-level [Link].
Add /tools/cmake to CMAKE_MODULE_PATH and include core modules plus the various
helper/third-party scripts.
Set build tools/executables such as default Python interpreter.
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
Get ESP-IDF git revision and store as IDF_VER .
Set global build specifications i.e., compile options, compile definitions, include directories
for all components in the build.
Add components in components to the build.
The initial part of the custom project() command performs the following steps:
Set IDF_TARGET from environment variable or CMake cache and the corresponding
CMAKE_TOOLCHAIN_FILE to be used.
Add components in EXTRA_COMPONENT_DIRS to the build.
Prepare arguments for calling command idf_build_process() from variables such as
COMPONENTS / EXCLUDE_COMPONENTS , SDKCONFIG , SDKCONFIG_DEFAULTS .
This phase builds a final list of components to be processed in the build, and is performed in the first half
of idf_build_process() .
Retrieve each component's public and private requirements. A child process is created which
executes each component's [Link] in script mode. The values of idf_component_register
REQUIRES and PRIV_REQUIRES argument is returned to the parent build process. This is called
early expansion. The variable CMAKE_BUILD_EARLY_EXPANSION is defined during this step.
Recursively include components based on public and private requirements.
Unless IDF Component Manager is disabled, it is called to resolve the dependencies of the
components: - Looks for manifests and dependencies contained in the project. - Starts the version
solving process to resolve the dependencies of the components. - When the version solving
process succeeds, the IDF Component Manager downloads dependencies, integrates them into
the build, and creates a [Link] file that contains a list of the exact versions of the
dependencies installed by the IDF Component Manager.
Processing
This phase processes the components in the build, and is the second half of idf_build_process() .
Load project configuration from sdkconfig file and generate an [Link] and sdkconfig.h
header. These define configuration variables/macros that are accessible from the build scripts and
C/C++ source/header files, respectively.
Include each component's project_include.cmake .
Add each component as a subdirectory, processing its [Link]. The component [Link]
calls the registration command, idf_component_register which adds source files, include directories,
creates component library, links dependencies, etc.
Finalization
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
This phase is everything after idf_build_process() .
Some features are significantly different or removed in the CMake-based system. The following variables no
longer exist in the CMake-based build system:
instead.
COMPONENT_ADD_LINKER_DEPS : List of files that linking should depend on. target_link_libraries will usually
infer these dependencies automatically. For linker scripts, use the provided custom CMake function
target_linker_scripts .
COMPONENT_SUBMODULES : No longer used, the build system will automatically enumerate all submodules in
the ESP-IDF repository.
COMPONENT_EXTRA_INCLUDES : Used to be an alternative to COMPONENT_PRIV_INCLUDEDIRS for absolute paths.
Use PRIV_INCLUDE_DIRS argument to idf_component_register for all cases now (can be relative or
absolute).
COMPONENT_OBJS : Previously, component sources could be specified as a list of object files. Now they can
be specified as a list of source files via SRCS argument to idf_component_register.
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
COMPONENT_OBJEXCLUDE : Has been replaced with EXCLUDE_SRCS argument to idf_component_register .
Specify source files (as absolute paths or relative to component directory), instead.
COMPONENT_EXTRA_CLEAN : Set property ADDITIONAL_CLEAN_FILES instead but note CMake has some
Only Components.
CFLAGS , CPPFLAGS , CXXFLAGS : Use equivalent CMake commands instead. See Controlling Component
Compilation.
No Default Values
Unlike in the legacy Make-based build system, the following have no default values:
in CMake)
Include directories ( COMPONENT_ADD_INCLUDEDIRS variable in Make, INCLUDE_DIRS argument to
idf_component_register in CMake)
No Longer Necessary
In the legacy Make-based build system, it is required to also set COMPONENT_SRCDIRS if COMPONENT_SRCS is
set. In CMake, the equivalent is not necessary i.e., specifying SRC_DIRS to idf_component_register if
SRCS is also specified (in fact, SRCS is ignored if SRC_DIRS is specified).
make flash and similar targets still work to build and flash. However, project sdkconfig no longer specifies
serial port and baud rate. Environment variables can be used to override these. See Flashing with Ninja or
Make for more details.
Application Examples
build_system/wrappers demonstrates how to use a linker feature to redefine or override any public
function in both ESP-IDF and the bootloader, allowing modification or extension of a function's default
behavior.
custom_bootloader/bootloader_override demonstrates how to override the second stage bootloader
from a regular project, providing a custom bootloader that prints an extra message on startup, with the
ability to conditionally override the bootloader based on certain conditions like target-dependency or
Kconfig options.
build_system/cmake/import_lib demonstrates how to import and use third-party libraries using
ExternalProject CMake module.
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF
build_system/cmake/import_prebuilt demonstrates how to import a prebuilt static library into the ESP-
IDF build system, build a component with dependencies, and link it to the main component, ultimately
outputting the current running partition.
build_system/cmake/idf_as_lib demonstrates the creation of an application equivalent to hello world
application using a custom CMake project.
build_system/cmake/multi_config demonstrates how to build multiple configurations of a single
application from a single codebase, it is useful for creating binaries for multiple similar products.
build_system/cmake/plugins demonstrates features of the ESP-IDF build system related to link time
registration of plugins, allowing you to add multiple implementations of a certain feature without the
need to make the application aware of all these implementations.
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd HTML to PDF