mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
cmake: build system changes
This commit is contained in:
parent
56078159d4
commit
c6dc47b3e2
271
CMakeLists.txt
271
CMakeLists.txt
@ -1,161 +1,150 @@
|
|||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
project(esp-idf C CXX ASM)
|
project(esp-idf C CXX ASM)
|
||||||
|
|
||||||
if(NOT IDF_PATH)
|
# Include the sdkconfig cmake file, since the following operations require
|
||||||
set(IDF_PATH ${CMAKE_CURRENT_LIST_DIR})
|
# knowledge of config values.
|
||||||
endif()
|
idf_build_get_property(sdkconfig_cmake SDKCONFIG_CMAKE)
|
||||||
|
include(${sdkconfig_cmake})
|
||||||
|
|
||||||
include(tools/cmake/idf_functions.cmake)
|
# Make each build property available as a read-only variable
|
||||||
|
idf_build_get_property(build_properties __BUILD_PROPERTIES)
|
||||||
#
|
foreach(build_property ${build_properties})
|
||||||
# Set variables that control the build configuration and the build itself
|
idf_build_get_property(val ${build_property})
|
||||||
#
|
set(${build_property} "${val}")
|
||||||
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")
|
|
||||||
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}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Generate project configuration
|
|
||||||
kconfig_process_config()
|
|
||||||
|
|
||||||
# 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()
|
endforeach()
|
||||||
|
|
||||||
#
|
# Check that the CMake target value matches the Kconfig target value.
|
||||||
# Add each component to the build as a library
|
__target_check()
|
||||||
#
|
|
||||||
foreach(COMPONENT_PATH ${BUILD_COMPONENT_PATHS})
|
|
||||||
get_filename_component(COMPONENT_NAME ${COMPONENT_PATH} NAME)
|
|
||||||
|
|
||||||
list(FIND BUILD_TEST_COMPONENT_PATHS ${COMPONENT_PATH} idx)
|
unset(compile_options)
|
||||||
|
unset(c_compile_options)
|
||||||
|
unset(cxx_compile_options)
|
||||||
|
unset(compile_definitions)
|
||||||
|
|
||||||
if(NOT idx EQUAL -1)
|
# Add the following build specifications here, since these seem to be dependent
|
||||||
list(GET BUILD_TEST_COMPONENTS ${idx} test_component)
|
# on config values on the root Kconfig.
|
||||||
set(COMPONENT_NAME ${test_component})
|
|
||||||
|
# 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 "-DGCC_NOT_5_2_0=${GCC_NOT_5_2_0}")
|
||||||
|
|
||||||
|
if(CONFIG_OPTIMIZATION_LEVEL_RELEASE)
|
||||||
|
list(APPEND compile_options "-Os")
|
||||||
|
else()
|
||||||
|
list(APPEND compile_options "-Og")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CONFIG_CXX_EXCEPTIONS)
|
||||||
|
list(APPEND cxx_compile_options "-fexceptions")
|
||||||
|
else()
|
||||||
|
list(APPEND cxx_compile_options "-fno-exceptions")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
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(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()
|
||||||
|
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)
|
||||||
|
|
||||||
|
# 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()
|
endforeach()
|
||||||
unset(COMPONENT_NAME)
|
|
||||||
unset(COMPONENT_PATH)
|
|
||||||
|
|
||||||
# each component should see the include directories of its requirements
|
# Add each component as a subdirectory, processing each component's CMakeLists.txt
|
||||||
#
|
foreach(component_target ${build_component_targets})
|
||||||
# (we can't do this until all components are registered and targets exist in cmake, as we have
|
__component_get_property(dir ${component_target} COMPONENT_DIR)
|
||||||
# a circular requirements graph...)
|
__component_get_property(_name ${component_target} COMPONENT_NAME)
|
||||||
foreach(component ${BUILD_COMPONENTS})
|
__component_get_property(prefix ${component_target} __PREFIX)
|
||||||
component_get_target(component_target ${component})
|
__component_get_property(alias ${component_target} COMPONENT_ALIAS)
|
||||||
if(TARGET ${component_target})
|
set(COMPONENT_NAME ${_name})
|
||||||
get_component_requirements(${component} deps priv_deps)
|
set(COMPONENT_DIR ${dir})
|
||||||
|
set(COMPONENT_ALIAS ${alias})
|
||||||
|
set(COMPONENT_PATH ${dir}) # same deprecation situation here
|
||||||
|
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()
|
||||||
|
|
||||||
list(APPEND priv_deps ${IDF_COMPONENT_REQUIRES_COMMON})
|
# 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()
|
||||||
|
|
||||||
foreach(dep ${deps})
|
get_property(type TARGET ${component_lib} PROPERTY TYPE)
|
||||||
component_get_target(dep_target ${dep})
|
if(type STREQUAL STATIC_LIBRARY)
|
||||||
add_component_dependencies(${component_target} ${dep_target} PUBLIC)
|
__component_get_property(reqs ${component_target} __REQUIRES)
|
||||||
endforeach()
|
__component_get_property(priv_reqs ${component_target} __PRIV_REQUIRES)
|
||||||
|
foreach(req ${reqs} ${priv_reqs})
|
||||||
foreach(dep ${priv_deps})
|
__component_get_property(req_lib ${req} COMPONENT_LIB)
|
||||||
component_get_target(dep_target ${dep})
|
if(TARGET ${req_lib})
|
||||||
add_component_dependencies(${component_target} ${dep_target} PRIVATE)
|
set_property(TARGET ${component_lib} APPEND PROPERTY LINK_LIBRARIES ${req_lib})
|
||||||
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
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()
|
|
||||||
|
@ -357,9 +357,9 @@ ESP-IDF 在搜索所有待构建的组件时,会按照 ``COMPONENT_DIRS`` 指
|
|||||||
|
|
||||||
.. highlight:: cmake
|
.. highlight:: cmake
|
||||||
|
|
||||||
在编译特定组件的源文件时,可以使用 ``component_compile_options`` 命令来传递编译器选项::
|
在编译特定组件的源文件时,可以使用 ``target_compile_options(${COMPONENT_TARGET} PRIVATE `` 命令来传递编译器选项::
|
||||||
|
|
||||||
component_compile_options(-Wno-unused-variable)
|
target_compile_options(${COMPONENT_TARGET} PRIVATE -Wno-unused-variable)
|
||||||
|
|
||||||
这条命令封装了 CMake 的 `target_compile_options`_ 命令。
|
这条命令封装了 CMake 的 `target_compile_options`_ 命令。
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ It will enable coverage info for all source files of your component. If you need
|
|||||||
`gcov_example.o: CFLAGS += --coverage`
|
`gcov_example.o: CFLAGS += --coverage`
|
||||||
Replace `gcov_example.o` with path to your file.
|
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_TARGET} PRIVATE --coverage)` or: ` set_source_files_properties(gcov_example.c PROPERTIES COMPILE_FLAGS --coverage`
|
||||||
|
|
||||||
|
|
||||||
### Hard-coded Dump Call
|
### Hard-coded Dump Call
|
||||||
|
434
tools/cmake/build.cmake
Normal file
434
tools/cmake/build.cmake
Normal file
@ -0,0 +1,434 @@
|
|||||||
|
|
||||||
|
# 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()
|
||||||
|
|
||||||
|
#
|
||||||
|
# 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()
|
||||||
|
|
||||||
|
# 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
|
||||||
|
function(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(NOT target OR 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}")
|
||||||
|
|
||||||
|
# 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()
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# 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()
|
460
tools/cmake/component.cmake
Normal file
460
tools/cmake/component.cmake
Normal file
@ -0,0 +1,460 @@
|
|||||||
|
#
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
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()
|
@ -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()
|
|
@ -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()
|
|
@ -173,7 +173,7 @@ def convert_component(project_path, component_path):
|
|||||||
else:
|
else:
|
||||||
f.write("register_config_only_component()\n")
|
f.write("register_config_only_component()\n")
|
||||||
if cflags is not None:
|
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)
|
print("Converted %s" % cmakelists_path)
|
||||||
|
|
||||||
|
@ -31,7 +31,8 @@ function(crosstool_version_check expected_ctng_version)
|
|||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
function(get_expected_ctng_version _toolchain_ver _gcc_ver)
|
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})
|
foreach(name_and_value ${config_contents})
|
||||||
# Strip spaces
|
# Strip spaces
|
||||||
string(REPLACE " " "" name_and_value ${name_and_value})
|
string(REPLACE " " "" name_and_value ${name_and_value})
|
||||||
|
45
tools/cmake/idf.cmake
Normal file
45
tools/cmake/idf.cmake
Normal 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()
|
@ -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()
|
|
@ -1,147 +1,209 @@
|
|||||||
include(ExternalProject)
|
include(ExternalProject)
|
||||||
|
|
||||||
macro(kconfig_set_variables)
|
function(__kconfig_init)
|
||||||
set_default(IDF_SDKCONFIG_DEFAULTS "")
|
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)
|
# Fall back to the old binary which was called 'mconf' not 'mconf-idf'
|
||||||
set_default(SDKCONFIG ${IDF_PROJECT_PATH}/sdkconfig)
|
if(NOT MCONF)
|
||||||
set(SDKCONFIG_HEADER ${CONFIG_DIR}/sdkconfig.h)
|
find_program(MCONF mconf)
|
||||||
set(SDKCONFIG_CMAKE ${CONFIG_DIR}/sdkconfig.cmake)
|
if(MCONF)
|
||||||
set(SDKCONFIG_JSON ${CONFIG_DIR}/sdkconfig.json)
|
message(WARNING "Falling back to mconf binary '${MCONF}' not mconf-idf. "
|
||||||
set(KCONFIG_JSON_MENUS ${CONFIG_DIR}/kconfig_menus.json)
|
"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)
|
if(NOT MCONF)
|
||||||
endmacro()
|
find_program(NATIVE_GCC gcc)
|
||||||
|
if(NOT NATIVE_GCC)
|
||||||
if(CMAKE_HOST_WIN32)
|
message(FATAL_ERROR
|
||||||
# Prefer a prebuilt mconf-idf on Windows
|
"Windows requires a prebuilt mconf-idf for your platform "
|
||||||
if(DEFINED ENV{MSYSTEM})
|
"on the PATH, or an MSYS2 version of gcc on the PATH to build mconf-idf. "
|
||||||
find_program(WINPTY winpty)
|
"Consult the setup docs for ESP-IDF on Windows.")
|
||||||
else()
|
endif()
|
||||||
unset(WINPTY CACHE) # in case previous CMake run was in a tty and this one is not
|
elseif(WINPTY)
|
||||||
endif()
|
set(MCONF "${WINPTY}" "${MCONF}")
|
||||||
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.")
|
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT MCONF)
|
if(NOT MCONF)
|
||||||
find_program(NATIVE_GCC gcc)
|
# Use the existing Makefile to build mconf (out of tree) when needed
|
||||||
if(NOT NATIVE_GCC)
|
#
|
||||||
message(FATAL_ERROR
|
set(MCONF ${CMAKE_BINARY_DIR}/kconfig_bin/mconf-idf)
|
||||||
"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. "
|
externalproject_add(mconf-idf
|
||||||
"Consult the setup docs for ESP-IDF on Windows.")
|
SOURCE_DIR ${idf_path}/tools/kconfig
|
||||||
endif()
|
CONFIGURE_COMMAND ""
|
||||||
elseif(WINPTY)
|
BINARY_DIR "kconfig_bin"
|
||||||
set(MCONF "${WINPTY}" "${MCONF}")
|
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()
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT MCONF)
|
idf_build_set_property(__MCONF ${MCONF})
|
||||||
# Use the existing Makefile to build mconf (out of tree) when needed
|
idf_build_set_property(__MENUCONFIG_DEPENDS "${menuconfig_depends}")
|
||||||
#
|
|
||||||
set(MCONF ${CMAKE_BINARY_DIR}/kconfig_bin/mconf-idf)
|
|
||||||
|
|
||||||
externalproject_add(mconf-idf
|
idf_build_get_property(idf_path IDF_PATH)
|
||||||
SOURCE_DIR ${IDF_PATH}/tools/kconfig
|
idf_build_set_property(__ROOT_KCONFIG ${idf_path}/Kconfig)
|
||||||
CONFIGURE_COMMAND ""
|
idf_build_set_property(__OUTPUT_SDKCONFIG 1)
|
||||||
BINARY_DIR "kconfig_bin"
|
endfunction()
|
||||||
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
|
# Initialize Kconfig-related properties for components.
|
||||||
${mconf_srcfiles}
|
# This function assumes that all basic properties of the components have been
|
||||||
${IDF_PATH}/tools/kconfig/Makefile
|
# set prior to calling it.
|
||||||
${CMAKE_CURRENT_LIST_FILE})
|
#
|
||||||
unset(mconf_srcfiles)
|
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)
|
#
|
||||||
|
# Generate the config files and create config related targets and configure
|
||||||
endif()
|
# dependencies.
|
||||||
|
#
|
||||||
# Find all Kconfig files for all components
|
function(__kconfig_generate_config sdkconfig sdkconfig_defaults)
|
||||||
function(kconfig_process_config)
|
# List all Kconfig and Kconfig.projbuild in known components
|
||||||
file(MAKE_DIRECTORY "${CONFIG_DIR}")
|
idf_build_get_property(component_targets __COMPONENT_TARGETS)
|
||||||
set(kconfigs)
|
foreach(component_target ${component_targets})
|
||||||
set(kconfigs_projbuild)
|
__component_get_property(kconfig ${component_target} KCONFIG)
|
||||||
|
__component_get_property(kconfig_projbuild ${component_target} KCONFIG_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")
|
|
||||||
if(kconfig)
|
if(kconfig)
|
||||||
set(kconfigs "${kconfigs} ${kconfig}")
|
list(APPEND kconfigs ${kconfig})
|
||||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${kconfig})
|
|
||||||
endif()
|
endif()
|
||||||
file(GLOB kconfig ${dir}/Kconfig.projbuild)
|
if(kconfig_projbuild)
|
||||||
if(kconfig)
|
list(APPEND kconfig_projbuilds ${kconfig_projbuild})
|
||||||
set(kconfigs_projbuild "${kconfigs_projbuild} ${kconfig}")
|
|
||||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${kconfig})
|
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
if(IDF_SDKCONFIG_DEFAULTS)
|
# Store the list version of kconfigs and kconfig_projbuilds
|
||||||
set(defaults_arg --defaults "${IDF_SDKCONFIG_DEFAULTS}")
|
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()
|
endif()
|
||||||
|
|
||||||
if(EXISTS "${IDF_SDKCONFIG_DEFAULTS}.${IDF_TARGET}")
|
if(EXISTS "${sdkconfig_defaults}.${idf_target}")
|
||||||
list(APPEND defaults_arg --defaults "${IDF_SDKCONFIG_DEFAULTS}.${IDF_TARGET}")
|
list(APPEND defaults_arg --defaults "${sdkconfig_defaults}.${idf_target}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Set these in the parent scope, so that they can be written to project_description.json
|
idf_build_get_property(idf_path IDF_PATH)
|
||||||
set(kconfigs "${kconfigs}")
|
idf_build_get_property(root_kconfig __ROOT_KCONFIG)
|
||||||
set(COMPONENT_KCONFIGS "${kconfigs}" PARENT_SCOPE)
|
idf_build_get_property(python PYTHON)
|
||||||
set(COMPONENT_KCONFIGS_PROJBUILD "${kconfigs_projbuild}" PARENT_SCOPE)
|
|
||||||
|
string(REPLACE ";" " " kconfigs "${kconfigs}")
|
||||||
|
string(REPLACE ";" " " kconfig_projbuilds "${kconfig_projbuilds}")
|
||||||
|
|
||||||
set(confgen_basecommand
|
set(confgen_basecommand
|
||||||
${PYTHON} ${IDF_PATH}/tools/kconfig_new/confgen.py
|
${python} ${idf_path}/tools/kconfig_new/confgen.py
|
||||||
--kconfig ${ROOT_KCONFIG}
|
--kconfig ${root_kconfig}
|
||||||
--config ${SDKCONFIG}
|
--config ${sdkconfig}
|
||||||
${defaults_arg}
|
${defaults_arg}
|
||||||
--env "COMPONENT_KCONFIGS=${kconfigs}"
|
--env "COMPONENT_KCONFIGS=${kconfigs}"
|
||||||
--env "COMPONENT_KCONFIGS_PROJBUILD=${kconfigs_projbuild}"
|
--env "COMPONENT_KCONFIGS_PROJBUILD=${kconfig_projbuilds}"
|
||||||
--env "IDF_CMAKE=y")
|
--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)
|
||||||
|
|
||||||
# Generate the menuconfig target (uses C-based mconf-idf tool, either prebuilt or via mconf-idf target above)
|
# Generate the menuconfig target (uses C-based mconf-idf tool, either prebuilt or via mconf-idf target above)
|
||||||
add_custom_target(menuconfig
|
add_custom_target(menuconfig
|
||||||
${menuconfig_depends}
|
${menuconfig_depends}
|
||||||
# create any missing config file, with defaults if necessary
|
# 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
|
COMMAND ${CMAKE_COMMAND} -E env
|
||||||
"COMPONENT_KCONFIGS=${kconfigs}"
|
"COMPONENT_KCONFIGS=${kconfigs}"
|
||||||
"COMPONENT_KCONFIGS_PROJBUILD=${kconfigs_projbuild}"
|
"COMPONENT_KCONFIGS_PROJBUILD=${kconfig_projbuilds}"
|
||||||
"IDF_CMAKE=y"
|
"IDF_CMAKE=y"
|
||||||
"KCONFIG_CONFIG=${SDKCONFIG}"
|
"KCONFIG_CONFIG=${sdkconfig}"
|
||||||
"IDF_TARGET=${IDF_TARGET}"
|
${MCONF} ${root_kconfig}
|
||||||
${MCONF} ${ROOT_KCONFIG}
|
|
||||||
VERBATIM
|
VERBATIM
|
||||||
USES_TERMINAL
|
USES_TERMINAL
|
||||||
# additional run of confgen esures that the deprecated options will be inserted into sdkconfig (for backward
|
# additional run of confgen esures that the deprecated options will be inserted into sdkconfig (for backward
|
||||||
# compatibility)
|
# 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
|
# Custom target to run confserver.py from the build tool
|
||||||
@ -152,47 +214,4 @@ function(kconfig_process_config)
|
|||||||
${PYTHON} ${IDF_PATH}/tools/kconfig_new/confserver.py --kconfig ${IDF_PATH}/Kconfig --config ${SDKCONFIG}
|
${PYTHON} ${IDF_PATH}/tools/kconfig_new/confserver.py --kconfig ${IDF_PATH}/Kconfig --config ${SDKCONFIG}
|
||||||
VERBATIM
|
VERBATIM
|
||||||
USES_TERMINAL)
|
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()
|
endfunction()
|
||||||
|
@ -1,81 +1,84 @@
|
|||||||
# Utilities for supporting linker script generation in the build system
|
# Utilities for supporting linker script generation in the build system
|
||||||
|
|
||||||
# ldgen_set_variables
|
# __ldgen_add_fragment_files
|
||||||
#
|
|
||||||
# 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
|
|
||||||
#
|
#
|
||||||
# Add one or more linker fragment files, and append it to the list of fragment
|
# Add one or more linker fragment files, and append it to the list of fragment
|
||||||
# files found so far.
|
# files found so far.
|
||||||
function(ldgen_add_fragment_files component fragment_files)
|
function(__ldgen_add_fragment_files fragment_files)
|
||||||
spaces2list(fragment_files)
|
spaces2list(fragment_files)
|
||||||
|
|
||||||
foreach(fragment_file ${fragment_files})
|
foreach(fragment_file ${fragment_files})
|
||||||
get_filename_component(_fragment_file ${fragment_file} ABSOLUTE)
|
get_filename_component(abs_path ${fragment_file} ABSOLUTE)
|
||||||
list(APPEND _fragment_files ${_fragment_file})
|
list(APPEND _fragment_files ${abs_path})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
set_property(TARGET ldgen APPEND PROPERTY FRAGMENT_FILES ${_fragment_files})
|
idf_build_set_property(__LDGEN_FRAGMENT_FILES "${_fragment_files}" APPEND)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# ldgen_component_add
|
# __ldgen_add_component
|
||||||
#
|
#
|
||||||
# Add component to known libraries for linker script generation
|
# Generate sections info for specified target to be used in linker script generation
|
||||||
function(ldgen_component_add component_lib)
|
function(__ldgen_add_component component_lib)
|
||||||
set_property(TARGET ldgen APPEND PROPERTY OUTPUT_LIBRARIES "$<TARGET_FILE:${component_lib}>")
|
idf_build_set_property(__LDGEN_LIBRARIES "$<TARGET_FILE:${component_lib}>" APPEND)
|
||||||
set_property(TARGET ldgen APPEND PROPERTY LIBRARIES ${component_lib})
|
idf_build_set_property(__LDGEN_DEPENDS ${component_lib} APPEND)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# ldgen_process_template
|
# __ldgen_process_template
|
||||||
#
|
#
|
||||||
# Passes a linker script template to the linker script generation tool for
|
# Passes a linker script template to the linker script generation tool for
|
||||||
# processing
|
# processing
|
||||||
function(ldgen_process_template template output)
|
function(__ldgen_process_template output_var template)
|
||||||
get_property(output_libraries TARGET ldgen PROPERTY OUTPUT_LIBRARIES)
|
idf_build_get_property(idf_target IDF_TARGET)
|
||||||
file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/ldgen_libraries.in CONTENT "$<JOIN:${output_libraries},\n>")
|
idf_build_get_property(idf_path IDF_PATH)
|
||||||
file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/ldgen_libraries INPUT ${CMAKE_BINARY_DIR}/ldgen_libraries.in)
|
|
||||||
|
|
||||||
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}"
|
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
|
APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
|
||||||
"${CMAKE_BINARY_DIR}/ldgen_libraries.in"
|
"${build_dir}/ldgen_libraries.in"
|
||||||
"${CMAKE_BINARY_DIR}/ldgen_libraries")
|
"${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(
|
add_custom_command(
|
||||||
OUTPUT ${output}
|
OUTPUT ${output}
|
||||||
COMMAND ${PYTHON} ${IDF_PATH}/tools/ldgen/ldgen.py
|
COMMAND ${python} ${idf_path}/tools/ldgen/ldgen.py
|
||||||
--config ${SDKCONFIG}
|
--config ${sdkconfig}
|
||||||
--fragments "$<JOIN:$<TARGET_PROPERTY:ldgen,FRAGMENT_FILES>,\t>"
|
--fragments "$<JOIN:${ldgen_fragment_files},\t>"
|
||||||
--input ${template}
|
--input ${template}
|
||||||
--output ${output}
|
--output ${output}
|
||||||
--kconfig ${ROOT_KCONFIG}
|
--kconfig ${root_kconfig}
|
||||||
--env "COMPONENT_KCONFIGS=${COMPONENT_KCONFIGS}"
|
--env "COMPONENT_KCONFIGS=${kconfigs}"
|
||||||
--env "COMPONENT_KCONFIGS_PROJBUILD=${COMPONENT_KCONFIGS_PROJBUILD}"
|
--env "COMPONENT_KCONFIGS_PROJBUILD=${kconfig_projbuilds}"
|
||||||
--env "IDF_CMAKE=y"
|
--env "IDF_CMAKE=y"
|
||||||
--env "IDF_PATH=${IDF_PATH}"
|
--env "IDF_PATH=${idf_path}"
|
||||||
--env "IDF_TARGET=${IDF_TARGET}"
|
--env "IDF_TARGET=${idf_target}"
|
||||||
--libraries-file ${CMAKE_BINARY_DIR}/ldgen_libraries
|
--libraries-file ${build_dir}/ldgen_libraries
|
||||||
--objdump ${CMAKE_OBJDUMP}
|
--objdump ${CMAKE_OBJDUMP}
|
||||||
DEPENDS ${template} $<TARGET_PROPERTY:ldgen,FRAGMENT_FILES>
|
DEPENDS ${template} ${ldgen_fragment_files} ${ldgen_depends} ${SDKCONFIG}
|
||||||
$<TARGET_PROPERTY:ldgen,LIBRARIES> ${SDKCONFIG}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
get_filename_component(output_name ${output} NAME)
|
get_filename_component(_name ${output} NAME)
|
||||||
add_custom_target(ldgen_${output_name}_script DEPENDS ${output})
|
add_custom_target(__ldgen_output_${_name} DEPENDS ${output})
|
||||||
add_dependencies(ldgen ldgen_${output_name}_script)
|
add_dependencies(__idf_build_target __ldgen_output_${_name})
|
||||||
endfunction()
|
idf_build_set_property(LINK_DEPENDS ${output} APPEND)
|
||||||
|
|
||||||
# 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()
|
|
||||||
endfunction()
|
endfunction()
|
@ -1,11 +1,226 @@
|
|||||||
# Designed to be included from an IDF app's CMakeLists.txt file
|
# Designed to be included from an IDF app's CMakeLists.txt file
|
||||||
#
|
|
||||||
cmake_minimum_required(VERSION 3.5)
|
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")
|
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
|
# 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
|
# using an underscore prefixed function of the same name. The following lines make sure that __project calls
|
||||||
@ -16,72 +231,14 @@ endfunction()
|
|||||||
function(_project)
|
function(_project)
|
||||||
endfunction()
|
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
|
__target_set_toolchain()
|
||||||
# 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()
|
|
||||||
|
|
||||||
# Enable ccache if it's on the path
|
# Enable ccache if it's on the path
|
||||||
if(NOT CCACHE_DISABLE)
|
if(NOT CCACHE_DISABLE)
|
||||||
@ -92,50 +249,11 @@ macro(project name)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
__project(${name} C CXX ASM)
|
# The actual call to project()
|
||||||
|
__project(${project_name} C CXX ASM)
|
||||||
|
|
||||||
set(IDF_BUILD_ARTIFACTS ON)
|
# Generate compile_commands.json (needs to come after project call).
|
||||||
set(IDF_PROJECT_EXECUTABLE ${CMAKE_PROJECT_NAME}.elf)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
|
||||||
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}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Since components can import third-party libraries, the original definition of project() should be restored
|
# Since components can import third-party libraries, the original definition of project() should be restored
|
||||||
# before the call to add components to the build.
|
# before the call to add components to the build.
|
||||||
@ -144,7 +262,140 @@ macro(project name)
|
|||||||
__project(${${project_ARGV}})
|
__project(${${project_ARGV}})
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# Finally, add the rest of the components to the build.
|
# Prepare the following arguments for the idf_build_process() call using external
|
||||||
idf_import_components(components $ENV{IDF_PATH} esp-idf)
|
# user values:
|
||||||
idf_link_components(${IDF_PROJECT_EXECUTABLE} "${components}")
|
#
|
||||||
|
# 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,--gc-sections")
|
||||||
|
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}")
|
||||||
endmacro()
|
endmacro()
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"project_name": "${IDF_PROJECT_NAME}",
|
"project_name": "${PROJECT_NAME}",
|
||||||
"project_path": "${IDF_PROJECT_PATH}",
|
"project_path": "${PROJECT_PATH}",
|
||||||
"build_dir": "${IDF_BUILD_ARTIFACTS_DIR}",
|
"build_dir": "${BUILD_DIR}",
|
||||||
"config_file": "${SDKCONFIG}",
|
"config_file": "${SDKCONFIG}",
|
||||||
"config_defaults": "${IDF_SDKCONFIG_DEFAULTS}",
|
"config_defaults": "${SDKCONFIG_DEFAULTS}",
|
||||||
"app_elf": "${IDF_PROJECT_EXECUTABLE}",
|
"app_elf": "${PROJECT_EXECUTABLE}",
|
||||||
"app_bin": "${IDF_PROJECT_BIN}",
|
"app_bin": "${PROJECT_BIN}",
|
||||||
"git_revision": "${IDF_VER}",
|
"git_revision": "${IDF_VER}",
|
||||||
"phy_data_partition": "${CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION}",
|
"phy_data_partition": "${CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION}",
|
||||||
"monitor_baud" : "${CONFIG_MONITOR_BAUD}",
|
"monitor_baud" : "${CONFIG_MONITOR_BAUD}",
|
||||||
|
49
tools/cmake/scripts/component_get_requirements.cmake
Normal file
49
tools/cmake/scripts/component_get_requirements.cmake
Normal 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)
|
@ -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")
|
|
@ -1,6 +1,7 @@
|
|||||||
include(component_utils)
|
#
|
||||||
|
# Set the target used for the standard project build.
|
||||||
macro(idf_set_target)
|
#
|
||||||
|
macro(__target_init)
|
||||||
# Input is IDF_TARGET environement variable
|
# Input is IDF_TARGET environement variable
|
||||||
set(env_idf_target $ENV{IDF_TARGET})
|
set(env_idf_target $ENV{IDF_TARGET})
|
||||||
|
|
||||||
@ -26,28 +27,38 @@ macro(idf_set_target)
|
|||||||
|
|
||||||
# Finally, set IDF_TARGET in cache
|
# Finally, set IDF_TARGET in cache
|
||||||
set(IDF_TARGET ${env_idf_target} CACHE STRING "IDF Build Target")
|
set(IDF_TARGET ${env_idf_target} CACHE STRING "IDF Build Target")
|
||||||
|
|
||||||
message(STATUS "Building for target ${IDF_TARGET}")
|
|
||||||
endmacro()
|
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 "
|
message(FATAL_ERROR "CONFIG_IDF_TARGET in sdkconfig does not match "
|
||||||
"IDF_TARGET environement variable. To change the target, delete "
|
"IDF_TARGET environement variable. To change the target, delete "
|
||||||
"sdkconfig file and build the project again.")
|
"sdkconfig file and build the project again.")
|
||||||
endif()
|
endif()
|
||||||
endmacro()
|
endfunction()
|
||||||
|
|
||||||
macro(idf_set_toolchain)
|
#
|
||||||
# First try to load the toolchain file from the tools/cmake/ directory of IDF
|
# Used by the project CMake file to set the toolchain before project() call.
|
||||||
set(toolchain_file_global $ENV{IDF_PATH}/tools/cmake/toolchain-${IDF_TARGET}.cmake)
|
#
|
||||||
|
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})
|
if(EXISTS ${toolchain_file_global})
|
||||||
set(CMAKE_TOOLCHAIN_FILE ${toolchain_file_global})
|
set(CMAKE_TOOLCHAIN_FILE ${toolchain_file_global})
|
||||||
else()
|
else()
|
||||||
# Try to load the toolchain file from the directory of ${IDF_TARGET} component
|
__component_get_target(component_target ${IDF_TARGET})
|
||||||
components_find_all("${IDF_COMPONENT_DIRS}" ALL_COMPONENT_PATHS ALL_COMPONENTS ALL_TEST_COMPONENTS)
|
if(NOT component_target)
|
||||||
find_component_path(${IDF_TARGET} "${ALL_COMPONENTS}" "${ALL_COMPONENT_PATHS}" target_component_path)
|
message(FATAL_ERROR "Unable to resolve '${IDF_TARGET}' for setting toolchain file.")
|
||||||
set(toolchain_file_component ${target_component_path}/toolchain-${IDF_TARGET}.cmake)
|
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})
|
if(EXISTS ${toolchain_file_component})
|
||||||
set(CMAKE_TOOLCHAIN_FILE ${toolchain_file_component})
|
set(CMAKE_TOOLCHAIN_FILE ${toolchain_file_component})
|
||||||
else()
|
else()
|
||||||
@ -55,4 +66,4 @@ macro(idf_set_toolchain)
|
|||||||
"checked ${toolchain_file_global} and ${toolchain_file_component}")
|
"checked ${toolchain_file_global} and ${toolchain_file_component}")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endmacro()
|
endmacro()
|
@ -77,21 +77,23 @@ endfunction()
|
|||||||
# by converting it to a generated source file which is then compiled
|
# by converting it to a generated source file which is then compiled
|
||||||
# to a binary object as part of the build
|
# to a binary object as part of the build
|
||||||
function(target_add_binary_data target embed_file embed_type)
|
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(embed_file "${embed_file}" ABSOLUTE)
|
||||||
|
|
||||||
get_filename_component(name "${embed_file}" NAME)
|
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}"
|
add_custom_command(OUTPUT "${embed_srcfile}"
|
||||||
COMMAND "${CMAKE_COMMAND}"
|
COMMAND "${CMAKE_COMMAND}"
|
||||||
-D "DATA_FILE=${embed_file}"
|
-D "DATA_FILE=${embed_file}"
|
||||||
-D "SOURCE_FILE=${embed_srcfile}"
|
-D "SOURCE_FILE=${embed_srcfile}"
|
||||||
-D "FILE_TYPE=${embed_type}"
|
-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}"
|
MAIN_DEPENDENCY "${embed_file}"
|
||||||
DEPENDS "${IDF_PATH}/tools/cmake/scripts/data_file_embed_asm.cmake"
|
DEPENDS "${idf_path}/tools/cmake/scripts/data_file_embed_asm.cmake"
|
||||||
WORKING_DIRECTORY "${IDF_BUILD_ARTIFACTS_DIR}"
|
WORKING_DIRECTORY "${build_dir}"
|
||||||
VERBATIM)
|
VERBATIM)
|
||||||
|
|
||||||
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${embed_srcfile}")
|
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),
|
# 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
|
# and then adds -T with the filename only. This allows INCLUDE directives to be
|
||||||
# used to include other linker scripts in the same directory.
|
# used to include other linker scripts in the same directory.
|
||||||
function(target_linker_script target)
|
function(target_linker_script target scriptfiles)
|
||||||
foreach(scriptfile ${ARGN})
|
cmake_parse_arguments(_ "PROCESS" "" "" ${ARGN})
|
||||||
|
foreach(scriptfile ${scriptfiles})
|
||||||
get_filename_component(abs_script "${scriptfile}" ABSOLUTE)
|
get_filename_component(abs_script "${scriptfile}" ABSOLUTE)
|
||||||
message(STATUS "Adding linker script ${abs_script}")
|
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(search_dir "${abs_script}" DIRECTORY)
|
||||||
get_filename_component(scriptname "${abs_script}" NAME)
|
get_filename_component(scriptname "${abs_script}" NAME)
|
||||||
|
|
||||||
get_target_property(link_libraries "${target}" LINK_LIBRARIES)
|
get_target_property(type ${target} TYPE)
|
||||||
list(FIND "${link_libraries}" "-L ${search_dir}" found_search_dir)
|
if(type STREQUAL "INTERFACE_LIBRARY")
|
||||||
if(found_search_dir EQUAL "-1") # not already added as a search path
|
set(is_interface "INTERFACE")
|
||||||
target_link_libraries("${target}" "-L ${search_dir}")
|
|
||||||
endif()
|
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
|
# 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.
|
# executable(s) the library is linked to. Attach manually to executable once it is known.
|
||||||
set_property(TARGET "${target}" APPEND PROPERTY LINK_DEPENDS "${abs_script}")
|
#
|
||||||
|
# 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()
|
endforeach()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
@ -177,6 +204,7 @@ endfunction()
|
|||||||
# We cannot use CMAKE_CONFIGURE_DEPENDS instead because it only works for files which exist at CMake runtime.
|
# 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)
|
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}")
|
set(message_lines COMMAND ${CMAKE_COMMAND} -E echo "${message_line0}")
|
||||||
foreach(message_line ${ARGN})
|
foreach(message_line ${ARGN})
|
||||||
set(message_lines ${message_lines} COMMAND ${CMAKE_COMMAND} -E echo "${message_line}")
|
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
|
add_custom_target(${target_name} ALL
|
||||||
${message_lines}
|
${message_lines}
|
||||||
COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_BINARY_DIR}/CMakeCache.txt"
|
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)
|
VERBATIM)
|
||||||
endfunction()
|
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()
|
||||||
|
@ -301,6 +301,8 @@ def write_cmake(deprecated_options, config, filename):
|
|||||||
#
|
#
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
configs_list = list()
|
||||||
|
|
||||||
def write_node(node):
|
def write_node(node):
|
||||||
sym = node.item
|
sym = node.item
|
||||||
if not isinstance(sym, kconfiglib.Symbol):
|
if not isinstance(sym, kconfiglib.Symbol):
|
||||||
@ -314,10 +316,15 @@ def write_cmake(deprecated_options, config, filename):
|
|||||||
val = "" # write unset values as empty variables
|
val = "" # write unset values as empty variables
|
||||||
write("set({}{} \"{}\")\n".format(
|
write("set({}{} \"{}\")\n".format(
|
||||||
prefix, sym.name, val))
|
prefix, sym.name, val))
|
||||||
|
|
||||||
|
configs_list.append(prefix + sym.name)
|
||||||
dep_opt = deprecated_options.get_deprecated_option(sym.name)
|
dep_opt = deprecated_options.get_deprecated_option(sym.name)
|
||||||
if dep_opt:
|
if dep_opt:
|
||||||
tmp_dep_list.append("set({}{} \"{}\")\n".format(prefix, dep_opt, val))
|
tmp_dep_list.append("set({}{} \"{}\")\n".format(prefix, dep_opt, val))
|
||||||
|
configs_list.append(prefix + dep_opt)
|
||||||
|
|
||||||
config.walk_menu(write_node)
|
config.walk_menu(write_node)
|
||||||
|
write("set(CONFIGS_LIST {})".format(";".join(configs_list)))
|
||||||
|
|
||||||
if len(tmp_dep_list) > 0:
|
if len(tmp_dep_list) > 0:
|
||||||
write('\n# List of deprecated options for backward compatibility\n')
|
write('\n# List of deprecated options for backward compatibility\n')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user