Merge branch 'feature/cmake_changes_for_4.0' into 'master'

CMake for 4.0

See merge request idf/esp-idf!4452
This commit is contained in:
Angus Gratton 2019-05-17 14:21:48 +08:00
commit 907471ce41
100 changed files with 2737 additions and 1877 deletions

View file

@ -1,161 +1,120 @@
cmake_minimum_required(VERSION 3.5)
project(esp-idf C CXX ASM)
if(NOT IDF_PATH)
set(IDF_PATH ${CMAKE_CURRENT_LIST_DIR})
unset(compile_options)
unset(c_compile_options)
unset(cxx_compile_options)
unset(compile_definitions)
# Add the following build specifications here, since these seem to be dependent
# on config values on the root Kconfig.
# Temporary trick to support both gcc5 and gcc8 builds
if(CMAKE_C_COMPILER_VERSION VERSION_EQUAL 5.2.0)
set(GCC_NOT_5_2_0 0 CACHE STRING "GCC is 5.2.0 version")
else()
set(GCC_NOT_5_2_0 1 CACHE STRING "GCC is not 5.2.0 version")
endif()
include(tools/cmake/idf_functions.cmake)
list(APPEND compile_definitions "-DGCC_NOT_5_2_0=${GCC_NOT_5_2_0}")
#
# Set variables that control the build configuration and the build itself
#
idf_set_variables()
kconfig_set_variables()
#
# Generate a component dependencies file, enumerating components to be included in the build
# as well as their dependencies.
#
execute_process(COMMAND "${CMAKE_COMMAND}"
-D "COMPONENTS=${IDF_COMPONENTS}"
-D "COMPONENT_REQUIRES_COMMON=${IDF_COMPONENT_REQUIRES_COMMON}"
-D "EXCLUDE_COMPONENTS=${IDF_EXCLUDE_COMPONENTS}"
-D "TEST_COMPONENTS=${IDF_TEST_COMPONENTS}"
-D "TEST_EXCLUDE_COMPONENTS=${IDF_TEST_EXCLUDE_COMPONENTS}"
-D "BUILD_TESTS=${IDF_BUILD_TESTS}"
-D "DEPENDENCIES_FILE=${CMAKE_BINARY_DIR}/component_depends.cmake"
-D "COMPONENT_DIRS=${IDF_COMPONENT_DIRS}"
-D "BOOTLOADER_BUILD=${BOOTLOADER_BUILD}"
-D "IDF_TARGET=${IDF_TARGET}"
-D "IDF_PATH=${IDF_PATH}"
-D "DEBUG=${DEBUG}"
-P "${IDF_PATH}/tools/cmake/scripts/expand_requirements.cmake"
WORKING_DIRECTORY "${PROJECT_PATH}"
RESULT_VARIABLE expand_requirements_result)
if(expand_requirements_result)
message(FATAL_ERROR "Failed to expand component requirements")
if(CONFIG_OPTIMIZATION_LEVEL_RELEASE)
list(APPEND compile_options "-Os")
else()
list(APPEND compile_options "-Og")
endif()
include("${CMAKE_BINARY_DIR}/component_depends.cmake")
#
# We now have the following component-related variables:
#
# IDF_COMPONENTS is the list of initial components set by the user
# (or empty to include all components in the build).
# BUILD_COMPONENTS is the list of components to include in the build.
# BUILD_COMPONENT_PATHS is the paths to all of these components, obtained from the component dependencies file.
#
# Print the list of found components and test components
#
string(REPLACE ";" " " BUILD_COMPONENTS_SPACES "${BUILD_COMPONENTS}")
message(STATUS "Component names: ${BUILD_COMPONENTS_SPACES}")
unset(BUILD_COMPONENTS_SPACES)
message(STATUS "Component paths: ${BUILD_COMPONENT_PATHS}")
# Print list of test components
if(TESTS_ALL EQUAL 1 OR TEST_COMPONENTS)
string(REPLACE ";" " " BUILD_TEST_COMPONENTS_SPACES "${BUILD_TEST_COMPONENTS}")
message(STATUS "Test component names: ${BUILD_TEST_COMPONENTS_SPACES}")
unset(BUILD_TEST_COMPONENTS_SPACES)
message(STATUS "Test component paths: ${BUILD_TEST_COMPONENT_PATHS}")
if(CONFIG_CXX_EXCEPTIONS)
list(APPEND cxx_compile_options "-fexceptions")
else()
list(APPEND cxx_compile_options "-fno-exceptions")
endif()
# Generate project configuration
kconfig_process_config()
if(CONFIG_DISABLE_GCC8_WARNINGS)
list(APPEND compile_options "-Wno-parentheses"
"-Wno-sizeof-pointer-memaccess"
"-Wno-clobbered")
# Include sdkconfig.cmake so rest of the build knows the configuration
include(${SDKCONFIG_CMAKE})
# Verify the environment is configured correctly
idf_verify_environment()
# Check git revision (may trigger reruns of cmake)
## sets IDF_VER to IDF git revision
idf_get_git_revision()
# Check that the targets set in cache, sdkconfig, and in environment all match
idf_check_config_target()
## get PROJECT_VER
if(NOT BOOTLOADER_BUILD)
app_get_revision("${CMAKE_SOURCE_DIR}")
endif()
# Add some idf-wide definitions
idf_set_global_compile_options()
# generate compile_commands.json (needs to come after project)
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
#
# Setup variables for linker script generation
#
ldgen_set_variables()
# Include any top-level project_include.cmake files from components
foreach(component ${BUILD_COMPONENT_PATHS})
set(COMPONENT_PATH "${component}")
include_if_exists("${component}/project_include.cmake")
unset(COMPONENT_PATH)
endforeach()
#
# Add each component to the build as a library
#
foreach(COMPONENT_PATH ${BUILD_COMPONENT_PATHS})
get_filename_component(COMPONENT_NAME ${COMPONENT_PATH} NAME)
list(FIND BUILD_TEST_COMPONENT_PATHS ${COMPONENT_PATH} idx)
if(NOT idx EQUAL -1)
list(GET BUILD_TEST_COMPONENTS ${idx} test_component)
set(COMPONENT_NAME ${test_component})
# doesn't use GCC_NOT_5_2_0 because idf_set_global_variables was not called before
if(GCC_NOT_5_2_0)
list(APPEND compile_options "-Wno-format-overflow"
"-Wno-stringop-truncation"
"-Wno-misleading-indentation"
"-Wno-cast-function-type"
"-Wno-implicit-fallthrough"
"-Wno-unused-const-variable"
"-Wno-switch-unreachable"
"-Wno-format-truncation"
"-Wno-memset-elt-size"
"-Wno-int-in-bool-context")
endif()
endif()
component_get_target(COMPONENT_TARGET ${COMPONENT_NAME})
if(CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED)
list(APPEND compile_definitions "NDEBUG")
endif()
add_subdirectory(${COMPONENT_PATH} ${COMPONENT_NAME})
if(CONFIG_STACK_CHECK_NORM)
list(APPEND compile_options "-fstack-protector")
elseif(CONFIG_STACK_CHECK_STRONG)
list(APPEND compile_options "-fstack-protector-strong")
elseif(CONFIG_STACK_CHECK_ALL)
list(APPEND compile_options "-fstack-protector-all")
endif()
# All targets built under this scope is with the ESP-IDF build system
set(ESP_PLATFORM 1)
list(APPEND compile_definitions "-DESP_PLATFORM")
idf_build_set_property(COMPILE_OPTIONS "${compile_options}" APPEND)
idf_build_set_property(C_COMPILE_OPTIONS "${c_compile_options}" APPEND)
idf_build_set_property(CXX_COMPILE_OPTIONS "${cxx_compile_options}" APPEND)
idf_build_set_property(COMPILE_DEFINITIONS "${compile_definitions}" APPEND)
idf_build_get_property(build_component_targets __BUILD_COMPONENT_TARGETS)
# Add each component as a subdirectory, processing each component's CMakeLists.txt
foreach(component_target ${build_component_targets})
__component_get_property(dir ${component_target} COMPONENT_DIR)
__component_get_property(_name ${component_target} COMPONENT_NAME)
__component_get_property(prefix ${component_target} __PREFIX)
__component_get_property(alias ${component_target} COMPONENT_ALIAS)
set(COMPONENT_NAME ${_name})
set(COMPONENT_DIR ${dir})
set(COMPONENT_ALIAS ${alias})
set(COMPONENT_PATH ${dir}) # also deprecated, see comment in previous loop
idf_build_get_property(build_prefix __PREFIX)
set(__idf_component_context 1)
if(NOT prefix STREQUAL build_prefix)
add_subdirectory(${dir} ${prefix}_${_name} EXCLUDE_FROM_ALL)
else()
add_subdirectory(${dir} ${_name} EXCLUDE_FROM_ALL)
endif()
set(__idf_component_context 0)
endforeach()
unset(COMPONENT_NAME)
unset(COMPONENT_PATH)
# each component should see the include directories of its requirements
#
# (we can't do this until all components are registered and targets exist in cmake, as we have
# a circular requirements graph...)
foreach(component ${BUILD_COMPONENTS})
component_get_target(component_target ${component})
if(TARGET ${component_target})
get_component_requirements(${component} deps priv_deps)
# Establish dependencies between components
idf_build_get_property(build_components BUILD_COMPONENTS)
foreach(build_component ${build_components})
__component_get_target(component_target ${build_component})
__component_get_property(component_lib ${component_target} COMPONENT_LIB)
__component_get_property(reqs ${component_target} __REQUIRES)
foreach(req ${reqs})
__component_get_property(req_lib ${req} COMPONENT_LIB)
if(TARGET ${req_lib})
set_property(TARGET ${component_lib} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${req_lib})
endif()
endforeach()
list(APPEND priv_deps ${IDF_COMPONENT_REQUIRES_COMMON})
foreach(dep ${deps})
component_get_target(dep_target ${dep})
add_component_dependencies(${component_target} ${dep_target} PUBLIC)
endforeach()
foreach(dep ${priv_deps})
component_get_target(dep_target ${dep})
add_component_dependencies(${component_target} ${dep_target} PRIVATE)
get_property(type TARGET ${component_lib} PROPERTY TYPE)
if(type STREQUAL STATIC_LIBRARY)
__component_get_property(reqs ${component_target} __REQUIRES)
__component_get_property(priv_reqs ${component_target} __PRIV_REQUIRES)
foreach(req ${reqs} ${priv_reqs})
__component_get_property(req_lib ${req} COMPONENT_LIB)
if(TARGET ${req_lib})
set_property(TARGET ${component_lib} APPEND PROPERTY LINK_LIBRARIES ${req_lib})
endif()
endforeach()
endif()
endforeach()
if(IDF_BUILD_ARTIFACTS)
# Write project description JSON file
make_json_list("${BUILD_COMPONENTS}" build_components_json)
make_json_list("${BUILD_COMPONENT_PATHS}" build_component_paths_json)
configure_file("${IDF_PATH}/tools/cmake/project_description.json.in"
"${IDF_BUILD_ARTIFACTS_DIR}/project_description.json")
unset(build_components_json)
unset(build_component_paths_json)
endif()
set(BUILD_COMPONENTS ${BUILD_COMPONENTS} PARENT_SCOPE)
ldgen_add_dependencies()
endforeach()

View file

@ -30,6 +30,5 @@ register_component()
# disable --coverage for this component, as it is used as transport
# for gcov
component_compile_options("-fno-profile-arcs" "-fno-test-coverage")
target_link_libraries(${COMPONENT_TARGET} gcov)
target_compile_options(${COMPONENT_LIB} PRIVATE "-fno-profile-arcs" "-fno-test-coverage")
target_link_libraries(${COMPONENT_LIB} gcov ${LIBC} ${LIBM})

View file

@ -8,35 +8,40 @@ register_component()
# esp_app_desc structure is added as an undefined symbol because otherwise the
# linker will ignore this structure as it has no other files depending on it.
target_link_libraries(${COMPONENT_TARGET} "-u esp_app_desc")
target_link_libraries(${COMPONENT_LIB} "-u esp_app_desc")
# cut PROJECT_VER and PROJECT_NAME to required 32 characters.
string(SUBSTRING "${PROJECT_VER}" 0 31 PROJECT_VER_CUT)
string(SUBSTRING "${PROJECT_NAME}" 0 31 PROJECT_NAME_CUT)
idf_build_get_property(project_ver PROJECT_VER)
idf_build_get_property(project_name PROJECT_NAME)
string(SUBSTRING "${project_ver}" 0 31 PROJECT_VER_CUT)
string(SUBSTRING "${project_name}" 0 31 PROJECT_NAME_CUT)
set_source_files_properties(
SOURCE "esp_app_desc.c"
PROPERTIES COMPILE_DEFINITIONS
"PROJECT_VER=\"${PROJECT_VER_CUT}\"; PROJECT_NAME=\"${PROJECT_NAME_CUT}\"")
if (NOT BOOTLOADER_BUILD AND IDF_BUILD_ARTIFACTS)
if(NOT BOOTLOADER_BUILD)
partition_table_get_partition_info(otadata_offset "--partition-type data --partition-subtype ota" "offset")
partition_table_get_partition_info(otadata_size "--partition-type data --partition-subtype ota" "size")
set(blank_otadata_file ${IDF_BUILD_ARTIFACTS_DIR}/ota_data_initial.bin)
# Add custom target for generating empty otadata partition for flashing
if(otadata_size AND otadata_offset)
idf_build_get_property(build_dir BUILD_DIR)
set(blank_otadata_file ${build_dir}/ota_data_initial.bin)
idf_build_get_property(idf_path IDF_PATH)
idf_build_get_property(python PYTHON)
add_custom_command(OUTPUT ${blank_otadata_file}
COMMAND ${PYTHON} ${IDF_PATH}/components/partition_table/parttool.py
COMMAND ${python} ${idf_path}/components/partition_table/parttool.py
--partition-type data --partition-subtype ota -q
--partition-table-file ${PARTITION_CSV_PATH} generate_blank_partition_file
--output ${blank_otadata_file})
add_custom_target(blank_ota_data ALL DEPENDS ${blank_otadata_file})
add_dependencies(flash blank_ota_data)
add_dependencies(app blank_ota_data)
set(otatool_py ${PYTHON} ${COMPONENT_PATH}/otatool.py)
set(otatool_py ${python} ${COMPONENT_DIR}/otatool.py)
add_custom_target(read_otadata DEPENDS "${PARTITION_CSV_PATH}"
COMMAND ${otatool_py} --partition-table-file ${PARTITION_CSV_PATH} read_otadata)

View file

@ -1,5 +1,7 @@
register_component()
# Do not generate flash file when building bootloader or is in early expansion of the build
if(CMAKE_BUILD_EARLY_EXPANSION OR BOOTLOADER_BUILD)
if(BOOTLOADER_BUILD)
return()
endif()
@ -9,4 +11,4 @@ set(BOOTLOADER_OFFSET 0x1000)
esptool_py_flash_project_args(bootloader ${BOOTLOADER_OFFSET}
${BOOTLOADER_BUILD_DIR}/bootloader.bin
FLASH_IN_PROJECT
FLASH_FILE_TEMPLATE flash_bootloader_args.in)
FLASH_FILE_TEMPLATE flash_bootloader_args.in)

View file

@ -1,8 +1,15 @@
# Do not generate flash file when building bootloader or is in early expansion of the build
if(BOOTLOADER_BUILD)
return()
endif()
idf_build_get_property(project_dir PROJECT_DIR)
# This is for tracking the top level project path
if(BOOTLOADER_BUILD)
set(main_project_path "${CMAKE_BINARY_DIR}/../..")
else()
set(main_project_path "${IDF_PROJECT_PATH}")
set(main_project_path "${project_dir}")
endif()
get_filename_component(secure_boot_signing_key
@ -19,15 +26,13 @@ else()
add_custom_target(gen_secure_boot_signing_key)
endif()
if(BOOTLOADER_BUILD OR NOT IDF_BUILD_ARTIFACTS)
return() # don't keep recursing, generate on project builds
endif()
# Glue to build the bootloader subproject binary as an external
# cmake project under this one
#
#
set(BOOTLOADER_BUILD_DIR "${IDF_BUILD_ARTIFACTS_DIR}/bootloader")
idf_build_get_property(build_dir BUILD_DIR)
set(BOOTLOADER_BUILD_DIR "${build_dir}/bootloader")
set(bootloader_binary_files
"${BOOTLOADER_BUILD_DIR}/bootloader.elf"
"${BOOTLOADER_BUILD_DIR}/bootloader.bin"
@ -47,12 +52,16 @@ endif()
if((NOT CONFIG_SECURE_BOOT_ENABLED) OR
CONFIG_SECURE_BOOTLOADER_REFLASHABLE OR
CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH)
idf_build_get_property(idf_path IDF_PATH)
idf_build_get_property(sdkconfig SDKCONFIG)
idf_build_get_property(idf_target IDF_TARGET)
externalproject_add(bootloader
# TODO: support overriding the bootloader in COMPONENT_PATHS
SOURCE_DIR "${IDF_PATH}/components/bootloader/subproject"
SOURCE_DIR "${idf_path}/components/bootloader/subproject"
BINARY_DIR "${BOOTLOADER_BUILD_DIR}"
CMAKE_ARGS -DSDKCONFIG=${SDKCONFIG} -DIDF_PATH=${IDF_PATH} -DIDF_TARGET=${IDF_TARGET}
CMAKE_ARGS -DSDKCONFIG=${sdkconfig} -DIDF_PATH=${idf_path} -DIDF_TARGET=${idf_target}
-DSECURE_BOOT_SIGNING_KEY=${secure_boot_signing_key}
-DPYTHON_DEPS_CHECKED=1
INSTALL_COMMAND ""
BUILD_ALWAYS 1 # no easy way around this...
BUILD_BYPRODUCTS ${bootloader_binary_files}
@ -69,4 +78,4 @@ endif()
# So for now we just have the top-level build remove the final build products...
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY
ADDITIONAL_MAKE_CLEAN_FILES
${bootloader_binary_files})
${bootloader_binary_files})

View file

@ -17,33 +17,17 @@ endif()
set(COMPONENTS bootloader esptool_py partition_table soc bootloader_support log spi_flash micro-ecc main efuse)
set(BOOTLOADER_BUILD 1)
add_definitions(-DBOOTLOADER_BUILD=1)
set(COMPONENT_REQUIRES_COMMON log esp_rom esp_common xtensa)
if (CONFIG_LEGACY_INCLUDE_COMMON_HEADERS)
list(APPEND COMPONENT_REQUIRES_COMMON "soc")
endif()
include("${IDF_PATH}/tools/cmake/project.cmake")
set(common_req log esp_rom esp_common xtensa)
if (CONFIG_LEGACY_INCLUDE_COMMON_HEADERS)
list(APPEND common_req soc)
endif()
idf_build_set_property(__COMPONENT_REQUIRES_COMMON "${common_req}")
idf_build_set_property(__OUTPUT_SDKCONFIG 0)
project(bootloader)
target_linker_script(bootloader.elf
"main/${IDF_TARGET}.bootloader.ld"
"main/${IDF_TARGET}.bootloader.rom.ld"
)
# as cmake won't attach linker args to a header-only library, attach
# linker args directly to the bootloader.elf
# esp32.rom.newlib-funcs.ld is included to use memset/memcpy.
set(BOOTLOADER_LINKER_SCRIPTS
"${IDF_PATH}/components/esp_rom/${IDF_TARGET}/ld/${IDF_TARGET}.rom.ld"
"${IDF_PATH}/components/esp_rom/${IDF_TARGET}/ld/${IDF_TARGET}.rom.newlib-funcs.ld"
"${IDF_PATH}/components/${IDF_TARGET}/ld/${IDF_TARGET}.peripherals.ld")
target_linker_script(bootloader.elf ${BOOTLOADER_LINKER_SCRIPTS})
target_link_libraries(bootloader.elf gcc)
idf_build_set_property(COMPILE_DEFINITIONS "-DBOOTLOADER_BUILD=1" APPEND)
idf_build_set_property(COMPILE_OPTIONS "-fno-stack-protector" APPEND)
set(secure_boot_signing_key ${SECURE_BOOT_SIGNING_KEY})

View file

@ -1,8 +1,4 @@
# only compile the "micro-ecc/uECC.c" source file
set(COMPONENT_SRCS "micro-ecc/uECC.c")
set(COMPONENT_ADD_INCLUDEDIRS micro-ecc)
set(COMPONENT_REQUIRES)
register_component()

View file

@ -1,4 +1,10 @@
set(COMPONENT_SRCS "bootloader_start.c")
set(COMPONENT_ADD_INCLUDEDIRS "")
set(COMPONENT_REQUIRES "bootloader bootloader_support")
set(COMPONENT_REQUIRES bootloader bootloader_support)
register_component()
idf_build_get_property(target IDF_TARGET)
set(scripts "${target}.bootloader.ld"
"${target}.bootloader.rom.ld")
target_linker_script(${COMPONENT_LIB} "${scripts}")

View file

@ -7,7 +7,7 @@ set(COMPONENT_SRCS "src/bootloader_clock.c"
"src/flash_partitions.c"
"src/flash_qio_mode.c")
if(${BOOTLOADER_BUILD})
if(BOOTLOADER_BUILD)
set(COMPONENT_ADD_INCLUDEDIRS "include include_bootloader")
set(COMPONENT_REQUIRES soc) #unfortunately the header directly uses SOC registers
set(COMPONENT_PRIV_REQUIRES spi_flash micro-ecc efuse)
@ -55,8 +55,8 @@ else()
"src/idf/secure_boot_signatures.c")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_PRIV_INCLUDEDIRS "include_bootloader")
set(COMPONENT_REQUIRES soc) #unfortunately the header directly uses SOC registers
set(COMPONENT_PRIV_REQUIRES spi_flash mbedtls efuse)
set(COMPONENT_REQUIRES mbedtls soc) #unfortunately the header directly uses SOC registers
set(COMPONENT_PRIV_REQUIRES spi_flash efuse)
endif()
register_component()
register_component()

View file

@ -280,9 +280,9 @@ register_component()
if(CONFIG_BT_ENABLED)
if(GCC_NOT_5_2_0)
component_compile_options(-Wno-implicit-fallthrough -Wno-unused-const-variable)
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-implicit-fallthrough -Wno-unused-const-variable)
endif()
target_link_libraries(${COMPONENT_TARGET} "-L${CMAKE_CURRENT_LIST_DIR}/lib")
target_link_libraries(${COMPONENT_TARGET} btdm_app)
target_link_libraries(${COMPONENT_LIB} "-L${CMAKE_CURRENT_LIST_DIR}/lib")
target_link_libraries(${COMPONENT_LIB} btdm_app)
endif()

View file

@ -26,3 +26,9 @@ register_component()
# Silence format truncation warning, until it is fixed upstream
set_source_files_properties(libcoap/src/coap_debug.c PROPERTIES COMPILE_FLAGS -Wno-format-truncation)
# Needed for coap headers in public builds, also.
#
# TODO: find a way to move this to a port header
target_compile_definitions(${COMPONENT_LIB} PUBLIC WITH_POSIX)

View file

@ -3,8 +3,5 @@ set(COMPONENT_SRCS "commands.c"
"split_argv.c"
"argtable3/argtable3.c"
"linenoise/linenoise.c")
set(COMPONENT_REQUIRES)
register_component()

View file

@ -1,12 +1,10 @@
set(COMPONENT_SRCS "cxx_exception_stubs.cpp"
"cxx_guards.cpp")
set(COMPONENT_REQUIRES)
register_component()
target_link_libraries(${COMPONENT_TARGET} stdc++)
target_link_libraries(${COMPONENT_TARGET} "-u __cxa_guard_dummy")
target_link_libraries(${COMPONENT_LIB} stdc++)
target_link_libraries(${COMPONENT_LIB} "-u __cxa_guard_dummy")
if(NOT CONFIG_CXX_EXCEPTIONS)
target_link_libraries(${COMPONENT_TARGET} "-u __cxx_fatal_exception")
target_link_libraries(${COMPONENT_LIB} "-u __cxx_fatal_exception")
endif()

View file

@ -1,43 +1,44 @@
set(SOC_NAME ${IDF_TARGET})
idf_build_get_property(soc_name IDF_TARGET)
if(EXISTS "${COMPONENT_PATH}/${SOC_NAME}")
include(${COMPONENT_PATH}/${SOC_NAME}/sources.cmake)
if(EXISTS "${COMPONENT_DIR}/${soc_name}")
include(${COMPONENT_DIR}/${soc_name}/sources.cmake)
spaces2list(EFUSE_SOC_SRCS)
add_prefix(COMPONENT_SRCS "${SOC_NAME}/" ${EFUSE_SOC_SRCS})
set(COMPONENT_ADD_INCLUDEDIRS include
${SOC_NAME}/include)
add_prefix(COMPONENT_SRCS "${soc_name}/" ${EFUSE_SOC_SRCS})
set(COMPONENT_ADD_INCLUDEDIRS include ${soc_name}/include)
endif()
list(APPEND COMPONENT_SRCS "src/esp_efuse_api.c"
"src/esp_efuse_fields.c"
"src/esp_efuse_utility.c")
set(COMPONENT_REQUIRES)
set(COMPONENT_PRIV_REQUIRES bootloader_support soc)
register_component()
set(GEN_EFUSE_TABLE_ARG --max_blk_len ${CONFIG_EFUSE_MAX_BLK_LEN})
idf_build_get_property(python PYTHON)
###################
# Make common files esp_efuse_table.c and include/esp_efuse_table.h files.
set(EFUSE_COMMON_TABLE_CSV_PATH "${COMPONENT_PATH}/${SOC_NAME}/esp_efuse_table.csv")
set(EFUSE_COMMON_TABLE_CSV_PATH "${COMPONENT_DIR}/${soc_name}/esp_efuse_table.csv")
add_custom_target(efuse_common_table COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_COMMON_TABLE_CSV_PATH} ${GEN_EFUSE_TABLE_ARG})
add_custom_target(efuse_common_table COMMAND "${python}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_COMMON_TABLE_CSV_PATH} ${GEN_EFUSE_TABLE_ARG})
###################
# Make custom files project/main/esp_efuse_custom_table.c and project/main/include/esp_efuse_custom_table.h files.
# Path to CSV file is relative to project path for custom CSV files.
if(${CONFIG_EFUSE_CUSTOM_TABLE})
# Custom filename expands any path relative to the project
get_filename_component(EFUSE_CUSTOM_TABLE_CSV_PATH "${CONFIG_EFUSE_CUSTOM_TABLE_FILENAME}" ABSOLUTE BASE_DIR "${IDF_PROJECT_PATH}")
add_custom_target(efuse_custom_table COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_COMMON_TABLE_CSV_PATH} ${EFUSE_CUSTOM_TABLE_CSV_PATH} ${GEN_EFUSE_TABLE_ARG})
idf_build_get_property(project_dir PROJECT_DIR)
get_filename_component(EFUSE_CUSTOM_TABLE_CSV_PATH "${CONFIG_EFUSE_CUSTOM_TABLE_FILENAME}" ABSOLUTE BASE_DIR "${project_dir}")
add_custom_target(efuse_custom_table COMMAND "${python}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_COMMON_TABLE_CSV_PATH} ${EFUSE_CUSTOM_TABLE_CSV_PATH} ${GEN_EFUSE_TABLE_ARG})
else()
add_custom_target(efuse_custom_table COMMAND)
endif()#if(${CONFIG_EFUSE_CUSTOM_TABLE})
add_custom_target(show_efuse_table COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_COMMON_TABLE_CSV_PATH} ${EFUSE_CUSTOM_TABLE_CSV_PATH} ${GEN_EFUSE_TABLE_ARG} "--info")
add_custom_target(show_efuse_table COMMAND "${python}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_COMMON_TABLE_CSV_PATH} ${EFUSE_CUSTOM_TABLE_CSV_PATH} ${GEN_EFUSE_TABLE_ARG} "--info")
###################
# Generates files for unit test. This command is run manually.
set(EFUSE_TEST_TABLE_CSV_PATH "${COMPONENT_PATH}/test/esp_efuse_test_table.csv")
add_custom_target(efuse_test_table COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_TEST_TABLE_CSV_PATH} ${GEN_EFUSE_TABLE_ARG})
set(EFUSE_TEST_TABLE_CSV_PATH "${COMPONENT_DIR}/test/esp_efuse_test_table.csv")
add_custom_target(efuse_test_table COMMAND "${python}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_TEST_TABLE_CSV_PATH} ${GEN_EFUSE_TABLE_ARG})

View file

@ -3,9 +3,8 @@ require_idf_targets(esp32)
if(BOOTLOADER_BUILD)
# For bootloader, all we need from esp32 is headers
set(COMPONENT_ADD_INCLUDEDIRS include)
set(COMPONENT_REQUIRES ${IDF_COMPONENTS} soc) #unfortunately rom/uart uses SOC registers directly
set(COMPONENT_SRCS )
register_component()
target_linker_script(${COMPONENT_LIB} "ld/esp32.peripherals.ld")
else()
# Regular app build
@ -35,64 +34,54 @@ else()
"task_wdt.c")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES driver esp_event efuse soc) #unfortunately rom/uart uses SOC registers directly
set(COMPONENT_REQUIRES app_update driver esp_event efuse pthread soc) #unfortunately rom/uart uses SOC registers directly
# driver is a public requirement because esp_sleep.h uses gpio_num_t & touch_pad_t
# app_update is added here because cpu_start.c uses esp_ota_get_app_description() function.
set(COMPONENT_PRIV_REQUIRES
app_trace app_update bootloader_support log mbedtls nvs_flash
pthread smartconfig_ack spi_flash vfs wpa_supplicant espcoredump esp_common esp_wifi)
smartconfig_ack spi_flash vfs wpa_supplicant espcoredump esp_common esp_wifi)
set(COMPONENT_ADD_LDFRAGMENTS linker.lf ld/esp32_fragments.lf)
register_component()
target_linker_script(${COMPONENT_TARGET} "${CMAKE_CURRENT_BINARY_DIR}/esp32_out.ld")
target_linker_script(${COMPONENT_LIB} "${CMAKE_CURRENT_BINARY_DIR}/esp32_out.ld")
# Rely on user code to define app_main
target_link_libraries(${COMPONENT_LIB} "-u app_main")
if(CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY)
# This has to be linked before esp32.project.ld
target_linker_script(${COMPONENT_TARGET} "ld/esp32.extram.bss.ld")
target_linker_script(${COMPONENT_LIB} "ld/esp32.extram.bss.ld")
endif()
if(IDF_PROJECT_EXECUTABLE)
# Process the template file through the linker script generation mechanism, and use the output for linking the
# final binary
set(esp32_project_script "${CMAKE_CURRENT_BINARY_DIR}/esp32.project.ld")
set(esp32_project_template "${CMAKE_CURRENT_LIST_DIR}/ld/esp32.project.ld.in")
# Process the template file through the linker script generation mechanism, and use the output for linking the
# final binary
target_linker_script(${COMPONENT_LIB} "${CMAKE_CURRENT_LIST_DIR}/ld/esp32.project.ld.in" PROCESS)
ldgen_process_template(${esp32_project_template} ${esp32_project_script})
target_link_libraries(${COMPONENT_TARGET} "-T ${esp32_project_script}")
set_property(TARGET ${IDF_PROJECT_EXECUTABLE} APPEND PROPERTY LINK_DEPENDS ${esp32_project_script})
endif()
target_linker_script(${COMPONENT_TARGET} "ld/esp32.peripherals.ld")
target_link_libraries(${COMPONENT_TARGET} gcc)
target_link_libraries(${COMPONENT_TARGET} "-u call_user_start_cpu0")
target_linker_script(${COMPONENT_LIB} "ld/esp32.peripherals.ld")
target_link_libraries(${COMPONENT_LIB} gcc)
target_link_libraries(${COMPONENT_LIB} "-u call_user_start_cpu0")
#ld_include_panic_highint_hdl is added as an undefined symbol because otherwise the
#linker will ignore panic_highint_hdl.S as it has no other files depending on any
#symbols in it.
target_link_libraries(${COMPONENT_TARGET} "-u ld_include_panic_highint_hdl")
target_link_libraries(${COMPONENT_LIB} "-u ld_include_panic_highint_hdl")
idf_build_get_property(sdkconfig_header SDKCONFIG_HEADER)
get_filename_component(config_dir ${sdkconfig_header} DIRECTORY)
# Preprocess esp32.ld linker script to include configuration, becomes esp32_out.ld
set(LD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ld)
add_custom_command(
OUTPUT esp32_out.ld
COMMAND "${CMAKE_C_COMPILER}" -C -P -x c -E -o esp32_out.ld -I ${CONFIG_DIR} ${LD_DIR}/esp32.ld
COMMAND "${CMAKE_C_COMPILER}" -C -P -x c -E -o esp32_out.ld -I ${config_dir} ${LD_DIR}/esp32.ld
MAIN_DEPENDENCY ${LD_DIR}/esp32.ld ${SDKCONFIG_H}
COMMENT "Generating linker script..."
VERBATIM)
add_custom_target(esp32_linker_script DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/esp32_out.ld)
add_dependencies(${COMPONENT_TARGET} esp32_linker_script)
# Enable dynamic esp_timer overflow value if building unit tests
if(esp32_test IN_LIST BUILD_TEST_COMPONENTS)
add_definitions(-DESP_TIMER_DYNAMIC_OVERFLOW_VAL)
endif()
add_dependencies(${COMPONENT_LIB} esp32_linker_script)
# disable stack protection in files which are involved in initialization of that feature
set_source_files_properties(

View file

@ -3,6 +3,19 @@ if(CONFIG_SPIRAM_CACHE_WORKAROUND)
# are not part of the ESP-IDF build system (for cases where a generic
# non-IDF CMakeLists.txt file is imported into a component) don't depend
# on the esp32 component so don't get the extra flag. This handles that case.
add_compile_options(-mfix-esp32-psram-cache-issue)
idf_build_set_property(COMPILE_OPTIONS "-mfix-esp32-psram-cache-issue" APPEND)
endif()
# Check toolchain is configured properly in cmake
if(NOT ( ${CMAKE_SYSTEM_NAME} STREQUAL "Generic" AND ${CMAKE_C_COMPILER} MATCHES xtensa))
message(FATAL_ERROR "Internal error, toolchain has not been set correctly by project "
"(or an invalid CMakeCache.txt file has been generated somehow)")
endif()
#
# Warn if the toolchain version doesn't match
#
# TODO: make these platform-specific for diff toolchains
get_expected_ctng_version(expected_toolchain expected_gcc)
gcc_version_check("${expected_gcc}")
crosstool_version_check("${expected_toolchain}")

View file

@ -7,9 +7,11 @@ register_component()
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test_tjpgd_logo.h"
COMMAND xxd -i "logo.jpg" "${CMAKE_CURRENT_BINARY_DIR}/test_tjpgd_logo.h"
WORKING_DIRECTORY ${COMPONENT_PATH}
WORKING_DIRECTORY ${COMPONENT_DIR}
DEPENDS "${CMAKE_CURRENT_LIST_DIR}/logo.jpg")
add_custom_target(esp32_test_logo DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/test_tjpgd_logo.h")
add_dependencies(${COMPONENT_TARGET} esp32_test_logo)
add_dependencies(${COMPONENT_LIB} esp32_test_logo)
idf_build_set_property(COMPILE_DEFINITIONS "-DESP_TIMER_DYNAMIC_OVERFLOW_VAL" APPEND)

View file

@ -4,6 +4,7 @@ if(BOOTLOADER_BUILD)
set(COMPONENT_REQUIRES ${IDF_COMPONENTS})
set(COMPONENT_SRCS )
register_component()
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-Wl,--gc-sections")
else()
# Regular app build
set(COMPONENT_SRCS
@ -26,4 +27,6 @@ else()
"src/stack_check.c"
PROPERTIES COMPILE_FLAGS
-fno-stack-protector)
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY LINK_LIBRARIES "-Wl,--gc-sections")
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-Wl,--gc-sections")
endif()

