Commit Graph

35 Commits

Author SHA1 Message Date
Sudeep Mohanty
f951ae5b18 feat(cmakev2): Added component validation checks for cmakev2
This commit adds component validation checks for cmakev2. The file
component_validation.cmake is ported to cmakev2 and updated to work in
the buildv2 environment.
2025-12-18 13:54:13 +01:00
Frantisek Hrbata
261856e02c feat(cmakev2/build): add idf_build_generate_depgraph function
The idf_build_generate_depgraph function creates a component dependency
graph in dot (graphviz) format for a specified executable. It uses
existing helper functions from cmakev1, ensuring that the generated dot
files are produced in the same manner as in cmakev1. While adjustments
might be needed in the future if necessary, the current implementation
is intended to offer the same functionality as cmakev1.  Similar to
cmakev1, the dot files are only generated only when the
__BUILD_COMPONENT_DEPGRAPH_ENABLED build property is set.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-12-11 14:00:55 +08:00
Daniel Paul
b12c0e35f4 feat(cmakev2): Add source of the component into project_description.json 2025-12-03 19:58:47 +08:00
Frantisek Hrbata
ca3974c937 feat(cmakev2/ldgen): provide ldgen with a list of mutable libraries
The build system keeps track of each component source. Currently
there are four types of sources:

1. "project_components" - project components
2. "project_extra_components" - components from EXTRA_COMPONENT_DIRS
3. "project_managed_components" - custom project dependencies managed by the IDF Component Manager
4. "idf_components" - ESP-IDF built-in components, typically under /components

This can be used to identify the component libraries that are likely to
change during application development and pass them to ldgen as mutable
libraries. Add all components with "project_components" as their source
as mutable.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-11-24 14:58:02 +01:00
Frantisek Hrbata
bba4446ee0 fix(cmakev2/build): display a warning when the MINIMAL_BUILD property is set
The MINIMAL_BUILD property is not relevant in cmakev2, as only
components explicitly linked through targets are included in the build
by design. Display a warning when this outdated build property is set.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-11-19 11:34:03 +01:00
Frantisek Hrbata
2b35b5b1bb fix(cmakev2/build): fix the generation of the link map file
The link flag for generating the map file is currently added globally to
the link_options. If multiple executables are generated, the link map
file is overwritten by the last created executable. Since cmakev2
supports building multiple executables, the link map file options need
to be set for each executable individually. To address this, add a new
MAPFILE_TARGET option to the idf_build_executable function. When set,
the link map file will be generated by the linker, and a target
specified in the MAPFILE_TARGET option will be created for the map file.

This also splits the idf_project_default macro.  Only the
idf_project_init macro needs be called within the global scope, as it
includes the project_include.cmake files and the cmake version of the
configuration. The remaining functionality of the idf_project_default
macro is implemented in a __project_default helper function to avoid
polluting the global variable space.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-11-19 11:33:57 +01:00
Frantisek Hrbata
e97027214e fix(cmakev2/build): pass binary target to idf_build_generate_metadata
Currently, the `idf_build_generate_metadata` function takes an
executable target as an argument, and the binary name is stored in the
`EXECUTABLE_BINARY` property. This approach is inconvenient because a
single executable might generate multiple binary images, making it
unreliable to store the binary image name in the executable property due
to the N:1 relationship. To address this, pass the binary image target
instead of the executable target to the `idf_build_generate_metadata`
function. This change is facilitated by linking the binary target,
executable target, and library interface targets with the following
properties:

binary:EXECUTABLE_TARGET -> executable:LIBRARY_INTERFACE -> library

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-11-19 11:30:18 +01:00
Frantisek Hrbata
2760eca984 feat(cmakev2/build): rename LINKER_SCRIPTS_STATIC to LINKER_SCRIPTS
Rename the LINKER_SCRIPTS_STATIC component property to LINKER_SCRIPTS.
This property stores linker scripts that are not processed by ldgen,
which essentially includes all of them. The only linker script processed
by ldgen is sections.ld, which is handled by the esp_system component.
This implies that there is likely no practical use case for other
components to utilize ldgen processed linker scripts. This change is
purely cosmetic to allow components to add linker scripts with:

idf_component_set_property(${COMPONENT_TARGET} LINKER_SCRIPTS linker_script.ld APPEND)

instead of

