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(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 the sdkconfig cmake file, since the following operations require
+# knowledge of config values.
+idf_build_get_property(sdkconfig_cmake SDKCONFIG_CMAKE)
+include(${sdkconfig_cmake})
+
+# Make each build property available as a read-only variable
+idf_build_get_property(build_properties __BUILD_PROPERTIES)
+foreach(build_property ${build_properties})
+ idf_build_get_property(val ${build_property})
+ set(${build_property} "${val}")
+endforeach()
-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()
+# Check that the CMake target value matches the Kconfig target value.
+__target_check()
-# Generate project configuration
-kconfig_process_config()
+unset(compile_options)
+unset(c_compile_options)
+unset(cxx_compile_options)
+unset(compile_definitions)
-# Include sdkconfig.cmake so rest of the build knows the configuration
-include(${SDKCONFIG_CMAKE})
+# Add the following build specifications here, since these seem to be dependent
+# on config values on the root Kconfig.
-# Verify the environment is configured correctly
-idf_verify_environment()
+# 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()
-# Check git revision (may trigger reruns of cmake)
-## sets IDF_VER to IDF git revision
-idf_get_git_revision()
+list(APPEND compile_definitions "-DGCC_NOT_5_2_0=${GCC_NOT_5_2_0}")
-# Check that the targets set in cache, sdkconfig, and in environment all match
-idf_check_config_target()
+if(CONFIG_OPTIMIZATION_LEVEL_RELEASE)
+ list(APPEND compile_options "-Os")
+else()
+ list(APPEND compile_options "-Og")
+endif()
-## get PROJECT_VER
-if(NOT BOOTLOADER_BUILD)
- app_get_revision("${CMAKE_SOURCE_DIR}")
+if(CONFIG_CXX_EXCEPTIONS)
+ list(APPEND cxx_compile_options "-fexceptions")
+else()
+ list(APPEND cxx_compile_options "-fno-exceptions")
endif()
-# Add some idf-wide definitions
-idf_set_global_compile_options()
+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()
-# generate compile_commands.json (needs to come after project)
-set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
+if(CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED)
+ list(APPEND compile_definitions "NDEBUG")
+endif()
-#
-# Setup variables for linker script generation
-#
-ldgen_set_variables()
+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()
-# 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)
+# 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()
-#
-# Add each component to the build as a library
-#
-foreach(COMPONENT_PATH ${BUILD_COMPONENT_PATHS})
- get_filename_component(COMPONENT_NAME ${COMPONENT_PATH} NAME)
-
- list(FIND BUILD_TEST_COMPONENT_PATHS ${COMPONENT_PATH} idx)
-
- if(NOT idx EQUAL -1)
- list(GET BUILD_TEST_COMPONENTS ${idx} test_component)
- set(COMPONENT_NAME ${test_component})
+# 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()
-
- component_get_target(COMPONENT_TARGET ${COMPONENT_NAME})
-
- add_subdirectory(${COMPONENT_PATH} ${COMPONENT_NAME})
+ set(__idf_component_context 0)
endforeach()
-unset(COMPONENT_NAME)
-unset(COMPONENT_PATH)
-
-# each component should see the include directories of its requirements
-#
-# (we can't do this until all components are registered and targets exist in cmake, as we have
-# a circular requirements graph...)
-foreach(component ${BUILD_COMPONENTS})
- component_get_target(component_target ${component})
- if(TARGET ${component_target})
- get_component_requirements(${component} deps priv_deps)
-
- list(APPEND priv_deps ${IDF_COMPONENT_REQUIRES_COMMON})
-
- foreach(dep ${deps})
- component_get_target(dep_target ${dep})
- add_component_dependencies(${component_target} ${dep_target} PUBLIC)
- endforeach()
- foreach(dep ${priv_deps})
- component_get_target(dep_target ${dep})
- add_component_dependencies(${component_target} ${dep_target} PRIVATE)
+# 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()
+
+ 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()
.. 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`_ 命令。
`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
--- /dev/null
+
+# 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()
\ No newline at end of file
--- /dev/null
+#
+# 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()
\ No newline at end of file
+++ /dev/null
-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()
+++ /dev/null
-# 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()
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)
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})
--- /dev/null
+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()
\ No newline at end of file
+++ /dev/null
-#
-# 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()
include(ExternalProject)
-macro(kconfig_set_variables)
- set_default(IDF_SDKCONFIG_DEFAULTS "")
-
- 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)
-
- 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)
+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)
+
+ # 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()
- # 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)
-
- 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)
+ idf_build_set_property(__MCONF ${MCONF})
+ idf_build_set_property(__MENUCONFIG_DEPENDS "${menuconfig_depends}")
-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)
+ 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()
- foreach(component ${components})
- list(FIND BUILD_COMPONENTS ${component} idx)
- list(GET BUILD_COMPONENT_PATHS ${idx} component_path)
- list(APPEND component_paths ${component_path})
- endforeach()
+#
+# 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()
- # 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
${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()
# 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()
\ No newline at end of file
# 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})
-# 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
-# the original project(). See https://cmake.org/pipermail/cmake/2015-October/061751.html.
-function(project)
-endfunction()
+# 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()
-function(_project)
+# 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()
-macro(project name)
+#
+# 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()
- # Bridge existing documented variable names with library namespaced
- # variables in order for old projects to work.
+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})
- get_filename_component(component_dir ${component_dir} ABSOLUTE BASE_DIR ${CMAKE_SOURCE_DIR})
- list(APPEND IDF_COMPONENT_DIRS "${component_dir}")
+ __project_component_dir(${component_dir})
endforeach()
- endif()
+ 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()
- if(EXTRA_COMPONENT_DIRS)
- spaces2list(EXTRA_COMPONENT_DIRS)
+ __project_component_dir("${CMAKE_CURRENT_LIST_DIR}/components")
+ 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}")
+ __project_component_dir("${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)
+ 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()
- if(TEST_COMPONENTS)
- set(IDF_TEST_COMPONENTS "${TEST_COMPONENTS}")
- endif()
+ set(${components_var} "${components}" PARENT_SCOPE)
+ set(${test_components_var} "${test_components}" PARENT_SCOPE)
+endfunction()
- if(TEST_EXCLUDE_COMPONENTS)
- set(IDF_TEST_EXCLUDE_COMPONENTS "${TEST_EXCLUDE_COMPONENTS}")
- endif()
+# 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
+# the original project(). See https://cmake.org/pipermail/cmake/2015-October/061751.html.
+function(project)
+endfunction()
- 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()
+function(_project)
+endfunction()
- # Set build variables
- idf_set_variables()
+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)
- # 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)
endif()
endif()
- __project(${name} C CXX ASM)
+ # The actual call to project()
+ __project(${project_name} C CXX ASM)
+
+ # 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.
+ function(project)
+ set(project_ARGV ARGV)
+ __project(${${project_ARGV}})
+ endfunction()
+
+ # 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()
- set(IDF_BUILD_ARTIFACTS ON)
- set(IDF_PROJECT_EXECUTABLE ${CMAKE_PROJECT_NAME}.elf)
- set(IDF_BUILD_ARTIFACTS_DIR ${CMAKE_BINARY_DIR})
+ 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(MAIN_SRCS)
- spaces2list(MAIN_SRCS)
- add_executable(${IDF_PROJECT_EXECUTABLE} ${MAIN_SRCS})
+ 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()
- # 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)
+ set(build_dir ${CMAKE_BINARY_DIR})
+ endif()
- add_custom_target(dummy_main_src DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/dummy_main_src.c)
+ __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()
- add_dependencies(${IDF_PROJECT_EXECUTABLE} dummy_main_src)
+ 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()
- set(mapfile "${CMAKE_PROJECT_NAME}.map")
+ 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})
- target_link_libraries(${IDF_PROJECT_EXECUTABLE} "-Wl,--cref -Wl,--Map=${mapfile}")
+ 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
- "${CMAKE_CURRENT_BINARY_DIR}/${mapfile}")
+ "${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 ${exe_target}
- COMMAND ${PYTHON} ${IDF_PATH}/tools/idf_size.py ${mapfile}
+ DEPENDS ${project_elf}
+ 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}
+ DEPENDS ${project_elf}
+ 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}
+ DEPENDS ${project_elf}
+ COMMAND ${python} ${idf_path}/tools/idf_size.py --archives ${mapfile}
)
- # Since components can import third-party libraries, the original definition of project() should be restored
- # before the call to add components to the build.
- function(project)
- set(project_ARGV ARGV)
- __project(${${project_ARGV}})
- endfunction()
+ idf_build_executable(${project_elf})
- # 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}")
+ __project_info("${test_components}")
endmacro()
{
- "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}",
--- /dev/null
+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)
+++ /dev/null
-# 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")
-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})
# 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()
"checked ${toolchain_file_global} and ${toolchain_file_component}")
endif()
endif()
-endmacro()
+endmacro()
\ No newline at end of file
# 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}")
# 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)
+ get_target_property(type ${target} TYPE)
+ if(type STREQUAL "INTERFACE_LIBRARY")
+ set(is_interface "INTERFACE")
+ endif()
+
+ 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}" "-L ${search_dir}")
+ target_link_libraries("${target}" "${is_interface}" "-L ${search_dir}")
endif()
- target_link_libraries("${target}" "-T ${scriptname}")
+ 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()
# 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}")
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()
#
""")
+ configs_list = list()
+
def write_node(node):
sym = node.item
if not isinstance(sym, kconfiglib.Symbol):
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')