cmake: build system changes

pull/3513/head
Renz Christian Bagaporo 2019-04-26 13:42:10 +08:00
rodzic 56078159d4
commit c6dc47b3e2
20 zmienionych plików z 1829 dodań i 1344 usunięć

Wyświetl plik

@ -1,161 +1,150 @@
cmake_minimum_required(VERSION 3.5)
project(esp-idf C CXX ASM)
if(NOT IDF_PATH)
set(IDF_PATH ${CMAKE_CURRENT_LIST_DIR})
endif()
# Include the sdkconfig cmake file, since the following operations require
# knowledge of config values.
idf_build_get_property(sdkconfig_cmake SDKCONFIG_CMAKE)
include(${sdkconfig_cmake})
include(tools/cmake/idf_functions.cmake)
#
# Set variables that control the build configuration and the build itself
#
idf_set_variables()
kconfig_set_variables()
#
# Generate a component dependencies file, enumerating components to be included in the build
# as well as their dependencies.
#
execute_process(COMMAND "${CMAKE_COMMAND}"
-D "COMPONENTS=${IDF_COMPONENTS}"
-D "COMPONENT_REQUIRES_COMMON=${IDF_COMPONENT_REQUIRES_COMMON}"
-D "EXCLUDE_COMPONENTS=${IDF_EXCLUDE_COMPONENTS}"
-D "TEST_COMPONENTS=${IDF_TEST_COMPONENTS}"
-D "TEST_EXCLUDE_COMPONENTS=${IDF_TEST_EXCLUDE_COMPONENTS}"
-D "BUILD_TESTS=${IDF_BUILD_TESTS}"
-D "DEPENDENCIES_FILE=${CMAKE_BINARY_DIR}/component_depends.cmake"
-D "COMPONENT_DIRS=${IDF_COMPONENT_DIRS}"
-D "BOOTLOADER_BUILD=${BOOTLOADER_BUILD}"
-D "IDF_TARGET=${IDF_TARGET}"
-D "IDF_PATH=${IDF_PATH}"
-D "DEBUG=${DEBUG}"
-P "${IDF_PATH}/tools/cmake/scripts/expand_requirements.cmake"
WORKING_DIRECTORY "${PROJECT_PATH}"
RESULT_VARIABLE expand_requirements_result)
if(expand_requirements_result)
message(FATAL_ERROR "Failed to expand component requirements")
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)
# Make each build property available as a read-only variable
idf_build_get_property(build_properties __BUILD_PROPERTIES)
foreach(build_property ${build_properties})
idf_build_get_property(val ${build_property})
set(${build_property} "${val}")
endforeach()
#
# Add each component to the build as a library
#
foreach(COMPONENT_PATH ${BUILD_COMPONENT_PATHS})
get_filename_component(COMPONENT_NAME ${COMPONENT_PATH} NAME)
# Check that the CMake target value matches the Kconfig target value.
__target_check()
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)
list(GET BUILD_TEST_COMPONENTS ${idx} test_component)
set(COMPONENT_NAME ${test_component})
# Add the following build specifications here, since these seem to be dependent
# on config values on the root Kconfig.
# Temporary trick to support both gcc5 and gcc8 builds
if(CMAKE_C_COMPILER_VERSION VERSION_EQUAL 5.2.0)
set(GCC_NOT_5_2_0 0 CACHE STRING "GCC is 5.2.0 version")
else()
set(GCC_NOT_5_2_0 1 CACHE STRING "GCC is not 5.2.0 version")
endif()
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()
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()
unset(COMPONENT_NAME)
unset(COMPONENT_PATH)
# each component should see the include directories of its requirements
#
# (we can't do this until all components are registered and targets exist in cmake, as we have
# a circular requirements graph...)
foreach(component ${BUILD_COMPONENTS})
component_get_target(component_target ${component})
if(TARGET ${component_target})
get_component_requirements(${component} deps priv_deps)
# Add each component as a subdirectory, processing each component's CMakeLists.txt
foreach(component_target ${build_component_targets})
__component_get_property(dir ${component_target} COMPONENT_DIR)
__component_get_property(_name ${component_target} COMPONENT_NAME)
__component_get_property(prefix ${component_target} __PREFIX)
__component_get_property(alias ${component_target} COMPONENT_ALIAS)
set(COMPONENT_NAME ${_name})
set(COMPONENT_DIR ${dir})
set(COMPONENT_ALIAS ${alias})
set(COMPONENT_PATH ${dir}) # 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})
component_get_target(dep_target ${dep})
add_component_dependencies(${component_target} ${dep_target} PUBLIC)
endforeach()
foreach(dep ${priv_deps})
component_get_target(dep_target ${dep})
add_component_dependencies(${component_target} ${dep_target} PRIVATE)
get_property(type TARGET ${component_lib} PROPERTY TYPE)
if(type STREQUAL STATIC_LIBRARY)
__component_get_property(reqs ${component_target} __REQUIRES)
__component_get_property(priv_reqs ${component_target} __PRIV_REQUIRES)
foreach(req ${reqs} ${priv_reqs})
__component_get_property(req_lib ${req} COMPONENT_LIB)
if(TARGET ${req_lib})
set_property(TARGET ${component_lib} APPEND PROPERTY LINK_LIBRARIES ${req_lib})
endif()
endforeach()
endif()
endforeach()
if(IDF_BUILD_ARTIFACTS)
# Write project description JSON file
make_json_list("${BUILD_COMPONENTS}" build_components_json)
make_json_list("${BUILD_COMPONENT_PATHS}" build_component_paths_json)
configure_file("${IDF_PATH}/tools/cmake/project_description.json.in"
"${IDF_BUILD_ARTIFACTS_DIR}/project_description.json")
unset(build_components_json)
unset(build_component_paths_json)
endif()
set(BUILD_COMPONENTS ${BUILD_COMPONENTS} PARENT_SCOPE)
ldgen_add_dependencies()

Wyświetl plik

@ -357,9 +357,9 @@ ESP-IDF 在搜索所有待构建的组件时,会按照 ``COMPONENT_DIRS`` 指
.. 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`_ 命令。

Wyświetl plik

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

Wyświetl plik

@ -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()

Wyświetl plik

@ -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()

Wyświetl plik

@ -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()

Wyświetl plik

@ -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()

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

@ -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()

Wyświetl plik

@ -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()

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

@ -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)

Wyświetl plik

@ -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")

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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