idf_component_set_property(${COMPONENT_TARGET} LINKER_SCRIPTS_STATIC linker_script.ld APPEND)

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
229000b186 fix(cmakev2/docs): keep only the very basic functions in API
Currently, we include numerous functions in the automatically generated
documentation for the build system API. Let's begin with only the
essential functions and gradually add more to the API based on requests
and actual needs.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Sudeep Mohanty
577c0117cc feat(cmakev2): Create executable dummy source only if it does not exist
idf_build_executable() creates a dummy source file to create the
executable target. Since this file is created unconditionally everytime
CMake configuration happens, a source file change is registered which
causes CMake to execute other targets even though no other source file
changed.
2025-10-30 17:17:49 +08:00
Peter Dragun
a66fecf16e fix: Update esptool commands to use new syntax 2025-10-30 17:17:49 +08:00
Frantisek Hrbata
31ce25ba60 feat(cmakev2/build): preprocess linker scripts with the C preprocessor
When a linker script file with a .in extension is added using the
target_linker_script function, it is processed with the C preprocessor.
The linker scripts are preprocessed only once, even if they are used in
multiple libraries, because they are the same.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
abddda342f fix(cmakev2/docs): reformat function arguments for API documentation
The function arguments in the documentation comments were using field
list, which caused text overflow in the generated documentation and
generally resulted in poor formatting. Let's use paragraphs for
the argument descriptions instead.

The documentation comments are written in reStructuredText, but
currently, they use inconsistent indentation. Standardize all the
documentation comments to use a four-character indentation.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
aacbd1773b fix(cmakev2/build): rename FILE to OUTPUT_FILE option for idf_build_generate_metadata
All other functions, such as idf_build_binary, use OUTPUT_FILE. This is
more descriptive and provides more flexibility to add additional
file-related options in the future if necessary. Make
idf_build_generate_metadata consistent with the other function
interfaces by using OUTPUT_FILE.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
b514ed5ae7 feat(cmakev2/build): add idf_check_binary_signed function
Given the binary target generated by the idf_build_binary or
idf_sign_binary function, add a new POST_BUILD dependency that displays
a message indicating the binary image must be manually signed before
flashing. This situation arises when CONFIG_SECURE_SIGNED_APPS is
enabled, but CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES is not set.  As a
result, the binary image is not signed during the build process and
requires manual signing.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
73ee5ee8e2 feat(cmakev2/build): add idf_check_binary_size function
Given the binary target created by the idf_build_binary or
idf_sign_binary function, add a new dependency that verifies whether the
binary image fits within the smallest application partition.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
1dbdeb6bb1 feat(cmakev2/build): add idf_flash_binary function
Create a new flash target for a previously created binary target using
the idf_build_binary or idf_sign_binary function. Specify the new target
name with the TARGET option. The binary image path is stored in the
BINARY_PATH property of the binary target and is set when the binary
target is created using the idf_build_binary or idf_sign_binary
function. Use the NAME option as a prefix for the generated esptool
argument file, and the FLASH option can be used to include the binary
image flashing in the global flash target.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
db2770b281 feat(cmakev2/build): add idf_sign_binary function
Create a signed binary image from a previously generated binary using
the `idf_build_binary` function. This image can be signed with an
optional key from a KEYFILE or, by default, with the key specified in
the sdkconfig. A new custom command is added to generate the signed
binary, which is stored at the location specified by the OUTPUT_FILE
option and a new custom target is created for it, with the name provided
in the TARGET option. The BINARY_PATH property is added to this new
TARGET, containing the path to the signed binary image.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
646c16f4f2 feat(cmakev2/build): add idf_build_binary function
The `idf_build_binary` function generates a binary image for a specified
executable target, which may or may not have been created using the
`idf_build_executable` function. It adds a custom command to generate
the binary image file at the location specified by the `OUTPUT_FILE`
option and creates a new target for it, with the name specified by the
`TARGET` option. The path of the generated binary file is also stored in
the `BINARY_PATH` property of the newly created binary target.
Additionally, this binary path is stored in the `EXECUTABLE_BINARY`
property of the given executable. This information is used by the
`idf_build_generate_metadata` function, which takes the executable
target as an argument and includes the binary name in the
`project_description.json`.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
b36e5adeff feat(cmakev2/build): add idf_build_generate_metadata function
The `idf_build_generate_metadata()` function is used to generate project
metadata, specifically the `project_description.json` file, for a given
executable target. The output file path can be specified as an argument
to the function, allowing metadata generation for multiple executables.
It identifies the library, created by the `idf_build_library` function,
that is linked to the executable based on the `LINK_LIBRARIES`
executable target property. The `LIBRARY_INTERFACES` build property
tracks all library interfaces created with the `idf_build_library`
function, so the targets in the `LINK_LIBRARIES` executable property are
checked against this list to find the library. The library contains
information about components linked to it in the
`LIBRARY_COMPONENTS_LINKED` library property. These components are
processed and added to the `build_component_info` dictionary in the
`project_description.json` along with other information.

