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>
This commit is contained in:
Frantisek Hrbata
2025-11-17 14:51:14 +01:00
parent e97027214e
commit 2b35b5b1bb
3 changed files with 79 additions and 40 deletions
+26 -4
View File
@@ -503,6 +503,16 @@ endfunction()
Optional ``executable`` suffix.
*MAPFILE_TARGET[in,opt]*
Name of the target for the map file. If provided, the link map file is
generated for the specified executable, and the ``MAPFILE_TARGET``
target name is created for it. The ``MAPFILE_PATH`` property with the
link map file path is added to the ``MAPFILE_TARGET`` target. This can
be used for other targets that depend on the link map file. The link map file
is not generated on Darwin host, so the target ``MAPFILE_TARGET`` may not
be created if link map file is not generated.
Create a new executable target using the name specified in the
``executable`` argument, and link it to the library created with the
component names provided in the ``COMPONENTS`` option. If the
@@ -513,7 +523,7 @@ endfunction()
#]]
function(idf_build_executable executable)
set(options)
set(one_value NAME SUFFIX)
set(one_value NAME SUFFIX MAPFILE_TARGET)
set(multi_value COMPONENTS)
cmake_parse_arguments(ARG "${options}" "${one_value}" "${multi_value}" ${ARGN})
@@ -536,9 +546,7 @@ function(idf_build_executable executable)
endif()
add_executable(${executable} "${executable_src}")
if(ARG_NAME)
set_target_properties(${executable} PROPERTIES OUTPUT_NAME ${ARG_NAME})
endif()
set_target_properties(${executable} PROPERTIES OUTPUT_NAME ${ARG_NAME})
if(ARG_SUFFIX)
set_target_properties(${executable} PROPERTIES SUFFIX ${ARG_SUFFIX})
@@ -546,6 +554,20 @@ function(idf_build_executable executable)
target_link_libraries(${executable} PRIVATE ${library})
idf_build_get_property(linker_type LINKER_TYPE)
if(ARG_MAPFILE_TARGET AND "${linker_type}" STREQUAL "GNU")
set(mapfile "${CMAKE_BINARY_DIR}/${ARG_NAME}.map")
target_link_options(${executable} PRIVATE "LINKER:--Map=${mapfile}")
add_custom_command(
OUTPUT "${mapfile}"
DEPENDS ${executable}
)
add_custom_target(${ARG_MAPFILE_TARGET}
DEPENDS "${mapfile}"
)
set_target_properties(${ARG_MAPFILE_TARGET} PROPERTIES MAPFILE_PATH ${mapfile})
endif()
set_target_properties(${executable} PROPERTIES LIBRARY_INTERFACE ${library})
endfunction()
+49 -34
View File
@@ -90,6 +90,21 @@ function(__init_project_configuration)
idf_build_get_property(project_dir PROJECT_DIR)
idf_build_get_property(project_name PROJECT_NAME)
# 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.
if(CONFIG_IDF_TARGET_LINUX AND CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
# Compiling for the host, and the host is macOS, so the linker is Darwin LD.
# Note, when adding support for Clang and LLD based toolchain this check will
# need to be modified.
set(linker_type "Darwin")
else()
set(linker_type "GNU")
endif()
idf_build_set_property(LINKER_TYPE "${linker_type}")
list(APPEND compile_definitions "_GLIBCXX_USE_POSIX_SEMAPHORE" # These two lines enable libstd++ to use
"_GLIBCXX_HAVE_POSIX_SEMAPHORE" # posix-semaphores from components/pthread
"_GNU_SOURCE")
@@ -407,16 +422,13 @@ function(__init_project_configuration)
list(APPEND link_options "-specs=picolibc.specs")
endif()
if(CMAKE_C_COMPILER_ID MATCHES "GNU")
set(mapfile "${build_dir}/${project_name}.map")
if("${linker_type}" STREQUAL "GNU")
set(target_upper "${idf_target}")
string(TOUPPER ${target_upper} target_upper)
# Add cross-reference table to the map file
list(APPEND link_options "-Wl,--cref")
# Add this symbol as a hint for esp_idf_size to guess the target name
list(APPEND link_options "-Wl,--defsym=IDF_TARGET_${target_upper}=0")
# Enable map file output
list(APPEND link_options "-Wl,--Map=${mapfile}")
# Check if linker supports --no-warn-rwx-segments
execute_process(COMMAND ${CMAKE_LINKER} "--no-warn-rwx-segments" "--version"
RESULT_VARIABLE result
@@ -486,21 +498,6 @@ function(__init_project_configuration)
idf_build_set_property(ASM_COMPILE_OPTIONS "${asm_compile_options}" APPEND)
idf_build_set_property(COMPILE_DEFINITIONS "${compile_definitions}" APPEND)
idf_build_set_property(LINK_OPTIONS "${link_options}" APPEND)
# 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.
if(CONFIG_IDF_TARGET_LINUX AND CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
# Compiling for the host, and the host is macOS, so the linker is Darwin LD.
# Note, when adding support for Clang and LLD based toolchain this check will
# need to be modified.
set(linker_type "Darwin")
else()
set(linker_type "GNU")
endif()
idf_build_set_property(LINKER_TYPE "${linker_type}")
endfunction()
#[[
@@ -694,26 +691,22 @@ function(idf_build_generate_flasher_args)
INPUT "${build_dir}/flasher_args.json.in")
endfunction()
#[[api
.. cmakev2:macro:: idf_project_default
#[[
.. cmakev2:macro:: __project_default
.. code-block:: cmake
idf_project_default()
__project_default()
Create a default project executable based on the main component and its
transitive dependencies. The executable name is derived from the
``PROJECT_NAME`` variable, which by default uses the ``CMAKE_PROJECT_NAME``
value specified in the CMake's ``project()`` call.
Generate the binary image for the executable, signed or unsigned based on
the configuration, and add flash targets for it.
Helper function implementing the main idf_project_default macro
functionality, preventing global variable scope pollution.
#]]
macro(idf_project_default)
idf_project_init()
function(__project_default)
idf_build_get_property(build_dir BUILD_DIR)
idf_build_get_property(executable PROJECT_NAME)
idf_build_executable("${executable}" COMPONENTS main SUFFIX ".elf")
idf_build_executable("${executable}"
COMPONENTS main
MAPFILE_TARGET "${executable}_mapfile")
if(CONFIG_APP_BUILD_GENERATE_BINARIES)
# Is it possible to have a configuration where
@@ -770,7 +763,29 @@ macro(idf_project_default)
idf_create_uf2("${executable}"
TARGET uf2-app
APP_ONLY)
endfunction()
unset(build_dir)
unset(executable)
#[[api
.. cmakev2:macro:: idf_project_default
.. code-block:: cmake
idf_project_default()
Create a default project executable based on the main component and its
transitive dependencies. The executable name is derived from the
``PROJECT_NAME`` variable, which by default uses the ``CMAKE_PROJECT_NAME``
value specified in the CMake's ``project()`` call.
Generate the binary image for the executable, signed or unsigned based on
the configuration, and add flash targets for it.
#]]
macro(idf_project_default)
idf_project_init()
# 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.
__project_default()
endmacro()
+4 -2
View File
@@ -219,7 +219,8 @@ endfunction()
# idf.py confserver-fatfs
function(test_executable)
idf_build_executable(fatfs_example
COMPONENTS fatfs_example)
COMPONENTS fatfs_example
MAPFILE_TARGET fatfs_example_mapfile)
idf_build_binary(fatfs_example
TARGET fatfs_example_bin
OUTPUT_FILE fatfs_example.bin)
@@ -236,7 +237,8 @@ function(test_executable)
idf_build_executable(hello_world_example
COMPONENTS hello_world_example)
COMPONENTS hello_world_example
MAPFILE_TARGET hello_world_example_mapfile)
idf_build_binary(hello_world_example
TARGET hello_world_example_bin
OUTPUT_FILE hello_world_example.bin)