idf_functions.cmake 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. #
  2. # Load cmake modules
  3. #
  4. get_property(__idf_environment_set GLOBAL PROPERTY __IDF_ENVIRONMENT_SET)
  5. if(NOT __idf_environment_set)
  6. # Set IDF_PATH, as nothing else will work without this.
  7. set(IDF_PATH "$ENV{IDF_PATH}")
  8. if(NOT IDF_PATH)
  9. # Documentation says you should set IDF_PATH in your environment, but we
  10. # can infer it relative to tools/cmake directory if it's not set.
  11. get_filename_component(IDF_PATH "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE)
  12. endif()
  13. file(TO_CMAKE_PATH "${IDF_PATH}" IDF_PATH)
  14. set(ENV{IDF_PATH} ${IDF_PATH})
  15. set(CMAKE_MODULE_PATH
  16. "${IDF_PATH}/tools/cmake"
  17. "${IDF_PATH}/tools/cmake/third_party"
  18. ${CMAKE_MODULE_PATH})
  19. include(utilities)
  20. include(components)
  21. include(kconfig)
  22. include(targets)
  23. include(git_submodules)
  24. include(GetGitRevisionDescription)
  25. include(crosstool_version_check)
  26. include(ldgen)
  27. set_default(PYTHON "python")
  28. if(NOT PYTHON_DEPS_CHECKED AND NOT BOOTLOADER_BUILD)
  29. message(STATUS "Checking Python dependencies...")
  30. execute_process(COMMAND "${PYTHON}" "${IDF_PATH}/tools/check_python_dependencies.py"
  31. RESULT_VARIABLE result)
  32. if(NOT result EQUAL 0)
  33. message(FATAL_ERROR "Some Python dependencies must be installed. Check above message for details.")
  34. endif()
  35. endif()
  36. idf_set_target()
  37. set_property(GLOBAL APPEND PROPERTY __IDF_COMPONENTS_PREFIX "idf_component")
  38. set_property(GLOBAL PROPERTY __IDF_ENVIRONMENT_SET 1)
  39. endif()
  40. macro(idf_set_variables)
  41. set_default(IDF_BUILD_ARTIFACTS OFF)
  42. if(IDF_BUILD_ARTIFACTS)
  43. if(NOT IDF_BUILD_ARTIFACTS_DIR OR NOT IDF_PROJECT_EXECUTABLE)
  44. message(FATAL_ERROR "IDF_BUILD_ARTIFACTS and IDF_PROJECT_EXECUTABLE needs to be specified \
  45. if IDF_BUILD_ARTIFACTS is ON.")
  46. endif()
  47. endif()
  48. set_default(IDF_COMPONENT_DIRS "${IDF_EXTRA_COMPONENT_DIRS} ${IDF_PATH}/components")
  49. set_default(IDF_COMPONENTS "")
  50. set_default(IDF_COMPONENT_REQUIRES_COMMON "cxx ${IDF_TARGET} newlib freertos heap log soc")
  51. set(IDF_PROJECT_PATH "${CMAKE_SOURCE_DIR}")
  52. set(ESP_PLATFORM 1 CACHE BOOL INTERNAL)
  53. spaces2list(IDF_COMPONENT_DIRS)
  54. spaces2list(IDF_COMPONENTS)
  55. spaces2list(IDF_COMPONENT_REQUIRES_COMMON)
  56. endmacro()
  57. # Add all the IDF global compiler & preprocessor options
  58. # (applied to all components). Some are config-dependent
  59. #
  60. # If you only want to set options for a particular component,
  61. # don't call or edit this function. TODO DESCRIBE WHAT TO DO INSTEAD
  62. #
  63. function(idf_set_global_compile_options)
  64. # Temporary trick to support both gcc5 and gcc8 builds
  65. if(CMAKE_C_COMPILER_VERSION VERSION_EQUAL 5.2.0)
  66. set(GCC_NOT_5_2_0 0 CACHE STRING "GCC is 5.2.0 version")
  67. else()
  68. set(GCC_NOT_5_2_0 1 CACHE STRING "GCC is not 5.2.0 version")
  69. endif()
  70. list(APPEND compile_definitions "GCC_NOT_5_2_0=${GCC_NOT_5_2_0}")
  71. list(APPEND compile_definitions "ESP_PLATFORM" "HAVE_CONFIG_H")
  72. list(APPEND compile_options "${CMAKE_C_FLAGS}")
  73. list(APPEND c_compile_options "${CMAKE_C_FLAGS}")
  74. list(APPEND cxx_compile_options "${CMAKE_CXX_FLAGS}")
  75. if(CONFIG_OPTIMIZATION_LEVEL_RELEASE)
  76. list(APPEND compile_options "-Os")
  77. else()
  78. list(APPEND compile_options "-Og")
  79. endif()
  80. list(APPEND c_compile_options "-std=gnu99")
  81. list(APPEND cxx_compile_options "-std=gnu++11" "-fno-rtti")
  82. if(CONFIG_CXX_EXCEPTIONS)
  83. list(APPEND cxx_compile_options "-fexceptions")
  84. else()
  85. list(APPEND cxx_compile_options "-fno-exceptions")
  86. endif()
  87. # Default compiler configuration
  88. list(APPEND compile_options "-ffunction-sections"
  89. "-fdata-sections"
  90. "-fstrict-volatile-bitfields"
  91. "-nostdlib")
  92. list(APPEND compile_options "-Wall"
  93. "-Werror=all"
  94. "-Wno-error=unused-function"
  95. "-Wno-error=unused-but-set-variable"
  96. "-Wno-error=unused-variable"
  97. "-Wno-error=deprecated-declarations"
  98. "-Wextra"
  99. "-Wno-unused-parameter"
  100. "-Wno-sign-compare")
  101. list(APPEND c_compile_options "-Wno-old-style-declaration")
  102. if(CONFIG_DISABLE_GCC8_WARNINGS)
  103. list(APPEND compile_options
  104. "-Wno-parentheses"
  105. "-Wno-sizeof-pointer-memaccess"
  106. "-Wno-clobbered"
  107. )
  108. # doesn't use GCC_NOT_5_2_0 because idf_set_global_variables was not called before
  109. if(NOT CMAKE_C_COMPILER_VERSION VERSION_EQUAL 5.2.0)
  110. list(APPEND compile_options
  111. "-Wno-format-overflow"
  112. "-Wno-stringop-truncation"
  113. "-Wno-misleading-indentation"
  114. "-Wno-cast-function-type"
  115. "-Wno-implicit-fallthrough"
  116. "-Wno-unused-const-variable"
  117. "-Wno-switch-unreachable"
  118. "-Wno-format-truncation"
  119. "-Wno-memset-elt-size"
  120. "-Wno-int-in-bool-context"
  121. )
  122. endif()
  123. endif()
  124. # Stack protection
  125. if(NOT BOOTLOADER_BUILD)
  126. if(CONFIG_STACK_CHECK_NORM)
  127. list(APPEND compile_options "-fstack-protector")
  128. elseif(CONFIG_STACK_CHECK_STRONG)
  129. list(APPEND compile_options "-fstack-protector-strong")
  130. elseif(CONFIG_STACK_CHECK_ALL)
  131. list(APPEND compile_options "-fstack-protector-all")
  132. endif()
  133. endif()
  134. if(CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED)
  135. list(APPEND compile_definitions "NDEBUG")
  136. endif()
  137. # Always generate debug symbols (even in Release mode, these don't
  138. # go into the final binary so have no impact on size)
  139. list(APPEND compile_options "-ggdb")
  140. # Use EXTRA_CFLAGS, EXTRA_CXXFLAGS and EXTRA_CPPFLAGS to add more priority options to the compiler
  141. # EXTRA_CPPFLAGS is used for both C and C++
  142. # Unlike environments' CFLAGS/CXXFLAGS/CPPFLAGS which work for both host and target build,
  143. # these works only for target build
  144. set(EXTRA_CFLAGS "$ENV{EXTRA_CFLAGS}")
  145. set(EXTRA_CXXFLAGS "$ENV{EXTRA_CXXFLAGS}")
  146. set(EXTRA_CPPFLAGS "$ENV{EXTRA_CPPFLAGS}")
  147. spaces2list(EXTRA_CFLAGS)
  148. spaces2list(EXTRA_CXXFLAGS)
  149. spaces2list(EXTRA_CPPFLAGS)
  150. list(APPEND c_compile_options ${EXTRA_CFLAGS})
  151. list(APPEND cxx_compile_options ${EXTRA_CXXFLAGS})
  152. list(APPEND compile_options ${EXTRA_CPPFLAGS})
  153. set_default(IDF_COMPILE_DEFINITIONS "${compile_definitions}")
  154. set_default(IDF_COMPILE_OPTIONS "${compile_options}")
  155. set_default(IDF_C_COMPILE_OPTIONS "${c_compile_options}")
  156. set_default(IDF_CXX_COMPILE_OPTIONS "${cxx_compile_options}")
  157. set_default(IDF_INCLUDE_DIRECTORIES "${CONFIG_DIR}")
  158. set(IDF_COMPILE_DEFINITIONS ${IDF_COMPILE_DEFINITIONS} PARENT_SCOPE)
  159. set(IDF_COMPILE_OPTIONS ${IDF_COMPILE_OPTIONS} PARENT_SCOPE)
  160. set(IDF_C_COMPILE_OPTIONS ${IDF_C_COMPILE_OPTIONS} PARENT_SCOPE)
  161. set(IDF_CXX_COMPILE_OPTIONS ${IDF_CXX_COMPILE_OPTIONS} PARENT_SCOPE)
  162. set(IDF_INCLUDE_DIRECTORIES ${CONFIG_DIR} PARENT_SCOPE)
  163. endfunction()
  164. # Verify the IDF environment is configured correctly (environment, toolchain, etc)
  165. function(idf_verify_environment)
  166. if(NOT CMAKE_PROJECT_NAME)
  167. message(FATAL_ERROR "Internal error, IDF project.cmake should have set this variable already")
  168. endif()
  169. # Check toolchain is configured properly in cmake
  170. if(NOT ( ${CMAKE_SYSTEM_NAME} STREQUAL "Generic" AND ${CMAKE_C_COMPILER} MATCHES xtensa))
  171. message(FATAL_ERROR "Internal error, toolchain has not been set correctly by project "
  172. "(or an invalid CMakeCache.txt file has been generated somehow)")
  173. endif()
  174. #
  175. # Warn if the toolchain version doesn't match
  176. #
  177. # TODO: make these platform-specific for diff toolchains
  178. get_expected_ctng_version(expected_toolchain expected_gcc)
  179. gcc_version_check("${expected_gcc}")
  180. crosstool_version_check("${expected_toolchain}")
  181. endfunction()
  182. # idf_get_git_revision
  183. #
  184. # Set global IDF_VER to the git revision of ESP-IDF.
  185. #
  186. # Running git_describe() here automatically triggers rebuilds
  187. # if the ESP-IDF git version changes
  188. function(idf_get_git_revision)
  189. git_describe(IDF_VER_GIT "${IDF_PATH}")
  190. if(EXISTS "${IDF_PATH}/version.txt")
  191. file(STRINGS "${IDF_PATH}/version.txt" IDF_VER)
  192. set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${IDF_PATH}/version.txt")
  193. else()
  194. set(IDF_VER ${IDF_VER_GIT})
  195. endif()
  196. message(STATUS "IDF_VER: ${IDF_VER}")
  197. add_definitions(-DIDF_VER=\"${IDF_VER}\")
  198. git_submodule_check("${IDF_PATH}")
  199. set(IDF_VER ${IDF_VER} PARENT_SCOPE)
  200. endfunction()
  201. # app_get_revision
  202. #
  203. # Set global PROJECT_VER
  204. #
  205. # If PROJECT_VER variable set in project CMakeLists.txt file, its value will be used.
  206. # Else, if the _project_path/version.txt exists, its contents will be used as PROJECT_VER.
  207. # Else, if the project is located inside a Git repository, the output of git describe will be used.
  208. # Otherwise, PROJECT_VER will be "1".
  209. function(app_get_revision _project_path)
  210. if(NOT DEFINED PROJECT_VER)
  211. if(EXISTS "${_project_path}/version.txt")
  212. file(STRINGS "${_project_path}/version.txt" PROJECT_VER)
  213. set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${_project_path}/version.txt")
  214. else()
  215. git_describe(PROJECT_VER_GIT "${_project_path}")
  216. if(PROJECT_VER_GIT)
  217. set(PROJECT_VER ${PROJECT_VER_GIT})
  218. else()
  219. message(STATUS "Project is not inside a git repository, \
  220. will not use 'git describe' to determine PROJECT_VER.")
  221. set(PROJECT_VER "1")
  222. endif()
  223. endif()
  224. endif()
  225. message(STATUS "Project version: ${PROJECT_VER}")
  226. set(PROJECT_VER ${PROJECT_VER} PARENT_SCOPE)
  227. endfunction()
  228. # idf_link_components
  229. #
  230. # Link library components to the target
  231. function(idf_link_components target components)
  232. foreach(component ${components})
  233. component_get_target(component_target ${component})
  234. # Add each component library's link-time dependencies (which are otherwise ignored) to the executable
  235. # LINK_DEPENDS in order to trigger a re-link when needed (on Ninja/Makefile generators at least).
  236. # (maybe this should probably be something CMake does, but it doesn't do it...)
  237. if(TARGET ${component_target})
  238. get_target_property(type ${component_target} TYPE)
  239. get_target_property(imported ${component_target} IMPORTED)
  240. if(NOT imported)
  241. if(${type} STREQUAL STATIC_LIBRARY OR ${type} STREQUAL EXECUTABLE)
  242. get_target_property(link_depends "${component_target}" LINK_DEPENDS)
  243. if(link_depends)
  244. set_property(TARGET ${target} APPEND PROPERTY LINK_DEPENDS "${link_depends}")
  245. endif()
  246. endif()
  247. endif()
  248. if(${type} MATCHES .+_LIBRARY)
  249. list(APPEND libraries ${component_target})
  250. endif()
  251. endif()
  252. endforeach()
  253. if(libraries)
  254. # gc-sections is necessary for linking some IDF binary libraries
  255. # (and without it, IDF apps are much larger than they should be)
  256. target_link_libraries(${target} "-Wl,--gc-sections")
  257. target_link_libraries(${target} "-Wl,--start-group")
  258. target_link_libraries(${target} ${libraries})
  259. message(STATUS "Component libraries: ${IDF_COMPONENT_LIBRARIES}")
  260. endif()
  261. endfunction()
  262. # idf_import_components
  263. #
  264. # Adds ESP-IDF as a subdirectory to the current project and imports the components
  265. function(idf_import_components var idf_path build_path)
  266. add_subdirectory(${idf_path} ${build_path})
  267. set(${var} ${BUILD_COMPONENTS} PARENT_SCOPE)
  268. endfunction()