View file

@ -4,6 +4,12 @@ if(BOOTLOADER_BUILD)
set(COMPONENT_REQUIRES ${IDF_COMPONENTS})
set(COMPONENT_SRCS)
register_component()
set(scripts
"esp32/ld/esp32.rom.ld"
"esp32/ld/esp32.rom.newlib-funcs.ld"
"esp32/ld/esp32.rom.libgcc.ld"
)
target_linker_script(${COMPONENT_LIB} "${scripts}")
else()
# Regular app build
set(COMPONENT_SRCS "esp_rom.c")
@ -11,27 +17,32 @@ else()
register_component()
target_linker_script(${COMPONENT_TARGET}
"esp32/ld/esp32.rom.ld"
"esp32/ld/esp32.rom.libgcc.ld"
"esp32/ld/esp32.rom.syscalls.ld"
"esp32/ld/esp32.rom.newlib-data.ld")
set(scripts
"esp32/ld/esp32.rom.ld"
"esp32/ld/esp32.rom.libgcc.ld"
"esp32/ld/esp32.rom.syscalls.ld"
"esp32/ld/esp32.rom.newlib-data.ld"
)
target_linker_script(${COMPONENT_LIB} "${scripts}")
if(CONFIG_SPIRAM_CACHE_WORKAROUND)
target_compile_options(${COMPONENT_TARGET} PUBLIC -mfix-esp32-psram-cache-issue)
# Note: Adding as a PUBLIC compile option here causes this option to propagate to all components that depend on esp32.
#
# To handle some corner cases, the same flag is set in project_include.cmake
target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-issue)
else()
target_linker_script(${COMPONENT_TARGET} "esp32/ld/esp32.rom.newlib-funcs.ld")
target_linker_script(${COMPONENT_LIB} "esp32/ld/esp32.rom.newlib-funcs.ld")
endif()
if(CONFIG_NEWLIB_NANO_FORMAT)
target_linker_script(${COMPONENT_TARGET} "esp32/ld/esp32.rom.newlib-nano.ld")
target_linker_script(${COMPONENT_LIB} "esp32/ld/esp32.rom.newlib-nano.ld")
endif()
if(NOT GCC_NOT_5_2_0)
target_linker_script(${COMPONENT_TARGET} "esp32/ld/esp32.rom.newlib-locale.ld")
target_linker_script(${COMPONENT_LIB} "esp32/ld/esp32.rom.newlib-locale.ld")
endif()
if(NOT CONFIG_SPI_FLASH_ROM_DRIVER_PATCH)
target_linker_script(${COMPONENT_TARGET} "esp32/ld/esp32.rom.spiflash.ld")
target_linker_script(${COMPONENT_LIB} "esp32/ld/esp32.rom.spiflash.ld")
endif()
endif()

View file

@ -16,29 +16,31 @@ if(NOT CONFIG_NO_BLOBS)
endif()
register_component()
target_link_libraries(${COMPONENT_LIB} "-L ${CMAKE_CURRENT_SOURCE_DIR}/lib_${IDF_TARGET}")
if(NOT CONFIG_NO_BLOBS)
target_link_libraries(${COMPONENT_TARGET} "-L ${CMAKE_CURRENT_SOURCE_DIR}/lib_${IDF_TARGET}")
target_link_libraries(${COMPONENT_TARGET} coexist core espnow mesh net80211 phy pp rtc smartconfig wpa2 wpa wps)
target_link_libraries(${COMPONENT_LIB} "-L ${CMAKE_CURRENT_SOURCE_DIR}/lib_${IDF_TARGET}")
target_link_libraries(${COMPONENT_LIB} coexist core espnow mesh net80211 phy pp rtc smartconfig wpa2 wpa wps)
endif()
if(CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION AND IDF_BUILD_ARTIFACTS)
if(CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION)
idf_build_get_property(build_dir BUILD_DIR)
partition_table_get_partition_info(phy_partition_offset "--partition-type data --partition-subtype phy" "offset")
set(phy_init_data_bin "${IDF_BUILD_ARTIFACTS_DIR}/phy_init_data.bin")
set(phy_init_data_bin "${build_dir}/phy_init_data.bin")
# To get the phy_init_data.bin file, compile phy_init_data.h as a C file and then objcopy
# the object file to a raw binary
add_custom_command(
OUTPUT ${phy_init_data_bin}
DEPENDS ${CMAKE_CURRENT_LIST_DIR}/include/phy_init_data.h
DEPENDS ${CMAKE_CURRENT_LIST_DIR}/phy_init_data.h
COMMAND ${CMAKE_C_COMPILER} -x c -c
-I ${CMAKE_CURRENT_LIST_DIR} -I ${CMAKE_CURRENT_LIST_DIR}/include -I ${IDF_BUILD_ARTIFACTS_DIR}
-I ${CMAKE_CURRENT_LIST_DIR} -I ${CMAKE_CURRENT_LIST_DIR}/include -I ${build_dir}
-o phy_init_data.obj
${CMAKE_CURRENT_LIST_DIR}/include/phy_init_data.h
${CMAKE_CURRENT_LIST_DIR}/phy_init_data.h
COMMAND ${CMAKE_OBJCOPY} -O binary phy_init_data.obj ${phy_init_data_bin}
)
add_custom_target(phy_init_data ALL DEPENDS ${phy_init_data_bin})
add_dependencies(flash phy_init_data)
add_dependencies(app phy_init_data)
esptool_py_flash_project_args(phy ${phy_partition_offset} ${phy_init_data_bin} FLASH_IN_PROJECT)
endif()
endif()

View file

@ -5,20 +5,21 @@ set(COMPONENT_REQUIRES unity test_utils nvs_flash ulp esp_common)
register_component()
idf_build_get_property(idf_path IDF_PATH)
# Calculate MD5 value of header file esp_wifi_os_adapter.h
execute_process(COMMAND md5sum ${IDF_PATH}/components/esp_wifi/include/esp_private/wifi_os_adapter.h
execute_process(COMMAND md5sum ${idf_path}/components/esp_wifi/include/esp_wifi_os_adapter.h
COMMAND cut -c 1-7
OUTPUT_VARIABLE WIFI_OS_ADAPTER_MD5
OUTPUT_STRIP_TRAILING_WHITESPACE)
# Calculate MD5 value of header file esp_wifi_crypto_types.h
execute_process(COMMAND md5sum ${IDF_PATH}/components/esp_wifi/include/esp_wifi_crypto_types.h
execute_process(COMMAND md5sum ${idf_path}/components/esp_wifi/include/esp_wifi_crypto_types.h
COMMAND cut -c 1-7
OUTPUT_VARIABLE WIFI_CRYPTO_MD5
OUTPUT_STRIP_TRAILING_WHITESPACE)
# Calculate MD5 value of header file esp_coexist_adapter.h
execute_process(COMMAND md5sum ${IDF_PATH}/components/esp_wifi/include/esp_coexist_adapter.h
execute_process(COMMAND md5sum ${idf_path}/components/esp_wifi/include/esp_coexist_adapter.h
COMMAND cut -c 1-7
OUTPUT_VARIABLE COEX_ADAPTER_MD5
OUTPUT_STRIP_TRAILING_WHITESPACE)

View file

@ -1,6 +1,5 @@
set(COMPONENT_PRIV_INCLUDEDIRS "include_core_dump")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES)
set(COMPONENT_PRIV_REQUIRES spi_flash soc)
set(COMPONENT_ADD_LDFRAGMENTS linker.lf)
set(COMPONENT_SRCS "src/core_dump_common.c"

View file

@ -1,6 +1,6 @@
register_config_only_component()
set(COMPONENT_PRIV_REQUIRES bootloader)
register_component()
if(IDF_BUILD_ARTIFACTS)
string(REPLACE ";" " " ESPTOOLPY_FLASH_PROJECT_OPTIONS "${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS}")
set(ESPTOOLPY_FLASH_PROJECT_OPTIONS
"${ESPTOOLPY_FLASH_PROJECT_OPTIONS}"
@ -13,15 +13,27 @@ endif()
# Generate the flash project args and the flasher args json file using the accumulated values
# from esptool_py_flash_project_args calls. The file is first configured using configure_file() for all variable values,
# and then generated using file(GENERATE... for generator expressions.
configure_file(${COMPONENT_PATH}/flash_project_args.in
configure_file(${COMPONENT_DIR}/flash_project_args.in
${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in)
file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/flash_project_args
file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in2
INPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in)
file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/flash_project_args
INPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in2)
configure_file(${COMPONENT_PATH}/flasher_args.json.in
configure_file(${COMPONENT_DIR}/flasher_args.json.in
${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in)
file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/flasher_args.json
file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in2
INPUT ${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in)
endif()
file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/flasher_args.json
INPUT ${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in2)
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
"${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in"
"${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in2"
"${CMAKE_BINARY_DIR}/flash_project_args"
"${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in"
"${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in2"
"${CMAKE_BINARY_DIR}/flasher_args.json")

View file

@ -1,13 +1,10 @@
if(NOT IDF_BUILD_ARTIFACTS)
return()
endif()
# Set some global esptool.py variables
#
# Many of these are read when generating flash_app_args & flash_project_args
set(ESPTOOLPY ${PYTHON} "${CMAKE_CURRENT_LIST_DIR}/esptool/esptool.py" --chip esp32)
set(ESPSECUREPY ${PYTHON} "${CMAKE_CURRENT_LIST_DIR}/esptool/espsecure.py")
set(ESPEFUSEPY ${PYTHON} "${CMAKE_CURRENT_LIST_DIR}/esptool/espefuse.py")
idf_build_get_property(python PYTHON)
set(ESPTOOLPY ${python} "${CMAKE_CURRENT_LIST_DIR}/esptool/esptool.py" --chip esp32)
set(ESPSECUREPY ${python} "${CMAKE_CURRENT_LIST_DIR}/esptool/espsecure.py")
set(ESPEFUSEPY ${python} "${CMAKE_CURRENT_LIST_DIR}/esptool/espefuse.py")
set(ESPFLASHMODE ${CONFIG_ESPTOOLPY_FLASHMODE})
set(ESPFLASHFREQ ${CONFIG_ESPTOOLPY_FLASHFREQ})
@ -62,44 +59,51 @@ if(CONFIG_ESPTOOLPY_FLASHSIZE_DETECT)
set(ESPFLASHSIZE detect)
endif()
get_filename_component(IDF_PROJECT_NAME ${IDF_PROJECT_EXECUTABLE} NAME_WE)
idf_build_get_property(build_dir BUILD_DIR)
idf_build_get_property(elf_name EXECUTABLE_NAME GENERATOR_EXPRESSION)
idf_build_get_property(elf EXECUTABLE GENERATOR_EXPRESSION)
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES AND NOT BOOTLOADER_BUILD)
set(unsigned_project_binary "${IDF_PROJECT_NAME}-unsigned.bin")
set(unsigned_project_binary "${elf_name}-unsigned.bin")
else()
set(unsigned_project_binary "${IDF_PROJECT_NAME}.bin")
set(unsigned_project_binary "${elf_name}.bin")
endif()
set(PROJECT_BIN "${elf_name}.bin")
#
# Add 'app.bin' target - generates with elf2image
#
add_custom_command(OUTPUT "${IDF_BUILD_ARTIFACTS_DIR}/${unsigned_project_binary}"
add_custom_command(OUTPUT "${build_dir}/.app_hash"
COMMAND ${ESPTOOLPY} elf2image ${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS} ${ESPTOOLPY_ELF2IMAGE_OPTIONS}
-o "${IDF_BUILD_ARTIFACTS_DIR}/${unsigned_project_binary}" "${IDF_PROJECT_EXECUTABLE}"
DEPENDS ${IDF_PROJECT_EXECUTABLE}
-o "${build_dir}/${unsigned_project_binary}" "${elf}"
COMMAND ${CMAKE_COMMAND} -E md5sum "${build_dir}/${unsigned_project_binary}" > "${build_dir}/.app_hash"
DEPENDS ${elf}
VERBATIM
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
WORKING_DIRECTORY ${build_dir}
)
get_filename_component(IDF_PROJECT_BIN ${IDF_PROJECT_EXECUTABLE} NAME_WE)
set(IDF_PROJECT_BIN ${IDF_PROJECT_BIN}.bin)
add_custom_target(gen_project_binary DEPENDS "${build_dir}/.app_hash")
if(NOT BOOTLOADER_BUILD AND
CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
# for locally signed secure boot image, add a signing step to get from unsigned app to signed app
add_custom_target(gen_unsigned_project_binary ALL DEPENDS "${IDF_BUILD_ARTIFACTS_DIR}/${unsigned_project_binary}")
add_custom_command(OUTPUT "${IDF_BUILD_ARTIFACTS_DIR}/${IDF_PROJECT_BIN}"
add_custom_command(OUTPUT "${build_dir}/.signed_app_hash"
COMMAND ${ESPSECUREPY} sign_data --keyfile ${secure_boot_signing_key}
-o "${IDF_BUILD_ARTIFACTS_DIR}/${IDF_PROJECT_BIN}" "${IDF_BUILD_ARTIFACTS_DIR}/${unsigned_project_binary}"
DEPENDS gen_unsigned_project_binary
-o "${build_dir}/${PROJECT_BIN}" "${build_dir}/${unsigned_project_binary}"
COMMAND ${CMAKE_COMMAND} -E md5sum "${build_dir}/${PROJECT_BIN}" > "${build_dir}/.signed_app_hash"
DEPENDS "${build_dir}/.app_hash"
VERBATIM
)
add_custom_target(gen_signed_project_binary DEPENDS "${build_dir}/.signed_app_hash")
add_dependencies(gen_project_binary gen_signed_project_binary)
endif()
if(NOT BOOTLOADER_BUILD)
add_custom_target(app ALL DEPENDS "${IDF_BUILD_ARTIFACTS_DIR}/${IDF_PROJECT_BIN}")
add_custom_target(app ALL DEPENDS gen_project_binary)
else()
add_custom_target(bootloader ALL DEPENDS "${IDF_BUILD_ARTIFACTS_DIR}/${IDF_PROJECT_BIN}")
add_custom_target(bootloader ALL DEPENDS gen_project_binary)
endif()
if(NOT BOOTLOADER_BUILD AND
@ -109,7 +113,7 @@ if(NOT BOOTLOADER_BUILD AND
COMMAND ${CMAKE_COMMAND} -E echo
"App built but not signed. Sign app before flashing"
COMMAND ${CMAKE_COMMAND} -E echo
"\t${ESPSECUREPY} sign_data --keyfile KEYFILE ${IDF_BUILD_ARTIFACTS_DIR}/${IDF_PROJECT_BIN}"
"\t${ESPSECUREPY} sign_data --keyfile KEYFILE ${build_dir}/${elf_bin}"
VERBATIM)
endif()
@ -117,12 +121,13 @@ endif()
# Add 'flash' target - not all build systems can run this directly
#
function(esptool_py_custom_target target_name flasher_filename dependencies)
idf_build_get_property(idf_path IDF_PATH)
add_custom_target(${target_name} DEPENDS ${dependencies}
COMMAND ${CMAKE_COMMAND}
-D IDF_PATH="${IDF_PATH}"
-D IDF_PATH="${idf_path}"
-D ESPTOOLPY="${ESPTOOLPY}"
-D ESPTOOL_ARGS="write_flash;@flash_${flasher_filename}_args"
-D ESPTOOL_WORKING_DIR="${IDF_BUILD_ARTIFACTS_DIR}"
-D ESPTOOL_WORKING_DIR="${build_dir}"
-P run_esptool.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
USES_TERMINAL
@ -142,8 +147,9 @@ function(esptool_py_flash_project_args entry offset image)
set(options FLASH_IN_PROJECT) # flash the image when flashing the project
set(single_value FLASH_FILE_TEMPLATE) # template file to use to be able to
# flash the image individually using esptool
cmake_parse_arguments(flash_entry "${options}" "${single_value}" "" "${ARGN}")
cmake_parse_arguments(_ "${options}" "${single_value}" "" "${ARGN}")
idf_build_get_property(build_dir BUILD_DIR)
get_property(flash_project_entries TARGET flash_project_args_target PROPERTY FLASH_PROJECT_ENTRIES)
if(${entry} IN_LIST flash_project_entries)
@ -156,14 +162,16 @@ function(esptool_py_flash_project_args entry offset image)
file(RELATIVE_PATH image ${CMAKE_BINARY_DIR} ${image})
# Generate the standalone flash file to flash the image individually using esptool
set(entry_flash_args ${IDF_BUILD_ARTIFACTS_DIR}/flash_${entry}_args)
if(NOT flash_entry_FLASH_FILE_TEMPLATE)
set(entry_flash_args ${build_dir}/flash_${entry}_args)
if(NOT __FLASH_FILE_TEMPLATE)
file(GENERATE OUTPUT ${entry_flash_args} CONTENT "${offset} ${image}")
else()
configure_file(${flash_entry_FLASH_FILE_TEMPLATE} ${entry_flash_args})
get_filename_component(template "${__FLASH_FILE_TEMPLATE}" ABSOLUTE)
file(GENERATE OUTPUT ${entry_flash_args} INPUT ${template})
endif()
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${entry_flash_args})
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${entry_flash_args})
# Generate standalone entries in the flasher args json file
get_property(flash_project_args_entry_json TARGET
@ -174,7 +182,7 @@ function(esptool_py_flash_project_args entry offset image)
PROPERTY FLASH_PROJECT_ARGS_ENTRY_JSON "${flash_project_args_entry_json}")
# Generate entries in the flasher args json file
if(flash_entry_FLASH_IN_PROJECT)
if(__FLASH_IN_PROJECT)
get_property(flash_project_args TARGET flash_project_args_target PROPERTY FLASH_PROJECT_ARGS)
list(APPEND flash_project_args "${offset} ${image}")
set_property(TARGET flash_project_args_target PROPERTY FLASH_PROJECT_ARGS "${flash_project_args}")

View file

@ -5,15 +5,12 @@ set(COMPONENT_SRCS "expat/expat/lib/loadlibrary.c"
"expat/expat/lib/xmltok.c"
"expat/expat/lib/xmltok_impl.c"
"expat/expat/lib/xmltok_ns.c")
set(COMPONENT_REQUIRES)
register_component()
component_compile_definitions(HAVE_EXPAT_CONFIG_H)
component_compile_definitions(HAVE_GETRANDOM)
target_compile_definitions(${COMPONENT_LIB} PRIVATE HAVE_EXPAT_CONFIG_H)
target_compile_definitions(${COMPONENT_LIB} PRIVATE HAVE_GETRANDOM)
# Temporary suppress "fallthrough" warnings until they are fixed in expat repo
if(GCC_NOT_5_2_0)
component_compile_options(-Wno-implicit-fallthrough)
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-implicit-fallthrough)
endif()

View file

@ -1,7 +1,5 @@
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(COMPONENT_SRCS "common/esp_modbus_master.c"
"common/esp_modbus_slave.c"
"modbus/mb.c"

View file

@ -25,7 +25,7 @@ set(COMPONENT_ADD_LDFRAGMENTS linker.lf)
register_component()
target_link_libraries(${COMPONENT_TARGET} "-Wl,--undefined=uxTopUsedPriority")
target_link_libraries(${COMPONENT_LIB} "-Wl,--undefined=uxTopUsedPriority")
set_source_files_properties(
tasks.c

View file

@ -16,9 +16,7 @@ endif()
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_ADD_LDFRAGMENTS linker.lf)
set(COMPONENT_REQUIRES "")
set(COMPONENT_PRIV_REQUIRES soc)
register_component()
if(CONFIG_HEAP_TRACING)
@ -34,7 +32,7 @@ if(CONFIG_HEAP_TRACING)
heap_caps_realloc_default)
foreach(wrap ${WRAP_FUNCTIONS})
target_link_libraries(${COMPONENT_TARGET} "-Wl,--wrap=${wrap}")
target_link_libraries(${COMPONENT_LIB} "-Wl,--wrap=${wrap}")
endforeach()
endif()

View file

@ -1,3 +1,2 @@
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES)
register_component()

View file

@ -1,6 +1,3 @@
set(COMPONENT_SRCS "src/jsmn.c")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES "")
register_component()

View file

@ -2,7 +2,4 @@ set(COMPONENT_SRCS "cJSON/cJSON.c"
"cJSON/cJSON_Utils.c"
"cJSON/test.c")
set(COMPONENT_ADD_INCLUDEDIRS cJSON)
set(COMPONENT_REQUIRES "")
register_component()

View file

@ -1,7 +1,4 @@
set(SRC libsodium/src/libsodium)
set(COMPONENT_REQUIRES "mbedtls")
# Derived from libsodium/src/libsodium/Makefile.am
# (ignoring the !MINIMAL set)
set(COMPONENT_SRCS "${SRC}/crypto_aead/chacha20poly1305/sodium/aead_chacha20poly1305.c"
@ -129,9 +126,10 @@ endif()
set(COMPONENT_ADD_INCLUDEDIRS ${SRC}/include port_include)
set(COMPONENT_PRIV_INCLUDEDIRS ${SRC}/include/sodium port_include/sodium port)
set(COMPONENT_REQUIRES mbedtls vfs)
register_component()
component_compile_definitions(
target_compile_definitions(${COMPONENT_LIB} PRIVATE
CONFIGURED
NATIVE_LITTLE_ENDIAN
HAVE_WEAK_SYMBOLS

View file

@ -1,5 +1,4 @@
set(COMPONENT_SRCS "log.c")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES)
set(COMPONENT_PRIV_REQUIRES soc)
register_component()

View file

@ -130,7 +130,7 @@ set(COMPONENT_ADD_LDFRAGMENTS linker.lf)
register_component()
# lots of LWIP source files evaluate macros that check address of stack variables
component_compile_options(-Wno-address)
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-address)
if(GCC_NOT_5_2_0)
set_source_files_properties(

View file

@ -18,7 +18,7 @@ function(project)
endfunction()
# Needed to for include_next includes to work from within mbedtls
include_directories("${COMPONENT_PATH}/port/include")
include_directories("${COMPONENT_DIR}/port/include")
# Workaround issue with creating symbolic links due to issues with native
# path conversion (TO_NATIVE_PATH). The following summarizes what CMake invocations
@ -46,20 +46,21 @@ if(CMAKE_HOST_WIN32)
"mbedtls/scripts")
foreach(target_link ${target_links})
file(TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR}/${target_link} link)
file(TO_NATIVE_PATH ${COMPONENT_PATH}/${target_link} target)
file(TO_NATIVE_PATH ${COMPONENT_DIR}/${target_link} target)
idf_build_get_property(python PYTHON)
if(NOT EXISTS ${link})
if (IS_DIRECTORY ${target})
set(command ${PYTHON} ${COMPONENT_PATH}/mklink.py /j ${link} ${target})
if(IS_DIRECTORY ${target})
set(command ${python} ${COMPONENT_DIR}/mklink.py /j ${link} ${target})
else()
set(command ${PYTHON} ${COMPONENT_PATH}/mklink.py /h ${link} ${target})
set(command ${python} ${COMPONENT_DIR}/mklink.py /h ${link} ${target})
endif()
execute_process(COMMAND ${command}
RESULT_VARIABLE result
ERROR_VARIABLE output)
if (NOT ${result} EQUAL 0)
if(NOT ${result} EQUAL 0)
message(FATAL_ERROR "Could not create symbolic link for: ${target} --> ${output}")
endif()
endif()
@ -78,37 +79,26 @@ set_property(TARGET mbedtls PROPERTY SOURCES ${src_tls})
set(mbedtls_targets mbedtls mbedcrypto mbedx509)
# Add port files to mbedtls targets
target_sources(mbedtls PRIVATE "${COMPONENT_PATH}/port/esp_bignum.c"
"${COMPONENT_PATH}/port/esp_hardware.c"
"${COMPONENT_PATH}/port/esp_mem.c"
target_sources(mbedtls PRIVATE "${COMPONENT_DIR}/port/esp_bignum.c"
"${COMPONENT_DIR}/port/esp_hardware.c"
"${COMPONENT_PATH}/port/esp_sha.c"
"${COMPONENT_PATH}/port/esp_sha1.c"
"${COMPONENT_PATH}/port/esp_sha256.c"
"${COMPONENT_PATH}/port/esp_sha512.c"
"${COMPONENT_PATH}/port/mbedtls_debug.c"
"${COMPONENT_PATH}/port/net_sockets.c"
"${COMPONENT_PATH}/port/esp32/aes.c"
"${COMPONENT_PATH}/port/esp32/sha.c")
"${COMPONENT_DIR}/port/esp_sha1.c"
"${COMPONENT_DIR}/port/esp_sha256.c"
"${COMPONENT_DIR}/port/esp_sha512.c"
"${COMPONENT_DIR}/port/mbedtls_debug.c"
"${COMPONENT_DIR}/port/net_sockets.c"
"${COMPONENT_DIR}/port/esp32/aes.c"
"${COMPONENT_DIR}/port/esp32/sha.c")
target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/esp_mem.c")
foreach(target ${mbedtls_targets})
# Propagate compile options to mbedtls library targets
target_include_directories(${target} PRIVATE "${IDF_INCLUDE_DIRECTORIES}")
target_compile_options(${target} PRIVATE "${IDF_COMPILE_OPTIONS};${IDF_C_COMPILE_OPTIONS}")
target_compile_definitions(${target} PRIVATE "${IDF_COMPILE_DEFINITIONS}")
target_compile_definitions(${target} PUBLIC -DMBEDTLS_CONFIG_FILE="mbedtls/esp_config.h")
# The mbedtls targets also depends on core components
foreach(common ${MBEDTLS_PRIV_REQUIRES})
component_get_target(common_target ${common})
set_property(TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${common_target})
set_property(TARGET ${target} APPEND PROPERTY LINK_LIBRARIES ${common_target})
endforeach()
endforeach()
# Link mbedtls libraries to component library
target_link_libraries(${COMPONENT_TARGET} ${mbedtls_targets})
target_link_libraries(${COMPONENT_LIB} ${mbedtls_targets})
# Catch usage of deprecated mbedTLS functions when building tests
if(mbedtls_test IN_LIST BUILD_TEST_COMPONENTS)
add_definitions(-DMBEDTLS_DEPRECATED_WARNING)
endif()
endif()

View file

@ -63,12 +63,21 @@ list(APPEND COMPONENT_ADD_LDFRAGMENTS newlib.lf)
register_component()
if (LIB_PATH)
target_link_libraries(${COMPONENT_TARGET} "-L ${LIB_PATH}")
target_link_libraries(${COMPONENT_LIB} "-L ${LIB_PATH}")
endif()
if(GCC_NOT_5_2_0)
# Toolchain libraries require code defined in this component
add_library(extra INTERFACE)
idf_component_get_property(newlib newlib COMPONENT_LIB)
target_link_libraries(extra INTERFACE ${LIBC} ${LIBM} "$<TARGET_FILE:${newlib}>")
target_link_libraries(${COMPONENT_LIB} extra)
else()
target_link_libraries(${COMPONENT_LIB} ${LIBC} ${LIBM})
endif()
target_link_libraries(${COMPONENT_TARGET} ${LIBC} ${LIBM})
set_source_files_properties(heap.c PROPERTIES COMPILE_FLAGS -fno-builtin)
if(EXTRA_LINK_FLAGS)
target_link_libraries(${COMPONENT_TARGET} "${EXTRA_LINK_FLAGS}")
target_link_libraries(${COMPONENT_LIB} "${EXTRA_LINK_FLAGS}")
endif()

View file

@ -1,6 +1,8 @@
register_config_only_component()
if(NOT BOOTLOADER_BUILD AND IDF_BUILD_ARTIFACTS)
if(BOOTLOADER_BUILD)
return()
endif()
set(partition_csv "${PARTITION_CSV_PATH}")
@ -28,28 +30,31 @@ else()
set(partition_secure_opt "")
endif()
add_custom_command(OUTPUT "${IDF_BUILD_ARTIFACTS_DIR}/partition_table/${unsigned_partition_bin}"
COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/gen_esp32part.py"
idf_build_get_property(build_dir BUILD_DIR)
idf_build_get_property(python PYTHON)
add_custom_command(OUTPUT "${build_dir}/partition_table/${unsigned_partition_bin}"
COMMAND "${python}" "${CMAKE_CURRENT_SOURCE_DIR}/gen_esp32part.py"
-q --offset ${PARTITION_TABLE_OFFSET} ${md5_opt} ${flashsize_opt}
${partition_secure_opt} ${partition_csv} ${IDF_BUILD_ARTIFACTS_DIR}/partition_table/${unsigned_partition_bin}
${partition_secure_opt} ${partition_csv} ${build_dir}/partition_table/${unsigned_partition_bin}
DEPENDS ${partition_csv} "${CMAKE_CURRENT_SOURCE_DIR}/gen_esp32part.py"
VERBATIM)
# Add signing steps
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
add_custom_target(gen_unsigned_partition_bin ALL DEPENDS
"${IDF_BUILD_ARTIFACTS_DIR}/partition_table/${unsigned_partition_bin}")
"${build_dir}/partition_table/${unsigned_partition_bin}")
add_custom_command(OUTPUT "${IDF_BUILD_ARTIFACTS_DIR}/partition_table/${final_partition_bin}"
add_custom_command(OUTPUT "${build_dir}/partition_table/${final_partition_bin}"
COMMAND ${ESPSECUREPY} sign_data --keyfile "${secure_boot_signing_key}"
-o "${IDF_BUILD_ARTIFACTS_DIR}/partition_table/${final_partition_bin}"
"${IDF_BUILD_ARTIFACTS_DIR}/partition_table/${unsigned_partition_bin}"
DEPENDS "${IDF_BUILD_ARTIFACTS_DIR}/partition_table/${unsigned_partition_bin}"
-o "${build_dir}/partition_table/${final_partition_bin}"
"${build_dir}/partition_table/${unsigned_partition_bin}"
DEPENDS "${build_dir}/partition_table/${unsigned_partition_bin}"
VERBATIM)
endif()
if(EXISTS ${partition_csv})
add_custom_target(partition_table ALL DEPENDS "${IDF_BUILD_ARTIFACTS_DIR}/partition_table/${final_partition_bin}")
add_custom_target(partition_table ALL DEPENDS "${build_dir}/partition_table/${final_partition_bin}")
else()
# If the partition input CSV is not found, create a phony partition_table target that
# fails the build. fail_at_build_time also touches CMakeCache.txt to cause a cmake run next time
@ -86,15 +91,12 @@ add_dependencies(app partition_table)
# the list of esptool write arguments for flashing
set_property(GLOBAL APPEND_STRING PROPERTY
ESPTOOL_WRITE_FLASH_ARGS
"${PARTITION_TABLE_OFFSET} ${IDF_BUILD_ARTIFACTS_DIR}/partition_table/${final_partition_bin} ")
"${PARTITION_TABLE_OFFSET} ${build_dir}/partition_table/${final_partition_bin} ")
esptool_py_flash_project_args(partition_table ${PARTITION_TABLE_OFFSET}
${IDF_BUILD_ARTIFACTS_DIR}/partition_table/partition-table.bin FLASH_IN_PROJECT)
${build_dir}/partition_table/partition-table.bin FLASH_IN_PROJECT)
if (NOT BOOTLOADER_BUILD)
partition_table_get_partition_info(app_partition_offset "--partition-boot-default" "offset")
esptool_py_flash_project_args(app ${app_partition_offset} ${CMAKE_BINARY_DIR}/${IDF_PROJECT_BIN} FLASH_IN_PROJECT)
endif()
partition_table_get_partition_info(app_partition_offset "--partition-boot-default" "offset")
esptool_py_flash_project_args(app ${app_partition_offset} ${build_dir}/${PROJECT_BIN} FLASH_IN_PROJECT)
endif()

View file

@ -1,38 +1,42 @@
if(NOT BOOTLOADER_BUILD)
set(PARTITION_TABLE_OFFSET ${CONFIG_PARTITION_TABLE_OFFSET})
set(PARTITION_TABLE_OFFSET ${CONFIG_PARTITION_TABLE_OFFSET})
# Set PARTITION_CSV_PATH to the configured partition CSV file
# absolute path
if(CONFIG_PARTITION_TABLE_CUSTOM)
# Custom filename expands any path relative to the project
get_filename_component(PARTITION_CSV_PATH "${CONFIG_PARTITION_TABLE_FILENAME}"
ABSOLUTE BASE_DIR "${IDF_PROJECT_PATH}")
# Set PARTITION_CSV_PATH to the configured partition CSV file
# absolute path
if(CONFIG_PARTITION_TABLE_CUSTOM)
idf_build_get_property(project_dir PROJECT_DIR)
# Custom filename expands any path relative to the project
get_filename_component(PARTITION_CSV_PATH "${CONFIG_PARTITION_TABLE_FILENAME}"
ABSOLUTE BASE_DIR "${project_dir}")
if(NOT EXISTS "${PARTITION_CSV_PATH}")
message(WARNING "Partition table CSV file ${PARTITION_CSV_PATH} not found. "
"Change custom partition CSV path in menuconfig.")
# Note: partition_table CMakeLists.txt contains some logic to create a dummy
# partition_table target in this case, see comments in that file.
if(NOT EXISTS "${PARTITION_CSV_PATH}")
message(WARNING "Partition table CSV file ${PARTITION_CSV_PATH} not found. "
"Change custom partition CSV path in menuconfig.")
# Note: partition_table CMakeLists.txt contains some logic to create a dummy
# partition_table target in this case, see comments in that file.
endif()
else()
# Other .csv files are always in the component directory
get_filename_component(PARTITION_CSV_PATH "${COMPONENT_DIR}/${CONFIG_PARTITION_TABLE_FILENAME}" ABSOLUTE)
if(NOT EXISTS "${PARTITION_CSV_PATH}")
message(FATAL_ERROR "Internal error, built-in ${PARTITION_CSV_PATH} not found.")
endif()
endif()
else()
# Other .csv files are always in the component directory
get_filename_component(PARTITION_CSV_PATH "${COMPONENT_PATH}/${CONFIG_PARTITION_TABLE_FILENAME}" ABSOLUTE)
if(NOT EXISTS "${PARTITION_CSV_PATH}")
message(FATAL_ERROR "Internal error, built-in ${PARTITION_CSV_PATH} not found.")
endif()
# need to re-run CMake if the partition CSV changes, as the offsets/sizes of partitions may change
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${PARTITION_CSV_PATH})
endif()
# need to re-run CMake if the partition CSV changes, as the offsets/sizes of partitions may change
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${PARTITION_CSV_PATH})
# partition_table_get_partition_info
#
# Get information about a partition from the partition table
function(partition_table_get_partition_info result get_part_info_args part_info)
idf_build_get_property(python PYTHON)
idf_build_get_property(idf_path IDF_PATH)
separate_arguments(get_part_info_args)
execute_process(COMMAND ${PYTHON}
${IDF_PATH}/components/partition_table/parttool.py -q
execute_process(COMMAND ${python}
${idf_path}/components/partition_table/parttool.py -q
--partition-table-offset ${PARTITION_TABLE_OFFSET}
--partition-table-file ${PARTITION_CSV_PATH}
${get_part_info_args} get_partition_info --info ${part_info}
@ -45,5 +49,3 @@ function(partition_table_get_partition_info result get_part_info_args part_info)
endif()
set(${result} ${info} PARENT_SCOPE)
endfunction()
endif()

View file

@ -2,9 +2,8 @@ set(COMPONENT_SRCS "pthread.c"
"pthread_cond_var.c"
"pthread_local_storage.c")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES)
register_component()
if(CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK)
target_link_libraries(${COMPONENT_TARGET} "-Wl,--wrap=vPortCleanUpTCB")
target_link_libraries(${COMPONENT_LIB} "-Wl,--wrap=vPortCleanUpTCB")
endif()

View file

@ -1,11 +1,11 @@
set(SOC_NAME ${IDF_TARGET})
idf_build_get_property(soc_name IDF_TARGET)
if(EXISTS "${COMPONENT_PATH}/${SOC_NAME}")
include(${COMPONENT_PATH}/${SOC_NAME}/sources.cmake)
if(EXISTS "${COMPONENT_DIR}/${soc_name}")
include(${COMPONENT_DIR}/${soc_name}/sources.cmake)
spaces2list(SOC_SRCS)
add_prefix(COMPONENT_SRCS "${SOC_NAME}/" ${SOC_SRCS})
set(COMPONENT_ADD_INCLUDEDIRS ${SOC_NAME}/include)
add_prefix(COMPONENT_SRCS "${soc_name}/" ${SOC_SRCS})
set(COMPONENT_ADD_INCLUDEDIRS ${soc_name}/include)
endif()
list(APPEND COMPONENT_ADD_INCLUDEDIRS include)

View file

@ -1,8 +1,8 @@
set(SOC_NAME ${IDF_TARGET})
set(SOC_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../${SOC_NAME}/test)
if(EXISTS "${SOC_TEST_DIR}")
set(COMPONENT_SRCDIRS "${SOC_TEST_DIR}")
set(COMPONENT_ADD_INCLUDEDIRS "${SOC_TEST_DIR}")
idf_build_get_property(soc_name IDF_TARGET)
get_filename_component(soc_test "${CMAKE_CURRENT_SOURCE_DIR}/../${soc_name}/test" ABSOLUTE)
if(EXISTS "${soc_test}")
set(COMPONENT_SRCS "${soc_test}")
set(COMPONENT_ADD_INCLUDEDIRS "${soc_test}")
endif()
set(COMPONENT_REQUIRES unity test_utils)

View file

@ -9,12 +9,11 @@ else()
"flash_ops.c"
"partition.c"
"spi_flash_rom_patch.c")
set(COMPONENT_PRIV_REQUIRES bootloader_support app_update soc)
set(COMPONENT_REQUIRES app_update)
set(COMPONENT_PRIV_REQUIRES bootloader_support soc)
endif()
set(COMPONENT_ADD_INCLUDEDIRS include)
set(COMPONENT_REQUIRES)
set(COMPONENT_ADD_LDFRAGMENTS linker.lf)
register_component()

View file

@ -6,7 +6,8 @@ function(spiffs_create_partition_image partition base_dir)
set(options FLASH_IN_PROJECT)
cmake_parse_arguments(arg "${options}" "" "" "${ARGN}")
set(spiffsgen_py ${PYTHON} ${IDF_PATH}/components/spiffs/spiffsgen.py)
idf_build_get_property(idf_path IDF_PATH)
set(spiffsgen_py ${PYTHON} ${idf_path}/components/spiffs/spiffsgen.py)
get_filename_component(base_dir_full_path ${base_dir} ABSOLUTE)

View file

@ -1,7 +1,4 @@
set(COMPONENT_SRCS "ulp.c"
"ulp_macro.c")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES)
register_component()

