sample project
A directory tree structure for an example project might look like this:
- myProject/ - CMakeLists.txt - sdkconfig - components/ - component1/ - CMakeLists.txt - Kconfig - src1.c - component2/ - CMakeLists.txt - Kconfig - src1.c - include/ - component2.h - main/ - src1.c - src2.c - build/
The sample project myproject
contains the following components:
-
The top-level project CMakeLists.txt file, which is the main file used by CMake to learn how to build the project, can set the global CMake variables of the project in this file. The top-level project CMakeLists.txt file imports the /tools/cmake/project.cmake file, which implements the rest of the build system. The file ends with setting the name of the project and defines the project.
-
sdkconfig
Project configuration file,idf.py menuconfig
this file will be created or updated during execution, and the configuration information of all components in the project (including ESP-IDF itself) is saved in the file.sdkconfig
Files may or may not be added to the project's source control system. -
The optional
component
directory contains some custom components of the project. Not every project needs such custom components, but it helps to build reusable code or import third parties (not part of ESP-IDF) s component. -
main
A directory is a special one伪组件
that contains the source code for the project itself.main
is the default name, CMake variablesCOMPONENT_DIRS
include this component by default, but you can modify this variable. Alternatively, you can also set variables in the top-level CMakeLists.txtEXTRA_COMPONENT_DIRS
to look for components at other specified locations. See Renaming the main component for details . If there are many source files in the project, it is recommended to attribute them to the component, not all of themmain
. -
build
The directory is where the build output is stored. If there is no such directory,idf.py
it will be created automatically. CMake will configure the project and generate temporary build files in this directory. Later, during the run of the main build process, this directory also holds temporary object files, library files, and final output binaries. This directory is usually not added to the project's source control system, nor is it distributed with the project's source code.
Each component directory contains a CMakeLists.txt
file that defines variables to control the build process of that component and its integration with the overall project. See the component CMakeLists file for more details .
Each component can also contain a Kconfig
file that defines the configurationmenuconfig
options for the component to display . Some components may also include and special files that override some of the project's settings .Kconfig.projbuild
project_include.cmake
Project CMakeLists file
Every project has a top-level CMakeLists.txt
file that contains build settings for the entire project. By default, project CMakeLists files will be very small.
Example minimal CMakeLists file
Minimum item:
cmake_minimum_required(VERSION 3.5) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(myProject)
necessary part
Add the above three lines of code to each project in the order shown above:
-
cmake_minimum_required(VERSION 3.5)
Must be placed on the first line of the CMakeLists.txt file, it will tell CMake the minimum version number required to build the project. ESP-IDF supports CMake 3.5 or higher. -
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
The rest of CMake's functionality is imported to configure projects, retrieve components, and more. -
project(myProject)
The project itself is created, and a project name is specified. This name will be used as the name of the final output binary file, iemyProject.elf
andmyProject.bin
. Only one project can be defined per CMakeLists file.
optional project variable
The following variables have default values that users can override to customize build behavior. For more implementation details, please refer to the /tools/cmake/project.cmake file.
-
COMPONENT_DIRS
: The search directory for components, the default is${IDF_PATH}/components
,${PROJECT_PATH}/components
andEXTRA_COMPONENT_DIRS
. Override this variable if you do not want to search for components in these locations. -
EXTRA_COMPONENT_DIRS
: An optional list of additional directories to search for components. Paths can be relative to the project directory or absolute. -
COMPONENTS
: A list of component names to be built into the project, defaulting toCOMPONENT_DIRS
all components retrieved under the directory. Use this variable to "thin" your project to improve build times. Note that if a componentCOMPONENT_REQUIRES
specifies another component it depends on, it will be automatically added to itCOMPONENTS
, soCOMPONENTS
the list can be very short. -
COMPONENT_REQUIRES_COMMON
: A list of common components required by each component that are automatically added to each component'sCOMPONENT_PRIV_REQUIRES
list as well as to the project'sCOMPONENTS
list. By default, this variable is set to the minimum set of core "system" components required by an ESP-IDF project. Usually you don't need to change this variable in your project.
The path in the above variables can be an absolute path, or a relative path relative to the project directory.
Please use the set command in cmake to set these variables, ie set(VARIABLE "VALUE")
. Please note that set()
the command needs to be placed include(...)
before and cmake_minimum(...)
after.
rename main
component
main
Components are handled specially by the build system . Provided main
the component is in the expected location (i.e. ${PROJECT_PATH}/main), then it is automatically added to the build system. Other components are also added to the build system as their dependencies, which frees users from having to deal with dependencies and provides out-of-the-box build functionality. Renaming main
components alleviates this behind-the-scenes work, but requires the user to specify the location of the renamed component and manually add dependencies to it. The steps to rename main
a component are as follows:
-
Rename
main
the directory. -
Set in the project CMakeLists.txt file
EXTRA_COMPONENT_DIRS
and add the renamedmain
directory. -
COMPONENT_REQUIRES
Set orCOMPONENT_PRIV_REQUIRES
specify dependencies in the component's CMakeLists.txt file .
Component CMakeLists file
Each project contains one or more components, which are either part of ESP-IDF, part of the project's own component directory, or added from a custom component directory (see above ) .
A component is any directory that contains files COMPONENT_DIRS
in the list .CMakeLists.txt
search component
COMPONENT_DIRS
A list of directories in which to search for components of a project, either the component itself (i.e. the directory containing the CMakeLists.txt file), or the top-level directory of the component as a subdirectory .
When CMake runs the project configuration, it records the list of components included in this build, which can be used to debug the addition/exclusion of certain components.
Component with the same name
When ESP-IDF searches for all components to build, it COMPONENT_DIRS
does so in the specified order, which means that by default, ESP-IDF internal components are searched first, then project components, and finally components EXTRA_COMPONENT_DIRS
in . If two or more of these directories contain components with the same name, the component in the last location searched is used. This allows components to be copied into the project directory and then modified to overwrite the ESP-IDF components, if used this way, the ESP-IDF directory itself can remain unchanged.
Minimal component CMakeLists file
The content of the minimal component CMakeLists.txt
file is as follows:
set(COMPONENT_SRCS "foo.c") set(COMPONENT_ADD_INCLUDEDIRS "include") register_component()
-
COMPONENT_SRCS
is a space-separated list of source files (*.c
,*.cpp
,*.cc
,*.S
), all of which will be compiled into the component library. -
COMPONENT_ADD_INCLUDEDIRS
is a space-separated list of directories that will be added to the global include search path of all components that require this component (including the main component). -
register_component()
The component is added to the build system with the variables set above, and the build produces a library with the same name as the component, which is finally linked into the application. If this step is skipped because of using an if command in CMake or similar, the component will not be added to the build system.
The above directory is usually set as CMakeLists.txt
a relative path relative to the file, of course, it can also be set as an absolute path.
For a more complete CMakeLists.txt
example, see the component CMakeLists example .
Default component variables
The following component-specific variables can be used in component CMakeLists, but modification is not recommended:
-
COMPONENT_PATH
: The component directory, that is,CMakeLists.txt
the absolute path of the included file. It isCMAKE_CURRENT_SOURCE_DIR
the same as a variable, and the path cannot contain spaces. -
COMPONENT_NAME
: Component name, which is the same as the component directory name. -
COMPONENT_TARGET
: The name of the library target, which is created internally by the build system for the component.
The following variables are set at the project level, but are available in component CMakeLists:
-
PROJECT_NAME
: Project name, set in the project CMakeLists.txt file. -
PROJECT_PATH
: Absolute path to the project directory (containing the project CMakeLists file),CMAKE_SOURCE_DIR
same as the variable. -
COMPONENTS
: The names of all components included in this build, in the form of a semicolon-separated CMake list. -
CONFIG_*
: Each value in the project configuration corresponds to aCONFIG_
variable starting with cmake in cmake. See Kconfig for more details . -
IDF_VER
: The git version number of ESP-IDF,git describe
generated by the command. -
IDF_VERSION_MAJOR
,IDF_VERSION_MINOR
,IDF_VERSION_PATCH
: A component version of ESP-IDF that can be used in conditional expressions. Please note that the accuracy of these information is not as good as theIDF_VER
variable, version numberv4.0-dev-*
,v4.0-beta1
and the corresponding variable value is the same, but the value of is different.v4.0-rc1
v4.0
IDF_VERSION_*
IDF_VER
-
IDF_TARGET
: The hardware target name of the project. -
PROJECT_VER
: Project version number.-
If the variable is set in the project CMakeLists.txt file
PROJECT_VER
, the variable value can be used. -
Or, if
${PROJECT_PATH}/version.txt
the file exists, its contents are usedPROJECT_VER
as the value. -
Or, if the project is in some Git repository, use
git describe
the output of the command asPROJECT_VER
the value of . -
Otherwise,
PROJECT_VER
the value is null.
-
CMakeLists.txt
If you modify the above variables in a component , it will not affect the construction of other components, but it may make the component difficult to build or debug.
-
COMPONENT_ADD_INCLUDEDIRS
: The relative path relative to the component directory, which is added to the global include search path of all other components that need this component. If an include path is only required when compiling the current component, please add it toCOMPONENT_PRIV_INCLUDEDIRS
. -
COMPONENT_REQUIRES
is a space-separated list of components, listing other components that the current component depends on. If the current component has a header file locatedCOMPONENT_ADD_INCLUDEDIRS
in the directory, and the header file includes another component's header file, then the dependent component needs to beCOMPONENT_REQUIRES
pointed out in . This dependency can be recursive.COMPONENT_REQUIRES
Can be empty, because all components need some common components (such as libc library provided by newlib component, RTOS function provided by freertos component), these common components have been set in project-level variablesCOMPONENT_REQUIRES_COMMON
.If a component only requires the header files of additional components to compile its source files (rather than importing their header files globally), then these dependent components need to be indicated in
COMPONENT_PRIV_REQUIRES
.See Component Dependencies for details.
Optional component specific variables
The following variables can CMakeLists.txt
be set in to control the build behavior of this component:
-
COMPONENT_PRIV_INCLUDEDIRS
: The relative path relative to the component directory will only be added to the include search path of this component. -
COMPONENT_PRIV_REQUIRES
: A space-separated list of components to compile or link the source files for the current component. The header file path for these components is not passed to the rest of the components that need it, it is only used to compile the source code of the current component. See Component Dependencies for more details . -
COMPONENT_SRCS
: The path of the source files to be compiled into the current component. It is recommended to use this method to add source files to the build system. -
COMPONENT_SRCDIRS
: Source file directory path relative to the component directory, used to search for source files (*.cpp
,*.c
,*.S
). The source file that matches successfully will replaceCOMPONENT_SRCS
the source file specified in , and then be compiled into the component. That is, the settingCOMPONENT_SRCDIRS
will causeCOMPONENT_SRCS
it to be ignored. This approach makes it easy to import source files into components in their entirety, but is not recommended (see File Wildcards & Incremental Builds for details ). -
COMPONENT_SRCEXCLUDE
: The source file path that needs to be excluded from the component. When there are a large number of source files in a directory that need to be imported into the component, but at the same time there are individual files that do not need to be imported, they can be setCOMPONENT_SRCDIRS
together with variables. Paths can be relative to the component directory or absolute. -
COMPONENT_ADD_LDFRAGMENTS
: The path to the linker fragment file used by the component to automatically generate the linker script file. See Linker Script Generation Mechanisms for details .
annotation
If COMPONENT_SRCDIRS
or is not set COMPONENT_SRCS
, the component will not be compiled into a library file, but can still be added to the include path for use when compiling other components.
Component compilation control
When compiling source files for a specific component, target_compile_options
compiler options can be passed using the command:
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-variable)
This command encapsulates CMake's target_compile_options command.
To specify compiler flags for individual source files, use CMake's set_source_files_properties command:
set_source_files_properties(mysrc.c PROPERTIES COMPILE_FLAGS -Wno-unused-variable )
This may be useful if the upstream code emits warnings when compiling.
Note that the above two commands can only register_component()
be called after the commands in the component CMakeLists file.
component configuration
Each component can contain a Kconfig
file and CMakeLists.txt
be placed in the same directory. Kconfig
The file contains information about some configuration settings to be added to the component's configuration menu.
Component Settings
These settings can be found under the menu bar when you run menuconfig .
The easiest way to create a component's Kconfig file is to use the existing Kconfig file in ESP-IDF as a template and modify it on this basis.
See Adding Conditional Configuration for an example .
preprocessor definition
The ESP-IDF build system adds the following C preprocessor definitions to the command line:
-
ESP_PLATFORM
: Can be used to detect build behavior within ESP-IDF. -
IDF_VER
: Define the git version string, for example:v2.0
it is used to mark the released version,v1.0-275-g0efaa4f
and it is used to mark any commit record. -
PROJECT_VER
: Project version number, for details, please refer to the preset component variables . -
PROJECT_NAME
: Project name, defined in the project CMakeLists.txt file.
Component dependencies
As each component is compiled, the ESP-IDF system recursively evaluates its components.
The source files for each component are compiled with the header files in the following paths:
-
COMPONENT_ADD_INCLUDEDIRS
The sum of the current componentsCOMPONENT_PRIV_INCLUDEDIRS
. -
The current component's
COMPONENT_REQUIRES
andCOMPONENT_PRIV_REQUIRES
other components specified by the variable (that is, all public and private dependencies of the current component)COMPONENT_ADD_INCLUDEDIRS
. -
COMPONENT_REQUIRES
The recursive operation of all components , that is, all the public dependencies of the component after recursive operation.
Write components
-
COMPONENT_REQUIRES
Need to include all components where the header files are #included by the current component's public header file. -
COMPONENT_PRIV_REQUIRES
Need to include the component whose header file is #included by the current component's source file (unless it is already set inCOMPONENT_PRIV_REQUIRES
). Or a component that must be linked to the current component to work properly. -
COMPONENT_REQUIRES
,COMPONENT_PRIV_REQUIRES
need to be set before callingregister_component()
. -
COMPONENT_REQUIRES
The value of andCOMPONENT_PRIV_REQUIRES
cannot depend on any configuration options (CONFIG_xxx
), because the dependencies are expanded before the configuration is loaded. Other component variables (such asCOMPONENT_SRCS
andCOMPONENT_ADD_INCLUDEDIRS
) can depend on configuration choices. -
If the current component
COMPONENT_REQUIRES_COMMON
does not depend on other components except for the common components set in (such as RTOS, libc, etc.), then the above twoREQUIRES
variables can be empty.
If a component only supports certain hardware targets (ie depends on specific ones IDF_TARGET
), require_idf_targets(NAMES...)
a CMake function can be called to declare this requirement. In this case, an error will be raised if the build system imports a component that does not support the current hardware target.
create project
-
Each component is included in the build system by default.
-
If
COMPONENTS
the variable is set to the minimal list of components used directly by the project, the build system imports:-
COMPONENTS
Components explicitly mentioned in . -
Dependencies of these components (and components recursively).
-
Common components that every component depends on.
-
-
Will
COMPONENTS
be set to a minimal list of required components, which can significantly reduce your project's build time.
Implementation details of dependency handling in the build system
-
Scripts are run early in the CMake configuration process
expand_requirements.cmake
. The script will perform local operations on the CMakeLists.txt files of all components to obtain a component dependency graph (this graph may have a closed loop). This image is used to generate files in the build directorycomponent_depends.cmake
. -
BUILD_COMPONENTS
The main CMake process imports this file and uses it to determine the list of components ( variables used internally) to include in the build system .BUILD_COMPONENTS
Variables are sorted, dependent components come first. Since there may be closed loops in the component dependency graph, there is no guarantee that every component will satisfy this ordering. Given the same set of components and dependencies, then the final ranking should be deterministic. -
CMake will
BUILD_COMPONENTS
print out the value of 'Component names:'. -
Configuration of each component included in the build system is then performed.
-
Each component is included in the build system normally, and then the CMakeLists.txt file is executed again to add the component library to the build system.
Component dependency order
BUILD_COMPONENTS
The order of the components in the variable determines the rest of the order in the build process, including:
-
The order in which the project imports the project_include.cmake file.
-
-I
The order in which the list of header file paths is generated for compilation (via arguments). Note that for a given component's source files, the compiler only needs to be told the path to the header files of that component's dependent components.
build internal process
For more information about CMake and CMake commands, please refer to the official CMake v3.5 documentation .
Contents of project.cmake
Some useful modules and global variables are defined when the project CMakeLists file imports project.cmake
the file . It also automatically sets the variable project.cmake
if it is not set in the system environment .IDF_PATH
IDF_PATH
project.cmake
The file also overrides CMake built-in project
functions to add all ESP-IDF project-specific functionality.
project function
The custom project()
function performs the following steps:
-
Determine the hardware target (
IDF_TARGET
set by environment variables), and save it in the CMake cache. If the hardware target set in the environment variable does not match the one in the CMake cache, it will report an error and exit. -
Computes component dependencies and constructs
BUILD_COMPONENTS
the variable, which is a list of all components that need to be imported into the build system ( see above for details ). -
Find all components in the project (search
COMPONENT_DIRS
, andCOMPONENTS
filter by (if this variable is set). -
sdkconfig
Load project configuration information from a file, buildsdkconfig.cmake
andsdkconfig.h
file, used to define configuration items in CMake and C/C++ respectively. If the project configuration changes, CMake will automatically re-run, regenerate the above two files, and then reconfigure the project. -
Depending on the value of the hardware target (
IDF_TARGET
), set the CMAKE_TOOLCHAIN_FILE variable to the corresponding toolchain file. -
Call CMake's project function to declare the actual CMake-level project.
-
Load the git version number. Some tricks are used to re-run CMake if a new version is checked out in git. For details, refer to File Wildcards & Incremental Builds .
-
Import this file from the component that includes the project_include.cmake file.
-
Each component is added to the build system. Each component's CMakeLists file will call
register_component
functions, which will call CMake's add_library function to add a library, then add source files, compile options, etc. -
Add the final application executable to the build system.
-
Go back and specify dependencies between components (adding each component's public header directory to other components).
See /tools/cmake/project.cmake file for more details .
CMake debugging
Some tips for debugging the ESP-IDF CMake build system:
-
When CMake runs, it prints a lot of diagnostic information, including component list and component path.
-
Run
cmake -DDEBUG=1
, the IDF build system produces more verbose diagnostic output. -
Runtime
cmake
specifications--trace
or--trace-expand
options provide a great deal of information about the flow of control. Please refer to the CMake command line documentation for details .
warn about undefined variables
By default, CMake is called with idf.py
flags passed to it, and CMake will print a warning if undefined variables are referenced during the build process . This is very useful for finding buggy CMake files.--warn-uninitialized
If you don't want to enable this feature, you can idf.py
pass --no-warnings
a flag to .
Override some of the project's settings
project_include.cmake
project_include.cmake
If some build behavior of the component needs to be executed before the component CMakeLists file, you can create a file named in the component directory , and project.cmake
this CMake file will be imported during operation.
project_include.cmake
The file is used internally by ESP-IDF to define project-wide build functionality, such as esptool.py
command-line arguments bootloader
for this particular application.
Different from component CMakeLists.txt
files, when importing the ``project_include.cmake`` file, the current source file directory (ie CMAKE_CURRENT_SOURCE_DIR
) and the working directory are the project directory. If you want to get the absolute path of the current component, you can use COMPONENT_PATH
variables.
Note that project_include.cmake
it is not required for most common components. For example, adding include search directories to the project, adding options to the final link step, LDFLAGS
etc. can CMakeLists.txt
be customized through files. See Optional project variables for details .
project_include.cmake
Files are BUILD_COMPONENTS
imported sequentially in the order of the components in the variable (as recorded by CMake). That is, only project_include.cmake
after the files of all dependent components of the current component are imported, project_include.cmake
the files of the current component will be imported, unless the two components are in the same dependency closed loop. This is especially the case if a project_include.cmake
file depends on variables set by another component. See Implementation Details of Dependency Handling in Build Systems for more details .
Be extra careful when setting variables or targets in project_include.cmake
files, these values are included in the project's top-level CMake file, so they can affect or break the functionality of all components.
KConfig.projbuild
Similar project_include.cmake
to , you can also define a KConfig file for a component to achieve global component configuration . If you want to add configuration options at the top level of menuconfig, rather than in the "Component Configuration" submenu, you can CMakeLists.txt
define these options in the KConfig.projbuild file in the same directory as the file.
Be careful when adding configurations in this file as they will be included in the overall project configuration. Where possible, create KConfig files for component configuration .
Only configuration components
A configuration-only component is a special type of component that does not contain a source file, but only a , Kconfig.projbuild
, KConfig
and CMakeLists.txt
file, which CMakeLists.txt
has only one line of code that calls register_config_only_component()
a function. This function will import the component into the project build, but will not build any libraries, and will not add header files to any include search paths.
If the CMakeLists.txt file does not call register_component()
or register_config_only_component()
, then the file will be excluded from the project build. Depending on the configuration of your project, this may sometimes be necessary.
Component CMakeLists example
Because the build environment tries to set sensible defaults that work most of the time, component CMakeLists.txt
files can be very small or even empty, see the minimal component CMakeLists file . But some functions often need to override the preset component variables to achieve.
The following is a more advanced example of a component CMakeLists file.
Add conditional configuration
The configuration system can be used to conditionally compile certain files based on 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.
CMakeLists.txt
:
set(COMPONENT_SRCS "foo.c" "more_foo.c") if(CONFIG_FOO_ENABLE_BAR) list(APPEND COMPONENT_SRCS "bar.c") endif()
The above example uses CMake's if function and list APPEND function.
Can also be used to select or remove an implementation, as follows:
Kconfig
:
config ENABLE_LCD_OUTPUT bool "Enable LCD output." help Select this if your board has a 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
CMakeLists.txt
:
if(CONFIG_ENABLE_LCD_OUTPUT) set(COMPONENT_SRCS lcd-real.c lcd-spi.c) else() set(COMPONENT_SRCS lcd-dummy.c) endif() # If the console or drawing function is enabled, you need to add font if(CONFIG_ENABLE_LCD_CONSOLE OR CONFIG_ENABLE_LCD_PLOT) list(APPEND COMPONENT_SRCS "font.c") endif()
Conditional judgment of hardware targets
CMake files can use IDF_TARGET
variables to get the current hardware target.
Additionally, if the current hardware target is xyz``(即 ``IDF_TARGET=xyz
), then the Kconfig variable CONFIG_IDF_TARGET_XYZ
will also be set.
Note that components can depend on IDF_TARGET
variables, but not this Kconfig variable. It is also not include
possible to use Kconfig variables in statements in CMake files, which are allowed in this context IDF_TARGET
.
generate source code
Some component source files may not be provided by the component itself, but must be generated from another file. Assuming a component requires a header file consisting of binary data converted from a BMP file (using the bmp2h tool), the header file is then included in a file named graphics_lib.c:
add_custom_command(OUTPUT logo.h COMMAND bmp2h -i ${COMPONENT_DIR}/logo.bmp -o log.h DEPENDS ${COMPONENT_DIR}/logo.bmp VERBATIM) add_custom_target(logo DEPENDS logo.h) add_dependencies(${COMPONENT_LIB} logo) set_property(DIRECTORY "${COMPONENT_DIR}" APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES logo.h)
This example was adapted from a CMake FAQ , which also includes some examples for the ESP-IDF build system as well.
This example generates a logo.h file in the current directory (the build directory), and a logo.bmp is provided with the component in the component directory. Since logo.h is a newly generated file, it should also be cleared whenever the project needs to be cleaned up. Therefore, add this file to the ADDITIONAL_MAKE_CLEAN_FILES property.
annotation
If you need to makefiles as part of the project CMakeLists.txt instead of as part of the component CMakeLists.txt, you need to use ${PROJECT_PATH}
overrides ${COMPONENT_DIR}
, use ${PROJECT_NAME}.elf
overrides ${COMPONENT_LIB}
.
If a source file is generated from another component and contains logo.h
files, it needs to be called add_dependencies
to add a dependency between the two components to ensure that the component source files are compiled in the correct order.
Embed binary data
Sometimes your component expects to use a binary or text file, but you don't want to reformat them as C source files. In this case, you can add COMPONENT_EMBED_FILES
variables to the component CMakeLists to specify the file names to embed (space-separated ):
set(COMPONENT_EMBED_FILES server_root_cert.der)
Or, if the file is a string, you can set COMPONENT_EMBED_TXTFILES
the variable to convert the contents of the file into a null-terminated string for embedding:
set(COMPONENT_EMBED_TXTFILES server_root_cert.pem)
The content of the file will be added to the .rodata section of Flash, and the user can access it by symbolic name, as follows:
extern const uint8_t server_root_cert_pem_start[] asm("_binary_server_root_cert_pem_start"); extern const uint8_t server_root_cert_pem_end[] asm("_binary_server_root_cert_pem_end");
Symbolic names are generated from the full file name, as COMPONENT_EMBED_FILES
shown in , characters /
, .
etc. are replaced by underscores. The _binary prefix in symbol names is added by the objcopy command, for both text and binary files.
If you want to embed the file in the project, not in the component, you can call target_add_binary_data
the function:
target_add_binary_data(myproject.elf "main/data.bin" TEXT)
And put this line of code project()
after the command of the project CMakeLists.txt, and modify it myproject.elf
to your own project name. TEXT
The build system embeds the null-terminated string if the last parameter is set to , BINARY
and embeds the file contents as-is if the last parameter is set to .
See protocols/https_request for an example of using this technique , the contents of the certificate file are loaded from the .pem file at compile time.
code and data storage
ESP-IDF also supports automatic generation of linker scripts, which allow components to define where their code and data reside in memory by linking fragment files. The build system processes these linker fragment files and augments the resulting linker scripts to direct the linking process of the application binary. For more details and a quick start guide, see Linker Script Generation Mechanism .
Complete coverage of the component's build process
Of course, in some cases, the methods mentioned above may not be enough. If the component encapsulates another third-party component, and this third-party component does not work directly in the ESP-IDF build system, in this case, you need to abandon the ESP-IDF build system and use CMake's ExternalProject instead Function. An example of component CMakeLists is as follows:
# External build process for quirc, run in the source directory and generate libquirc.a externalproject_add(quirc_build PREFIX ${COMPONENT_DIR} SOURCE_DIR ${COMPONENT_DIR}/quirc CONFIGURE_COMMAND "" BUILD_IN_SOURCE 1 BUILD_COMMAND make CC=${CMAKE_C_COMPILER} libquirc.a INSTALL_COMMAND "" ) # Add libquirc.a to the build system add_library(quirc STATIC IMPORTED GLOBAL) add_dependencies(quirc quirc_build) set_target_properties(quirc PROPERTIES IMPORTED_LOCATION ${COMPONENT_DIR}/quirc/libquirc.a) set_target _properties(quirc PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${COMPONENT_DIR }/quirc/lib) set_directory_properties( PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${COMPONENT_DIR}/quirc/libquirc.a")
(The above CMakeLists.txt can be used to create a component named , which builds the quircquirc
project with its own Makefile .)
-
externalproject_add
Defines an external build system.-
Set
SOURCE_DIR
,CONFIGURE_COMMAND
,BUILD_COMMAND
andINSTALL_COMMAND
.CONFIGURE_COMMAND
Can be set to an empty string if the external build system does not configure this step . In ESP-IDF's build system,INSTALL_COMMAND
variables are generally set to empty. -
Setup
BUILD_IN_SOURCE
, i.e. the build directory is the same as the source directory. Otherwise, you can also setBUILD_DIR
variables. -
externalproject_add()
See ExternalProject for details on the command .
-
-
The second set of commands adds a target library that points to the library files generated by the external build system. In order to add the include directory and tell CMake where the file is, some more properties need to be set.
-
Finally, the generated library is added to ADDITIONAL_MAKE_CLEAN_FILES .
make clean
That is, the library will be deleted after execution . Note that other object files in the build system are not removed.