Note that, compared to cmakev1, the `all_component_info` dictionary in
`project_description` does not include some information by default, such
as included directories. This information is available in cmakev1 due to
early component evaluation, which is not done in cmakev2. This will
likely require some adjustments on the hints side.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
2a093bcb0c feat(cmakev2/build): add idf_build_executable function
Create an empty source file for the add_executable target, along with a
library containing specified components, and then create an executable.
This approach allows for the easy creation of multiple executables by
specifying the component with the app_main function, as demonstrated in
the test.

```
idf_build_executable(fatfs_example COMPONENTS fatfs_example)
idf_build_executable(hello_world_example COMPONENTS hello_world_example)
```

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
213d128718 feat(cmakev2/build): remove INTERFACE option from idf_build_library
The option is unnecessary and complicates the interface. Additionally,
it does not adhere to the previously established naming convention. The
target name for the library interface is provided as a standard function
argument.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
3804fcfb2c feat(cmakev2/ldgen): add ldgen integration
Integrate the ldgen into cmakev2. With this change, it becomes possible
to actually link the project executables.

In cmakev2, the handling of linker scripts is deferred to
idf_build_library, unlike in cmakev1, where linker scripts were added
and generated during the target_linker_script call. In cmakev2, the
target_linker_script only adds the linker scripts and templates, along
with the output filenames for the linker scripts generated from the
templates, to the component property. When idf_build_library is called
and all the requested components are included, it uses the
__get_target_dependencies function to obtain all transitively linked
targets to the library interface target. These targets are mapped to the
components, and the LIBRARY_COMPONENTS_LINKED library property is set.
It contains all components linked to the library interface target. The
components from LIBRARY_COMPONENTS_LINKED are used to collect linker
fragments and linker scripts utilized in the library. Additionally, all
targets transitively linked to the library are used to identify archive
files used in the library. This includes component archives and archives
added with the add_prebuilt_library function. The archives and
ldfragments related to the components linked to the library are used
when ldgen generates the linker scripts from templates.

The linker scripts, both static and generated by ldgen, are added to the
library interface link options and INTERFACE_LINK_DEPENDS property. For
generated linker scripts, a custom target is created and added as a
dependency for the library interface to ensure they are generated before
the link.

The difference compared to cmakev1 is that the generated linker scripts,
currently only sections.ld, are not global in the project but are
generated per library. This means there might be multiple versions of
sections.ld depending on the components included in the library. For
example, a component like esp_system may be linked to multiple library
interface targets, each with a different set of components. This results
in different sets of fragment files and library archives and different
versions of the sections.ld linker script. This should ensure proper
dependencies between targets. In other words, if a component changes its
linker fragment, only executables linked to libraries using this
component should be re-linked. As a consequence of this approach, the
generated linker scripts for different libraries need to have different
names or be stored in different directories to avoid overwriting the
linker script for one library with the linker script for another library
using the same component. This is handled with a suffix, which is based
on the library interface target name and appended to the generated
linker script. So, for example, there is no sections.ld, but instead
sections.ld_fatfs_lib or sections.ld_hello_world_lib. As a next step, we
can add a DEFAULT option to idf_build_library and avoid adding the
suffix for the default library.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
e06624f552 feat(cmakev2/build): track components linked to library
There may be multiple libraries, each linking a different set of
components. Introduce a new library property, LIBRARY_COMPONENTS_LINKED,
to track the components linked with a specific library. This property
can be used, for example, by menuconfig to distinguish between included
and excluded components on a per-library or per-executable basis, or by
ldgen to identify linker scripts for the linked components.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
70f5366408 feat(cmakev2/project): move all project-related items into project.cmake
The current approach involves transparently calling __init_build within
idf_build_library and performing all post-project() initialization
there. The issue with this method is that project_include.cmake files
also need to be included during post-project() initialization, but they
should be included in the global scope. This cannot be achieved within
the __init_build function unless it is converted into a macro. Although
using a macro is a potential solution, it risks causing global scope
pollution. Another complication is the location where project() can be
invoked; it must be explicitly[1] stated in the project's
CMakeLists.txt.  This requirement conflicts with our intention to wrap
it within the idf_project_default helper. Given these challenges, it
makes sense to introduce an explicit idf_project_init macro, where all
post-project() initialization occurs, including the inclusion of
project_include.cmake files. While we can still encapsulate this within
idf_project_default, for the plumbing commands (idf_build_library,
idf_build_executable, ...), it will need to be explicitly called after
the project() invocation.

