idf_functions.cmake 12 KB

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