420 lines
16 KiB
CMake
420 lines
16 KiB
CMake
#
|
|
# 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 soc")
|
|
|
|
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")
|
|
|
|
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")
|
|
|
|
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
|
|
macro(idf_import_components var idf_path build_path)
|
|
#
|
|
# Set variables that control the build configuration and the build itself
|
|
#
|
|
idf_set_variables()
|
|
|
|
kconfig_set_variables()
|
|
|
|
#
|
|
# Generate a component dependencies file, enumerating components to be included in the build
|
|
# as well as their dependencies.
|
|
#
|
|
execute_process(COMMAND "${CMAKE_COMMAND}"
|
|
-D "COMPONENTS=${IDF_COMPONENTS}"
|
|
-D "COMPONENT_REQUIRES_COMMON=${IDF_COMPONENT_REQUIRES_COMMON}"
|
|
-D "EXCLUDE_COMPONENTS=${IDF_EXCLUDE_COMPONENTS}"
|
|
-D "TEST_COMPONENTS=${IDF_TEST_COMPONENTS}"
|
|
-D "TEST_EXCLUDE_COMPONENTS=${IDF_TEST_EXCLUDE_COMPONENTS}"
|
|
-D "BUILD_TESTS=${IDF_BUILD_TESTS}"
|
|
-D "DEPENDENCIES_FILE=${CMAKE_BINARY_DIR}/component_depends.cmake"
|
|
-D "COMPONENT_DIRS=${IDF_COMPONENT_DIRS}"
|
|
-D "BOOTLOADER_BUILD=${BOOTLOADER_BUILD}"
|
|
-D "IDF_TARGET=${IDF_TARGET}"
|
|
-D "IDF_PATH=${IDF_PATH}"
|
|
-D "DEBUG=${DEBUG}"
|
|
-P "${IDF_PATH}/tools/cmake/scripts/expand_requirements.cmake"
|
|
WORKING_DIRECTORY "${PROJECT_PATH}"
|
|
RESULT_VARIABLE expand_requirements_result)
|
|
|
|
if(expand_requirements_result)
|
|
message(FATAL_ERROR "Failed to expand component requirements")
|
|
endif()
|
|
|
|
include("${CMAKE_BINARY_DIR}/component_depends.cmake")
|
|
|
|
#
|
|
# We now have the following component-related variables:
|
|
#
|
|
# IDF_COMPONENTS is the list of initial components set by the user
|
|
# (or empty to include all components in the build).
|
|
# BUILD_COMPONENTS is the list of components to include in the build.
|
|
# BUILD_COMPONENT_PATHS is the paths to all of these components, obtained from the component dependencies file.
|
|
#
|
|
# Print the list of found components and test components
|
|
#
|
|
string(REPLACE ";" " " BUILD_COMPONENTS_SPACES "${BUILD_COMPONENTS}")
|
|
message(STATUS "Component names: ${BUILD_COMPONENTS_SPACES}")
|
|
unset(BUILD_COMPONENTS_SPACES)
|
|
message(STATUS "Component paths: ${BUILD_COMPONENT_PATHS}")
|
|
|
|
# Print list of test components
|
|
if(TESTS_ALL EQUAL 1 OR TEST_COMPONENTS)
|
|
string(REPLACE ";" " " BUILD_TEST_COMPONENTS_SPACES "${BUILD_TEST_COMPONENTS}")
|
|
message(STATUS "Test component names: ${BUILD_TEST_COMPONENTS_SPACES}")
|
|
unset(BUILD_TEST_COMPONENTS_SPACES)
|
|
message(STATUS "Test component paths: ${BUILD_TEST_COMPONENT_PATHS}")
|
|
endif()
|
|
|
|
# Generate project configuration
|
|
kconfig_process_config()
|
|
|
|
# Include sdkconfig.cmake so rest of the build knows the configuration
|
|
include(${SDKCONFIG_CMAKE})
|
|
|
|
# Verify the environment is configured correctly
|
|
idf_verify_environment()
|
|
|
|
# Check git revision (may trigger reruns of cmake)
|
|
## sets IDF_VER to IDF git revision
|
|
idf_get_git_revision()
|
|
|
|
# Check that the targets set in cache, sdkconfig, and in environment all match
|
|
idf_check_config_target()
|
|
|
|
## get PROJECT_VER
|
|
if(NOT BOOTLOADER_BUILD)
|
|
app_get_revision("${CMAKE_SOURCE_DIR}")
|
|
endif()
|
|
|
|
# Add some idf-wide definitions
|
|
idf_set_global_compile_options()
|
|
|
|
# generate compile_commands.json (needs to come after project)
|
|
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
|
|
|
|
#
|
|
# Setup variables for linker script generation
|
|
#
|
|
ldgen_set_variables()
|
|
|
|
# Include any top-level project_include.cmake files from components
|
|
foreach(component ${BUILD_COMPONENT_PATHS})
|
|
set(COMPONENT_PATH "${component}")
|
|
include_if_exists("${component}/project_include.cmake")
|
|
unset(COMPONENT_PATH)
|
|
endforeach()
|
|
|
|
add_subdirectory(${idf_path} ${build_path})
|
|
|
|
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()
|
|
|
|
ldgen_add_dependencies()
|
|
|
|
set(${var} ${BUILD_COMPONENTS})
|
|
endmacro()
|