View file

@ -38,7 +38,7 @@ foreach(include ${COMPONENT_INCLUDES})
endforeach()
list(APPEND ULP_PREPROCESSOR_ARGS ${component_includes})
list(APPEND ULP_PREPROCESSOR_ARGS -I${COMPONENT_PATH})
list(APPEND ULP_PREPROCESSOR_ARGS -I${COMPONENT_DIR})
list(APPEND ULP_PREPROCESSOR_ARGS -I${sdkconfig_dir})
include_directories(${component_includes})

View file

@ -25,19 +25,23 @@ if(NOT CMAKE_BUILD_EARLY_EXPANSION)
# the external ULP project. This is a workaround to the bug https://public.kitware.com/Bug/view.php?id=16137.
string(REPLACE ";" "|" ulp_s_sources "${ulp_s_sources}")
idf_build_get_property(sdkconfig_header SDKCONFIG_HEADER)
idf_build_get_property(idf_path IDF_PATH)
idf_build_get_property(python PYTHON)
externalproject_add(${ULP_APP_NAME}
SOURCE_DIR ${IDF_PATH}/components/ulp/cmake
SOURCE_DIR ${idf_path}/components/ulp/cmake
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${ULP_APP_NAME}
INSTALL_COMMAND ""
CMAKE_ARGS -DCMAKE_GENERATOR=${CMAKE_GENERATOR}
-DCMAKE_TOOLCHAIN_FILE=${IDF_PATH}/components/ulp/cmake/toolchain-ulp.cmake
-DCMAKE_TOOLCHAIN_FILE=${idf_path}/components/ulp/cmake/toolchain-ulp.cmake
-DULP_S_SOURCES=${ulp_s_sources} -DULP_APP_NAME=${ULP_APP_NAME}
-DCOMPONENT_PATH=${COMPONENT_PATH}
-DCOMPONENT_DIR=${COMPONENT_DIR}
# Even though this resolves to a ';' separated list, this is fine. This must be special behavior
# for generator expressions.
-DCOMPONENT_INCLUDES=$<TARGET_PROPERTY:${COMPONENT_TARGET},INTERFACE_INCLUDE_DIRECTORIES>
-DIDF_PATH=${IDF_PATH}
-DSDKCONFIG=${SDKCONFIG_HEADER}
-DCOMPONENT_INCLUDES=$<TARGET_PROPERTY:${COMPONENT_LIB},INTERFACE_INCLUDE_DIRECTORIES>
-DIDF_PATH=${idf_path}
-DSDKCONFIG=${sdkconfig_header}
-DPYTHON=${python}
BUILD_COMMAND ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/${ULP_APP_NAME} --target build
BUILD_BYPRODUCTS ${ulp_artifacts} ${ulp_artifacts_extras} ${ulp_ps_sources}
${CMAKE_CURRENT_BINARY_DIR}/${ULP_APP_NAME}/${ULP_APP_NAME}
@ -52,8 +56,8 @@ if(NOT CMAKE_BUILD_EARLY_EXPANSION)
add_custom_target(${ULP_APP_NAME}_artifacts DEPENDS ${ULP_APP_NAME})
add_dependencies(${COMPONENT_TARGET} ${ULP_APP_NAME}_artifacts)
add_dependencies(${COMPONENT_LIB} ${ULP_APP_NAME}_artifacts)
target_linker_script(${COMPONENT_TARGET} ${CMAKE_CURRENT_BINARY_DIR}/${ULP_APP_NAME}/${ULP_APP_NAME}.ld)
target_add_binary_data(${COMPONENT_TARGET} ${CMAKE_CURRENT_BINARY_DIR}/${ULP_APP_NAME}/${ULP_APP_NAME}.bin BINARY)
target_linker_script(${COMPONENT_LIB} ${CMAKE_CURRENT_BINARY_DIR}/${ULP_APP_NAME}/${ULP_APP_NAME}.ld)
target_add_binary_data(${COMPONENT_LIB} ${CMAKE_CURRENT_BINARY_DIR}/${ULP_APP_NAME}/${ULP_APP_NAME}.bin BINARY)
endif()

View file

@ -8,4 +8,5 @@ register_component()
set(ULP_APP_NAME ulp_test_app)
set(ULP_S_SOURCES "ulp/test_jumps.S")
set(ULP_EXP_DEP_SRCS "test_ulp_as.c")
include(${IDF_PATH}/components/ulp/component_ulp_common.cmake)
idf_build_get_property(idf_path IDF_PATH)
include(${idf_path}/components/ulp/component_ulp_common.cmake)

View file

@ -14,10 +14,10 @@ endif()
register_component()
target_compile_definitions(${COMPONENT_TARGET} PUBLIC
target_compile_definitions(${COMPONENT_LIB} PUBLIC
-DUNITY_INCLUDE_CONFIG_H
)
if(GCC_NOT_5_2_0)
component_compile_options(-Wno-unused-const-variable)
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-const-variable)
endif()

View file

@ -2,7 +2,4 @@ set(COMPONENT_SRCS "vfs.c"
"vfs_uart.c"
"vfs_semihost.c")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES)
register_component()

View file

@ -79,8 +79,8 @@ set(COMPONENT_PRIV_REQUIRES mbedtls)
register_component()
component_compile_options(-Wno-strict-aliasing)
component_compile_definitions(
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-strict-aliasing)
target_compile_definitions(${COMPONENT_LIB} PRIVATE
__ets__
EMBEDDED_SUPP
IEEE8021X_EAPOL

View file

@ -7,4 +7,4 @@ set(COMPONENT_PRIV_REQUIRES soc)
register_component()
target_link_libraries(${COMPONENT_TARGET} "${CMAKE_CURRENT_SOURCE_DIR}/${IDF_TARGET}/libhal.a")
target_link_libraries(${COMPONENT_LIB} "${CMAKE_CURRENT_SOURCE_DIR}/${IDF_TARGET}/libhal.a")

View file

@ -224,7 +224,6 @@ Project CMakeLists File
Each project has a single top-level ``CMakeLists.txt`` file that contains build settings for the entire project. By default, the project CMakeLists can be quite minimal.
Minimal Example CMakeLists
--------------------------
@ -254,10 +253,9 @@ Optional Project Variables
These variables all have default values that can be overridden for custom behaviour. Look in :idf_file:`/tools/cmake/project.cmake` for all of the implementation details.
- ``COMPONENT_DIRS``: Directories to search for components. Defaults to `${IDF_PATH}/components`, `${PROJECT_PATH}/components`, and ``EXTRA_COMPONENT_DIRS``. Override this variable if you don't want to search for components in these places.
- ``EXTRA_COMPONENT_DIRS``: 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 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 ``COMPONENT_REQUIRES`` will automatically have it added to this list, so the ``COMPONENTS`` list can be very short.
- ``COMPONENT_REQUIRES_COMMON``: A list of components that every component requires. These components are automatically added to every component's ``COMPONENT_PRIV_REQUIRES`` list and also the project's ``COMPONENTS`` list. By default, this variable is set to the minimal set of core "system" components needed for any ESP-IDF project. Usually, you would not change this variable in your project.
- ``COMPONENT_DIRS``,``COMPONENTS_DIRS``: Directories to search for components. Defaults to `IDF_PATH/components`, `PROJECT_DIR/components`, and ``EXTRA_COMPONENT_DIRS``. Override this variable if you don't want to search for components in these places.
- ``EXTRA_COMPONENT_DIRS``, ``EXTRA_COMPONENTS_DIRS``: 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 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.
Any paths in these variables can be absolute paths, or set relative to the project directory.
@ -269,19 +267,17 @@ 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_PATH}/main`. All other components in the build are also added as its dependencies,
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-scences heavy lifting, requiring the user to specify the location of the newly renamed component
and manually specifying its dependencies. Specifically, the steps to renaming ``main`` are as follows:
1. Rename ``main`` directory.
2. Set ``EXTRA_COMPONENT_DIRS`` in the project CMakeLists.txt to include the renamed ``main`` directory.
3. Specify the dependencies in the renamed component's CMakeLists.txt file via ``COMPONENT_REQUIRES`` or ``COMPONENT_PRIV_REQUIRES``.
3. Specify the dependencies in the renamed component's CMakeLists.txt file via REQUIRES or PRIV_REQUIRES arguments :ref:`on component registration<cmake_minimal_component_cmakelists>`.
.. _component-directories-cmake:
Component CMakeLists Files
==========================
@ -304,23 +300,27 @@ contain component sub-directories with the same name, the component in the last
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.
.. _cmake_minimal_component_cmakelists:
Minimal Component CMakeLists
----------------------------
.. highlight:: cmake
The minimal component ``CMakeLists.txt`` file is as follows::
The minimal component ``CMakeLists.txt`` file simply registers the component to the build system using ``idf_component_register``::
set(COMPONENT_SRCS "foo.c")
set(COMPONENT_ADD_INCLUDEDIRS "include")
register_component()
idf_component_register(SRCS "foo.c" "bar.c"
INCLUDE_DIRS "include")
- ``COMPONENT_SRCS`` is a (space-separated) list of source files (``*.c``, ``*.cpp``, ``*.cc``, ``*.S``). These source files will be compiled into the component library.
- ``COMPONENT_ADD_INCLUDEDIRS`` is a (space-separated) list of directories to add to the global include search path for any component which requires this component, and also the main source files.
- ``register_component()`` is required to add the component (using the variables set above) to the build. A library with the name of the component will be built and linked into the final app. If this step is skipped (perhaps due to use of a CMake `if function <cmake if_>`_ or similar), this component will not be part of the build.
- ``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.
A library with the name of the component will be built and linked into the final app.
Directories are usually specified relative to the ``CMakeLists.txt`` file itself, although they can be absolute.
There are other arguments that can be passed to ``idf_component_register``. These arguments
are discussed :ref:`here<cmake-component-register>`.
See `example component CMakeLists`_ for more complete component ``CMakeLists.txt`` examples.
.. _component variables:
@ -330,71 +330,44 @@ Preset Component Variables
The following component-specific variables are available for use inside component CMakeLists, but should not be modified:
- ``COMPONENT_PATH``: The component directory. Evaluates to the absolute path of the directory containing ``CMakeLists.txt``. The component path cannot contain spaces. This is the same as the ``CMAKE_CURRENT_SOURCE_DIR`` variable.
- ``COMPONENT_DIR``: The component directory. Evaluates to the absolute path of the directory containing ``CMakeLists.txt``. 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_TARGET``: Name of the library target created internally by the build system for the component.
- ``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.
The following variables are set at the project level, but available for use in component CMakeLists:
- ``PROJECT_NAME``: Name of the project, as set in project CMakeLists.txt file.
- ``PROJECT_PATH``: Absolute path of the project directory containing the project CMakeLists. Same as the ``CMAKE_SOURCE_DIR`` variable.
- ``COMPONENTS``: Names of all components that are included in this build, formatted as a semicolon-delimited CMake list.
- ``CONFIG_*``: Each value in the project configuration has a corresponding variable available in cmake. All names begin with ``CONFIG_``. :doc:`More information here </api-reference/kconfig>`.
- ``ESP_PLATFORM``: Set to 1 when the CMake file is processed within 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 CMakeLists.txt:
- ``PROJECT_NAME``: Name of the project, as set in project CMakeLists.txt file.
- ``PROJECT_DIR``: Absolute path of the project directory containing the project CMakeLists. Same as the ``CMAKE_SOURCE_DIR`` variable.
- ``COMPONENTS``: Names of all components that are included in this build, formatted as a semicolon-delimited CMake list.
- ``IDF_VER``: Git version of ESP-IDF (produced by ``git describe``)
- ``IDF_TARGET``: Name of the target for which the project is being built.
- ``PROJECT_VER``: Project version.
* If ``PROJECT_VER`` variable is set in project CMakeLists.txt file, its value will be used.
* Else, if the ``$(PROJECT_PATH}/version.txt`` exists, its contents will be used as ``PROJECT_VER``.
* Else, if the ``PROJECT_DIR/version.txt`` exists, its contents will be used as ``PROJECT_VER``.
* Else, if the project is located inside a Git repository, the output of git describe will be used.
* Otherwise, ``PROJECT_VER`` will be "1".
- ``ESP_PLATFORM``: Set to 1 whenever the ESP-IDF build system is being used.
If you modify any of these variables inside ``CMakeLists.txt`` then this will not prevent other components from building but it may make your component hard to build and/or debug.
- ``COMPONENT_ADD_INCLUDEDIRS``: Paths, relative to the component directory, which will be added to the include search path for
all other components which require this one. If an include directory is only needed to compile this specific component,
add it to ``COMPONENT_PRIV_INCLUDEDIRS`` instead.
- ``COMPONENT_REQUIRES`` is a (space-separated) list of components that are required to include this project's header files into other components. If this component has a header file in a ``COMPONENT_ADD_INCLUDEDIRS`` directory that includes a header from another component, that component should be listed in ``COMPONENT_REQUIRES``. Requirements are recursive.
The ``COMPONENT_REQUIRES`` list can be empty because some very common components (like newlib for libc, freertos for RTOS functions, etc) are always required by all components. This list is found in the project-level variable ``COMPONENT_REQUIRES_COMMON``.
If a component only requires another component's headers to compile its source files (not for including this component's headers), then these components should be listed in ``COMPONENT_PRIV_REQUIRES`` instead.
See `Component Requirements`_ for more details.
Optional Component-Specific Variables
-------------------------------------
The following variables can be set inside ``CMakeLists.txt`` to control the build of that component:
- ``COMPONENT_PRIV_INCLUDEDIRS``: 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.
- ``COMPONENT_PRIV_REQUIRES`` is a (space-separated) list of components that are required to either compile or link this component's source files. These components' header paths do not propagate to other components which require it, they are only used to compile this component's sources. See `Component Requirements`_ for more details.
- ``COMPONENT_SRCS``: Paths to individual source files to compile as part of the component. This is the recommended way of adding source files to the build.
- ``COMPONENT_SRCDIRS``: Directory paths, must be relative to the component directory, which will be searched for source files (``*.cpp``,
``*.c``, ``*.S``). Source files are globbed from the listed directories and compiled as part of the component in place of ``COMPONENT_SRCS``, i.e. setting this will cause ``COMPONENT_SRCS`` to be ignored.
This can be a convenient way of including source files to the components en masse, but is generally not recommended due to caveats attached to CMake globbing (see `File Globbing & Incremental Builds`).
- ``COMPONENT_SRCEXCLUDE``: Paths to source files to exclude from component. Can be set in conjunction with ``COMPONENT_SRCDIRS`` if there is a directory with a large number of source files to include in the component but one or more source files which should not be. Paths can be specified relative to the component directory or absolute.
- ``COMPONENT_ADD_LDFRAGMENTS``: Paths to linker fragment files for the linker script generation functionality. See :doc:`Linker Script Generation <linker-script-generation>`.
.. note::
If you don't set ``COMPONENT_SRCDIRS`` or ``COMPONENT_SRCS``, your component won't compile a library but it may still add include paths for use when compiling other components.
Other build properties are listed :ref:`here<cmake-build-properties>`.
Controlling Component Compilation
---------------------------------
.. highlight:: cmake
To pass compiler options when compiling source files belonging to a particular component, use the ``component_compile_options`` function::
To pass compiler options when compiling source files belonging to a particular component, use the ``target_compile_options`` function::
component_compile_options(-Wno-unused-variable)
This is a wrapper around the CMake `target_compile_options`_ command.
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-variable)
To apply the compilation flags to a single source file, use the CMake `set_source_files_properties`_ command::
@ -405,7 +378,7 @@ To apply the compilation flags to a single source file, use the CMake `set_sourc
This can be useful if there is upstream code that emits warnings.
When using these commands, place them after the ``register_component()`` line in the component CMakeLists file.
When using these commands, place them after the call to ``idf_component_register`` in the component CMakeLists file.
.. _component-configuration-cmake:
@ -434,22 +407,23 @@ Component Requirements
When compiling each component, the ESP-IDF build system recursively evaluates its components.
Each component's source file is compiled with these include path directories:
Each component's source file is compiled with these include path directories, as specified in the passed arguments
to ``idf_component_register``:
- The current component's ``COMPONENT_ADD_INCLUDEDIRS`` and ``COMPONENT_PRIV_INCLUDEDIRS``.
- The ``COMPONENT_ADD_INCLUDEDIRS`` set by all components in the current component's ``COMPONENT_REQUIRES`` and ``COMPONENT_PRIV_REQUIRES`` variables (ie all the current component's public and private dependencies).
- All of the ``COMPONENT_REQUIRES`` of those components, evaluated recursively (ie all public dependencies of this component's dependencies, recursively expanded).
- The current component's ``INCLUDE_DIRS`` and ``PRIV_INCLUDE_DIRS``.
- The ``INCLUDE_DIRS`` set by all components in the current component's ``REQUIRES`` and ``PRIV_REQUIRES`` variables (ie all the current component's public and private dependencies).
- All of the ``REQUIRES`` of those components, evaluated recursively (ie all public dependencies of this component's dependencies, recursively expanded).
When writing a component
------------------------
- ``COMPONENT_REQUIRES`` should be set to all components whose header files are #included from the *public* header files of this component.
- ``COMPONENT_PRIV_REQUIRES`` should be set to all components whose header files are #included from *any source files* of this component, unless already listed in ``COMPONENT_REQUIRES``. Or any component which is required to be linked in order for this component to function correctly.
- ``COMPONENT_REQUIRES`` and/or ``COMPONENT_PRIV_REQUIRES`` should be set before calling ``register_component()``.
- The values of ``COMPONENT_REQUIRES`` and ``COMPONENT_PRIV_REQUIRES`` should not depend on any configuration choices (``CONFIG_xxx`` macros). This is because requirements are expanded before configuration is loaded. Other component variables (like include paths or source files) can depend on configuration choices.
- ``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* of this component, unless already listed in ``COMPONENT_REQUIRES``. Or any component which is required to be linked in order for this component to function correctly.
- ``REQUIRES`` and/or ``PRIV_REQUIRES`` should be set before calling ``idf_component_register()``.
- The values of ``REQUIRES`` and ``PRIV_REQUIRES`` should not depend on any configuration choices (``CONFIG_xxx`` macros). This is because requirements are expanded before configuration is loaded. Other component variables (like include paths or source files) can depend on configuration choices.
- Not setting either or both ``REQUIRES`` variables is fine. If the component has no requirements except for the "common" components needed for RTOS, libc, etc (``COMPONENT_REQUIRES_COMMON``) then both variables can be empty or unset.
Components which support only some targets (values of ``IDF_TARGET``) may call ``require_idf_targets(NAMES...)`` CMake function to express these requirements. In this case the build system will generate an error if the component is included into the build, but does not support selected target.
Components which support only some targets (values of ``IDF_TARGET``) may 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 into the build, but does not support selected target.
When creating a project
-----------------------
@ -508,7 +482,7 @@ The custom ``project()`` function performs the following steps:
- Declares the actual cmake-level project by calling the `CMake project function <cmake project_>`_.
- Loads the git version. This includes some magic which will automatically re-run CMake if a new revision is checked out in git. See `File Globbing & Incremental Builds`_.
- Includes :ref:`project_include.cmake` files from any components which have them.
- Adds each component to the build. Each component CMakeLists file calls ``register_component``, calls the CMake `add_library <cmake add_library_>`_ function to add a library and then adds source files, compile options, etc.
- Adds each component to the build. Each component CMakeLists file calls ``idf_component_register``, calls the CMake `add_library <cmake add_library_>`_ function to add a library and then adds source files, compile options, etc.
- Adds the final app executable to the build.
- Goes back and adds inter-component dependencies between components (ie adding the public header directories of each component to each other component).
@ -546,7 +520,7 @@ component directory. This CMake file is included when ``project.cmake`` is evalu
``project_include.cmake`` files are used inside ESP-IDF, for defining project-wide build features such as ``esptool.py`` command line arguments and the ``bootloader`` "special app".
Unlike component ``CMakeLists.txt`` 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_PATH`` for the absolute directory of the component.
Unlike component ``CMakeLists.txt`` 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 customised via the ``CMakeLists.txt`` file itself. See `Optional Project Variables`_ for details.
@ -566,9 +540,8 @@ Take care when adding configuration values in this file, as they will be include
Configuration-Only Components
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Special components which contain no source files, only ``Kconfig.projbuild`` and ``KConfig``, can have a one-line ``CMakeLists.txt`` file which calls the function ``register_config_only_component()``. This function will include the component in the project build, but no library will be built *and* no header files will be added to any include paths.
If a CMakeLists.txt file doesn't call ``register_component()`` or ``register_config_only_component()``, it will be excluded from the project entirely. This may sometimes be desirable, depending on the project configuration.
Special components which contain no source files, only ``Kconfig.projbuild`` and ``KConfig``, can have a one-line ``CMakeLists.txt`` file which calls the function ``idf_component_register()`` with no
arguments specified. This function will include the component in the project build, but no library will be built *and* no header files will be added to any include paths.
Example Component CMakeLists
============================
@ -661,14 +634,14 @@ tool called bmp2h. The header file is then included in as C source
file called graphics_lib.c::
add_custom_command(OUTPUT logo.h
COMMAND bmp2h -i ${COMPONENT_PATH}/logo.bmp -o log.h
DEPENDS ${COMPONENT_PATH}/logo.bmp
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_TARGET} logo)
add_dependencies(${COMPONENT_LIB} logo)
set_property(DIRECTORY "${COMPONENT_PATH}" APPEND PROPERTY
set_property(DIRECTORY "${COMPONENT_DIR}" APPEND PROPERTY
ADDITIONAL_MAKE_CLEAN_FILES logo.h)
This answer is adapted from the `CMake FAQ entry <cmake faq generated files_>`_, which contains some other examples that will also work with ESP-IDF builds.
@ -681,23 +654,28 @@ it is added to the `ADDITIONAL_MAKE_CLEAN_FILES`_ property.
.. note::
If generating files as part of the project CMakeLists.txt file, not a component CMakeLists.txt, then use ``${PROJECT_PATH}`` instead of ``${COMPONENT_PATH}`` and ``${PROJECT_NAME}.elf`` instead of ``${COMPONENT_TARGET}``.)
If generating files as part of the project CMakeLists.txt file, not a component CMakeLists.txt, 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.
.. _cmake_embed_data:
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 C source.
You can set a variable ``COMPONENT_EMBED_FILES`` in your component's CMakeLists, giving space-delimited names of the files to embed::
You can specify argument ``COMPONENT_EMBED_FILES`` in the component registration, giving space-delimited names of the files to embed::
idf_component_register(...
EMBED_FILES server_root_cert.der)
set(COMPONENT_EMBED_FILES server_root_cert.der)
Or if the file is a string, you can use the variable ``COMPONENT_EMBED_TXTFILES``. This will embed the contents of the text file as a null-terminated string::
set(COMPONENT_EMBED_TXTFILES server_root_cert.pem)
idf_component_register(...
EMBED_TXTFILES server_root_cert.pem)
.. highlight:: c
@ -742,8 +720,8 @@ the ESP-IDF build system entirely by using a CMake feature called ExternalProjec
# External build process for quirc, runs in source dir and
# produces libquirc.a
externalproject_add(quirc_build
PREFIX ${COMPONENT_PATH}
SOURCE_DIR ${COMPONENT_PATH}/quirc
PREFIX ${COMPONENT_DIR}
SOURCE_DIR ${COMPONENT_DIR}/quirc
CONFIGURE_COMMAND ""
BUILD_IN_SOURCE 1
BUILD_COMMAND make CC=${CMAKE_C_COMPILER} libquirc.a
@ -756,12 +734,12 @@ the ESP-IDF build system entirely by using a CMake feature called ExternalProjec
add_dependencies(quirc quirc_build)
set_target_properties(quirc PROPERTIES IMPORTED_LOCATION
${COMPONENT_PATH}/quirc/libquirc.a)
${COMPONENT_DIR}/quirc/libquirc.a)
set_target_properties(quirc PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
${COMPONENT_PATH}/quirc/lib)
${COMPONENT_DIR}/quirc/lib)
set_directory_properties( PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES
"${COMPONENT_PATH}/quirc/libquirc.a")
"${COMPONENT_DIR}/quirc/libquirc.a")
(The above CMakeLists.txt can be used to create a component named ``quirc`` that builds the quirc_ project using its own Makefile.)
@ -882,7 +860,7 @@ not yet be provided by a component, or use another library for the same function
Importing a library might look like this for a hypothetical library ``foo`` to be used in the ``main`` component::
# Register the component
register_component()
idf_component_register()
# Set values of hypothetical variables that control the build of `foo`
set(FOO_BUILD_STATIC OFF)
@ -891,11 +869,6 @@ Importing a library might look like this for a hypothetical library ``foo`` to b
# Create and import the library targets
add_subdirectory(foo)
# Propagate IDF-wide compile settings/definitions/options to `foo`
target_include_directories(foo ${IDF_INCLUDE_DIRECTORIES})
target_compile_options(foo ${IDF_COMPILE_OPTIONS})
target_compile_definitions(foo ${IDF_COMPILE_DEFINITIONS})
# Link `foo` to `main` component
target_link_libraries(main foo)
@ -913,56 +886,241 @@ Using ESP-IDF in Custom CMake Projects
======================================
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 one. In these cases it is desirable to be able to consume IDF components
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).
.. highlight:: cmake
It is possible to do so by using the :ref:`build system APIs provided<cmake_buildsystem_api>` by :idf_file:`tools/cmake/idf.cmake`. For example:
It is possible to do so by using functions ``idf_import_components``
and ``idf_link_components`` provided provided by :idf_file:`tools/cmake/idf_functions.cmake`. For example::
.. code-block:: cmake
cmake_minimum_required(VERSION 3.5)
project(my_custom_app C)
# The source file main.c contains app_main() definition
# Include CMake file that provides ESP-IDF CMake build system APIs.
include($ENV{IDF_PATH}/tools/cmake/idf.cmake)
# Include ESP-IDF components in the build, may be thought as an equivalent of
# add_subdirectory() but with some additional procesing and magic for ESP-IDF build
# specific build processes.
idf_build_process(esp32)
# 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)
# Provides idf_import_components and idf_link_components
include($ENV{IDF_PATH}/tools/cmake/idf_functions.cmake)
# Do some configuration for idf_import_components. This enables creation of artifacts (which might not be
# needed) for some projects
set(IDF_BUILD_ARTIFACTS ON)
set(IDF_PROJECT_EXECUTABLE ${CMAKE_PROJECT_NAME}.elf)
set(IDF_BUILD_ARTIFACTS_DIR ${CMAKE_BINARY_DIR})
# Wraps add_subdirectory() to create library targets for components, and then `return` them using the given variable.
# In this case the variable is named `component`
idf_import_components(components $ENV{IDF_PATH} esp-idf)
# Wraps target_link_libraries() to link processed components by idf_import_components to target
idf_link_components(${CMAKE_PROJECT_NAME}.elf "${components}")
The snippet above includes all of the components in the ESP-IDF directory and uses KConfig defaults.
It also builds artifacts (partition table, project information json files, bootloader, etc.). There are also other build
parameters which can be set, the full list of which is as follows:
- ``IDF_BUILD_ARTIFACTS``: Build artifacts such as bootloader, partition table binary file, partition binaries, project information json typically needed for flashing binaries to the target chip. Requires ``IDF_PROJECT_EXECUTABLE`` and ``IDF_BUILD_ARTIFACTS_DIR`` to be set as well.
- ``IDF_PROJECT_EXECUTABLE``: Name of the final executable file. This parameter is needed for creating some of the artifacts.
- ``IDF_BUILD_ARTIFACTS_DIR``: Location where created artifacts are to be placed.
- ``IDF_EXTRA_COMPONENTS_DIR``: Locations to search for components in aside from the :idf:`default components directory <components>`
- ``IDF_COMPONENTS``: A list of components to import. Use this to trim down the imported components to only what is needed for faster builds. If not set, all components found from the default components directory as well as ``IDF_EXTRA_COMPONENTS_DIR`` (if specified) are imported. Note that dependencies of components in this list (other than ``IDF_COMPONENT_REQUIRES_COMMON``) will also get pulled into the build.
- ``IDF_COMPONENT_REQUIRES_COMMON``: List of components that every component requires. Components in this list (and their dependencies) are imported regardless of the value of ``IDF_COMPONENTS``. By default, this variable is set to the minimal set of core "system" components.
- ``IDF_SDKCONFIG_DEFAULTS``: Path to the configuration override file. If unset, components are built with default configurations.
- ``IDF_BUILD_TESTS``: Include component tests in the build. By default, all component tests are included. The component tests are filtered using ``IDF_TEST_COMPONENTS`` and ``IDF_TEST_EXCLUDE_COMPONENTS``.
- ``IDF_TEST_COMPONENTS``: If ``IDF_BUILD_TESTS`` is set, only component tests in this list will be included in the build. Ignored if ``IDF_BUILD_TESTS`` is not set.
- ``IDF_TEST_EXCLUDE_COMPONENTS``: If ``IDF_BUILD_TESTS`` is set, component tests in this list will not be included in the build. Ignored if ``IDF_BUILD_TESTS`` is not set. This variable takes precedence over ``IDF_TEST_COMPONENTS``. This means that a component test in this list will not be included in the build even if it is also present in ``IDF_TEST_COMPONENTS``.
# Let the build system know what the project executable is to attach more targets, dependencies, etc.
idf_build_executable(${CMAKE_PROJECT_NAME}.elf)
The example in :example:`build_system/cmake/idf_as_lib` demonstrates the creation of an application equivalent to :example:`hello world application <get-started/hello_world>`
using a custom CMake project.
.. note:: The IDF build system can only set compiler flags for source files that it builds. When an external CMakeLists.txt file is used and PSRAM is enabled, remember to add ``-mfix-esp32-psram-cache-issue`` to the C compiler arguments. See :ref:`CONFIG_SPIRAM_CACHE_WORKAROUND` for details of this flag.
.. _cmake_buildsystem_api:
ESP-IDF CMake Build System API
==============================
idf-build-commands
------------------
.. code-block:: none
idf_build_get_property(var property [GENERATOR_EXPRESSION])
Retrieve a :ref:`build property<cmake-build-properties>` *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.
.. code-block:: none
idf_build_set_property(property val [APPEND])
Set a :ref:`build property<cmake-build-properties>` *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.
.. code-block:: none
idf_build_component(component_dir)
Add a directory *component_dir* that contains a component to the build.
.. code-block:: none
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:
- PROJECT_DIR - directory of the project; defaults to CMAKE_SOURCE_DIR
- PROJECT_NAME - name of the project; defaults to CMAKE_PROJECT_NAME
- PROJECT_VER - version/revision of the project; defaults to "0.0.0"
- SDKCONFIG - output path of generated sdkconfig file; defaults to PROJECT_DIR/sdkconfig or CMAKE_SOURCE_DIR/sdkconfig depending if PROJECT_DIR is set
- SDKCONFIG_DEFAULTS - defaults file to use for the build; defaults to empty
- BUILD_DIR - directory to place ESP-IDF build-related artifacts, such as generated binaries, text files, components; defaults to CMAKE_BINARY_DIR
- COMPONENTS - starting components for trimming the build; components not in the list are automatically if they are required in the expanded dependency tree
.. code-block:: none
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``.
.. code-block:: none
idf_build_get_config(var config [GENERATOR_EXPRESSION])
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.
.. _cmake-build-properties:
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:
.. code-block: cmake
idf_build_get_property(python PYTHON)
message(STATUS "The Python intepreter is: ${python}")
- BUILD_DIR - build directory; set from ``idf_build_process`` BUILD_DIR argument
- BUILD_COMPONENTS - list of components (more specifically, component aliases) included in the build; set by ``idf_build_process``
- C_COMPILE_OPTIONS - compile options applied to all components' C source files
- COMPILE_OPTIONS - compile options applied to all components' source files, regardless of it being C or C++
- COMPILE_DEFINITIONS - compile definitions applied to all component source files
- CXX_COMPILE_OPTIONS - compile options applied to all components' C++ source files
- EXECUTABLE - project executable; set by call to ``idf_build_executable``
- EXECUTABLE_NAME - name of project executable without extension; set by call to ``idf_build_executable``
- IDF_PATH - ESP-IDF path; set from IDF_PATH environment variable, if not, inferred from the location of ``idf.cmake``
- 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
- KCONFIGS - list of Kconfig files found in components in build; set by ``idf_build_process``
- KCONFIG_PROJBUILDS - list of Kconfig.projbuild diles found in components in build; set by ``idf_build_process``
- 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 - full path to config defaults file; 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_CMAKE - full path to CMake file containing component configuration; set by ``idf_build_process``
- SDKCONFIG_JSON - full path to JSON 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
----------------------
.. code-block:: none
idf_component_get_property(var component property [GENERATOR_EXPRESSION])
Retrieve a specified *component*'s :ref:`component property<cmake-component-properties>`, *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.
.. code-block:: none
idf_component_set_property(property val [APPEND])
Set a specified *component*'s :ref:`component property<cmake-component-properties>`, *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.
.. _cmake-component-register:
.. code-block:: none
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 ...]
[EMBED_TXTFILES file1 file2 ...])
Register a component to the build system. Much like the ``project()`` CMake command, this should be called from the component's
CMakeLists.txt 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 are not valid in CMake script mode
- custom commands defined in project_include.cmake
- build system API commands except ``idf_build_get_property``; although consider whether the property may not have been set yet
Commands that set and operate on variables are generally okay to call before ``idf_component_register``.
The arguments for ``idf_component_register`` include:
- 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 :ref:`limitations of globbing in CMake<cmake-file-globbing>`. 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
The following are used for :ref:`embedding data into the component<cmake_embed_data>`, 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:
- EMBED_FILES - binary files to be embedded in the component
- EMBED_TXTFILES - text files to be embedded in the component
.. _cmake-component-properties:
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:
.. code-block: cmake
idf_component_get_property(dir freertos COMPONENT_DIR)
message(STATUS "The 'freertos' component directory is: ${dir}")
- 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``
- COMPONENT_LIB - name for created component static/interface library; set by ``idf_build_component`` and library itself
is created by ``idf_component_register``
- COMPONENT_NAME - name of the component; set by ``idf_build_component`` based on the component directory name
- COMPONENT_TYPE - type of the component, whether LIBRARY or CONFIG_ONLY. A component is of type LIBRARY if it specifies
source files or embeds a file
- EMBED_FILES - list of files to embed in component; set from ``idf_component_register`` EMBED_FILES argument
- EMBED_TXTFILES - list of text files to embed in component; set from ``idf_component_register`` 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``
- KCONFIG_PROJBUILD - component Kconfig.projbuild; set by ``idf_build_component``
- LDFRAGMENTS - list of component linker fragment files; set from ``idf_component_register`` LDFRAGMENTS argument
- PRIV_INCLUDE_DIRS - list of component private include directories; set from ``idf_component_register`` PRIV_INCLUDE_DIRS on components of type LIBRARY
- PRIV_REQUIRES - list of private component dependentices; set from ``idf_component_register`` PRIV_REQUIRES argument
- REQUIRED_IDF_TARGETS - list of targets the component supports; set from ``idf_component_register`` EMBED_TXTFILES argument
- REQUIRES - list of public component dependencies; set from ``idf_component_register`` REQUIRES argument
- SRCS - list of component source files; set from SRCS or SRC_DIRS/EXCLUDE_SRCS argument of ``idf_component_register``
.. _cmake-file-globbing:
@ -971,13 +1129,15 @@ File Globbing & Incremental Builds
.. highlight:: cmake
The preferred way to include source files in an ESP-IDF component is to list them manually in COMPONENT_SRCS::
The preferred way to include source files in an ESP-IDF component is to list them manually via SRCS argument to ``idf_component_register``::
set(COMPONENT_SRCS library/a.c library/b.c platform/platform.c)
idf_component_register(SRCS library/a.c library/b.c platform/platform.c
...)
This preference reflects the `CMake best practice <https://gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1/>`_ 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 ``COMPONENT_SRCDIRS``::
This preference reflects the `CMake best practice <https://gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1/>`_ 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``::
set(COMPONENT_SRCDIRS library platform)
idf_component_register(SRC_DIRS library platform
...)
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.