Usage for default project:

cmake_minimum_required(VERSION 3.22)
include($ENV{IDF_PATH}/tools/cmakev2/idf.cmake)
project()
idf_project_default()

Usage for plumbing commands:

cmake_minimum_required(VERSION 3.22)
include($ENV{IDF_PATH}/tools/cmakev2/idf.cmake)
project()
idf_project_init()
idf_build_library()
...

[1] https://cmake.org/cmake/help/latest/command/project.html#usage

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
f1e467eeee feat(cmakev2/build): add __generate_project_info stub
Currently, this generates a very basic project_description.json file,
allowing idf.py commands that call ensure_build_directory, such as
reconfigure, to be used with cmakev2. The ensure_build_directory
function sets a global context, which is presently used only for hints,
and the project_description.json file is loaded as part of this context.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
77e10e0df0 feat(cmakev2/build): use idf_component_include into idf_build_library
Call idf_component_include for all components requested in the library
and link them into it.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
f6f7edede2 feat(cmakev2/build): set LINKER_TYPE build property in __init_build_configuration
Set the LINKER_TYPE build property. Different linkers may have varying
options, so it's important to identify the linker type to configure the
options correctly. Currently, LINKER_TYPE is used to set the appropriate
linker options for linking the entire archive, which differs between the
GNU and Apple linkers when building on the host.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
72d4fecfa9 feat(cmakev2/build): set PROJECT_VER build property
Initialize the PROJECT_VER build property based on the following
precedence.

1. The PROJECT_VER environment or CMake variable.
2. The version.txt file located in the top-level project directory.
3. The VERSION argument, if provided, in the project() macro.
4. The output of git describe if the project is within a Git repository.
5. Defaults to 1 if none of the above conditions are met.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
754ef56594 feat(cmakev2/build): set PROJECT_NAME build property
Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
a4b0ad0cf3 feat(cmakev2/build): add build configuration
Add the __init_build_configuration() function to set all C, CXX, ASM,
and linker options, along with compilation defines, in a single
location. In cmakev1, these settings are scattered across multiple
places and it seems logical to group them together.

This function is called from the __init_build(), which is invoked after
project(). This sequence is necessary because some options depend on the
CMake information about the compiler, which is only available once the
toolchain has been initialized in project().

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
d58d08aacc feat(cmakev2/build): add __init_build() stub
Most of the global settings are configured in idf.cmake, but certain
elements can only be initialized after the project() function is called
and the toolchain is set up. For example, this includes the compilation
options, which may depend on identified compiler or the project name and
version set in the project() call. The __init_build function is called
at the beginning of the idf_build_library() function, meaning it should
be executed after the project() call. It ensures that initialization
occurs only once by setting the __BUILD_INITIALIZED build property.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
d669f1841b feat(cmakev2/build): add idf_build_library stub
Add idf_build_library function and enable setting and getting its
properties. This lays the groundwork for future initialization that
needs to occur after the project() call, such as determining compilation
options and others.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
b72b14a159 feat(cmakev2/utilities): add __set_property and __get_property helpers
The `idf_build_(set|get)_property` and
`idf_component_(set|get)_property` functions share a lot of similar
code. Move these common parts into new `__(set|get)_property` helper
functions. With the upcoming `idf_build_library` API function, we might
need to add properties for the interface target created for the library,
which would otherwise lead to yet another code duplication for setting
and getting library interface properties.

Update the current implementations of `idf_build_(set|get)_property` and
`idf_component_(set|get)_property` to utilize these new helper
functions.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00
Frantisek Hrbata
a9d55936ef feat(cmakev2): add basic component initialization
Discover component directories and initialize components within them.
This process does not include managed components, which should be added
separately at a later stage. To facilitate this, some minimal
functionalities are introduced, such as build properties, component
properties, and other helper functions.

Signed-off-by: Frantisek Hrbata <frantisek.hrbata@espressif.com>
2025-10-30 17:17:49 +08:00