View file

@ -59,13 +59,17 @@ fragment file. The path can either be an absolute path or a relative path from t
CMake
"""""
In the component's ``CMakeLists.txt`` file, set the variable ``COMPONENT_ADD_LDFRAGMENTS`` to the path of the created linker
fragment file before the ``register_component`` call. The path can either be an absolute path or a relative path from the component directory.
In the component's ``CMakeLists.txt`` file, specify argument ``LDFRAGMENTS`` in the ``idf_component_register`` call.
The value of ``LDFRAGMENTS`` can either be an absolute path or a relative path from the component directory to the
created linker fragment file.
.. code-block:: cmake
set(COMPONENT_ADD_LDFRAGMENTS "my_linker_fragment_file.lf")
register_component()
# file paths relative to CMakeLists.txt
idf_component_register(...
LDFRAGMENTS "path/to/linker_fragment_file.lf" "path/to/another_linker_fragment_file.lf"
...
)
Specifying placements

View file

@ -37,12 +37,9 @@ Overall, the minimal ``test`` subdirectory CMakeLists.txt file may look like as
.. code:: cmake
set(COMPONENT_SRCDIRS ".")
set(COMPONENT_ADD_INCLUDEDIRS ".")
set(COMPONENT_REQUIRES unity)
register_component()
idf_component_register(SRC_DIRS "."
INCLUDE_DIRS "."
REQUIRES unity)
See http://www.throwtheswitch.org/unity for more information about writing tests in Unity.

View file

@ -357,9 +357,9 @@ ESP-IDF 在搜索所有待构建的组件时,会按照 ``COMPONENT_DIRS`` 指
.. highlight:: cmake
在编译特定组件的源文件时,可以使用 ``component_compile_options`` 命令来传递编译器选项::
在编译特定组件的源文件时,可以使用 ``target_compile_options`` 命令来传递编译器选项::
component_compile_options(-Wno-unused-variable)
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-variable)
这条命令封装了 CMake 的 `target_compile_options`_ 命令。
@ -628,14 +628,14 @@ CMake 文件可以使用 ``IDF_TARGET`` 变量来获取当前的硬件目标。
有些组件的源文件可能并不是由组件本身提供,而必须从另外的文件生成。假设组件需要一个头文件,该文件由 BMP 文件转换后(使用 bmp2h 工具)的二进制数据组成,然后将头文件包含在名为 graphics_lib.c 的文件中::
add_custom_command(OUTPUT logo.h
COMMAND bmp2h -i ${COMPONENT_PATH}/logo.bmp -o log.h
DEPENDS ${COMPONENT_PATH}/logo.bmp
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_TARGET} logo)
add_dependencies(${COMPONENT_LIB} logo)
set_property(DIRECTORY "${COMPONENT_PATH}" APPEND PROPERTY
set_property(DIRECTORY "${COMPONENT_DIR}" APPEND PROPERTY
ADDITIONAL_MAKE_CLEAN_FILES logo.h)
这个示例改编自 `CMake 的一则 FAQ <cmake faq generated files_>`_,其中还包含了一些同样适用于 ESP-IDF 构建系统的示例。
@ -644,7 +644,7 @@ CMake 文件可以使用 ``IDF_TARGET`` 变量来获取当前的硬件目标。
.. Note::
如果需要生成文件作为项目 CMakeLists.txt 的一部分,而不是作为组件 CMakeLists.txt 的一部分,此时需要使用 ``${PROJECT_PATH}`` 替代 ``${COMPONENT_PATH}``,使用 ``${PROJECT_NAME}.elf`` 替代 ``${COMPONENT_TARGET}``
如果需要生成文件作为项目 CMakeLists.txt 的一部分,而不是作为组件 CMakeLists.txt 的一部分,此时需要使用 ``${PROJECT_PATH}`` 替代 ``${COMPONENT_DIR}``,使用 ``${PROJECT_NAME}.elf`` 替代 ``${COMPONENT_LIB}``
如果某个源文件是从其他组件中生成,且包含 ``logo.h`` 文件,则需要调用 ``add_dependencies`` 在这两个组件之间添加一个依赖项,以确保组件源文件按照正确顺序进行编译。
@ -694,8 +694,8 @@ ESP-IDF 还支持自动生成链接脚本,它允许组件通过链接片段文
# 用于 quirc 的外部构建过程,在源目录中运行并生成 libquirc.a
externalproject_add(quirc_build
PREFIX ${COMPONENT_PATH}
SOURCE_DIR ${COMPONENT_PATH}/quirc
PREFIX ${COMPONENT_DIR}
SOURCE_DIR ${COMPONENT_DIR}/quirc
CONFIGURE_COMMAND ""
BUILD_IN_SOURCE 1
BUILD_COMMAND make CC=${CMAKE_C_COMPILER} libquirc.a
@ -707,12 +707,12 @@ ESP-IDF 还支持自动生成链接脚本,它允许组件通过链接片段文
add_dependencies(quirc quirc_build)
set_target_properties(quirc PROPERTIES IMPORTED_LOCATION
${COMPONENT_PATH}/quirc/libquirc.a)
${COMPONENT_DIR}/quirc/libquirc.a)
set_target_properties(quirc PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
${COMPONENT_PATH}/quirc/lib)
${COMPONENT_DIR}/quirc/lib)
set_directory_properties( PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES
"${COMPONENT_PATH}/quirc/libquirc.a")
"${COMPONENT_DIR}/quirc/libquirc.a")
(上述 CMakeLists.txt 可用于创建名为 ``quirc`` 的组件,该组件使用自己的 Makefile 构建 quirc_ 项目。)

View file

@ -7,5 +7,5 @@ set(COMPONENT_ADD_INCLUDEDIRS ".")
register_component()
if(GCC_NOT_5_2_0)
component_compile_options(-Wno-unused-const-variable)
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-const-variable)
endif()

View file

@ -1,24 +1,38 @@
cmake_minimum_required(VERSION 3.5)
project(idf_as_lib C)
# The source file main.c contains app_main() definition
add_executable(${CMAKE_PROJECT_NAME}.elf main.c)
if("${TARGET}" STREQUAL "esp32")
# Include for ESP-IDF build system functions
include($ENV{IDF_PATH}/tools/cmake/idf.cmake)
# Create idf::esp32 and idf::freertos static libraries
idf_build_process(esp32
# try and trim the build; additional components
# will be included as needed based on dependency tree
#
# although esptool_py does not generate static library,
# processing the component is needed for flashing related
# targets and file generation
COMPONENTS esp32 freertos esptool_py
SDKCONFIG ${CMAKE_BINARY_DIR}/sdkconfig
BUILD_DIR ${CMAKE_BINARY_DIR})
else()
# Create stubs for esp32 and freertos, stub::esp32 and stub::freertos
add_subdirectory(stubs/esp32)
add_subdirectory(stubs/freertos)
add_subdirectory(stubs/spi_flash)
endif()
# Provides idf_import_components() and idf_link_components()
include($ENV{IDF_PATH}/tools/cmake/idf_functions.cmake)
set(elf_file ${CMAKE_PROJECT_NAME}.elf)
add_executable(${elf_file} main.c)
# Create artifacts used for flashing the project to target chip
set(IDF_BUILD_ARTIFACTS ON)
set(IDF_PROJECT_EXECUTABLE ${CMAKE_PROJECT_NAME}.elf)
set(IDF_BUILD_ARTIFACTS_DIR ${CMAKE_BINARY_DIR})
# Link the static libraries to the executable
if("${TARGET}" STREQUAL "esp32")
target_link_libraries(${elf_file} idf::esp32 idf::freertos idf::spi_flash)
# Attach additional targets to the executable file for flashing,
# linker script generation, partition_table generation, etc.
idf_build_executable(${elf_file})
else()
target_link_libraries(${elf_file} stub::esp32 stub::freertos stub::spi_flash)
endif()
# Trim down components included in the build. Although freertos and spi_flash are the ones needed by the application
# itself, the bootloader and esptool_py components are also needed in order to create the artifacts to be used
# for flashing to the target chip
set(IDF_COMPONENTS freertos spi_flash bootloader esptool_py)
# Wraps add_subdirectory() to create library targets for components, and then return them using the specified variable
idf_import_components(components $ENV{IDF_PATH} esp-idf)
# Wraps target_link_libraries() to link processed components by idf_import_components to target
idf_link_components(${CMAKE_PROJECT_NAME}.elf "${components}")
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)

View file

@ -1,13 +1,17 @@
# Using ESP-IDF in Custom CMake Projects
This example illustrates using ESP-IDF components as libraries in custom CMake projects. This builds
an equivalent application to the `hello_world` example under `examples/get-started/hello_world`.
This example illustrates using ESP-IDF components as libraries in custom CMake projects. The application
in this example can run on either host or on an ESP32, and the appropriate libraries are linked
to the executable depending on which target is specified. If the target is an ESP32, the libraries
created from ESP-IDF components are linked. On the other hand, stub libraries are linked if example
is meant to be run on the host to simulate the same application behavior.
The application in this example is equivalent to the `hello_world` example under `examples/get-started/hello_world`.
## Example Flow
Users looking at this example should focus on the [top-level CMakeLists.txt file](./CMakeLists.txt). This builds an
application that can run on targets without relying on the typical ESP-IDF application template. The application itself
follows a similar code flow to the aforementioned `hello_world` example.
application that can run on the target without relying on the typical ESP-IDF application template.
### Output
@ -29,41 +33,38 @@ Restarting in 0 seconds...
## Building this Example
To build this example, run the following commands from this directory:
To build this example, the user can either run [build-esp32.sh](./build-esp32.sh) to build for the ESP32
or run [build.sh](./build.sh) to build for the host:
```bash
# Create a build directory, and change location to that directory.
mkdir build; cd build
# Invoke CMake, specifying the top-level CMakeLists.txt directory and toolchain file to use. This will generate
# the build system files.
cmake .. -DCMAKE_TOOLCHAIN_FILE=$IDF_PATH/tools/cmake/toolchain-esp32.cmake -DIDF_TARGET=esp32
# Build using the generated build system files.
cmake --build .
# Builds the example for ESP32
./build-esp32.sh
```
Or, execute `build.sh` script, which contains the same commands mentioned above.
or
```bash
# Builds the example to run on host
./build.sh
```
## Flashing and Running this Example
To flash this example, we will have to invoke `esptool.py` and `idf_monitor.py` manually. While still in the build directory:
### Flashing to target
To flash and run the example, users can run either [run-esp32.sh](./run-esp32.sh) or [run.sh](./run.sh) depending
on what the example was built for. In the case of ``run-esp32.sh``, the port needs to be specified:
```bash
# Write project binaries to flash.
esptool.py --port /dev/ttyUSB0 write_flash @flash_project_args
# Run the example on device connected to /dev/ttyUSB1
./run-esp32.sh /dev/ttyUSB1
```
### Running on target
or
```bash
# Monitor the output of the flashed firmware.
idf_monitor.py --port /dev/ttyUSB0 idf_as_lib.elf
# Run the example on the host
./run.sh
```
Of course, you should replace the specified ports in the commands specified above to the proper one where your device
is connected.
---
There is a discussion on using ESP-IDF in custom CMake projects in the programming guide under `API Guides` -> `Build System (CMake)` -> `Using ESP-IDF in Custom CMake Projects`

View file

@ -0,0 +1,4 @@
#!/bin/bash
rm -rf build && mkdir build && cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE=$IDF_PATH/tools/cmake/toolchain-esp32.cmake -DTARGET=esp32 -GNinja
cmake --build .

View file

@ -1,8 +1,4 @@
#!/bin/bash
#
# Build this example, which does not use that standard IDF app template. See README.md for
# more information about the build and how to run this example on the target once built.
mkdir build; cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE=$IDF_PATH/tools/cmake/toolchain-esp32.cmake -DIDF_TARGET=esp32
rm -rf build && mkdir build && cd build
cmake ..
cmake --build .

View file

@ -0,0 +1,4 @@
#!/bin/bash
cd build
python $IDF_PATH/components/esptool_py/esptool/esptool.py -p $1 write_flash @flash_project_args
python $IDF_PATH/tools/idf_monitor.py -p $1 idf_as_lib.elf

View file

@ -0,0 +1,3 @@
#!/bin/bash
cd build
./idf_as_lib.elf

View file

@ -0,0 +1,6 @@
add_library(stub_esp32 STATIC system_api.c flash_ops.c cpu_start.c)
target_include_directories(stub_esp32 PUBLIC .)
add_library(stub::esp32 ALIAS stub_esp32)
target_link_libraries(stub_esp32 "-u app_main")
target_link_libraries(stub_esp32 stub::spi_flash)

View file

@ -0,0 +1,11 @@
#include <stdbool.h>
#include <setjmp.h>
extern void app_main();
jmp_buf buf;
int main()
{
setjmp(buf);
app_main();
}

View file

@ -0,0 +1,15 @@
#pragma once
#include <stdint.h>
#define CHIP_FEATURE_EMB_FLASH (1UL << 0)
#define CHIP_FEATURE_BT (1UL << 4)
#define CHIP_FEATURE_BLE (1UL << 5)
typedef struct {
uint32_t features; //!< bit mask of CHIP_FEATURE_x feature flags
uint8_t cores; //!< number of CPU cores
uint8_t revision; //!< chip revision number
} esp_chip_info_t;
void esp_restart(void);
void esp_chip_info(esp_chip_info_t* out_info);

View file

@ -0,0 +1,6 @@
#include "esp_spi_flash.h"
int spi_flash_get_chip_size()
{
return (1024 * 1024 * 1024);
}

View file

@ -0,0 +1,19 @@
#include <stdio.h>
#include <unistd.h>
#include <setjmp.h>
#include "esp_system.h"
extern jmp_buf buf;
void esp_restart(void)
{
printf("\n");
sleep(1); // pause for dramatic effect
longjmp(buf, 0);
}
void esp_chip_info(esp_chip_info_t* out_info)
{
out_info->cores = 8;
out_info->features = (uint32_t) -1;
}

View file

@ -0,0 +1,3 @@
add_library(stub_freertos STATIC task.c)
target_include_directories(stub_freertos PUBLIC .)
add_library(stub::freertos ALIAS stub_freertos)

View file

@ -0,0 +1,7 @@
#pragma once
#include <stdint.h>
#define portTICK_PERIOD_MS 1000
void vTaskDelay( const uint32_t xTicksToDelay );

View file

@ -0,0 +1,7 @@
#include <unistd.h>
#include "freertos/task.h"
void vTaskDelay( const uint32_t xTicksToDelay )
{
sleep(xTicksToDelay);
}

View file

@ -0,0 +1,3 @@
add_library(stub_spi_flash INTERFACE)
target_include_directories(stub_spi_flash INTERFACE .)
add_library(stub::spi_flash ALIAS stub_spi_flash)

View file

@ -0,0 +1,5 @@
#pragma once
#include <stddef.h>
int spi_flash_get_chip_size();

View file

@ -3,4 +3,4 @@
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(import_cmake_lib)
project(import_lib)

View file

@ -9,13 +9,18 @@ register_component()
option(BUILD_SHARED_LIBS OFF)
option(BUILD_TESTING OFF)
# Unfortunately the library performs install and export. Would
# have been nice if devs made that an option like BUILD_SHARED_LIBS
# and BUILD_TESTING. Override install() and export() to do nothing
# instead.
function(install)
endfunction()
function(export)
endfunction()
# Import tinyxml2 targets
add_subdirectory(lib/tinyxml2)
# Propagate compile settings to tinyxml2
target_include_directories(tinyxml2 PRIVATE ${IDF_INCLUDE_DIRECTORIES})
target_compile_options(tinyxml2 PRIVATE "${IDF_COMPILE_OPTIONS}")
target_compile_options(tinyxml2 PRIVATE "${IDF_CXX_COMPILE_OPTIONS}")
# Link tinyxml2 to main component
target_link_libraries(${COMPONENT_TARGET} tinyxml2)
target_link_libraries(${COMPONENT_LIB} tinyxml2)

View file

@ -1,5 +1,5 @@
set(COMPONENT_SRCS "mesh_light.c"
"mesh_main.c")
set(COMPONENT_ADD_INCLUDEDIRS ". include")
set(COMPONENT_ADD_INCLUDEDIRS "." "include")
register_component()

View file

@ -25,7 +25,7 @@ It will enable coverage info for all source files of your component. If you need
`gcov_example.o: CFLAGS += --coverage`
Replace `gcov_example.o` with path to your file.
For CMake-based build system, use `component_compile_options(--coverage)` or: ` set_source_files_properties(gcov_example.c PROPERTIES COMPILE_FLAGS --coverage`
For CMake-based build system, use `target_compile_options(${COMPONENT_LIB} PRIVATE --coverage)` or: ` set_source_files_properties(gcov_example.c PROPERTIES COMPILE_FLAGS --coverage`
### Hard-coded Dump Call

View file

@ -3,6 +3,7 @@ set(COMPONENT_ADD_INCLUDEDIRS ".")
# Embed the server root certificate into the final binary
set(COMPONENT_EMBED_TXTFILES ${IDF_PROJECT_PATH}/server_certs/ca_cert.pem)
idf_build_get_property(project_dir PROJECT_DIR)
set(COMPONENT_EMBED_TXTFILES ${project_dir}/server_certs/ca_cert.pem)
register_component()

View file

@ -2,6 +2,7 @@ set(COMPONENT_SRCS "native_ota_example.c")
set(COMPONENT_ADD_INCLUDEDIRS ".")
# Embed the server root certificate into the final binary
set(COMPONENT_EMBED_TXTFILES ${IDF_PROJECT_PATH}/server_certs/ca_cert.pem)
idf_build_get_property(project_dir PROJECT_DIR)
set(COMPONENT_EMBED_TXTFILES ${project_dir}/server_certs/ca_cert.pem)
register_component()

View file

@ -3,6 +3,7 @@ set(COMPONENT_ADD_INCLUDEDIRS ".")
# Embed the server root certificate into the final binary
set(COMPONENT_EMBED_TXTFILES ${IDF_PROJECT_PATH}/server_certs/ca_cert.pem)
idf_build_get_property(project_dir PROJECT_DIR)
set(COMPONENT_EMBED_TXTFILES ${project_dir}/server_certs/ca_cert.pem)
register_component()

View file

@ -66,7 +66,7 @@ LOG_SUSPECTED=${LOG_PATH}/common_log.txt
touch ${LOG_SUSPECTED}
SDKCONFIG_DEFAULTS_CI=sdkconfig.ci
EXAMPLE_PATHS=$( find ${IDF_PATH}/examples/ -type f -name CMakeLists.txt | grep -v "/components/" | grep -v "/common_components/" | grep -v "/main/" | sort )
EXAMPLE_PATHS=$( find ${IDF_PATH}/examples/ -type f -name CMakeLists.txt | grep -v "/components/" | grep -v "/common_components/" | grep -v "/main/" | grep -v "/idf_as_lib/stubs/" | sort )
if [ $# -eq 0 ]
then
@ -142,7 +142,7 @@ build_example () {
idf.py build >>${BUILDLOG} 2>&1
else
rm -rf build &&
./build.sh >>${BUILDLOG} 2>&1
./build-esp32.sh >>${BUILDLOG} 2>&1
fi ||
{
RESULT=$?; FAILED_EXAMPLES+=" ${EXAMPLE_NAME}" ;

View file

@ -73,7 +73,10 @@ components/espcoredump/test/test_espcoredump.sh
tools/ldgen/ldgen.py
tools/ldgen/test/test_fragments.py
tools/ldgen/test/test_generation.py
examples/build_system/cmake/idf_as_lib/build-esp32.sh
examples/build_system/cmake/idf_as_lib/build.sh
examples/build_system/cmake/idf_as_lib/run-esp32.sh
examples/build_system/cmake/idf_as_lib/run.sh
examples/storage/parttool/parttool_example.py
examples/system/ota/otatool/otatool_example.py
tools/check_kconfigs.py

View file

@ -58,7 +58,7 @@ function run_tests()
BOOTLOADER_BINS="bootloader/bootloader.elf bootloader/bootloader.bin"
APP_BINS="app-template.elf app-template.bin"
PARTITION_BIN="partition_table/partition-table.bin"
IDF_COMPONENT_PREFIX="idf_component"
IDF_COMPONENT_PREFIX="__idf"
print_status "Initial clean build"
# if build fails here, everything fails
@ -342,6 +342,7 @@ function run_tests()
rm sdkconfig.defaults;
print_status "Building a project with CMake library imported and PSRAM workaround, all files compile with workaround"
# Test for libraries compiled within ESP-IDF
rm -rf build
echo "CONFIG_SPIRAM_SUPPORT=y" >> sdkconfig.defaults
echo "CONFIG_SPIRAM_CACHE_WORKAROUND=y" >> sdkconfig.defaults
@ -349,7 +350,16 @@ function run_tests()
idf.py -C $IDF_PATH/examples/build_system/cmake/import_lib -B `pwd`/build reconfigure -D SDKCONFIG_DEFAULTS="`pwd`/sdkconfig.defaults"
grep -q '"command"' build/compile_commands.json || failure "compile_commands.json missing or has no no 'commands' in it"
(grep '"command"' build/compile_commands.json | grep -v mfix-esp32-psram-cache-issue) && failure "All commands in compile_commands.json should use PSRAM cache workaround"
rm sdkconfig.defaults
rm -r sdkconfig.defaults build
# Test for external libraries in custom CMake projects with ESP-IDF components linked
mkdir build && touch build/sdkconfig
echo "CONFIG_SPIRAM_SUPPORT=y" >> build/sdkconfig
echo "CONFIG_SPIRAM_CACHE_WORKAROUND=y" >> build/sdkconfig
# note: we just need to run cmake
(cd build && cmake $IDF_PATH/examples/build_system/cmake/idf_as_lib -DCMAKE_TOOLCHAIN_FILE=$IDF_PATH/tools/cmake/toolchain-esp32.cmake -DTARGET=esp32)
grep -q '"command"' build/compile_commands.json || failure "compile_commands.json missing or has no no 'commands' in it"
(grep '"command"' build/compile_commands.json | grep -v mfix-esp32-psram-cache-issue) && failure "All commands in compile_commands.json should use PSRAM cache workaround"
rm -r build
print_status "Make sure a full build never runs '/usr/bin/env python' or similar"
OLDPATH="$PATH"

502
tools/cmake/build.cmake Normal file
View file

@ -0,0 +1,502 @@
# idf_build_get_property
#
# @brief Retrieve the value of the specified property related to ESP-IDF build.
#
# @param[out] var the variable to store the value in
# @param[in] property the property to get the value of
#
# @param[in, optional] GENERATOR_EXPRESSION (option) retrieve the generator expression for the property
# instead of actual value
function(idf_build_get_property var property)
cmake_parse_arguments(_ "GENERATOR_EXPRESSION" "" "" ${ARGN})
if(__GENERATOR_EXPRESSION)
set(val "$<TARGET_PROPERTY:__idf_build_target,${property}>")
else()
get_property(val TARGET __idf_build_target PROPERTY ${property})
endif()
set(${var} ${val} PARENT_SCOPE)
endfunction()
# idf_build_set_property
#
# @brief Set the value of the specified property related to ESP-IDF build. The property is
# also added to the internal list of build properties if it isn't there already.
#
# @param[in] property the property to set the value of
# @param[out] value value of the property
#
# @param[in, optional] APPEND (option) append the value to the current value of the
# property instead of replacing it
function(idf_build_set_property property value)
cmake_parse_arguments(_ "APPEND" "" "" ${ARGN})
if(__APPEND)
set_property(TARGET __idf_build_target APPEND PROPERTY ${property} ${value})
else()
set_property(TARGET __idf_build_target PROPERTY ${property} ${value})
endif()
# Keep track of set build properties so that they can be exported to a file that
# will be included in early expansion script.
idf_build_get_property(build_properties __BUILD_PROPERTIES)
if(NOT property IN_LIST build_properties)
idf_build_set_property(__BUILD_PROPERTIES "${property}" APPEND)
endif()
endfunction()
# idf_build_unset_property
#
# @brief Unset the value of the specified property related to ESP-IDF build. Equivalent
# to setting the property to an empty string; though it also removes the property
# from the internal list of build properties.
#
# @param[in] property the property to unset the value of
function(idf_build_unset_property property)
idf_build_set_property(${property} "") # set to an empty value
idf_build_get_property(build_properties __BUILD_PROPERTIES) # remove from tracked properties
list(REMOVE_ITEM build_properties ${property})
idf_build_set_property(__BUILD_PROPERTIES "${build_properties}")
endfunction()
#
# Retrieve the IDF_PATH repository's version, either using a version
# file or Git revision. Sets the IDF_VER build property.
#
function(__build_get_idf_git_revision)
idf_build_get_property(idf_path IDF_PATH)
git_describe(idf_ver_git "${idf_path}")
if(EXISTS "${idf_path}/version.txt")
file(STRINGS "${idf_path}/version.txt" idf_ver_t)
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${idf_path}/version.txt")
else()
set(idf_ver_t ${idf_ver_git})
endif()
# cut IDF_VER to required 32 characters.
string(SUBSTRING "${idf_ver_t}" 0 31 idf_ver)
idf_build_set_property(COMPILE_DEFINITIONS "-DIDF_VER=\"${idf_ver}\"" APPEND)
git_submodule_check("${idf_path}")
idf_build_set_property(IDF_VER ${idf_ver})
endfunction()
#
# Sets initial list of build specifications (compile options, definitions, etc.) common across
# all library targets built under the ESP-IDF build system. These build specifications are added
# privately using the directory-level CMake commands (add_compile_options, include_directories, etc.)
# during component registration.
#
function(__build_set_default_build_specifications)
unset(compile_definitions)
unset(compile_options)
unset(c_compile_options)
unset(cxx_compile_options)
list(APPEND compile_definitions "-DHAVE_CONFIG_H")
list(APPEND compile_options "-ffunction-sections"
"-fdata-sections"
"-fstrict-volatile-bitfields"
"-nostdlib"
# warning-related flags
"-Wall"
"-Werror=all"
"-Wno-error=unused-function"
"-Wno-error=unused-but-set-variable"
"-Wno-error=unused-variable"
"-Wno-error=deprecated-declarations"
"-Wextra"
"-Wno-unused-parameter"
"-Wno-sign-compare"
# always generate debug symbols (even in release mode, these don't
# go into the final binary so have no impact on size
"-ggdb")
list(APPEND c_compile_options "-std=gnu99"
"-Wno-old-style-declaration")
list(APPEND cxx_compile_options "-std=gnu++11"
"-fno-rtti")
idf_build_set_property(COMPILE_DEFINITIONS "${compile_definitions}" APPEND)
idf_build_set_property(COMPILE_OPTIONS "${compile_options}" APPEND)
idf_build_set_property(C_COMPILE_OPTIONS "${c_compile_options}" APPEND)
idf_build_set_property(CXX_COMPILE_OPTIONS "${cxx_compile_options}" APPEND)
endfunction()
#
# Initialize the build. This gets called upon inclusion of idf.cmake to set internal
# properties used for the processing phase of the build.
#
function(__build_init idf_path)
# Create the build target, to which the ESP-IDF build properties, dependencies are attached to
add_custom_target(__idf_build_target)
set_default(python "python")
idf_build_set_property(PYTHON ${python})
idf_build_set_property(IDF_PATH ${idf_path})
idf_build_set_property(__PREFIX idf)
idf_build_set_property(__CHECK_PYTHON 1)
__build_set_default_build_specifications()
# Add internal components to the build
idf_build_get_property(idf_path IDF_PATH)
idf_build_get_property(prefix __PREFIX)
file(GLOB component_dirs ${idf_path}/components/*)
foreach(component_dir ${component_dirs})
get_filename_component(component_dir ${component_dir} ABSOLUTE)
__component_add(${component_dir} ${prefix})
endforeach()
# Set components required by all other components in the build
set(requires_common cxx newlib freertos heap log soc esp_rom esp_common xtensa)
idf_build_set_property(__COMPONENT_REQUIRES_COMMON "${requires_common}")
__build_get_idf_git_revision()
__kconfig_init()
endfunction()
# idf_build_component
#
# @brief Specify component directory for the build system to process.
# Relative paths are converted to absolute paths with respect to current directory.
# Any component that needs to be processed has to be specified using this
# command before calling idf_build_process.
#
# @param[in] component_dir directory of the component to process
function(idf_build_component component_dir)
idf_build_get_property(prefix __PREFIX)
__component_add(${component_dir} ${prefix} 0)
endfunction()
#
# Resolve the requirement component to the component target created for that component.
#
function(__build_resolve_and_add_req var component_target req type)
__component_get_target(_component_target ${req})
if(NOT _component_target)
message(FATAL_ERROR "Failed to resolve component '${req}'.")
endif()
__component_set_property(${component_target} ${type} ${_component_target} APPEND)
set(${var} ${_component_target} PARENT_SCOPE)
endfunction()
#
# Build a list of components (in the form of component targets) to be added to the build
# based on public and private requirements. This list is saved in an internal property,
# __BUILD_COMPONENT_TARGETS.
#
function(__build_expand_requirements component_target)
# Since there are circular dependencies, make sure that we do not infinitely
# expand requirements for each component.
idf_build_get_property(component_targets_seen __COMPONENT_TARGETS_SEEN)
if(component_target IN_LIST component_targets_seen)
return()
endif()
idf_build_set_property(__COMPONENT_TARGETS_SEEN ${component_target} APPEND)
get_property(reqs TARGET ${component_target} PROPERTY REQUIRES)
get_property(priv_reqs TARGET ${component_target} PROPERTY PRIV_REQUIRES)
foreach(req ${reqs})
__build_resolve_and_add_req(_component_target ${component_target} ${req} __REQUIRES)
__build_expand_requirements(${_component_target})
endforeach()
foreach(req ${priv_reqs})
__build_resolve_and_add_req(_component_target ${component_target} ${req} __PRIV_REQUIRES)
__build_expand_requirements(${_component_target})
endforeach()
idf_build_get_property(build_component_targets __BUILD_COMPONENT_TARGETS)
if(NOT component_target IN_LIST build_component_targets)
idf_build_set_property(__BUILD_COMPONENT_TARGETS ${component_target} APPEND)
endif()
endfunction()
#
# Write a CMake file containing set build properties, owing to the fact that an internal
# list of properties is maintained in idf_build_set_property() call. This is used to convert
# those set properties to variables in the scope the output file is included in.
#
function(__build_write_properties output_file)
idf_build_get_property(build_properties __BUILD_PROPERTIES)
foreach(property ${build_properties})
idf_build_get_property(val ${property})
set(build_properties_text "${build_properties_text}\nset(${property} ${val})")
endforeach()
file(WRITE ${output_file} "${build_properties_text}")
endfunction()
#
# Check if the Python interpreter used for the build has all the required modules.
#
function(__build_check_python)
idf_build_get_property(check __CHECK_PYTHON)
if(check)
idf_build_get_property(python PYTHON)
idf_build_get_property(idf_path IDF_PATH)
message(STATUS "Checking Python dependencies...")
execute_process(COMMAND "${python}" "${idf_path}/tools/check_python_dependencies.py"
RESULT_VARIABLE result)
if(NOT result EQUAL 0)
message(FATAL_ERROR "Some Python dependencies must be installed. Check above message for details.")
endif()
endif()
endfunction()
#
# Prepare for component processing expanding each component's project include
#
macro(__build_process_project_includes)
# Include the sdkconfig cmake file, since the following operations require
# knowledge of config values.
idf_build_get_property(sdkconfig_cmake SDKCONFIG_CMAKE)
include(${sdkconfig_cmake})
# Make each build property available as a read-only variable
idf_build_get_property(build_properties __BUILD_PROPERTIES)
foreach(build_property ${build_properties})
idf_build_get_property(val ${build_property})
set(${build_property} "${val}")
endforeach()
# Check that the CMake target value matches the Kconfig target value.
__target_check()
idf_build_get_property(build_component_targets __BUILD_COMPONENT_TARGETS)
# Include each component's project_include.cmake
foreach(component_target ${build_component_targets})
__component_get_property(dir ${component_target} COMPONENT_DIR)
__component_get_property(_name ${component_target} COMPONENT_NAME)
set(COMPONENT_NAME ${_name})
set(COMPONENT_DIR ${dir})
set(COMPONENT_PATH ${dir}) # this is deprecated, users are encouraged to use COMPONENT_DIR;
# retained for compatibility
if(EXISTS ${COMPONENT_DIR}/project_include.cmake)
include(${COMPONENT_DIR}/project_include.cmake)
endif()
endforeach()
endmacro()
#
# Utility macro for setting default property value if argument is not specified
# for idf_build_process().
#
macro(__build_set_default var default)
set(_var __${var})
if(${_var})
idf_build_set_property(${var} "${${_var}}")
else()
idf_build_set_property(${var} "${default}")
endif()
unset(_var)
endmacro()
#
# Import configs as build instance properties so that they are accessible
# using idf_build_get_config(). Config has to have been generated before calling
# this command.
#
function(__build_import_configs)
# Include the sdkconfig cmake file, since the following operations require
# knowledge of config values.
idf_build_get_property(sdkconfig_cmake SDKCONFIG_CMAKE)
include(${sdkconfig_cmake})
idf_build_set_property(__CONFIG_VARIABLES "${CONFIGS_LIST}")
foreach(config ${CONFIGS_LIST})
set_property(TARGET __idf_build_target PROPERTY ${config} "${${config}}")
endforeach()
endfunction()
# idf_build_process
#
# @brief Main processing step for ESP-IDF build: config generation, adding components to the build,
# dependency resolution, etc.
#
# @param[in] target ESP-IDF target
#
# @param[in, optional] PROJECT_DIR (single value) directory of the main project the buildsystem
# is processed for; defaults to CMAKE_SOURCE_DIR
# @param[in, optional] PROJECT_VER (single value) version string of the main project; defaults
# to 0.0.0
# @param[in, optional] PROJECT_NAME (single value) main project name, defaults to CMAKE_PROJECT_NAME
# @param[in, optional] SDKCONFIG (single value) sdkconfig output path, defaults to PROJECT_DIR/sdkconfig
# if PROJECT_DIR is set and CMAKE_SOURCE_DIR/sdkconfig if not
# @param[in, optional] SDKCONFIG_DEFAULTS (single value) config defaults file to use for the build; defaults
# to none (Kconfig defaults or previously generated config are used)
# @param[in, optional] BUILD_DIR (single value) directory for build artifacts; defautls to CMAKE_BINARY_DIR
# @param[in, optional] COMPONENTS (multivalue) starting components for trimming build
macro(idf_build_process target)
set(options)
set(single_value PROJECT_DIR PROJECT_VER PROJECT_NAME BUILD_DIR SDKCONFIG SDKCONFIG_DEFAULTS)
set(multi_value COMPONENTS)
cmake_parse_arguments(_ "${options}" "${single_value}" "${multi_value}" ${ARGN})
idf_build_set_property(BOOTLOADER_BUILD "${BOOTLOADER_BUILD}")
# Check build target is specified. Since this target corresponds to a component
# name, the target component is automatically added to the list of common component
# requirements.
if(target STREQUAL "")
message(FATAL_ERROR "Build target not specified.")
endif()
idf_build_set_property(IDF_TARGET ${target})
__build_set_default(PROJECT_DIR ${CMAKE_SOURCE_DIR})
__build_set_default(PROJECT_NAME ${CMAKE_PROJECT_NAME})
__build_set_default(PROJECT_VER "0.0.0")
__build_set_default(BUILD_DIR ${CMAKE_BINARY_DIR})
idf_build_get_property(project_dir PROJECT_DIR)
__build_set_default(SDKCONFIG "${project_dir}/sdkconfig")
__build_set_default(SDKCONFIG_DEFAULTS "")
# Check for required Python modules
__build_check_python()
# Generate config values in different formats
idf_build_get_property(sdkconfig SDKCONFIG)
idf_build_get_property(sdkconfig_defaults SDKCONFIG_DEFAULTS)
__kconfig_generate_config("${sdkconfig}" "${sdkconfig_defaults}")
__build_import_configs()
# Write the partial build properties to a temporary file.
# The path to this generated file is set to a short-lived build
# property BUILD_PROPERTIES_FILE.
idf_build_get_property(build_dir BUILD_DIR)
set(build_properties_file ${build_dir}/build_properties.temp.cmake)
idf_build_set_property(BUILD_PROPERTIES_FILE ${build_properties_file})
__build_write_properties(${build_properties_file})
# Perform early expansion of component CMakeLists.txt in CMake scripting mode.
# It is here we retrieve the public and private requirements of each component.
# It is also here we add the common component requirements to each component's
# own requirements.
idf_build_get_property(component_targets __COMPONENT_TARGETS)
idf_build_set_property(__COMPONENT_REQUIRES_COMMON ${target} APPEND)
idf_build_get_property(common_reqs __COMPONENT_REQUIRES_COMMON)
foreach(component_target ${component_targets})
get_property(component_dir TARGET ${component_target} PROPERTY COMPONENT_DIR)
__component_get_requirements(error reqs priv_reqs ${component_dir})
if(error)
message(FATAL_ERROR "${error}")
endif()
list(APPEND reqs "${common_reqs}")
# Remove duplicates and the component itself from its requirements
__component_get_property(alias ${component_target} COMPONENT_ALIAS)
__component_get_property(_name ${component_target} COMPONENT_NAME)
# Prevent component from linking to itself.
if(reqs)
list(REMOVE_DUPLICATES reqs)
list(REMOVE_ITEM reqs ${alias} ${_name})
endif()
if(priv_reqs)
list(REMOVE_DUPLICATES priv_reqs)
list(REMOVE_ITEM priv_reqs ${alias} ${_name})
endif()
__component_set_property(${component_target} REQUIRES "${reqs}")
__component_set_property(${component_target} PRIV_REQUIRES "${priv_reqs}")
endforeach()
idf_build_unset_property(BUILD_PROPERTIES_FILE)
file(REMOVE ${build_properties_file})
# Finally, do component expansion. In this case it simply means getting a final list
# of build component targets given the requirements set by each component.
if(__COMPONENTS)
unset(component_targets)
foreach(component ${__COMPONENTS})
__component_get_target(component_target ${component})
if(NOT component_target)
message(FATAL_ERROR "Failed to resolve component '${component}'.")
endif()
list(APPEND component_targets ${component_target})
endforeach()
endif()
foreach(component_target ${component_targets})
__build_expand_requirements(${component_target})
endforeach()
unset(__COMPONENT_TARGETS_SEEN)
# Get a list of common component requirements in component targets form (previously
# we just have a list of component names)
foreach(common_req ${common_reqs})
__component_get_target(component_target ${common_req})
__component_get_property(lib ${component_target} COMPONENT_LIB)
idf_build_set_property(___COMPONENT_REQUIRES_COMMON ${lib} APPEND)
endforeach()
__build_process_project_includes()
# Perform component processing (inclusion of project_include.cmake, adding component
# subdirectories, creating library targets, linking libraries, etc.)
idf_build_get_property(idf_path IDF_PATH)
add_subdirectory(${idf_path} ${build_dir}/esp-idf)
endmacro()
# idf_build_executable
#
# @brief Specify the executable the build system can attach dependencies to (for generating
# files used for linking, targets which should execute before creating the specified executable,
# generating additional binary files, generating files related to flashing, etc.)
function(idf_build_executable elf)
# Propagate link dependencies from component library targets to the executable
idf_build_get_property(build_components BUILD_COMPONENTS)
foreach(build_component ${build_components})
get_target_property(type ${build_component} TYPE)
if(type STREQUAL "INTERFACE_LIBRARY")
get_target_property(iface_link_depends ${build_component} INTERFACE_LINK_DEPENDS)
else()
get_target_property(link_depends ${build_component} LINK_DEPENDS)
get_target_property(iface_link_depends ${build_component} INTERFACE_LINK_DEPENDS)
endif()
if(iface_link_depends)
list(APPEND _link_depends ${iface_link_depends})
endif()
if(link_depends)
list(APPEND _link_depends ${link_depends})
endif()
endforeach()
idf_build_get_property(link_depends LINK_DEPENDS)
if(link_depends)
list(APPEND _link_depends ${link_depends})
endif()
set_property(TARGET ${elf} APPEND PROPERTY LINK_DEPENDS "${_link_depends}")
# Set the EXECUTABLE_NAME and EXECUTABLE properties since there are generator expression
# from components that depend on it
get_filename_component(elf_name ${elf} NAME_WE)
idf_build_set_property(EXECUTABLE_NAME ${elf_name})
idf_build_set_property(EXECUTABLE ${elf})
# Add dependency of the build target to the executable
add_dependencies(${elf} __idf_build_target)
endfunction()
# idf_build_get_config
#
# @brief Get value of specified config variable
function(idf_build_get_config var config)
cmake_parse_arguments(_ "GENERATOR_EXPRESSION" "" "" ${ARGN})
if(__GENERATOR_EXPRESSION)
set(val "$<TARGET_PROPERTY:__idf_build_target,${config}>")
else()
get_property(val TARGET __idf_build_target PROPERTY ${config})
endif()
set(${var} ${val} PARENT_SCOPE)
endfunction()

472
tools/cmake/component.cmake Normal file
View file

@ -0,0 +1,472 @@
#
# Internal function for retrieving component properties from a component target.
#
function(__component_get_property var component_target property)
get_property(val TARGET ${component_target} PROPERTY ${property})
set(${var} "${val}" PARENT_SCOPE)
endfunction()
#
# Internal function for setting component properties on a component target. As with build properties,
# set properties are also keeped track of.
#
function(__component_set_property component_target property val)
cmake_parse_arguments(_ "APPEND" "" "" ${ARGN})
if(__APPEND)
set_property(TARGET ${component_target} APPEND PROPERTY ${property} "${val}")
else()
set_property(TARGET ${component_target} PROPERTY ${property} "${val}")
endif()
# Keep track of set component properties
__component_get_property(properties ${component_target} __COMPONENT_PROPERTIES)
if(NOT property IN_LIST properties)
__component_set_property(${component_target} __COMPONENT_PROPERTIES ${property} APPEND)
endif()
endfunction()
#
# Given a component name or alias, get the corresponding component target.
#
function(__component_get_target var name_or_alias)
# Look at previously resolved names or aliases
idf_build_get_property(component_names_resolved __COMPONENT_NAMES_RESOLVED)
list(FIND component_names_resolved ${name_or_alias} result)
if(NOT result EQUAL -1)
# If it has been resolved before, return that value. The index is the same
# as in __COMPONENT_NAMES_RESOLVED as these are parallel lists.
idf_build_get_property(component_targets_resolved __COMPONENT_TARGETS_RESOLVED)
list(GET component_targets_resolved ${result} target)
set(${var} ${target} PARENT_SCOPE)
return()
endif()
idf_build_get_property(component_targets __COMPONENT_TARGETS)
# Assume first that the paramters is an alias.
string(REPLACE "::" "_" name_or_alias "${name_or_alias}")
set(component_target ___${name_or_alias})
if(component_target IN_LIST component_targets)
set(${var} ${component_target} PARENT_SCOPE)
set(target ${component_target})
else() # assumption is wrong, try to look for it manually
unset(target)
foreach(component_target ${component_targets})
__component_get_property(_component_name ${component_target} COMPONENT_NAME)
if(name_or_alias STREQUAL _component_name)
# There should only be one component of the same name
if(NOT target)
set(target ${component_target})
else()
message(FATAL_ERROR "Multiple components with name '${name_or_alias}' found.")
return()
endif()
endif()
endforeach()
set(${var} ${target} PARENT_SCOPE)
endif()
# Save the resolved name or alias
if(target)
idf_build_set_property(__COMPONENT_NAMES_RESOLVED ${name_or_alias} APPEND)
idf_build_set_property(__COMPONENT_TARGETS_RESOLVED ${target} APPEND)
endif()
endfunction()
#
# Called during component registration, sets basic properties of the current component.
#
macro(__component_set_properties)
__component_get_property(type ${component_target} COMPONENT_TYPE)
# Fill in the rest of component property
__component_set_property(${component_target} SRCS "${sources}")
__component_set_property(${component_target} INCLUDE_DIRS "${__INCLUDE_DIRS}")
if(type STREQUAL LIBRARY)
__component_set_property(${component_target} PRIV_INCLUDE_DIRS "${__PRIV_INCLUDE_DIRS}")
endif()
__component_set_property(${component_target} LDFRAGMENTS "${__LDFRAGMENTS}")
__component_set_property(${component_target} EMBED_FILES "${__EMBED_FILES}")
__component_set_property(${component_target} EMBED_TXTFILES "${__EMBED_TXTFILES}")
__component_set_property(${component_target} REQUIRED_IDF_TARGETS "${__REQUIRED_IDF_TARGETS}")
endmacro()
#
# Add a component to process in the build. The components are keeped tracked of in property
# __COMPONENT_TARGETS in component target form.
#
function(__component_add component_dir prefix)
# For each component, two entities are created: a component target and a component library. The
# component library is created during component registration (the actual static/interface library).
# On the other hand, component targets are created early in the build
# (during adding component as this function suggests).
# This is so that we still have a target to attach properties to up until the component registration.
# Plus, interface libraries have limitations on the types of properties that can be set on them,
# so later in the build, these component targets actually contain the properties meant for the
# corresponding component library.
idf_build_get_property(component_targets __COMPONENT_TARGETS)
get_filename_component(abs_dir ${component_dir} ABSOLUTE)
get_filename_component(base_dir ${abs_dir} NAME)
# Check this is really a directory and that a CMakeLists.txt file for this component exists
# - warn and skip anything which isn't valid looking (probably cruft)
if(NOT IS_DIRECTORY "${abs_dir}")
message(WARNING "Unexpected file in components directory: ${abs_dir}")
return()
endif()
if(NOT EXISTS "${abs_dir}/CMakeLists.txt")
message(WARNING "Component directory ${abs_dir} does not contain a CMakeLists.txt file. "
"No component will be added")
return()
endif()
set(component_name ${base_dir})
# The component target has three underscores as a prefix. The corresponding component library
# only has two.
set(component_target ___${prefix}_${component_name})
# If a component of the same name has not been added before If it has been added
# before just override the properties. As a side effect, components added later
# 'override' components added earlier.
if(NOT component_target IN_LIST component_targets)
if(NOT TARGET ${component_target})
add_custom_target(${component_target} EXCLUDE_FROM_ALL)
endif()
idf_build_set_property(__COMPONENT_TARGETS ${component_target} APPEND)
endif()
set(component_lib __${prefix}_${component_name})
set(component_dir ${abs_dir})
set(component_alias ${prefix}::${component_name}) # The 'alias' of the component library,
# used to refer to the component outside
# the build system. Users can use this name
# to resolve ambiguity with component names
# and to link IDF components to external targets.
# Set the basic properties of the component
__component_set_property(${component_target} COMPONENT_LIB ${component_lib})
__component_set_property(${component_target} COMPONENT_NAME ${component_name})
__component_set_property(${component_target} COMPONENT_DIR ${component_dir})
__component_set_property(${component_target} COMPONENT_ALIAS ${component_alias})
__component_set_property(${component_target} __PREFIX ${prefix})
# Set Kconfig related properties on the component
__kconfig_component_init(${component_target})
endfunction()
#
# Given a component directory, get the requirements by expanding it early. The expansion is performed
# using a separate CMake script (the expansion is performed in a separate instance of CMake in scripting mode).
#
function(__component_get_requirements error requires_var priv_requires_var component_dir)
idf_build_get_property(idf_path IDF_PATH)
idf_build_get_property(build_properties_file BUILD_PROPERTIES_FILE)
idf_build_get_property(idf_target IDF_TARGET)
# This function assumes that the directory has been checked to contain a component, thus
# no check is performed here.
execute_process(COMMAND "${CMAKE_COMMAND}"
-D "IDF_PATH=${idf_path}"
-D "IDF_TARGET=${idf_target}"
-D "COMPONENT_DIR=${component_dir}"
-D "BUILD_PROPERTIES_FILE=${build_properties_file}"
-D "CMAKE_BUILD_EARLY_EXPANSION=1"
-P "${idf_path}/tools/cmake/scripts/component_get_requirements.cmake"
RESULT_VARIABLE result
ERROR_VARIABLE error
)
if(NOT result EQUAL 0)
set(error "${error}" PARENT_SCOPE)
return()
endif()
string(REGEX REPLACE ";" "\\\\;" _output "${error}")
string(REGEX REPLACE "\n" ";" _output "${_output}")
list(REVERSE _output)
if(_output)
list(GET _output 1 _output)
string(REGEX MATCH "\(.*\):::\(.*\)" _output "${_output}")
string(REPLACE ":" ";" requires "${CMAKE_MATCH_1}")
string(REPLACE ":" ";" priv_requires "${CMAKE_MATCH_2}")
endif()
set(${requires_var} ${requires} PARENT_SCOPE)
set(${priv_requires_var} ${priv_requires} PARENT_SCOPE)
endfunction()
# __component_add_sources, __component_check_target
#
# Utility macros for component registration. Adds source files and checks target requirements
# respectively.
macro(__component_add_sources sources)
set(sources "")
if(__SRCS)
if(__SRC_DIRS)
message(WARNING "SRCS and SRC_DIRS are both specified; ignoring SRC_DIRS.")
endif()
foreach(src ${__SRCS})
get_filename_component(src "${src}" ABSOLUTE BASE_DIR ${COMPONENT_DIR})
list(APPEND sources ${src})
endforeach()
else()
if(__SRC_DIRS)
foreach(dir ${__SRC_DIRS})
get_filename_component(abs_dir ${dir} ABSOLUTE BASE_DIR ${COMPONENT_DIR})
if(NOT IS_DIRECTORY ${abs_dir})
message(FATAL_ERROR "SRC_DIRS entry '${dir}' does not exist.")
endif()
file(GLOB dir_sources "${abs_dir}/*.c" "${abs_dir}/*.cpp" "${abs_dir}/*.S")
if(dir_sources)
foreach(src ${dir_sources})
get_filename_component(src "${src}" ABSOLUTE BASE_DIR ${COMPONENT_DIR})
list(APPEND sources "${src}")
endforeach()
else()
message(WARNING "No source files found for SRC_DIRS entry '${dir}'.")
endif()
endforeach()
endif()
if(__EXCLUDE_SRCS)
foreach(src ${__EXCLUDE_SRCS})
get_filename_component(src "${src}" ABSOLUTE)
list(REMOVE_ITEM source "${src}")
endforeach()
endif()
endif()
list(REMOVE_DUPLICATES sources)
endmacro()
macro(__component_check_target)
if(__REQUIRED_IDF_TARGETS)
idf_build_get_property(idf_target IDF_TARGET)
if(NOT idf_target IN_LIST __REQUIRED_IDF_TARGETS)
message(FATAL_ERROR "Component ${COMPONENT_NAME} only supports targets: ${__REQUIRED_IDF_TARGETS}")
endif()
endif()
endmacro()
# idf_component_get_property
#
# @brief Retrieve the value of the specified component property
#
# @param[out] var the variable to store the value of the property in
# @param[in] component the component name or alias to get the value of the property of
# @param[in] property the property to get the value of
#
# @param[in, optional] GENERATOR_EXPRESSION (option) retrieve the generator expression for the property
# instead of actual value
function(idf_component_get_property var component property)
cmake_parse_arguments(_ "GENERATOR_EXPRESSION" "" "" ${ARGN})
__component_get_target(component_target ${component})
if(__GENERATOR_EXPRESSION)
set(val "$<TARGET_PROPERTY:${component_target},${property}>")
else()
__component_get_property(val ${component_target} ${property})
endif()
set(${var} "${val}" PARENT_SCOPE)
endfunction()
# idf_component_set_property
#
# @brief Set the value of the specified component property related. The property is
# also added to the internal list of component properties if it isn't there already.
#
# @param[in] component component name or alias of the component to set the property of
# @param[in] property the property to set the value of
# @param[out] value value of the property to set to
#
# @param[in, optional] APPEND (option) append the value to the current value of the
# property instead of replacing it
function(idf_component_set_property component property val)
cmake_parse_arguments(_ "APPEND" "" "" ${ARGN})
__component_get_target(component_target ${component})
if(__APPEND)
__component_set_property(${component_target} ${property} "${val}" APPEND)
else()
__component_set_property(${component_target} ${property} "${val}")
endif()
endfunction()
# idf_component_register
#
# @brief Register a component to the build, creating component library targets etc.
#
# @param[in, optional] SRCS (multivalue) list of source files for the component
# @param[in, optional] SRC_DIRS (multivalue) list of source directories to look for source files
# in (.c, .cpp. .S); ignored when SRCS is specified.
# @param[in, optional] EXCLUDE_SRCS (multivalue) used to exclude source files for the specified
# SRC_DIRS
# @param[in, optional] INCLUDE_DIRS (multivalue) public include directories for the created component library
# @param[in, optional] PRIV_INCLUDE_DIRS (multivalue) private include directories for the created component library
# @param[in, optional] LDFRAGMENTS (multivalue) linker script fragments for the component
# @param[in, optional] REQUIRES (multivalue) publicly required components in terms of usage requirements
# @param[in, optional] PRIV_REQUIRES (multivalue) privately required components in terms of usage requirements
# or components only needed for functions/values defined in its project_include.cmake
# @param[in, optional] REQUIRED_IDF_TARGETS (multivalue) the list of IDF build targets that the component only supports
# @param[in, optional] EMBED_FILES (multivalue) list of binary files to embed with the component
# @param[in, optional] EMBED_TXTFILES (multivalue) list of text files to embed with the component
function(idf_component_register)
set(options)
set(single_value)
set(multi_value SRCS SRC_DIRS EXCLUDE_SRCS
INCLUDE_DIRS PRIV_INCLUDE_DIRS LDFRAGMENTS REQUIRES
PRIV_REQUIRES REQUIRED_IDF_TARGETS EMBED_FILES EMBED_TXTFILES)
cmake_parse_arguments(_ "${options}" "${single_value}" "${multi_value}" ${ARGN})
if(NOT __idf_component_context)
message(FATAL_ERROR "Called idf_component_register from a non-component directory.")
endif()
__component_check_target()
__component_add_sources(sources)
# Create the final target for the component. This target is the target that is
# visible outside the build system.
__component_get_target(component_target ${COMPONENT_ALIAS})
__component_get_property(component_lib ${component_target} COMPONENT_LIB)
# Use generator expression so that users can append/override flags even after call to
# idf_build_process
idf_build_get_property(include_directories INCLUDE_DIRECTORIES GENERATOR_EXPRESSION)
idf_build_get_property(compile_options COMPILE_OPTIONS GENERATOR_EXPRESSION)
idf_build_get_property(c_compile_options C_COMPILE_OPTIONS GENERATOR_EXPRESSION)
idf_build_get_property(cxx_compile_options CXX_COMPILE_OPTIONS GENERATOR_EXPRESSION)
idf_build_get_property(common_reqs ___COMPONENT_REQUIRES_COMMON)
include_directories("${include_directories}")
add_compile_options("${compile_options}")
add_c_compile_options("${c_compile_options}")
add_cxx_compile_options("${cxx_compile_options}")
# Unfortunately add_definitions() does not support generator expressions. A new command
# add_compile_definition() does but is only available on CMake 3.12 or newer. This uses
# add_compile_options(), which can add any option as the workaround.
#
# TODO: Use add_compile_definitions() once minimum supported version is 3.12 or newer.
idf_build_get_property(compile_definitions COMPILE_DEFINITIONS GENERATOR_EXPRESSION)
add_compile_options("${compile_definitions}")
list(REMOVE_ITEM common_reqs ${component_lib})
link_libraries(${common_reqs})
idf_build_get_property(sdkconfig_h SDKCONFIG_HEADER)
get_filename_component(sdkconfig_h ${sdkconfig_h} DIRECTORY)
# The contents of 'sources' is from the __component_add_sources call
if(sources OR __EMBED_FILES OR __EMBED_TXTFILES)
add_library(${component_lib} STATIC ${sources})
__component_set_property(${component_target} COMPONENT_TYPE LIBRARY)
target_include_directories(${component_lib} PUBLIC ${__INCLUDE_DIRS})
target_include_directories(${component_lib} PRIVATE ${__PRIV_INCLUDE_DIRS})
target_include_directories(${component_lib} PUBLIC ${sdkconfig_h})
set_target_properties(${component_lib} PROPERTIES OUTPUT_NAME ${COMPONENT_NAME})
__ldgen_add_component(${component_lib})
else()
add_library(${component_lib} INTERFACE)
__component_set_property(${component_target} COMPONENT_TYPE CONFIG_ONLY)
target_include_directories(${component_lib} INTERFACE ${__INCLUDE_DIRS})
target_include_directories(${component_lib} INTERFACE ${sdkconfig_h})
endif()
# Alias the static/interface library created for linking to external targets.
# The alias is the <prefix>::<component name> name.
__component_get_property(component_alias ${component_target} COMPONENT_ALIAS)
add_library(${component_alias} ALIAS ${component_lib})
# Perform other component processing, such as embedding binaries and processing linker
# script fragments
foreach(file ${__EMBED_FILES})
target_add_binary_data(${component_lib} "${file}" "BINARY")
endforeach()
foreach(file ${__EMBED_TXTFILES})
target_add_binary_data(${component_lib} "${file}" "TEXT")
endforeach()
if(__LDFRAGMENTS)
__ldgen_add_fragment_files("${__LDFRAGMENTS}")
endif()
# Add the component to built components
idf_build_set_property(__BUILD_COMPONENTS ${component_lib} APPEND)
idf_build_set_property(BUILD_COMPONENTS ${component_alias} APPEND)
# Make the COMPONENT_LIB variable available in the component CMakeLists.txt
set(COMPONENT_LIB ${component_lib} PARENT_SCOPE)
# COMPONENT_TARGET is deprecated but is made available with same function
# as COMPONENT_LIB for compatibility.
set(COMPONENT_TARGET ${component_lib} PARENT_SCOPE)
endfunction()
#
# Deprecated functions
#
# register_component
#
# Compatibility function for registering 3.xx style components.
macro(register_component)
spaces2list(COMPONENT_SRCS)
spaces2list(COMPONENT_SRCDIRS)
spaces2list(COMPONENT_ADD_INCLUDEDIRS)
spaces2list(COMPONENT_PRIV_INCLUDEDIRS)
spaces2list(COMPONENT_REQUIRES)
spaces2list(COMPONENT_PRIV_REQUIRES)
spaces2list(COMPONENT_ADD_LDFRAGMENTS)
spaces2list(COMPONENT_EMBED_FILES)
spaces2list(COMPONENT_EMBED_TXTFILES)
spaces2list(COMPONENT_SRCEXCLUDE)
idf_component_register(SRCS "${COMPONENT_SRCS}"
SRC_DIRS "${COMPONENT_SRCDIRS}"
INCLUDE_DIRS "${COMPONENT_ADD_INCLUDEDIRS}"
PRIV_INCLUDE_DIRS "${COMPONENT_PRIV_INCLUDEDIRS}"
REQUIRES "${COMPONENT_REQUIRES}"
PRIV_REQUIRES "${COMPONENT_PRIV_REQUIRES}"
LDFRAGMENTS "${COMPONENT_ADD_LDFRAGMENTS}"
EMBED_FILES "${COMPONENT_EMBED_FILES}"
EMBED_TXTFILES "${COMPONENT_EMBED_TXTFILES}"
EXCLUDE_SRCS "${COMPONENT_SRCEXCLUDE}")
endmacro()
# require_idf_targets
#
# Compatibility function for requiring IDF build targets for 3.xx style components.
function(require_idf_targets)
set(__REQUIRED_IDF_TARGETS "${ARGN}")
__component_check_target()
endfunction()
# register_config_only_component
#
# Compatibility function for registering 3.xx style config components.
macro(register_config_only_component)
register_component()
endmacro()
# component_compile_options
#
# Wrapper around target_compile_options that passes the component name
function(component_compile_options)
target_compile_options(${COMPONENT_LIB} PRIVATE ${ARGV})
endfunction()
# component_compile_definitions
#
# Wrapper around target_compile_definitions that passes the component name
function(component_compile_definitions)
target_compile_definitions(${COMPONENT_LIB} PRIVATE ${ARGV})
endfunction()

View file

@ -1,76 +0,0 @@
function(debug message)
if(DEBUG)
message(STATUS "${message}")
endif()
endfunction()
# Given a component name (find_name) and a list of component paths (component_paths),
# return the path to the component in 'variable'
#
# Fatal error is printed if the component is not found.
function(find_component_path find_name components component_paths variable)
list(FIND components ${find_name} idx)
if(NOT idx EQUAL -1)
list(GET component_paths ${idx} path)
set("${variable}" "${path}" PARENT_SCOPE)
return()
else()
endif()
# TODO: find a way to print the dependency chain that lead to this not-found component
message(WARNING "Required component ${find_name} is not found in any of the provided COMPONENT_DIRS")
endfunction()
# components_find_all: Search 'component_dirs' for components and return them
# as a list of names in 'component_names' and a list of full paths in
# 'component_paths'
#
# component_paths contains only unique component names. Directories
# earlier in the component_dirs list take precedence.
function(components_find_all component_dirs component_paths component_names test_component_names)
# component_dirs entries can be files or lists of files
set(paths "")
set(names "")
set(test_names "")
# start by expanding the component_dirs list with all subdirectories
foreach(dir ${component_dirs})
# Iterate any subdirectories for values
file(GLOB subdirs LIST_DIRECTORIES true "${dir}/*")
foreach(subdir ${subdirs})
set(component_dirs "${component_dirs};${subdir}")
endforeach()
endforeach()
# Look for a component in each component_dirs entry
foreach(dir ${component_dirs})
debug("Looking for CMakeLists.txt in ${dir}")
file(GLOB component "${dir}/CMakeLists.txt")
if(component)
debug("CMakeLists.txt file ${component}")
get_filename_component(component "${component}" DIRECTORY)
get_filename_component(name "${component}" NAME)
if(NOT name IN_LIST names)
list(APPEND names "${name}")
list(APPEND paths "${component}")
# Look for test component directory
file(GLOB test "${component}/test/CMakeLists.txt")
if(test)
list(APPEND test_names "${name}")
endif()
endif()
else() # no CMakeLists.txt file
# test for legacy component.mk and warn
file(GLOB legacy_component "${dir}/component.mk")
if(legacy_component)
get_filename_component(legacy_component "${legacy_component}" DIRECTORY)
message(WARNING "Component ${legacy_component} contains old-style component.mk but no CMakeLists.txt. "
"Component will be skipped.")
endif()
endif()
endforeach()
set(${component_paths} ${paths} PARENT_SCOPE)
set(${component_names} ${names} PARENT_SCOPE)
set(${test_component_names} ${test_names} PARENT_SCOPE)
endfunction()

View file

@ -1,179 +0,0 @@
# Given a list of components in 'component_paths', filter only paths to the components
# mentioned in 'components' and return as a list in 'result_paths'
function(components_get_paths component_paths components result_paths)
set(result "")
foreach(path ${component_paths})
get_filename_component(name "${path}" NAME)
if("${name}" IN_LIST components)
list(APPEND result "${name}")
endif()
endforeach()
set("${result_path}" "${result}" PARENT_SCOPE)
endfunction()
# Add a component to the build, using the COMPONENT variables defined
# in the parent
#
function(register_component)
get_filename_component(component_dir ${CMAKE_CURRENT_LIST_FILE} DIRECTORY)
spaces2list(COMPONENT_SRCS)
spaces2list(COMPONENT_SRCDIRS)
spaces2list(COMPONENT_ADD_INCLUDEDIRS)
spaces2list(COMPONENT_SRCEXCLUDE)
if(COMPONENT_SRCDIRS)
# Warn user if both COMPONENT_SRCDIRS and COMPONENT_SRCS are set
if(COMPONENT_SRCS)
message(WARNING "COMPONENT_SRCDIRS and COMPONENT_SRCS are both set, COMPONENT_SRCS will be ignored")
endif()
set(COMPONENT_SRCS "")
foreach(dir ${COMPONENT_SRCDIRS})
get_filename_component(abs_dir ${dir} ABSOLUTE BASE_DIR ${component_dir})
if(NOT IS_DIRECTORY ${abs_dir})
message(FATAL_ERROR "${CMAKE_CURRENT_LIST_FILE}: COMPONENT_SRCDIRS entry '${dir}' does not exist")
endif()
file(GLOB matches "${abs_dir}/*.c" "${abs_dir}/*.cpp" "${abs_dir}/*.S")
if(matches)
list(SORT matches)
set(COMPONENT_SRCS "${COMPONENT_SRCS};${matches}")
else()
message(FATAL_ERROR "${CMAKE_CURRENT_LIST_FILE}: COMPONENT_SRCDIRS entry '${dir}' has no source files")
endif()
endforeach()
endif()
# Remove COMPONENT_SRCEXCLUDE matches
foreach(exclude ${COMPONENT_SRCEXCLUDE})
get_filename_component(exclude "${exclude}" ABSOLUTE ${component_dir})
foreach(src ${COMPONENT_SRCS})
get_filename_component(abs_src "${src}" ABSOLUTE ${component_dir})
if("${exclude}" STREQUAL "${abs_src}") # compare as canonical paths
list(REMOVE_ITEM COMPONENT_SRCS "${src}")
endif()
endforeach()
endforeach()
# add as a PUBLIC library (if there are source files) or INTERFACE (if header only)
if(COMPONENT_SRCS OR embed_binaries)
add_library(${COMPONENT_TARGET} STATIC ${COMPONENT_SRCS})
set(include_type PUBLIC)
set_property(TARGET ${COMPONENT_TARGET} PROPERTY OUTPUT_NAME ${COMPONENT_NAME})
ldgen_component_add(${COMPONENT_TARGET})
else()
add_library(${COMPONENT_TARGET} INTERFACE) # header-only component
set(include_type INTERFACE)
endif()
# binaries to embed directly in library
spaces2list(COMPONENT_EMBED_FILES)
spaces2list(COMPONENT_EMBED_TXTFILES)
foreach(embed_data ${COMPONENT_EMBED_FILES} ${COMPONENT_EMBED_TXTFILES})
if(embed_data IN_LIST COMPONENT_EMBED_TXTFILES)
set(embed_type "TEXT")
else()
set(embed_type "BINARY")
endif()
target_add_binary_data("${COMPONENT_TARGET}" "${embed_data}" "${embed_type}")
endforeach()
# add component public includes
foreach(include_dir ${COMPONENT_ADD_INCLUDEDIRS})
get_filename_component(abs_dir ${include_dir} ABSOLUTE BASE_DIR ${component_dir})
if(NOT IS_DIRECTORY ${abs_dir})
message(FATAL_ERROR "${CMAKE_CURRENT_LIST_FILE}: "
"COMPONENT_ADD_INCLUDEDIRS entry '${include_dir}' not found")
endif()
target_include_directories(${COMPONENT_TARGET} ${include_type} ${abs_dir})
endforeach()
# add component private includes
foreach(include_dir ${COMPONENT_PRIV_INCLUDEDIRS})
if(${include_type} STREQUAL INTERFACE)
message(FATAL_ERROR "${CMAKE_CURRENT_LIST_FILE} "
"sets no component source files but sets COMPONENT_PRIV_INCLUDEDIRS")
endif()
get_filename_component(abs_dir ${include_dir} ABSOLUTE BASE_DIR ${component_dir})
if(NOT IS_DIRECTORY ${abs_dir})
message(FATAL_ERROR "${CMAKE_CURRENT_LIST_FILE}: "
"COMPONENT_PRIV_INCLUDEDIRS entry '${include_dir}' does not exist")
endif()
target_include_directories(${COMPONENT_TARGET} PRIVATE ${abs_dir})
endforeach()
if(${COMPONENT_NAME} IN_LIST BUILD_TEST_COMPONENTS)
target_link_libraries(${COMPONENT_TARGET} "-L${CMAKE_CURRENT_BINARY_DIR}")
target_link_libraries(${COMPONENT_TARGET} "-Wl,--whole-archive -l${COMPONENT_NAME} -Wl,--no-whole-archive")
endif()
if(COMPONENT_SRCS OR embed_binaries)
target_include_directories(${COMPONENT_TARGET} PUBLIC ${IDF_INCLUDE_DIRECTORIES})
target_compile_options(${COMPONENT_TARGET} PUBLIC ${IDF_COMPILE_OPTIONS})
target_compile_options(${COMPONENT_TARGET} PUBLIC $<$<COMPILE_LANGUAGE:C>:${IDF_C_COMPILE_OPTIONS}>)
target_compile_options(${COMPONENT_TARGET} PUBLIC $<$<COMPILE_LANGUAGE:CXX>:${IDF_CXX_COMPILE_OPTIONS}>)
target_compile_definitions(${COMPONENT_TARGET} PUBLIC ${IDF_COMPILE_DEFINITIONS})
endif()
if(COMPONENT_ADD_LDFRAGMENTS)
spaces2list(COMPONENT_ADD_LDFRAGMENTS)
ldgen_add_fragment_files(${COMPONENT_TARGET} "${COMPONENT_ADD_LDFRAGMENTS}")
endif()
endfunction()
function(register_config_only_component)
get_filename_component(component_dir ${CMAKE_CURRENT_LIST_FILE} DIRECTORY)
get_filename_component(component ${component_dir} NAME)
# No-op for now...
endfunction()
function(add_component_dependencies target dep dep_type)
get_target_property(target_type ${target} TYPE)
get_target_property(target_imported ${target} IMPORTED)
if(${target_type} STREQUAL STATIC_LIBRARY OR ${target_type} STREQUAL EXECUTABLE)
if(TARGET ${dep})
# Add all compile options exported by dep into target
target_include_directories(${target} ${dep_type}
$<TARGET_PROPERTY:${dep},INTERFACE_INCLUDE_DIRECTORIES>)
target_compile_definitions(${target} ${dep_type}
$<TARGET_PROPERTY:${dep},INTERFACE_COMPILE_DEFINITIONS>)
target_compile_options(${target} ${dep_type}
$<TARGET_PROPERTY:${dep},INTERFACE_COMPILE_OPTIONS>)
endif()
endif()
endfunction()
function(require_idf_targets)
if(NOT ${IDF_TARGET} IN_LIST ARGN)
message(FATAL_ERROR "Component ${COMPONENT_NAME} only supports targets: ${ARGN}")
endif()
endfunction()
# component_compile_options
#
# Wrapper around target_compile_options that passes the component name
function(component_compile_options)
target_compile_options(${COMPONENT_TARGET} PRIVATE ${ARGV})
endfunction()
# component_compile_definitions
#
# Wrapper around target_compile_definitions that passes the component name
function(component_compile_definitions)
target_compile_definitions(${COMPONENT_TARGET} PRIVATE ${ARGV})
endfunction()
# component_get_target
#
# Get the library target created for the given component
function(component_get_target var component)
get_property(prefix GLOBAL PROPERTY __IDF_COMPONENTS_PREFIX)
set(${var} ${prefix}_${component} PARENT_SCOPE)
endfunction()

View file

@ -173,7 +173,7 @@ def convert_component(project_path, component_path):
else:
f.write("register_config_only_component()\n")
if cflags is not None:
f.write("component_compile_options(%s)\n" % cflags)
f.write("target_compile_options(${COMPONENT_LIB} PRIVATE %s)\n" % cflags)
print("Converted %s" % cmakelists_path)

View file

@ -31,7 +31,8 @@ function(crosstool_version_check expected_ctng_version)
endfunction()
function(get_expected_ctng_version _toolchain_ver _gcc_ver)
file(STRINGS ${IDF_PATH}/tools/toolchain_versions.mk config_contents)
idf_build_get_property(idf_path IDF_PATH)
file(STRINGS ${idf_path}/tools/toolchain_versions.mk config_contents)
foreach(name_and_value ${config_contents})
# Strip spaces
string(REPLACE " " "" name_and_value ${name_and_value})

45
tools/cmake/idf.cmake Normal file
View file

@ -0,0 +1,45 @@
get_property(__idf_env_set GLOBAL PROPERTY __IDF_ENV_SET)
if(NOT __idf_env_set)
# Infer an IDF_PATH relative to the tools/cmake directory
get_filename_component(_idf_path "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE)
file(TO_CMAKE_PATH "${_idf_path}" _idf_path)
# Get the path set in environment
set(idf_path $ENV{IDF_PATH})
file(TO_CMAKE_PATH "${idf_path}" idf_path)
# Environment IDF_PATH should match the inferred IDF_PATH. If not, warn the user.
if(idf_path)
if(NOT idf_path STREQUAL _idf_path)
message(WARNING "IDF_PATH environment variable is different from inferred IDF_PATH.
Check if your project's top-level CMakeLists.txt includes the right
CMake files. Environment IDF_PATH will be used for the build.")
endif()
else()
message(WARNING "IDF_PATH environment variable not found. Setting IDF_PATH to '${_idf_path}'.")
set(idf_path ${_idf_path})
set(ENV{IDF_PATH} ${_idf_path})
endif()
# Include other CMake modules required
set(CMAKE_MODULE_PATH
"${idf_path}/tools/cmake"
"${idf_path}/tools/cmake/third_party"
${CMAKE_MODULE_PATH})
include(build)
set(IDF_PATH ${idf_path})
include(GetGitRevisionDescription)
include(git_submodules)
include(crosstool_version_check)
include(kconfig)
include(component)
include(utilities)
include(targets)
include(ldgen)
__build_init("${idf_path}")
set_property(GLOBAL PROPERTY __IDF_ENV_SET 1)
endif()

View file

@ -1,326 +0,0 @@
#
# Load cmake modules
#
get_property(__idf_environment_set GLOBAL PROPERTY __IDF_ENVIRONMENT_SET)
if(NOT __idf_environment_set)
# Set IDF_PATH, as nothing else will work without this.
set(IDF_PATH "$ENV{IDF_PATH}")
if(NOT IDF_PATH)
# Documentation says you should set IDF_PATH in your environment, but we
# can infer it relative to tools/cmake directory if it's not set.
get_filename_component(IDF_PATH "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE)
endif()
file(TO_CMAKE_PATH "${IDF_PATH}" IDF_PATH)
set(ENV{IDF_PATH} ${IDF_PATH})
set(CMAKE_MODULE_PATH
"${IDF_PATH}/tools/cmake"
"${IDF_PATH}/tools/cmake/third_party"
${CMAKE_MODULE_PATH})
include(utilities)
include(components)
include(kconfig)
include(targets)
include(git_submodules)
include(GetGitRevisionDescription)
include(crosstool_version_check)
include(ldgen)
set_default(PYTHON "python")
if(NOT PYTHON_DEPS_CHECKED AND NOT BOOTLOADER_BUILD)
message(STATUS "Checking Python dependencies...")
execute_process(COMMAND "${PYTHON}" "${IDF_PATH}/tools/check_python_dependencies.py"
RESULT_VARIABLE result)
if(NOT result EQUAL 0)
message(FATAL_ERROR "Some Python dependencies must be installed. Check above message for details.")
endif()
endif()
idf_set_target()
set_property(GLOBAL APPEND PROPERTY __IDF_COMPONENTS_PREFIX "idf_component")
set_property(GLOBAL PROPERTY __IDF_ENVIRONMENT_SET 1)
endif()
macro(idf_set_variables)
set_default(IDF_BUILD_ARTIFACTS OFF)
if(IDF_BUILD_ARTIFACTS)
if(NOT IDF_BUILD_ARTIFACTS_DIR OR NOT IDF_PROJECT_EXECUTABLE)
message(FATAL_ERROR "IDF_BUILD_ARTIFACTS and IDF_PROJECT_EXECUTABLE needs to be specified \
if IDF_BUILD_ARTIFACTS is ON.")
endif()
endif()
set_default(IDF_COMPONENT_DIRS "${IDF_EXTRA_COMPONENT_DIRS} ${IDF_PATH}/components")
set_default(IDF_COMPONENTS "")
set_default(IDF_COMPONENT_REQUIRES_COMMON "cxx ${IDF_TARGET} newlib freertos heap log \
esp_rom esp_common xtensa")
list(FIND IDF_COMPONENT_REQUIRES_COMMON "${IDF_TARGET}" result)
if(result EQUAL -1)
list(APPEND IDF_COMPONENT_REQUIRES_COMMON "${IDF_TARGET}")
endif()
if(CONFIG_LEGACY_INCLUDE_COMMON_HEADERS)
list(APPEND IDF_COMPONENT_REQUIRES_COMMON "soc")
endif()
set(IDF_PROJECT_PATH "${CMAKE_SOURCE_DIR}")
set(ESP_PLATFORM 1 CACHE BOOL INTERNAL)
spaces2list(IDF_COMPONENT_DIRS)
spaces2list(IDF_COMPONENTS)
spaces2list(IDF_COMPONENT_REQUIRES_COMMON)
endmacro()
# Add all the IDF global compiler & preprocessor options
# (applied to all components). Some are config-dependent
#
# If you only want to set options for a particular component,
# don't call or edit this function. TODO DESCRIBE WHAT TO DO INSTEAD
#
function(idf_set_global_compile_options)
# Temporary trick to support both gcc5 and gcc8 builds
if(CMAKE_C_COMPILER_VERSION VERSION_EQUAL 5.2.0)
set(GCC_NOT_5_2_0 0 CACHE STRING "GCC is 5.2.0 version")
else()
set(GCC_NOT_5_2_0 1 CACHE STRING "GCC is not 5.2.0 version")
endif()
list(APPEND compile_definitions "GCC_NOT_5_2_0=${GCC_NOT_5_2_0}")
list(APPEND compile_definitions "ESP_PLATFORM" "HAVE_CONFIG_H")
spaces2list(CMAKE_C_FLAGS)
spaces2list(CMAKE_CXX_FLAGS)
list(APPEND compile_options "${CMAKE_C_FLAGS}")
list(APPEND c_compile_options "${CMAKE_C_FLAGS}")
list(APPEND cxx_compile_options "${CMAKE_CXX_FLAGS}")
if(CONFIG_OPTIMIZATION_LEVEL_RELEASE)
list(APPEND compile_options "-Os")
else()
list(APPEND compile_options "-Og")
endif()
list(APPEND c_compile_options "-std=gnu99")
list(APPEND cxx_compile_options "-std=gnu++11" "-fno-rtti")
# IDF uses some GNU extension from libc
list(APPEND compile_definitions "_GNU_SOURCE")
if(CONFIG_CXX_EXCEPTIONS)
list(APPEND cxx_compile_options "-fexceptions")
else()
list(APPEND cxx_compile_options "-fno-exceptions")
endif()
# Default compiler configuration
list(APPEND compile_options "-ffunction-sections"
"-fdata-sections"
"-fstrict-volatile-bitfields"
"-nostdlib")
list(APPEND compile_options "-Wall"
"-Werror=all"
"-Wno-error=unused-function"
"-Wno-error=unused-but-set-variable"
"-Wno-error=unused-variable"
"-Wno-error=deprecated-declarations"
"-Wextra"
"-Wno-unused-parameter"
"-Wno-sign-compare")
list(APPEND c_compile_options "-Wno-old-style-declaration")
if(CONFIG_DISABLE_GCC8_WARNINGS)
list(APPEND compile_options
"-Wno-parentheses"
"-Wno-sizeof-pointer-memaccess"
"-Wno-clobbered"
)
# doesn't use GCC_NOT_5_2_0 because idf_set_global_variables was not called before
if(NOT CMAKE_C_COMPILER_VERSION VERSION_EQUAL 5.2.0)
list(APPEND compile_options
"-Wno-format-overflow"
"-Wno-stringop-truncation"
"-Wno-misleading-indentation"
"-Wno-cast-function-type"
"-Wno-implicit-fallthrough"
"-Wno-unused-const-variable"
"-Wno-switch-unreachable"
"-Wno-format-truncation"
"-Wno-memset-elt-size"
"-Wno-int-in-bool-context"
)
endif()
endif()
# Stack protection
if(NOT BOOTLOADER_BUILD)
if(CONFIG_STACK_CHECK_NORM)
list(APPEND compile_options "-fstack-protector")
elseif(CONFIG_STACK_CHECK_STRONG)
list(APPEND compile_options "-fstack-protector-strong")
elseif(CONFIG_STACK_CHECK_ALL)
list(APPEND compile_options "-fstack-protector-all")
endif()
endif()
if(CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED)
list(APPEND compile_definitions "NDEBUG")
endif()
# Always generate debug symbols (even in Release mode, these don't
# go into the final binary so have no impact on size)
list(APPEND compile_options "-ggdb")
# Use EXTRA_CFLAGS, EXTRA_CXXFLAGS and EXTRA_CPPFLAGS to add more priority options to the compiler
# EXTRA_CPPFLAGS is used for both C and C++
# Unlike environments' CFLAGS/CXXFLAGS/CPPFLAGS which work for both host and target build,
# these works only for target build
set(EXTRA_CFLAGS "$ENV{EXTRA_CFLAGS}")
set(EXTRA_CXXFLAGS "$ENV{EXTRA_CXXFLAGS}")
set(EXTRA_CPPFLAGS "$ENV{EXTRA_CPPFLAGS}")
spaces2list(EXTRA_CFLAGS)
spaces2list(EXTRA_CXXFLAGS)
spaces2list(EXTRA_CPPFLAGS)
list(APPEND c_compile_options ${EXTRA_CFLAGS})
list(APPEND cxx_compile_options ${EXTRA_CXXFLAGS})
list(APPEND compile_options ${EXTRA_CPPFLAGS})
set_default(IDF_COMPILE_DEFINITIONS "${compile_definitions}")
set_default(IDF_COMPILE_OPTIONS "${compile_options}")
set_default(IDF_C_COMPILE_OPTIONS "${c_compile_options}")
set_default(IDF_CXX_COMPILE_OPTIONS "${cxx_compile_options}")
set_default(IDF_INCLUDE_DIRECTORIES "${CONFIG_DIR}")
set(IDF_COMPILE_DEFINITIONS ${IDF_COMPILE_DEFINITIONS} PARENT_SCOPE)
set(IDF_COMPILE_OPTIONS ${IDF_COMPILE_OPTIONS} PARENT_SCOPE)
set(IDF_C_COMPILE_OPTIONS ${IDF_C_COMPILE_OPTIONS} PARENT_SCOPE)
set(IDF_CXX_COMPILE_OPTIONS ${IDF_CXX_COMPILE_OPTIONS} PARENT_SCOPE)
set(IDF_INCLUDE_DIRECTORIES ${CONFIG_DIR} PARENT_SCOPE)
endfunction()
# Verify the IDF environment is configured correctly (environment, toolchain, etc)
function(idf_verify_environment)
if(NOT CMAKE_PROJECT_NAME)
message(FATAL_ERROR "Internal error, IDF project.cmake should have set this variable already")
endif()
# Check toolchain is configured properly in cmake
if(NOT ( ${CMAKE_SYSTEM_NAME} STREQUAL "Generic" AND ${CMAKE_C_COMPILER} MATCHES xtensa))
message(FATAL_ERROR "Internal error, toolchain has not been set correctly by project "
"(or an invalid CMakeCache.txt file has been generated somehow)")
endif()
#
# Warn if the toolchain version doesn't match
#
# TODO: make these platform-specific for diff toolchains
get_expected_ctng_version(expected_toolchain expected_gcc)
gcc_version_check("${expected_gcc}")
crosstool_version_check("${expected_toolchain}")
endfunction()
# idf_get_git_revision
#
# Set global IDF_VER to the git revision of ESP-IDF.
#
# Running git_describe() here automatically triggers rebuilds
# if the ESP-IDF git version changes
function(idf_get_git_revision)
git_describe(IDF_VER_GIT "${IDF_PATH}")
if(EXISTS "${IDF_PATH}/version.txt")
file(STRINGS "${IDF_PATH}/version.txt" IDF_VER_T)
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${IDF_PATH}/version.txt")
else()
set(IDF_VER_T ${IDF_VER_GIT})
endif()
# cut IDF_VER to required 32 characters.
string(SUBSTRING "${IDF_VER_T}" 0 31 IDF_VER)
message(STATUS "IDF_VER: ${IDF_VER}")
add_definitions(-DIDF_VER=\"${IDF_VER}\")
git_submodule_check("${IDF_PATH}")
set(IDF_VER ${IDF_VER} PARENT_SCOPE)
endfunction()
# app_get_revision
#
# Set global PROJECT_VER
#
# If PROJECT_VER variable set in project CMakeLists.txt file, its value will be used.
# Else, if the _project_path/version.txt exists, its contents will be used as PROJECT_VER.
# Else, if the project is located inside a Git repository, the output of git describe will be used.
# Otherwise, PROJECT_VER will be "1".
function(app_get_revision _project_path)
if(NOT DEFINED PROJECT_VER)
if(EXISTS "${_project_path}/version.txt")
file(STRINGS "${_project_path}/version.txt" PROJECT_VER)
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${_project_path}/version.txt")
else()
git_describe(PROJECT_VER_GIT "${_project_path}")
if(PROJECT_VER_GIT)
set(PROJECT_VER ${PROJECT_VER_GIT})
else()
message(STATUS "Project is not inside a git repository, \
will not use 'git describe' to determine PROJECT_VER.")
set(PROJECT_VER "1")
endif()
endif()
endif()
message(STATUS "Project version: ${PROJECT_VER}")
set(PROJECT_VER ${PROJECT_VER} PARENT_SCOPE)
endfunction()
# idf_link_components
#
# Link library components to the target
function(idf_link_components target components)
foreach(component ${components})
component_get_target(component_target ${component})
# Add each component library's link-time dependencies (which are otherwise ignored) to the executable
# LINK_DEPENDS in order to trigger a re-link when needed (on Ninja/Makefile generators at least).
# (maybe this should probably be something CMake does, but it doesn't do it...)
if(TARGET ${component_target})
get_target_property(type ${component_target} TYPE)
get_target_property(imported ${component_target} IMPORTED)
if(NOT imported)
if(${type} STREQUAL STATIC_LIBRARY OR ${type} STREQUAL EXECUTABLE)
get_target_property(link_depends "${component_target}" LINK_DEPENDS)
if(link_depends)
set_property(TARGET ${target} APPEND PROPERTY LINK_DEPENDS "${link_depends}")
endif()
endif()
endif()
if(${type} MATCHES .+_LIBRARY)
list(APPEND libraries ${component_target})
endif()
endif()
endforeach()
if(libraries)
# gc-sections is necessary for linking some IDF binary libraries
# (and without it, IDF apps are much larger than they should be)
target_link_libraries(${target} "-Wl,--gc-sections")
target_link_libraries(${target} "-Wl,--start-group")
target_link_libraries(${target} ${libraries})
message(STATUS "Component libraries: ${IDF_COMPONENT_LIBRARIES}")
endif()
endfunction()
# idf_import_components
#
# Adds ESP-IDF as a subdirectory to the current project and imports the components
function(idf_import_components var idf_path build_path)
add_subdirectory(${idf_path} ${build_path})
set(${var} ${BUILD_COMPONENTS} PARENT_SCOPE)
endfunction()

View file

@ -1,147 +1,211 @@
include(ExternalProject)
macro(kconfig_set_variables)
set_default(IDF_SDKCONFIG_DEFAULTS "")
function(__kconfig_init)
idf_build_get_property(idf_path IDF_PATH)
if(CMAKE_HOST_WIN32)
# Prefer a prebuilt mconf-idf on Windows
if(DEFINED ENV{MSYSTEM})
find_program(WINPTY winpty)
else()
unset(WINPTY CACHE) # in case previous CMake run was in a tty and this one is not
endif()
find_program(MCONF mconf-idf)
set_default(CONFIG_DIR ${IDF_BUILD_ARTIFACTS_DIR}/config)
set_default(SDKCONFIG ${IDF_PROJECT_PATH}/sdkconfig)
set(SDKCONFIG_HEADER ${CONFIG_DIR}/sdkconfig.h)
set(SDKCONFIG_CMAKE ${CONFIG_DIR}/sdkconfig.cmake)
set(SDKCONFIG_JSON ${CONFIG_DIR}/sdkconfig.json)
set(KCONFIG_JSON_MENUS ${CONFIG_DIR}/kconfig_menus.json)
# Fall back to the old binary which was called 'mconf' not 'mconf-idf'
if(NOT MCONF)
find_program(MCONF mconf)
if(MCONF)
message(WARNING "Falling back to mconf binary '${MCONF}' not mconf-idf. "
"This is probably because an old version of IDF mconf is installed and this is fine. "
"However if there are config problems please check the Getting Started guide for your platform.")
endif()
endif()
set(ROOT_KCONFIG ${IDF_PATH}/Kconfig)
endmacro()
if(CMAKE_HOST_WIN32)
# Prefer a prebuilt mconf-idf on Windows
if(DEFINED ENV{MSYSTEM})
find_program(WINPTY winpty)
else()
unset(WINPTY CACHE) # in case previous CMake run was in a tty and this one is not
endif()
find_program(MCONF mconf-idf)
# Fall back to the old binary which was called 'mconf' not 'mconf-idf'
if(NOT MCONF)
find_program(MCONF mconf)
if(MCONF)
message(WARNING "Falling back to mconf binary '${MCONF}' not mconf-idf. "
"This is probably because an old version of IDF mconf is installed and this is fine. "
"However if there are config problems please check the Getting Started guide for your platform.")
if(NOT MCONF)
find_program(NATIVE_GCC gcc)
if(NOT NATIVE_GCC)
message(FATAL_ERROR
"Windows requires a prebuilt mconf-idf for your platform "
"on the PATH, or an MSYS2 version of gcc on the PATH to build mconf-idf. "
"Consult the setup docs for ESP-IDF on Windows.")
endif()
elseif(WINPTY)
set(MCONF "${WINPTY}" "${MCONF}")
endif()
endif()
if(NOT MCONF)
find_program(NATIVE_GCC gcc)
if(NOT NATIVE_GCC)
message(FATAL_ERROR
"Windows requires a prebuilt mconf-idf for your platform "
"on the PATH, or an MSYS2 version of gcc on the PATH to build mconf-idf. "
"Consult the setup docs for ESP-IDF on Windows.")
endif()
elseif(WINPTY)
set(MCONF "${WINPTY}" "${MCONF}")
# Use the existing Makefile to build mconf (out of tree) when needed
#
set(MCONF ${CMAKE_BINARY_DIR}/kconfig_bin/mconf-idf)
externalproject_add(mconf-idf
SOURCE_DIR ${idf_path}/tools/kconfig
CONFIGURE_COMMAND ""
BINARY_DIR "kconfig_bin"
BUILD_COMMAND make -f ${idf_path}/tools/kconfig/Makefile mconf-idf
BUILD_BYPRODUCTS ${MCONF}
INSTALL_COMMAND ""
EXCLUDE_FROM_ALL 1
)
file(GLOB mconf_srcfiles ${idf_path}/tools/kconfig/*.c)
externalproject_add_stepdependencies(mconf-idf build
${mconf_srcfiles}
${idf_path}/tools/kconfig/Makefile
${CMAKE_CURRENT_LIST_FILE})
unset(mconf_srcfiles)
set(menuconfig_depends DEPENDS mconf-idf)
endif()
endif()
if(NOT MCONF)
# Use the existing Makefile to build mconf (out of tree) when needed
#
set(MCONF ${CMAKE_BINARY_DIR}/kconfig_bin/mconf-idf)
idf_build_set_property(__MCONF ${MCONF})
idf_build_set_property(__MENUCONFIG_DEPENDS "${menuconfig_depends}")
externalproject_add(mconf-idf
SOURCE_DIR ${IDF_PATH}/tools/kconfig
CONFIGURE_COMMAND ""
BINARY_DIR "kconfig_bin"
BUILD_COMMAND make -f ${IDF_PATH}/tools/kconfig/Makefile mconf-idf
BUILD_BYPRODUCTS ${MCONF}
INSTALL_COMMAND ""
EXCLUDE_FROM_ALL 1
)
idf_build_get_property(idf_path IDF_PATH)
idf_build_set_property(__ROOT_KCONFIG ${idf_path}/Kconfig)
idf_build_set_property(__OUTPUT_SDKCONFIG 1)
endfunction()
file(GLOB mconf_srcfiles ${IDF_PATH}/tools/kconfig/*.c)
externalproject_add_stepdependencies(mconf-idf build
${mconf_srcfiles}
${IDF_PATH}/tools/kconfig/Makefile
${CMAKE_CURRENT_LIST_FILE})
unset(mconf_srcfiles)
#
# Initialize Kconfig-related properties for components.
# This function assumes that all basic properties of the components have been
# set prior to calling it.
#
function(__kconfig_component_init component_target)
__component_get_property(component_dir ${component_target} COMPONENT_DIR)
file(GLOB kconfig "${component_dir}/Kconfig")
__component_set_property(${component_target} KCONFIG "${kconfig}")
file(GLOB kconfig "${component_dir}/Kconfig.projbuild")
__component_set_property(${component_target} KCONFIG_PROJBUILD "${kconfig}")
endfunction()
set(menuconfig_depends DEPENDS mconf-idf)
endif()
# Find all Kconfig files for all components
function(kconfig_process_config)
file(MAKE_DIRECTORY "${CONFIG_DIR}")
set(kconfigs)
set(kconfigs_projbuild)
# Components are usually sorted (somewhat) topologically via their dependencies. This extends to the component
# paths list. Obtain an alphabetical list in order to present menus also in the same order.
set(components ${BUILD_COMPONENTS})
list(SORT components)
foreach(component ${components})
list(FIND BUILD_COMPONENTS ${component} idx)
list(GET BUILD_COMPONENT_PATHS ${idx} component_path)
list(APPEND component_paths ${component_path})
endforeach()
# Find Kconfig and Kconfig.projbuild for each component as applicable
# if any of these change, cmake should rerun
foreach(dir ${component_paths})
file(GLOB kconfig "${dir}/Kconfig")
#
# Generate the config files and create config related targets and configure
# dependencies.
#
function(__kconfig_generate_config sdkconfig sdkconfig_defaults)
# List all Kconfig and Kconfig.projbuild in known components
idf_build_get_property(component_targets __COMPONENT_TARGETS)
foreach(component_target ${component_targets})
__component_get_property(kconfig ${component_target} KCONFIG)
__component_get_property(kconfig_projbuild ${component_target} KCONFIG_PROJBUILD)
if(kconfig)
set(kconfigs "${kconfigs} ${kconfig}")
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${kconfig})
list(APPEND kconfigs ${kconfig})
endif()
file(GLOB kconfig ${dir}/Kconfig.projbuild)
if(kconfig)
set(kconfigs_projbuild "${kconfigs_projbuild} ${kconfig}")
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${kconfig})
if(kconfig_projbuild)
list(APPEND kconfig_projbuilds ${kconfig_projbuild})
endif()
endforeach()
if(IDF_SDKCONFIG_DEFAULTS)
set(defaults_arg --defaults "${IDF_SDKCONFIG_DEFAULTS}")
# Store the list version of kconfigs and kconfig_projbuilds
idf_build_set_property(KCONFIGS "${kconfigs}")
idf_build_set_property(KCONFIG_PROJBUILDS "${kconfig_projbuilds}")
idf_build_get_property(idf_target IDF_TARGET)
if(sdkconfig_defaults)
set(defaults_arg --defaults "${sdkconfig_defaults}")
endif()
if(EXISTS "${IDF_SDKCONFIG_DEFAULTS}.${IDF_TARGET}")
list(APPEND defaults_arg --defaults "${IDF_SDKCONFIG_DEFAULTS}.${IDF_TARGET}")
if(EXISTS "${sdkconfig_defaults}.${idf_target}")
list(APPEND defaults_arg --defaults "${sdkconfig_defaults}.${idf_target}")
endif()
# Set these in the parent scope, so that they can be written to project_description.json
set(kconfigs "${kconfigs}")
set(COMPONENT_KCONFIGS "${kconfigs}" PARENT_SCOPE)
set(COMPONENT_KCONFIGS_PROJBUILD "${kconfigs_projbuild}" PARENT_SCOPE)
idf_build_get_property(idf_path IDF_PATH)
idf_build_get_property(root_kconfig __ROOT_KCONFIG)
idf_build_get_property(python PYTHON)
string(REPLACE ";" " " kconfigs "${kconfigs}")
string(REPLACE ";" " " kconfig_projbuilds "${kconfig_projbuilds}")
set(confgen_basecommand
${PYTHON} ${IDF_PATH}/tools/kconfig_new/confgen.py
--kconfig ${ROOT_KCONFIG}
--config ${SDKCONFIG}
${python} ${idf_path}/tools/kconfig_new/confgen.py
--kconfig ${root_kconfig}
--config ${sdkconfig}
${defaults_arg}
--env "COMPONENT_KCONFIGS=${kconfigs}"
--env "COMPONENT_KCONFIGS_PROJBUILD=${kconfigs_projbuild}"
--env "IDF_CMAKE=y")
--env "COMPONENT_KCONFIGS_PROJBUILD=${kconfig_projbuilds}"
--env "IDF_CMAKE=y"
--env "IDF_TARGET=${idf_target}")
idf_build_get_property(build_dir BUILD_DIR)
set(config_dir ${build_dir}/config)
file(MAKE_DIRECTORY "${config_dir}")
# Generate the config outputs
set(sdkconfig_cmake ${config_dir}/sdkconfig.cmake)
set(sdkconfig_header ${config_dir}/sdkconfig.h)
set(sdkconfig_json ${config_dir}/sdkconfig.json)
set(sdkconfig_json_menus ${config_dir}/${kconfig_menus}.json)
idf_build_get_property(output_sdkconfig __OUTPUT_SDKCONFIG)
if(output_sdkconfig)
execute_process(
COMMAND ${confgen_basecommand}
--output header ${sdkconfig_header}
--output cmake ${sdkconfig_cmake}
--output json ${sdkconfig_json}
--output json_menus ${sdkconfig_json_menus}
--output config ${sdkconfig}
RESULT_VARIABLE config_result)
else()
execute_process(
COMMAND ${confgen_basecommand}
--output header ${sdkconfig_header}
--output cmake ${sdkconfig_cmake}
--output json ${sdkconfig_json}
--output json_menus ${sdkconfig_json_menus}
RESULT_VARIABLE config_result)
endif()
if(config_result)
message(FATAL_ERROR "Failed to run confgen.py (${confgen_basecommand}). Error ${config_result}")
endif()
# Add the generated config header to build specifications.
idf_build_set_property(INCLUDE_DIRECTORIES ${config_dir} APPEND)
# When sdkconfig file changes in the future, trigger a cmake run
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${sdkconfig}")
# Ditto if either of the generated files are missing/modified (this is a bit irritating as it means
# you can't edit these manually without them being regenerated, but I don't know of a better way...)
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${sdkconfig_header}")
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${sdkconfig_cmake}")
# Or if the config generation tool changes
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${idf_path}/tools/kconfig_new/confgen.py")
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${idf_path}/tools/kconfig_new/kconfiglib.py")
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY
ADDITIONAL_MAKE_CLEAN_FILES "${sdkconfig_header}" "${sdkconfig_cmake}")
idf_build_set_property(SDKCONFIG_HEADER ${sdkconfig_header})
idf_build_set_property(SDKCONFIG_JSON ${sdkconfig_json})
idf_build_set_property(SDKCONFIG_CMAKE ${sdkconfig_cmake})
idf_build_set_property(SDKCONFIG_JSON_MENUS ${sdkconfig_json_menus})
idf_build_get_property(menuconfig_depends __MENUCONFIG_DEPENDS)
idf_build_get_property(mconf __MCONF)
# Generate the menuconfig target (uses C-based mconf-idf tool, either prebuilt or via mconf-idf target above)
add_custom_target(menuconfig
${menuconfig_depends}
# create any missing config file, with defaults if necessary
COMMAND ${confgen_basecommand} --env "IDF_TARGET=${IDF_TARGET}" --output config ${SDKCONFIG}
COMMAND ${confgen_basecommand} --env "IDF_TARGET=${idf_target}" --output config ${sdkconfig}
COMMAND ${CMAKE_COMMAND} -E env
"COMPONENT_KCONFIGS=${kconfigs}"
"COMPONENT_KCONFIGS_PROJBUILD=${kconfigs_projbuild}"
"COMPONENT_KCONFIGS_PROJBUILD=${kconfig_projbuilds}"
"IDF_CMAKE=y"
"KCONFIG_CONFIG=${SDKCONFIG}"
"IDF_TARGET=${IDF_TARGET}"
${MCONF} ${ROOT_KCONFIG}
"KCONFIG_CONFIG=${sdkconfig}"
${mconf} ${root_kconfig}
VERBATIM
USES_TERMINAL
# additional run of confgen esures that the deprecated options will be inserted into sdkconfig (for backward
# compatibility)
COMMAND ${confgen_basecommand} --env "IDF_TARGET=${IDF_TARGET}" --output config ${SDKCONFIG}
COMMAND ${confgen_basecommand} --env "IDF_TARGET=${idf_target}" --output config ${sdkconfig}
)
# Custom target to run confserver.py from the build tool
@ -152,47 +216,4 @@ function(kconfig_process_config)
${PYTHON} ${IDF_PATH}/tools/kconfig_new/confserver.py --kconfig ${IDF_PATH}/Kconfig --config ${SDKCONFIG}
VERBATIM
USES_TERMINAL)
# Generate configuration output via confgen.py
# makes sdkconfig.h and skdconfig.cmake
#
# This happens during the cmake run not during the build
if(NOT BOOTLOADER_BUILD)
execute_process(
COMMAND ${confgen_basecommand}
--output header ${SDKCONFIG_HEADER}
--output cmake ${SDKCONFIG_CMAKE}
--output json ${SDKCONFIG_JSON}
--output json_menus ${KCONFIG_JSON_MENUS}
--output config ${SDKCONFIG} # only generate config at the top-level project
RESULT_VARIABLE config_result)
else()
execute_process(
COMMAND ${confgen_basecommand}
--output header ${SDKCONFIG_HEADER}
--output cmake ${SDKCONFIG_CMAKE}
--output json ${SDKCONFIG_JSON}
--output json_menus ${KCONFIG_JSON_MENUS}
RESULT_VARIABLE config_result)
endif()
if(config_result)
message(FATAL_ERROR "Failed to run confgen.py (${confgen_basecommand}). Error ${config_result}")
endif()
# When sdkconfig file changes in the future, trigger a cmake run
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${SDKCONFIG}")
# Ditto if either of the generated files are missing/modified (this is a bit irritating as it means
# you can't edit these manually without them being regenerated, but I don't know of a better way...)
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${SDKCONFIG_HEADER}")
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${SDKCONFIG_CMAKE}")
# Or if the config generation tool changes
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${IDF_PATH}/tools/kconfig_new/confgen.py")
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${IDF_PATH}/tools/kconfig_new/kconfiglib.py")
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY
ADDITIONAL_MAKE_CLEAN_FILES
"${SDKCONFIG_HEADER}" "${SDKCONFIG_CMAKE}")
endfunction()

View file

@ -1,81 +1,84 @@
# Utilities for supporting linker script generation in the build system
# ldgen_set_variables
#
# Create the custom target to attach the fragment files and template files
# for the build to.
function(ldgen_set_variables)
add_custom_target(ldgen)
endfunction()
# ldgen_add_fragment_files
# __ldgen_add_fragment_files
#
# Add one or more linker fragment files, and append it to the list of fragment
# files found so far.
function(ldgen_add_fragment_files component fragment_files)
function(__ldgen_add_fragment_files fragment_files)
spaces2list(fragment_files)
foreach(fragment_file ${fragment_files})
get_filename_component(_fragment_file ${fragment_file} ABSOLUTE)
list(APPEND _fragment_files ${_fragment_file})
get_filename_component(abs_path ${fragment_file} ABSOLUTE)
list(APPEND _fragment_files ${abs_path})
endforeach()
set_property(TARGET ldgen APPEND PROPERTY FRAGMENT_FILES ${_fragment_files})
idf_build_set_property(__LDGEN_FRAGMENT_FILES "${_fragment_files}" APPEND)
endfunction()
# ldgen_component_add
# __ldgen_add_component
#
# Add component to known libraries for linker script generation
function(ldgen_component_add component_lib)
set_property(TARGET ldgen APPEND PROPERTY OUTPUT_LIBRARIES "$<TARGET_FILE:${component_lib}>")
set_property(TARGET ldgen APPEND PROPERTY LIBRARIES ${component_lib})
# Generate sections info for specified target to be used in linker script generation
function(__ldgen_add_component component_lib)
idf_build_set_property(__LDGEN_LIBRARIES "$<TARGET_FILE:${component_lib}>" APPEND)
idf_build_set_property(__LDGEN_DEPENDS ${component_lib} APPEND)
endfunction()
# ldgen_process_template
# __ldgen_process_template
#
# Passes a linker script template to the linker script generation tool for
# processing
function(ldgen_process_template template output)
get_property(output_libraries TARGET ldgen PROPERTY OUTPUT_LIBRARIES)
file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/ldgen_libraries.in CONTENT "$<JOIN:${output_libraries},\n>")
file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/ldgen_libraries INPUT ${CMAKE_BINARY_DIR}/ldgen_libraries.in)
function(__ldgen_process_template output_var template)
idf_build_get_property(idf_target IDF_TARGET)
idf_build_get_property(idf_path IDF_PATH)
get_filename_component(filename "${template}" NAME_WE)
idf_build_get_property(build_dir BUILD_DIR)
idf_build_get_property(ldgen_libraries __LDGEN_LIBRARIES GENERATOR_EXPRESSION)
file(GENERATE OUTPUT ${build_dir}/ldgen_libraries.in CONTENT $<JOIN:${ldgen_libraries},\n>)
file(GENERATE OUTPUT ${build_dir}/ldgen_libraries INPUT ${build_dir}/ldgen_libraries.in)
get_filename_component(filename "${template}" NAME)
set(output ${CMAKE_CURRENT_BINARY_DIR}/${filename}.ld)
set(${output_var} ${output} PARENT_SCOPE)
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
"${CMAKE_BINARY_DIR}/ldgen_libraries.in"
"${CMAKE_BINARY_DIR}/ldgen_libraries")
"${build_dir}/ldgen_libraries.in"
"${build_dir}/ldgen_libraries")
idf_build_get_property(ldgen_fragment_files __LDGEN_FRAGMENT_FILES GENERATOR_EXPRESSION)
idf_build_get_property(ldgen_depends __LDGEN_DEPENDS GENERATOR_EXPRESSION)
# Create command to invoke the linker script generator tool.
idf_build_get_property(sdkconfig SDKCONFIG)
idf_build_get_property(root_kconfig __ROOT_KCONFIG)
idf_build_get_property(kconfigs KCONFIGS)
idf_build_get_property(kconfig_projbuilds KCONFIG_PROJBUILDS)
idf_build_get_property(python PYTHON)
string(REPLACE ";" " " kconfigs "${kconfigs}")
string(REPLACE ";" " " kconfig_projbuilds "${kconfig_projbuilds}")
add_custom_command(
OUTPUT ${output}
COMMAND ${PYTHON} ${IDF_PATH}/tools/ldgen/ldgen.py
--config ${SDKCONFIG}
--fragments "$<JOIN:$<TARGET_PROPERTY:ldgen,FRAGMENT_FILES>,\t>"
COMMAND ${python} ${idf_path}/tools/ldgen/ldgen.py
--config ${sdkconfig}
--fragments "$<JOIN:${ldgen_fragment_files},\t>"
--input ${template}
--output ${output}
--kconfig ${ROOT_KCONFIG}
--env "COMPONENT_KCONFIGS=${COMPONENT_KCONFIGS}"
--env "COMPONENT_KCONFIGS_PROJBUILD=${COMPONENT_KCONFIGS_PROJBUILD}"
--kconfig ${root_kconfig}
--env "COMPONENT_KCONFIGS=${kconfigs}"
--env "COMPONENT_KCONFIGS_PROJBUILD=${kconfig_projbuilds}"
--env "IDF_CMAKE=y"
--env "IDF_PATH=${IDF_PATH}"
--env "IDF_TARGET=${IDF_TARGET}"
--libraries-file ${CMAKE_BINARY_DIR}/ldgen_libraries
--env "IDF_PATH=${idf_path}"
--env "IDF_TARGET=${idf_target}"
--libraries-file ${build_dir}/ldgen_libraries
--objdump ${CMAKE_OBJDUMP}
DEPENDS ${template} $<TARGET_PROPERTY:ldgen,FRAGMENT_FILES>
$<TARGET_PROPERTY:ldgen,LIBRARIES> ${SDKCONFIG}
DEPENDS ${template} ${ldgen_fragment_files} ${ldgen_depends} ${SDKCONFIG}
)
get_filename_component(output_name ${output} NAME)
add_custom_target(ldgen_${output_name}_script DEPENDS ${output})
add_dependencies(ldgen ldgen_${output_name}_script)
endfunction()
# ldgen_add_dependencies
#
# Add dependency of project executable to ldgen custom target.
function(ldgen_add_dependencies)
if(IDF_PROJECT_EXECUTABLE)
add_dependencies(${IDF_PROJECT_EXECUTABLE} ldgen)
endif()
get_filename_component(_name ${output} NAME)
add_custom_target(__ldgen_output_${_name} DEPENDS ${output})
add_dependencies(__idf_build_target __ldgen_output_${_name})
idf_build_set_property(LINK_DEPENDS ${output} APPEND)
endfunction()

View file

@ -1,11 +1,226 @@
# Designed to be included from an IDF app's CMakeLists.txt file
#
cmake_minimum_required(VERSION 3.5)
include(${CMAKE_CURRENT_LIST_DIR}/idf_functions.cmake)
# The mere inclusion of this CMake file sets up some interal build properties.
# These properties can be modified in between this inclusion the the idf_build_process
# call.
include(${CMAKE_CURRENT_LIST_DIR}/idf.cmake)
# Set the path of idf.py.
set(IDFTOOL ${PYTHON} "${IDF_PATH}/tools/idf.py")
# Internally, the Python interpreter is already set to 'python'. Re-set here
# to be absolutely sure.
set_default(PYTHON "python")
idf_build_set_property(PYTHON ${PYTHON})
# On processing, checking Python required modules can be turned off if it was
# already checked externally.
if(PYTHON_DEPS_CHECKED)
idf_build_set_property(__CHECK_PYTHON 0)
endif()
# Initialize build target for this build using the environment variable or
# value passed externally.
__target_init()
#
# Get the project version from either a version file or the Git revision. This is passed
# to the idf_build_process call. Dependencies are also set here for when the version file
# changes (if it is used).
#
function(__project_get_revision var)
set(_project_path "${CMAKE_CURRENT_LIST_DIR}")
if(NOT DEFINED PROJECT_VER)
if(EXISTS "${_project_path}/version.txt")
file(STRINGS "${_project_path}/version.txt" PROJECT_VER)
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${_project_path}/version.txt")
else()
git_describe(PROJECT_VER_GIT "${_project_path}")
if(PROJECT_VER_GIT)
set(PROJECT_VER ${PROJECT_VER_GIT})
else()
message(STATUS "Project is not inside a git repository, \
will not use 'git describe' to determine PROJECT_VER.")
set(PROJECT_VER "1")
endif()
endif()
endif()
message(STATUS "Project version: ${PROJECT_VER}")
set(${var} "${PROJECT_VER}" PARENT_SCOPE)
endfunction()
#
# Output the built components to the user. Generates files for invoking idf_monitor.py
# that doubles as an overview of some of the more important build properties.
#
function(__project_info test_components)
idf_build_get_property(prefix __PREFIX)
idf_build_get_property(_build_components BUILD_COMPONENTS)
idf_build_get_property(build_dir BUILD_DIR)
idf_build_get_property(idf_path IDF_PATH)
list(SORT _build_components)
unset(build_components)
unset(build_component_paths)
foreach(build_component ${_build_components})
__component_get_target(component_target "${build_component}")
__component_get_property(_name ${component_target} COMPONENT_NAME)
__component_get_property(_prefix ${component_target} __PREFIX)
__component_get_property(_alias ${component_target} COMPONENT_ALIAS)
__component_get_property(_dir ${component_target} COMPONENT_DIR)
if(_alias IN_LIST test_components)
list(APPEND test_component_paths ${_dir})
else()
if(_prefix STREQUAL prefix)
set(component ${_name})
else()
set(component ${_alias})
endif()
list(APPEND build_components ${component})
list(APPEND build_component_paths ${_dir})
endif()
endforeach()
set(PROJECT_NAME ${CMAKE_PROJECT_NAME})
idf_build_get_property(PROJECT_PATH PROJECT_DIR)
idf_build_get_property(BUILD_DIR BUILD_DIR)
idf_build_get_property(SDKCONFIG SDKCONFIG)
idf_build_get_property(SDKCONFIG_DEFAULTS SDKCONFIG_DEFAULTS)
idf_build_get_property(PROJECT_EXECUTABLE EXECUTABLE)
set(PROJECT_BIN ${CMAKE_PROJECT_NAME}.bin)
idf_build_get_property(IDF_VER IDF_VER)
idf_build_get_property(sdkconfig_cmake SDKCONFIG_CMAKE)
include(${sdkconfig_cmake})
idf_build_get_property(COMPONENT_KCONFIGS KCONFIGS)
idf_build_get_property(COMPONENT_KCONFIGS_PROJBUILD KCONFIG_PROJBUILDS)
# Write project description JSON file
idf_build_get_property(build_dir BUILD_DIR)
make_json_list("${build_components};${test_components}" build_components_json)
make_json_list("${build_component_paths};${test_component_paths}" build_component_paths_json)
configure_file("${idf_path}/tools/cmake/project_description.json.in"
"${build_dir}/project_description.json")
# We now have the following component-related variables:
#
# build_components is the list of components to include in the build.
# build_component_paths is the paths to all of these components, obtained from the component dependencies file.
#
# Print the list of found components and test components
string(REPLACE ";" " " build_components "${build_components}")
string(REPLACE ";" " " build_component_paths "${build_component_paths}")
message(STATUS "Components: ${build_components}")
message(STATUS "Component paths: ${build_component_paths}")
if(test_components)
string(REPLACE ";" " " test_components "${test_components}")
string(REPLACE ";" " " test_component_paths "${test_component_paths}")
message(STATUS "Test components: ${test_components}")
message(STATUS "Test component paths: ${test_component_paths}")
endif()
endfunction()
function(__project_init components_var test_components_var)
# Use EXTRA_CFLAGS, EXTRA_CXXFLAGS and EXTRA_CPPFLAGS to add more priority options to the compiler
# EXTRA_CPPFLAGS is used for both C and C++
# Unlike environments' CFLAGS/CXXFLAGS/CPPFLAGS which work for both host and target build,
# these works only for target build
set(extra_cflags "$ENV{EXTRA_CFLAGS}")
set(extra_cxxflags "$ENV{EXTRA_CXXFLAGS}")
set(extra_cppflags "$ENV{EXTRA_CPPFLAGS}")
spaces2list(extra_cflags)
spaces2list(extra_cxxflags)
spaces2list(extra_cppflags)
idf_build_set_property(C_COMPILE_OPTIONS "${extra_cflags}" APPEND)
idf_build_set_property(CXX_COMPILE_OPTIONS "${extra_cxxflags}" APPEND)
idf_build_set_property(COMPILE_OPTIONS "${extra_cppflags}" APPEND)
function(__project_component_dir component_dir)
get_filename_component(component_dir "${component_dir}" ABSOLUTE)
if(EXISTS ${component_dir}/CMakeLists.txt)
idf_build_component(${component_dir})
else()
file(GLOB component_dirs ${component_dir}/*)
foreach(component_dir ${component_dirs})
if(EXISTS ${component_dir}/CMakeLists.txt)
idf_build_component(${component_dir})
endif()
endforeach()
endif()
endfunction()
# Add component directories to the build, given the component filters, exclusions
# extra directories, etc. passed from the root CMakeLists.txt.
if(COMPONENT_DIRS)
# User wants to fully override where components are pulled from.
spaces2list(COMPONENT_DIRS)
idf_build_set_property(__COMPONENT_TARGETS "")
foreach(component_dir ${COMPONENT_DIRS})
__project_component_dir(${component_dir})
endforeach()
else()
# Look for components in the usual places: CMAKE_CURRENT_LIST_DIR/main,
# CMAKE_CURRENT_LIST_DIR/components, and the extra component dirs
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/main")
__project_component_dir("${CMAKE_CURRENT_LIST_DIR}/main")
endif()
__project_component_dir("${CMAKE_CURRENT_LIST_DIR}/components")
spaces2list(EXTRA_COMPONENT_DIRS)
foreach(component_dir ${EXTRA_COMPONENT_DIRS})
__project_component_dir("${component_dir}")
endforeach()
endif()
spaces2list(COMPONENTS)
spaces2list(EXCLUDE_COMPONENTS)
idf_build_get_property(component_targets __COMPONENT_TARGETS)
foreach(component_target ${component_targets})
__component_get_property(component_name ${component_target} COMPONENT_NAME)
set(include 1)
if(COMPONENTS AND NOT component_name IN_LIST COMPONENTS)
set(include 0)
endif()
if(EXCLUDE_COMPONENTS AND component_name IN_LIST EXCLUDE_COMPONENTS)
set(include 0)
endif()
if(include)
list(APPEND components ${component_name})
endif()
endforeach()
if(TESTS_ALL OR BUILD_TESTS OR TEST_COMPONENTS OR TEST_EXCLUDE_COMPONENTS)
spaces2list(TEST_COMPONENTS)
spaces2list(TEST_EXCLUDE_COMPONENTS)
idf_build_get_property(component_targets __COMPONENT_TARGETS)
foreach(component_target ${component_targets})
__component_get_property(component_dir ${component_target} COMPONENT_DIR)
__component_get_property(component_name ${component_target} COMPONENT_NAME)
if(component_name IN_LIST components)
set(include 1)
if(TEST_COMPONENTS AND NOT component_name IN_LIST TEST_COMPONENTS)
set(include 0)
endif()
if(TEST_EXCLUDE_COMPONENTS AND component_name IN_LIST TEST_EXCLUDE_COMPONENTS)
set(include 0)
endif()
if(include AND EXISTS ${component_dir}/test)
__component_add(${component_dir}/test ${component_name})
list(APPEND test_components ${component_name}::test)
endif()
endif()
endforeach()
endif()
set(${components_var} "${components}" PARENT_SCOPE)
set(${test_components_var} "${test_components}" PARENT_SCOPE)
endfunction()
# Trick to temporarily redefine project(). When functions are overriden in CMake, the originals can still be accessed
# using an underscore prefixed function of the same name. The following lines make sure that __project calls
@ -16,72 +231,14 @@ endfunction()
function(_project)
endfunction()
macro(project name)
macro(project project_name)
# Initialize project, preparing COMPONENTS argument for idf_build_process()
# call later using external COMPONENT_DIRS, COMPONENTS_DIRS, EXTRA_COMPONENTS_DIR,
# EXTRA_COMPONENTS_DIRS, COMPONENTS, EXLUDE_COMPONENTS, TEST_COMPONENTS,
# TEST_EXLUDE_COMPONENTS, TESTS_ALL, BUILD_TESTS
__project_init(components test_components)
# Bridge existing documented variable names with library namespaced
# variables in order for old projects to work.
if(COMPONENT_DIRS)
spaces2list(COMPONENT_DIRS)
foreach(component_dir ${COMPONENT_DIRS})
get_filename_component(component_dir ${component_dir} ABSOLUTE BASE_DIR ${CMAKE_SOURCE_DIR})
list(APPEND IDF_COMPONENT_DIRS "${component_dir}")
endforeach()
endif()
if(EXTRA_COMPONENT_DIRS)
spaces2list(EXTRA_COMPONENT_DIRS)
foreach(component_dir ${EXTRA_COMPONENT_DIRS})
get_filename_component(component_dir ${component_dir} ABSOLUTE BASE_DIR ${CMAKE_SOURCE_DIR})
list(APPEND IDF_EXTRA_COMPONENT_DIRS "${component_dir}")
endforeach()
endif()
list(APPEND IDF_EXTRA_COMPONENT_DIRS "${CMAKE_SOURCE_DIR}/components")
if(NOT MAIN_SRCS)
list(APPEND IDF_EXTRA_COMPONENT_DIRS "${CMAKE_SOURCE_DIR}/main")
endif()
if(COMPONENTS)
set(IDF_COMPONENTS "${COMPONENTS}")
endif()
if(COMPONENT_REQUIRES_COMMON)
set(IDF_COMPONENT_REQUIRES_COMMON "${COMPONENT_REQUIRES_COMMON}")
endif()
if(EXCLUDE_COMPONENTS)
set(IDF_EXCLUDE_COMPONENTS "${COMPONENT_EXCLUDES}")
endif()
if(TESTS_ALL EQUAL 1 OR TEST_COMPONENTS)
set(IDF_BUILD_TESTS 1)
endif()
if(TEST_COMPONENTS)
set(IDF_TEST_COMPONENTS "${TEST_COMPONENTS}")
endif()
if(TEST_EXCLUDE_COMPONENTS)
set(IDF_TEST_EXCLUDE_COMPONENTS "${TEST_EXCLUDE_COMPONENTS}")
endif()
if(NOT SDKCONFIG_DEFAULTS)
if(EXISTS ${CMAKE_SOURCE_DIR}/sdkconfig.defaults)
set(IDF_SDKCONFIG_DEFAULTS ${CMAKE_SOURCE_DIR}/sdkconfig.defaults)
endif()
else()
set(IDF_SDKCONFIG_DEFAULTS ${SDKCONFIG_DEFAULTS})
endif()
# Set build variables
idf_set_variables()
# Now the configuration is loaded, set the toolchain appropriately
idf_set_toolchain()
__target_set_toolchain()
# Enable ccache if it's on the path
if(NOT CCACHE_DISABLE)
@ -92,50 +249,11 @@ macro(project name)
endif()
endif()
__project(${name} C CXX ASM)
# The actual call to project()
__project(${project_name} C CXX ASM)
set(IDF_BUILD_ARTIFACTS ON)
set(IDF_PROJECT_EXECUTABLE ${CMAKE_PROJECT_NAME}.elf)
set(IDF_BUILD_ARTIFACTS_DIR ${CMAKE_BINARY_DIR})
if(MAIN_SRCS)
spaces2list(MAIN_SRCS)
add_executable(${IDF_PROJECT_EXECUTABLE} ${MAIN_SRCS})
else()
# Create a dummy file to work around CMake requirement of having a source
# file while adding an executable
add_executable(${IDF_PROJECT_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/dummy_main_src.c")
add_custom_command(OUTPUT dummy_main_src.c
COMMAND ${CMAKE_COMMAND} -E touch dummy_main_src.c
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
VERBATIM)
add_custom_target(dummy_main_src DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/dummy_main_src.c)
add_dependencies(${IDF_PROJECT_EXECUTABLE} dummy_main_src)
endif()
set(mapfile "${CMAKE_PROJECT_NAME}.map")
target_link_libraries(${IDF_PROJECT_EXECUTABLE} "-Wl,--cref -Wl,--Map=${mapfile}")
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY
ADDITIONAL_MAKE_CLEAN_FILES
"${CMAKE_CURRENT_BINARY_DIR}/${mapfile}")
# Add size targets, depend on map file, run idf_size.py
add_custom_target(size
DEPENDS ${exe_target}
COMMAND ${PYTHON} ${IDF_PATH}/tools/idf_size.py ${mapfile}
)
add_custom_target(size-files
DEPENDS ${exe_target}
COMMAND ${PYTHON} ${IDF_PATH}/tools/idf_size.py --files ${mapfile}
)
add_custom_target(size-components
DEPENDS ${exe_target}
COMMAND ${PYTHON} ${IDF_PATH}/tools/idf_size.py --archives ${mapfile}
)
# Generate compile_commands.json (needs to come after project call).
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
# Since components can import third-party libraries, the original definition of project() should be restored
# before the call to add components to the build.
@ -144,7 +262,150 @@ macro(project name)
__project(${${project_ARGV}})
endfunction()
# Finally, add the rest of the components to the build.
idf_import_components(components $ENV{IDF_PATH} esp-idf)
idf_link_components(${IDF_PROJECT_EXECUTABLE} "${components}")
# Prepare the following arguments for the idf_build_process() call using external
# user values:
#
# SDKCONFIG_DEFAULTS is from external SDKCONFIG_DEFAULTS
# SDKCONFIG is from external SDKCONFIG
# BUILD_DIR is set to project binary dir
#
# PROJECT_NAME is taken from the passed name from project() call
# PROJECT_DIR is set to the current directory
# PROJECT_VER is from the version text or git revision of the current repo
if(SDKCONFIG_DEFAULTS)
get_filename_component(sdkconfig_defaults "${SDKCONFIG_DEFAULTS}" ABSOLUTE)
if(NOT EXISTS "${sdkconfig_defaults}")
message(FATAL_ERROR "SDKCONFIG_DEFAULTS '${sdkconfig_defaults}' does not exist.")
endif()
else()
if(EXISTS "${CMAKE_SOURCE_DIR}/sdkconfig.defaults")
set(sdkconfig_defaults "${CMAKE_SOURCE_DIR}/sdkconfig.defaults")
else()
set(sdkconfig_defaults "")
endif()
endif()
if(SDKCONFIG)
get_filename_component(sdkconfig "${SDKCONFIG}" ABSOLUTE)
if(NOT EXISTS "${sdkconfig}")
message(FATAL_ERROR "SDKCONFIG '${sdkconfig}' does not exist.")
endif()
set(sdkconfig ${SDKCONFIG})
else()
set(sdkconfig "${CMAKE_CURRENT_LIST_DIR}/sdkconfig")
endif()
if(BUILD_DIR)
get_filename_component(build_dir "${BUILD_DIR}" ABSOLUTE)
if(NOT EXISTS "${build_dir}")
message(FATAL_ERROR "BUILD_DIR '${build_dir}' does not exist.")
endif()
else()
set(build_dir ${CMAKE_BINARY_DIR})
endif()
__project_get_revision(project_ver)
message(STATUS "Building ESP-IDF components for target ${IDF_TARGET}")
idf_build_process(${IDF_TARGET}
SDKCONFIG_DEFAULTS "${sdkconfig_defaults}"
SDKCONFIG ${sdkconfig}
BUILD_DIR ${build_dir}
PROJECT_NAME ${CMAKE_PROJECT_NAME}
PROJECT_DIR ${CMAKE_CURRENT_LIST_DIR}
PROJECT_VER "${project_ver}"
COMPONENTS "${components};${test_components}")
# Special treatment for 'main' component for standard projects (not part of core build system).
# Have it depend on every other component in the build. This is
# a convenience behavior for the standard project; thus is done outside of the core build system
# so that it treats components equally.
#
# This behavior should only be when user did not set REQUIRES/PRIV_REQUIRES manually.
idf_build_get_property(build_components BUILD_COMPONENTS)
if(idf::main IN_LIST build_components)
__component_get_target(main_target idf::main)
__component_get_property(reqs ${main_target} REQUIRES)
__component_get_property(priv_reqs ${main_target} PRIV_REQUIRES)
idf_build_get_property(common_reqs __COMPONENT_REQUIRES_COMMON)
if(reqs STREQUAL common_reqs AND NOT priv_reqs) #if user has not set any requirements
list(REMOVE_ITEM build_components idf::main)
__component_get_property(lib ${main_target} COMPONENT_LIB)
set_property(TARGET ${lib} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "${build_components}")
get_property(type TARGET ${lib} PROPERTY TYPE)
if(type STREQUAL STATIC_LIBRARY)
set_property(TARGET ${lib} APPEND PROPERTY LINK_LIBRARIES "${build_components}")
endif()
endif()
endif()
set(project_elf ${CMAKE_PROJECT_NAME}.elf)
# Create a dummy file to work around CMake requirement of having a source
# file while adding an executable
set(project_elf_src ${CMAKE_BINARY_DIR}/project_elf_src.c)
add_custom_command(OUTPUT ${project_elf_src}
COMMAND ${CMAKE_COMMAND} -E touch ${project_elf_src}
VERBATIM)
add_custom_target(_project_elf_src DEPENDS "${project_elf_src}")
add_executable(${project_elf} "${project_elf_src}")
add_dependencies(${project_elf} _project_elf_src)
target_link_libraries(${project_elf} "-Wl,--start-group")
if(test_components)
target_link_libraries(${project_elf} "-Wl,--whole-archive")
foreach(test_component ${test_components})
if(TARGET ${test_component})
target_link_libraries(${project_elf} ${test_component})
endif()
endforeach()
target_link_libraries(${project_elf} "-Wl,--no-whole-archive")
endif()
idf_build_get_property(build_components BUILD_COMPONENTS)
if(test_components)
list(REMOVE_ITEM build_components ${test_components})
endif()
target_link_libraries(${project_elf} ${build_components})
set(mapfile "${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.map")
target_link_libraries(${project_elf} "-Wl,--cref -Wl,--Map=${mapfile}")
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY
ADDITIONAL_MAKE_CLEAN_FILES
"${mapfile}" "${project_elf_src}")
idf_build_get_property(idf_path IDF_PATH)
idf_build_get_property(python PYTHON)
# Add size targets, depend on map file, run idf_size.py
add_custom_target(size
DEPENDS ${project_elf}
COMMAND ${python} ${idf_path}/tools/idf_size.py ${mapfile}
)
add_custom_target(size-files
DEPENDS ${project_elf}
COMMAND ${python} ${idf_path}/tools/idf_size.py --files ${mapfile}
)
add_custom_target(size-components
DEPENDS ${project_elf}
COMMAND ${python} ${idf_path}/tools/idf_size.py --archives ${mapfile}
)
idf_build_executable(${project_elf})
__project_info("${test_components}")
# Make build variables and config variables available after project call (of course the value
# of these variables can be accessed via idf_build_get_property or idf_build_get_config)
idf_build_get_property(sdkconfig_cmake SDKCONFIG_CMAKE)
include(${sdkconfig_cmake})
idf_build_get_property(build_properties __BUILD_PROPERTIES)
foreach(build_property ${build_properties})
idf_build_get_property(val ${build_property})
set(${build_property} "${val}")
endforeach()
endmacro()

View file

@ -1,11 +1,11 @@
{
"project_name": "${IDF_PROJECT_NAME}",
"project_path": "${IDF_PROJECT_PATH}",
"build_dir": "${IDF_BUILD_ARTIFACTS_DIR}",
"project_name": "${PROJECT_NAME}",
"project_path": "${PROJECT_PATH}",
"build_dir": "${BUILD_DIR}",
"config_file": "${SDKCONFIG}",
"config_defaults": "${IDF_SDKCONFIG_DEFAULTS}",
"app_elf": "${IDF_PROJECT_EXECUTABLE}",
"app_bin": "${IDF_PROJECT_BIN}",
"config_defaults": "${SDKCONFIG_DEFAULTS}",
"app_elf": "${PROJECT_EXECUTABLE}",
"app_bin": "${PROJECT_BIN}",
"git_revision": "${IDF_VER}",
"phy_data_partition": "${CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION}",
"monitor_baud" : "${CONFIG_MONITOR_BAUD}",

View file

@ -0,0 +1,49 @@
include(${IDF_PATH}/tools/cmake/utilities.cmake)
include("${BUILD_PROPERTIES_FILE}")
include("${SDKCONFIG_CMAKE}")
macro(require_idf_targets)
endmacro()
function(idf_build_get_property var property)
cmake_parse_arguments(_ "GENERATOR_EXPRESSION" "" "" ${ARGN})
if(__GENERATOR_EXPRESSION)
message(FATAL_ERROR "Getting build property generator expression not
supported before idf_component_register().")
endif()
set(${var} ${property} PARENT_SCOPE)
endfunction()
function(print_requires requires priv_requires)
spaces2list(requires)
spaces2list(priv_requires)
string(REPLACE ";" ":" requires "${requires}")
string(REPLACE ";" ":" priv_requires "${priv_requires}")
message("${requires}:::${priv_requires}")
endfunction()
macro(idf_component_register)
set(options)
set(single_value)
set(multi_value SRCS SRC_DIRS EXCLUDE_SRCS
INCLUDE_DIRS PRIV_INCLUDE_DIRS LDFRAGMENTS REQUIRES
PRIV_REQUIRES REQUIRED_IDF_TARGETS EMBED_FILES EMBED_TXTFILES)
cmake_parse_arguments(_ "${options}" "${single_value}" "${multi_value}" "${ARGN}")
print_requires("${__REQUIRES}" "${__PRIV_REQUIRES}")
set(__is_component 1)
return()
endmacro()
macro(register_component)
print_requires("${COMPONENT_REQUIRES}" "${COMPONENT_PRIV_REQUIRES}")
set(__is_component 1)
return()
endmacro()
macro(register_config_only_component)
register_component()
endmacro()
set(CMAKE_BUILD_EARLY_EXPANSION)
include(${COMPONENT_DIR}/CMakeLists.txt OPTIONAL)

View file

@ -1,269 +0,0 @@
# expand_requirements.cmake is a utility cmake script to expand component requirements early in the build,
# before the components are ready to be included.
#
# Parameters:
# - COMPONENTS = Space-separated list of initial components to include in the build.
# Can be empty, in which case all components are in the build.
# - COMPONENT_REQUIRES_COMMON = Components to always include in the build, and treated as dependencies
# of all other components.
# - DEPENDENCIES_FILE = Path of generated cmake file which will contain the expanded dependencies for these
# components.
# - COMPONENT_DIRS = List of paths to search for all components.
# - DEBUG = Set -DDEBUG=1 to debug component lists in the build.
#
# If successful, DEPENDENCIES_FILE can be expanded to set BUILD_COMPONENTS & BUILD_COMPONENT_PATHS with all
# components required for the build, and the get_component_requirements() function to return each component's
# recursively expanded requirements.
#
# BUILD_COMPONENTS & BUILD_COMPONENT_PATHS will be ordered in a best-effort way so that dependencies are listed first.
# (Note that IDF supports cyclic dependencies, and dependencies in a cycle have ordering guarantees.)
#
# Determinism:
#
# Given the the same list of names in COMPONENTS (regardless of order), and an identical value of
# COMPONENT_REQUIRES_COMMON, and all the same COMPONENT_REQUIRES & COMPONENT_PRIV_REQUIRES values in
# each component, then the output of BUILD_COMPONENTS should always be in the same
# order.
#
# BUILD_COMPONENT_PATHS will be in the same component order as BUILD_COMPONENTS, even if the
# actual component paths are different due to different paths.
#
# TODO: Error out if a component requirement is missing
cmake_minimum_required(VERSION 3.5)
include("${IDF_PATH}/tools/cmake/utilities.cmake")
include("${IDF_PATH}/tools/cmake/component_utils.cmake")
set(ESP_PLATFORM 1)
if(NOT DEPENDENCIES_FILE)
message(FATAL_ERROR "DEPENDENCIES_FILE must be set.")
endif()
if(NOT COMPONENT_DIRS)
message(FATAL_ERROR "COMPONENT_DIRS variable must be set")
endif()
spaces2list(COMPONENT_DIRS)
spaces2list(COMPONENT_REQUIRES_COMMON)
# Dummy register_component used to save requirements variables as global properties, for later expansion
#
# (expand_component_requirements() includes the component CMakeLists.txt, which then sets its component variables,
# calls this dummy macro, and immediately exits again.)
macro(register_component)
if(COMPONENT STREQUAL main AND NOT COMPONENT_REQUIRES)
set(main_component_requires ${COMPONENTS})
list(REMOVE_ITEM main_component_requires "main")
set_property(GLOBAL PROPERTY "${COMPONENT}_REQUIRES" "${main_component_requires}")
else()
spaces2list(COMPONENT_REQUIRES)
set_property(GLOBAL PROPERTY "${COMPONENT}_REQUIRES" "${COMPONENT_REQUIRES}")
endif()
spaces2list(COMPONENT_PRIV_REQUIRES)
set_property(GLOBAL PROPERTY "${COMPONENT}_PRIV_REQUIRES" "${COMPONENT_PRIV_REQUIRES}")
# This is tricky: we override register_component() so it returns out of the component CMakeLists.txt
# (as we're declaring it as a macro not a function, so it doesn't have its own scope.)
#
# This means no targets are defined, and the component expansion ends early.
return()
endmacro()
macro(register_config_only_component)
register_component()
endmacro()
function(require_idf_targets)
if(NOT ${IDF_TARGET} IN_LIST ARGN)
message(FATAL_ERROR "Component ${COMPONENT_NAME} only supports targets: ${ARGN}")
endif()
endfunction()
# expand_component_requirements: Recursively expand a component's requirements,
# setting global properties BUILD_COMPONENTS & BUILD_COMPONENT_PATHS and
# also invoking the components to call register_component() above,
# which will add per-component global properties with dependencies, etc.
function(expand_component_requirements component)
get_property(seen_components GLOBAL PROPERTY SEEN_COMPONENTS)
if(component IN_LIST seen_components)
return() # already added, or in process of adding, this component
endif()
set_property(GLOBAL APPEND PROPERTY SEEN_COMPONENTS ${component})
find_component_path("${component}" "${ALL_COMPONENTS}" "${ALL_COMPONENT_PATHS}" COMPONENT_PATH)
debug("Expanding dependencies of ${component} @ ${COMPONENT_PATH}")
if(NOT COMPONENT_PATH)
set_property(GLOBAL APPEND PROPERTY COMPONENTS_NOT_FOUND ${component})
return()
endif()
# include the component CMakeLists.txt to expand its properties
# into the global cache (via register_component(), above)
unset(COMPONENT_REQUIRES)
unset(COMPONENT_PRIV_REQUIRES)
set(COMPONENT ${component})
include(${COMPONENT_PATH}/CMakeLists.txt)
get_property(requires GLOBAL PROPERTY "${component}_REQUIRES")
get_property(requires_priv GLOBAL PROPERTY "${component}_PRIV_REQUIRES")
# Recurse dependencies first, so that they appear first in the list (when possible)
foreach(req ${COMPONENT_REQUIRES_COMMON} ${requires} ${requires_priv})
expand_component_requirements(${req})
endforeach()
list(FIND TEST_COMPONENTS ${component} idx)
if(NOT idx EQUAL -1)
list(GET TEST_COMPONENTS ${idx} test_component)
list(GET TEST_COMPONENT_PATHS ${idx} test_component_path)
set_property(GLOBAL APPEND PROPERTY BUILD_TEST_COMPONENTS ${test_component})
set_property(GLOBAL APPEND PROPERTY BUILD_TEST_COMPONENT_PATHS ${test_component_path})
endif()
# Now append this component to the full list (after its dependencies)
set_property(GLOBAL APPEND PROPERTY BUILD_COMPONENT_PATHS ${COMPONENT_PATH})
set_property(GLOBAL APPEND PROPERTY BUILD_COMPONENTS ${component})
endfunction()
# filter_components_list: Filter the components included in the build
# as specified by the user. Or, in the case of unit testing, filter out
# the test components to be built.
macro(filter_components_list)
spaces2list(COMPONENTS)
spaces2list(EXCLUDE_COMPONENTS)
spaces2list(TEST_COMPONENTS)
spaces2list(TEST_EXCLUDE_COMPONENTS)
list(LENGTH ALL_COMPONENTS all_components_length)
math(EXPR all_components_length "${all_components_length} - 1")
foreach(component_idx RANGE 0 ${all_components_length})
list(GET ALL_COMPONENTS ${component_idx} component)
list(GET ALL_COMPONENT_PATHS ${component_idx} component_path)
if(COMPONENTS)
if(${component} IN_LIST COMPONENTS)
set(add_component 1)
else()
set(add_component 0)
endif()
else()
set(add_component 1)
endif()
if(NOT ${component} IN_LIST EXCLUDE_COMPONENTS AND add_component EQUAL 1)
list(APPEND components ${component})
list(APPEND component_paths ${component_path})
if(BUILD_TESTS EQUAL 1)
if(TEST_COMPONENTS)
if(${component} IN_LIST TEST_COMPONENTS)
set(add_test_component 1)
else()
set(add_test_component 0)
endif()
else()
set(add_test_component 1)
endif()
if(${component} IN_LIST ALL_TEST_COMPONENTS)
if(NOT ${component} IN_LIST TEST_EXCLUDE_COMPONENTS AND add_test_component EQUAL 1)
list(APPEND test_components ${component}_test)
list(APPEND test_component_paths ${component_path}/test)
list(APPEND components ${component}_test)
list(APPEND component_paths ${component_path}/test)
endif()
endif()
endif()
endif()
endforeach()
set(COMPONENTS ${components})
set(TEST_COMPONENTS ${test_components})
set(TEST_COMPONENT_PATHS ${test_component_paths})
list(APPEND ALL_COMPONENTS "${TEST_COMPONENTS}")
list(APPEND ALL_COMPONENT_PATHS "${TEST_COMPONENT_PATHS}")
endmacro()
# Main functionality goes here
# Find every available component in COMPONENT_DIRS, save as ALL_COMPONENT_PATHS and ALL_COMPONENTS
components_find_all("${COMPONENT_DIRS}" ALL_COMPONENT_PATHS ALL_COMPONENTS ALL_TEST_COMPONENTS)
filter_components_list()
debug("ALL_COMPONENT_PATHS ${ALL_COMPONENT_PATHS}")
debug("ALL_COMPONENTS ${ALL_COMPONENTS}")
debug("ALL_TEST_COMPONENTS ${ALL_TEST_COMPONENTS}")
set_property(GLOBAL PROPERTY SEEN_COMPONENTS "") # anti-infinite-recursion
set_property(GLOBAL PROPERTY BUILD_COMPONENTS "")
set_property(GLOBAL PROPERTY BUILD_COMPONENT_PATHS "")
set_property(GLOBAL PROPERTY BUILD_TEST_COMPONENTS "")
set_property(GLOBAL PROPERTY BUILD_TEST_COMPONENT_PATHS "")
set_property(GLOBAL PROPERTY COMPONENTS_NOT_FOUND "")
# Indicate that the component CMakeLists.txt is being included in the early expansion phase of the build,
# and might not want to execute particular operations.
set(CMAKE_BUILD_EARLY_EXPANSION 1)
foreach(component ${COMPONENTS})
debug("Expanding initial component ${component}")
expand_component_requirements(${component})
endforeach()
unset(CMAKE_BUILD_EARLY_EXPANSION)
get_property(build_components GLOBAL PROPERTY BUILD_COMPONENTS)
get_property(build_component_paths GLOBAL PROPERTY BUILD_COMPONENT_PATHS)
get_property(build_test_components GLOBAL PROPERTY BUILD_TEST_COMPONENTS)
get_property(build_test_component_paths GLOBAL PROPERTY BUILD_TEST_COMPONENT_PATHS)
get_property(not_found GLOBAL PROPERTY COMPONENTS_NOT_FOUND)
debug("components in build: ${build_components}")
debug("components in build: ${build_component_paths}")
debug("components not found: ${not_found}")
function(line contents)
file(APPEND "${DEPENDENCIES_FILE}.tmp" "${contents}\n")
endfunction()
file(WRITE "${DEPENDENCIES_FILE}.tmp" "# Component requirements generated by expand_requirements.cmake\n\n")
line("set(BUILD_COMPONENTS ${build_components})")
line("set(BUILD_COMPONENT_PATHS ${build_component_paths})")
line("set(BUILD_TEST_COMPONENTS ${build_test_components})")
line("set(BUILD_TEST_COMPONENT_PATHS ${build_test_component_paths})")
line("")
line("# get_component_requirements: Generated function to read the dependencies of a given component.")
line("#")
line("# Parameters:")
line("# - component: Name of component")
line("# - var_requires: output variable name. Set to recursively expanded COMPONENT_REQUIRES ")
line("# for this component.")
line("# - var_private_requires: output variable name. Set to recursively expanded COMPONENT_PRIV_REQUIRES ")
line("# for this component.")
line("#")
line("# Throws a fatal error if 'componeont' is not found (indicates a build system problem).")
line("#")
line("function(get_component_requirements component var_requires var_private_requires)")
foreach(build_component ${build_components})
get_property(reqs GLOBAL PROPERTY "${build_component}_REQUIRES")
get_property(private_reqs GLOBAL PROPERTY "${build_component}_PRIV_REQUIRES")
line(" if(\"\$\{component}\" STREQUAL \"${build_component}\")")
line(" set(\${var_requires} \"${reqs}\" PARENT_SCOPE)")
line(" set(\${var_private_requires} \"${private_reqs}\" PARENT_SCOPE)")
line(" return()")
line(" endif()")
endforeach()
line(" message(FATAL_ERROR \"Component not found: \${component}\")")
line("endfunction()")
# only replace DEPENDENCIES_FILE if it has changed (prevents ninja/make build loops.)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${DEPENDENCIES_FILE}.tmp" "${DEPENDENCIES_FILE}")
execute_process(COMMAND ${CMAKE_COMMAND} -E remove "${DEPENDENCIES_FILE}.tmp")

View file

@ -1,6 +1,7 @@
include(component_utils)
macro(idf_set_target)
#
# Set the target used for the standard project build.
#
macro(__target_init)
# Input is IDF_TARGET environement variable
set(env_idf_target $ENV{IDF_TARGET})
@ -26,28 +27,38 @@ macro(idf_set_target)
# Finally, set IDF_TARGET in cache
set(IDF_TARGET ${env_idf_target} CACHE STRING "IDF Build Target")
message(STATUS "Building for target ${IDF_TARGET}")
endmacro()
macro(idf_check_config_target)
if(NOT ${IDF_TARGET} STREQUAL ${CONFIG_IDF_TARGET})
#
# Check that the set build target and the config target matches.
#
function(__target_check)
# Should be called after sdkconfig CMake file has been included.
idf_build_get_property(idf_target IDF_TARGET)
if(NOT ${idf_target} STREQUAL ${CONFIG_IDF_TARGET})
message(FATAL_ERROR "CONFIG_IDF_TARGET in sdkconfig does not match "
"IDF_TARGET environement variable. To change the target, delete "
"sdkconfig file and build the project again.")
endif()
endmacro()
endfunction()
macro(idf_set_toolchain)
# First try to load the toolchain file from the tools/cmake/ directory of IDF
set(toolchain_file_global $ENV{IDF_PATH}/tools/cmake/toolchain-${IDF_TARGET}.cmake)
#
# Used by the project CMake file to set the toolchain before project() call.
#
macro(__target_set_toolchain)
idf_build_get_property(idf_path IDF_PATH)
# First try to load the toolchain file from the tools/cmake/directory of IDF
set(toolchain_file_global ${idf_path}/tools/cmake/toolchain-${IDF_TARGET}.cmake)
if(EXISTS ${toolchain_file_global})
set(CMAKE_TOOLCHAIN_FILE ${toolchain_file_global})
else()
# Try to load the toolchain file from the directory of ${IDF_TARGET} component
components_find_all("${IDF_COMPONENT_DIRS}" ALL_COMPONENT_PATHS ALL_COMPONENTS ALL_TEST_COMPONENTS)
find_component_path(${IDF_TARGET} "${ALL_COMPONENTS}" "${ALL_COMPONENT_PATHS}" target_component_path)
set(toolchain_file_component ${target_component_path}/toolchain-${IDF_TARGET}.cmake)
__component_get_target(component_target ${IDF_TARGET})
if(NOT component_target)
message(FATAL_ERROR "Unable to resolve '${IDF_TARGET}' for setting toolchain file.")
endif()
get_property(component_dir TARGET ${component_target} PROPERTY COMPONENT_DIR)
# Try to load the toolchain file from the directory of IDF_TARGET component
set(toolchain_file_component ${component_dir}/toolchain-${IDF_TARGET}.cmake)
if(EXISTS ${toolchain_file_component})
set(CMAKE_TOOLCHAIN_FILE ${toolchain_file_component})
else()
@ -55,4 +66,4 @@ macro(idf_set_toolchain)
"checked ${toolchain_file_global} and ${toolchain_file_component}")
endif()
endif()
endmacro()
endmacro()

View file

@ -77,21 +77,23 @@ endfunction()
# by converting it to a generated source file which is then compiled
# to a binary object as part of the build
function(target_add_binary_data target embed_file embed_type)
idf_build_get_property(build_dir BUILD_DIR)
idf_build_get_property(idf_path IDF_PATH)
get_filename_component(embed_file "${embed_file}" ABSOLUTE)
get_filename_component(name "${embed_file}" NAME)
set(embed_srcfile "${IDF_BUILD_ARTIFACTS_DIR}/${name}.S")
set(embed_srcfile "${build_dir}/${name}.S")
add_custom_command(OUTPUT "${embed_srcfile}"
COMMAND "${CMAKE_COMMAND}"
-D "DATA_FILE=${embed_file}"
-D "SOURCE_FILE=${embed_srcfile}"
-D "FILE_TYPE=${embed_type}"
-P "${IDF_PATH}/tools/cmake/scripts/data_file_embed_asm.cmake"
-P "${idf_path}/tools/cmake/scripts/data_file_embed_asm.cmake"
MAIN_DEPENDENCY "${embed_file}"
DEPENDS "${IDF_PATH}/tools/cmake/scripts/data_file_embed_asm.cmake"
WORKING_DIRECTORY "${IDF_BUILD_ARTIFACTS_DIR}"
DEPENDS "${idf_path}/tools/cmake/scripts/data_file_embed_asm.cmake"
WORKING_DIRECTORY "${build_dir}"
VERBATIM)
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${embed_srcfile}")
@ -128,25 +130,50 @@ endfunction()
# Automatically adds a -L search path for the containing directory (if found),
# and then adds -T with the filename only. This allows INCLUDE directives to be
# used to include other linker scripts in the same directory.
function(target_linker_script target)
foreach(scriptfile ${ARGN})
function(target_linker_script target scriptfiles)
cmake_parse_arguments(_ "PROCESS" "" "" ${ARGN})
foreach(scriptfile ${scriptfiles})
get_filename_component(abs_script "${scriptfile}" ABSOLUTE)
message(STATUS "Adding linker script ${abs_script}")
if(__PROCESS)
__ldgen_process_template(output ${abs_script})
set(abs_script ${output})
endif()
get_filename_component(search_dir "${abs_script}" DIRECTORY)
get_filename_component(scriptname "${abs_script}" NAME)
get_target_property(link_libraries "${target}" LINK_LIBRARIES)
list(FIND "${link_libraries}" "-L ${search_dir}" found_search_dir)
if(found_search_dir EQUAL "-1") # not already added as a search path
target_link_libraries("${target}" "-L ${search_dir}")
get_target_property(type ${target} TYPE)
if(type STREQUAL "INTERFACE_LIBRARY")
set(is_interface "INTERFACE")
endif()
target_link_libraries("${target}" "-T ${scriptname}")
if(is_interface)
get_target_property(link_libraries "${target}" INTERFACE_LINK_LIBRARIES)
else()
get_target_property(link_libraries "${target}" LINK_LIBRARIES)
endif()
list(FIND "${link_libraries}" "-L ${search_dir}" found_search_dir)
if(found_search_dir EQUAL "-1") # not already added as a search path
target_link_libraries("${target}" "${is_interface}" "-L ${search_dir}")
endif()
target_link_libraries("${target}" "${is_interface}" "-T ${scriptname}")
# Note: In ESP-IDF, most targets are libraries and libary LINK_DEPENDS don't propagate to
# executable(s) the library is linked to. This is done manually in components.cmake.
set_property(TARGET "${target}" APPEND PROPERTY LINK_DEPENDS "${abs_script}")
# executable(s) the library is linked to. Attach manually to executable once it is known.
#
# Property INTERFACE_LINK_DEPENDS is available in CMake 3.13 which should propagate link
# dependencies.
if(NOT __PROCESS)
if(is_interface)
set_property(TARGET ${target} APPEND PROPERTY INTERFACE_LINK_DEPENDS ${abs_script})
else()
set_property(TARGET ${target} APPEND PROPERTY LINK_DEPENDS ${abs_script})
endif()
endif()
endforeach()
endfunction()
@ -177,6 +204,7 @@ endfunction()
# We cannot use CMAKE_CONFIGURE_DEPENDS instead because it only works for files which exist at CMake runtime.
#
function(fail_at_build_time target_name message_line0)
idf_build_get_property(idf_path IDF_PATH)
set(message_lines COMMAND ${CMAKE_COMMAND} -E echo "${message_line0}")
foreach(message_line ${ARGN})
set(message_lines ${message_lines} COMMAND ${CMAKE_COMMAND} -E echo "${message_line}")
@ -184,6 +212,44 @@ function(fail_at_build_time target_name message_line0)
add_custom_target(${target_name} ALL
${message_lines}
COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_BINARY_DIR}/CMakeCache.txt"
COMMAND ${CMAKE_COMMAND} -P ${IDF_PATH}/tools/cmake/scripts/fail.cmake
COMMAND ${CMAKE_COMMAND} -P ${idf_path}/tools/cmake/scripts/fail.cmake
VERBATIM)
endfunction()
function(check_exclusive_args args prefix)
set(_args ${args})
spaces2list(_args)
set(only_arg 0)
foreach(arg ${_args})
if(${prefix}_${arg} AND only_arg)
message(FATAL_ERROR "${args} are exclusive arguments")
endif()
if(${prefix}_${arg})
set(only_arg 1)
endif()
endforeach()
endfunction()
# add_compile_options variant for C++ code only
#
# This adds global options, set target properties for
# component-specific flags
function(add_cxx_compile_options)
foreach(option ${ARGV})
# note: the Visual Studio Generator doesn't support this...
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:${option}>)
endforeach()
endfunction()
# add_compile_options variant for C code only
#
# This adds global options, set target properties for
# component-specific flags
function(add_c_compile_options)
foreach(option ${ARGV})
# note: the Visual Studio Generator doesn't support this...
add_compile_options($<$<COMPILE_LANGUAGE:C>:${option}>)
endforeach()
endfunction()

View file

@ -301,6 +301,8 @@ def write_cmake(deprecated_options, config, filename):
#
""")
configs_list = list()
def write_node(node):
sym = node.item
if not isinstance(sym, kconfiglib.Symbol):
@ -314,10 +316,15 @@ def write_cmake(deprecated_options, config, filename):
val = "" # write unset values as empty variables
write("set({}{} \"{}\")\n".format(
prefix, sym.name, val))
configs_list.append(prefix + sym.name)
dep_opt = deprecated_options.get_deprecated_option(sym.name)
if dep_opt:
tmp_dep_list.append("set({}{} \"{}\")\n".format(prefix, dep_opt, val))
configs_list.append(prefix + dep_opt)
config.walk_menu(write_node)
write("set(CONFIGS_LIST {})".format(";".join(configs_list)))
if len(tmp_dep_list) > 0:
write('\n# List of deprecated options for backward compatibility\n')