component.cmake 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  1. #
  2. # Internal function for retrieving component properties from a component target.
  3. #
  4. function(__component_get_property var component_target property)
  5. get_property(val TARGET ${component_target} PROPERTY ${property})
  6. set(${var} "${val}" PARENT_SCOPE)
  7. endfunction()
  8. #
  9. # Internal function for setting component properties on a component target. As with build properties,
  10. # set properties are also keeped track of.
  11. #
  12. function(__component_set_property component_target property val)
  13. cmake_parse_arguments(_ "APPEND" "" "" ${ARGN})
  14. if(__APPEND)
  15. set_property(TARGET ${component_target} APPEND PROPERTY ${property} "${val}")
  16. else()
  17. set_property(TARGET ${component_target} PROPERTY ${property} "${val}")
  18. endif()
  19. # Keep track of set component properties
  20. __component_get_property(properties ${component_target} __COMPONENT_PROPERTIES)
  21. if(NOT property IN_LIST properties)
  22. __component_set_property(${component_target} __COMPONENT_PROPERTIES ${property} APPEND)
  23. endif()
  24. endfunction()
  25. #
  26. # Given a component name or alias, get the corresponding component target.
  27. #
  28. function(__component_get_target var name_or_alias)
  29. # Look at previously resolved names or aliases
  30. idf_build_get_property(component_names_resolved __COMPONENT_NAMES_RESOLVED)
  31. list(FIND component_names_resolved ${name_or_alias} result)
  32. if(NOT result EQUAL -1)
  33. # If it has been resolved before, return that value. The index is the same
  34. # as in __COMPONENT_NAMES_RESOLVED as these are parallel lists.
  35. idf_build_get_property(component_targets_resolved __COMPONENT_TARGETS_RESOLVED)
  36. list(GET component_targets_resolved ${result} target)
  37. set(${var} ${target} PARENT_SCOPE)
  38. return()
  39. endif()
  40. idf_build_get_property(component_targets __COMPONENT_TARGETS)
  41. # Assume first that the paramters is an alias.
  42. string(REPLACE "::" "_" name_or_alias "${name_or_alias}")
  43. set(component_target ___${name_or_alias})
  44. if(component_target IN_LIST component_targets)
  45. set(${var} ${component_target} PARENT_SCOPE)
  46. set(target ${component_target})
  47. else() # assumption is wrong, try to look for it manually
  48. unset(target)
  49. foreach(component_target ${component_targets})
  50. __component_get_property(_component_name ${component_target} COMPONENT_NAME)
  51. if(name_or_alias STREQUAL _component_name)
  52. set(target ${component_target})
  53. break()
  54. endif()
  55. endforeach()
  56. set(${var} ${target} PARENT_SCOPE)
  57. endif()
  58. # Save the resolved name or alias
  59. if(target)
  60. idf_build_set_property(__COMPONENT_NAMES_RESOLVED ${name_or_alias} APPEND)
  61. idf_build_set_property(__COMPONENT_TARGETS_RESOLVED ${target} APPEND)
  62. endif()
  63. endfunction()
  64. #
  65. # Called during component registration, sets basic properties of the current component.
  66. #
  67. macro(__component_set_properties)
  68. __component_get_property(type ${component_target} COMPONENT_TYPE)
  69. # Fill in the rest of component property
  70. __component_set_property(${component_target} SRCS "${sources}")
  71. __component_set_property(${component_target} INCLUDE_DIRS "${__INCLUDE_DIRS}")
  72. if(type STREQUAL LIBRARY)
  73. __component_set_property(${component_target} PRIV_INCLUDE_DIRS "${__PRIV_INCLUDE_DIRS}")
  74. endif()
  75. __component_set_property(${component_target} LDFRAGMENTS "${__LDFRAGMENTS}")
  76. __component_set_property(${component_target} EMBED_FILES "${__EMBED_FILES}")
  77. __component_set_property(${component_target} EMBED_TXTFILES "${__EMBED_TXTFILES}")
  78. __component_set_property(${component_target} REQUIRED_IDF_TARGETS "${__REQUIRED_IDF_TARGETS}")
  79. __component_set_property(${component_target} WHOLE_ARCHIVE ${__WHOLE_ARCHIVE})
  80. endmacro()
  81. #
  82. # Perform a quick check if given component dir satisfies basic requirements.
  83. #
  84. function(__component_dir_quick_check var component_dir)
  85. set(res 1)
  86. get_filename_component(abs_dir ${component_dir} ABSOLUTE)
  87. get_filename_component(base_dir ${abs_dir} NAME)
  88. string(SUBSTRING "${base_dir}" 0 1 first_char)
  89. # Check the component directory contains a CMakeLists.txt file
  90. # - warn and skip anything which isn't valid looking (probably cruft)
  91. if(NOT first_char STREQUAL ".")
  92. if(NOT EXISTS "${abs_dir}/CMakeLists.txt")
  93. message(STATUS "Component directory ${abs_dir} does not contain a CMakeLists.txt file. "
  94. "No component will be added")
  95. set(res 0)
  96. endif()
  97. else()
  98. set(res 0) # quietly ignore dot-folders
  99. endif()
  100. set(${var} ${res} PARENT_SCOPE)
  101. endfunction()
  102. #
  103. # Write a CMake file containing all component and their properties. This is possible because each component
  104. # keeps a list of all its properties.
  105. #
  106. function(__component_write_properties output_file)
  107. idf_build_get_property(component_targets __COMPONENT_TARGETS)
  108. foreach(component_target ${component_targets})
  109. __component_get_property(component_properties ${component_target} __COMPONENT_PROPERTIES)
  110. foreach(property ${component_properties})
  111. __component_get_property(val ${component_target} ${property})
  112. set(component_properties_text
  113. "${component_properties_text}\nset(__component_${component_target}_${property} \"${val}\")")
  114. endforeach()
  115. file(WRITE ${output_file} "${component_properties_text}")
  116. endforeach()
  117. endfunction()
  118. #
  119. # Add a component to process in the build. The components are keeped tracked of in property
  120. # __COMPONENT_TARGETS in component target form.
  121. #
  122. function(__component_add component_dir prefix)
  123. # For each component, two entities are created: a component target and a component library. The
  124. # component library is created during component registration (the actual static/interface library).
  125. # On the other hand, component targets are created early in the build
  126. # (during adding component as this function suggests).
  127. # This is so that we still have a target to attach properties to up until the component registration.
  128. # Plus, interface libraries have limitations on the types of properties that can be set on them,
  129. # so later in the build, these component targets actually contain the properties meant for the
  130. # corresponding component library.
  131. idf_build_get_property(component_targets __COMPONENT_TARGETS)
  132. get_filename_component(abs_dir ${component_dir} ABSOLUTE)
  133. get_filename_component(base_dir ${abs_dir} NAME)
  134. if(NOT EXISTS "${abs_dir}/CMakeLists.txt")
  135. message(FATAL_ERROR "Directory '${component_dir}' does not contain a component.")
  136. endif()
  137. set(component_name ${base_dir})
  138. # The component target has three underscores as a prefix. The corresponding component library
  139. # only has two.
  140. set(component_target ___${prefix}_${component_name})
  141. # If a component of the same name has not been added before If it has been added
  142. # before just override the properties. As a side effect, components added later
  143. # 'override' components added earlier.
  144. if(NOT component_target IN_LIST component_targets)
  145. if(NOT TARGET ${component_target})
  146. add_library(${component_target} STATIC IMPORTED)
  147. endif()
  148. idf_build_set_property(__COMPONENT_TARGETS ${component_target} APPEND)
  149. else()
  150. __component_get_property(dir ${component_target} COMPONENT_DIR)
  151. __component_set_property(${component_target} COMPONENT_OVERRIDEN_DIR ${dir})
  152. endif()
  153. set(component_lib __${prefix}_${component_name})
  154. set(component_dir ${abs_dir})
  155. set(component_alias ${prefix}::${component_name}) # The 'alias' of the component library,
  156. # used to refer to the component outside
  157. # the build system. Users can use this name
  158. # to resolve ambiguity with component names
  159. # and to link IDF components to external targets.
  160. # Set the basic properties of the component
  161. __component_set_property(${component_target} COMPONENT_LIB ${component_lib})
  162. __component_set_property(${component_target} COMPONENT_NAME ${component_name})
  163. __component_set_property(${component_target} COMPONENT_DIR ${component_dir})
  164. __component_set_property(${component_target} COMPONENT_ALIAS ${component_alias})
  165. __component_set_property(${component_target} __PREFIX ${prefix})
  166. # Set Kconfig related properties on the component
  167. __kconfig_component_init(${component_target})
  168. # set BUILD_COMPONENT_DIRS build property
  169. idf_build_set_property(BUILD_COMPONENT_DIRS ${component_dir} APPEND)
  170. endfunction()
  171. #
  172. # Given a component directory, get the requirements by expanding it early. The expansion is performed
  173. # using a separate CMake script (the expansion is performed in a separate instance of CMake in scripting mode).
  174. #
  175. function(__component_get_requirements)
  176. idf_build_get_property(idf_path IDF_PATH)
  177. idf_build_get_property(build_dir BUILD_DIR)
  178. set(build_properties_file ${build_dir}/build_properties.temp.cmake)
  179. set(component_properties_file ${build_dir}/component_properties.temp.cmake)
  180. set(component_requires_file ${build_dir}/component_requires.temp.cmake)
  181. __build_write_properties(${build_properties_file})
  182. __component_write_properties(${component_properties_file})
  183. execute_process(COMMAND "${CMAKE_COMMAND}"
  184. -D "ESP_PLATFORM=1"
  185. -D "BUILD_PROPERTIES_FILE=${build_properties_file}"
  186. -D "COMPONENT_PROPERTIES_FILE=${component_properties_file}"
  187. -D "COMPONENT_REQUIRES_FILE=${component_requires_file}"
  188. -P "${idf_path}/tools/cmake/scripts/component_get_requirements.cmake"
  189. RESULT_VARIABLE result
  190. ERROR_VARIABLE error)
  191. if(NOT result EQUAL 0)
  192. message(FATAL_ERROR "${error}")
  193. endif()
  194. idf_build_get_property(idf_component_manager IDF_COMPONENT_MANAGER)
  195. if(idf_component_manager EQUAL 1)
  196. idf_build_get_property(python PYTHON)
  197. idf_build_get_property(component_manager_interface_version __COMPONENT_MANAGER_INTERFACE_VERSION)
  198. # Call for the component manager once again to inject dependencies
  199. # It modifies the requirements file generated by component_get_requirements.cmake script by adding dependencies
  200. # defined in component manager manifests to REQUIRES and PRIV_REQUIRES fields.
  201. # These requirements are also set as MANAGED_REQUIRES and MANAGED_PRIV_REQUIRES component properties.
  202. execute_process(COMMAND ${python}
  203. "-m"
  204. "idf_component_manager.prepare_components"
  205. "--project_dir=${project_dir}"
  206. "--lock_path=${DEPENDENCIES_LOCK}"
  207. "--interface_version=${component_manager_interface_version}"
  208. "inject_requirements"
  209. "--idf_path=${idf_path}"
  210. "--build_dir=${build_dir}"
  211. "--component_requires_file=${component_requires_file}"
  212. RESULT_VARIABLE result
  213. ERROR_VARIABLE error)
  214. if(NOT result EQUAL 0)
  215. message(FATAL_ERROR "${error}")
  216. endif()
  217. endif()
  218. include(${component_requires_file})
  219. file(REMOVE ${build_properties_file})
  220. file(REMOVE ${component_properties_file})
  221. file(REMOVE ${component_requires_file})
  222. endfunction()
  223. # __component_add_sources, __component_check_target, __component_add_include_dirs
  224. #
  225. # Utility macros for component registration. Adds source files and checks target requirements,
  226. # and adds include directories respectively.
  227. macro(__component_add_sources sources)
  228. set(sources "")
  229. if(__SRCS)
  230. if(__SRC_DIRS)
  231. message(WARNING "SRCS and SRC_DIRS are both specified; ignoring SRC_DIRS.")
  232. endif()
  233. foreach(src ${__SRCS})
  234. get_filename_component(src "${src}" ABSOLUTE BASE_DIR ${COMPONENT_DIR})
  235. list(APPEND sources ${src})
  236. endforeach()
  237. else()
  238. if(__SRC_DIRS)
  239. foreach(dir ${__SRC_DIRS})
  240. get_filename_component(abs_dir ${dir} ABSOLUTE BASE_DIR ${COMPONENT_DIR})
  241. if(NOT IS_DIRECTORY ${abs_dir})
  242. message(FATAL_ERROR "SRC_DIRS entry '${dir}' does not exist.")
  243. endif()
  244. file(GLOB dir_sources "${abs_dir}/*.c" "${abs_dir}/*.cpp" "${abs_dir}/*.S")
  245. list(SORT dir_sources)
  246. if(dir_sources)
  247. foreach(src ${dir_sources})
  248. get_filename_component(src "${src}" ABSOLUTE BASE_DIR ${COMPONENT_DIR})
  249. list(APPEND sources "${src}")
  250. endforeach()
  251. else()
  252. message(WARNING "No source files found for SRC_DIRS entry '${dir}'.")
  253. endif()
  254. endforeach()
  255. endif()
  256. if(__EXCLUDE_SRCS)
  257. foreach(src ${__EXCLUDE_SRCS})
  258. get_filename_component(src "${src}" ABSOLUTE)
  259. list(REMOVE_ITEM sources "${src}")
  260. endforeach()
  261. endif()
  262. endif()
  263. list(REMOVE_DUPLICATES sources)
  264. endmacro()
  265. macro(__component_add_include_dirs lib dirs type)
  266. foreach(dir ${dirs})
  267. get_filename_component(_dir ${dir} ABSOLUTE BASE_DIR ${CMAKE_CURRENT_LIST_DIR})
  268. if(NOT IS_DIRECTORY ${_dir})
  269. message(FATAL_ERROR "Include directory '${_dir}' is not a directory.")
  270. endif()
  271. target_include_directories(${lib} ${type} ${_dir})
  272. endforeach()
  273. endmacro()
  274. macro(__component_check_target)
  275. if(__REQUIRED_IDF_TARGETS)
  276. idf_build_get_property(idf_target IDF_TARGET)
  277. if(NOT idf_target IN_LIST __REQUIRED_IDF_TARGETS)
  278. message(FATAL_ERROR "Component ${COMPONENT_NAME} only supports targets: ${__REQUIRED_IDF_TARGETS}")
  279. endif()
  280. endif()
  281. endmacro()
  282. # __component_set_dependencies, __component_set_all_dependencies
  283. #
  284. # Links public and private requirements for the currently processed component
  285. macro(__component_set_dependencies reqs type)
  286. foreach(req ${reqs})
  287. if(req IN_LIST build_component_targets)
  288. __component_get_property(req_lib ${req} COMPONENT_LIB)
  289. if("${type}" STREQUAL "PRIVATE")
  290. set_property(TARGET ${component_lib} APPEND PROPERTY LINK_LIBRARIES ${req_lib})
  291. set_property(TARGET ${component_lib} APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<LINK_ONLY:${req_lib}>)
  292. elseif("${type}" STREQUAL "PUBLIC")
  293. set_property(TARGET ${component_lib} APPEND PROPERTY LINK_LIBRARIES ${req_lib})
  294. set_property(TARGET ${component_lib} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${req_lib})
  295. else() # INTERFACE
  296. set_property(TARGET ${component_lib} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${req_lib})
  297. endif()
  298. endif()
  299. endforeach()
  300. endmacro()
  301. macro(__component_set_all_dependencies)
  302. __component_get_property(type ${component_target} COMPONENT_TYPE)
  303. idf_build_get_property(build_component_targets __BUILD_COMPONENT_TARGETS)
  304. if(NOT type STREQUAL CONFIG_ONLY)
  305. __component_get_property(reqs ${component_target} __REQUIRES)
  306. __component_set_dependencies("${reqs}" PUBLIC)
  307. __component_get_property(priv_reqs ${component_target} __PRIV_REQUIRES)
  308. __component_set_dependencies("${priv_reqs}" PRIVATE)
  309. else()
  310. __component_get_property(reqs ${component_target} __REQUIRES)
  311. __component_set_dependencies("${reqs}" INTERFACE)
  312. endif()
  313. endmacro()
  314. # idf_component_get_property
  315. #
  316. # @brief Retrieve the value of the specified component property
  317. #
  318. # @param[out] var the variable to store the value of the property in
  319. # @param[in] component the component name or alias to get the value of the property of
  320. # @param[in] property the property to get the value of
  321. #
  322. # @param[in, optional] GENERATOR_EXPRESSION (option) retrieve the generator expression for the property
  323. # instead of actual value
  324. function(idf_component_get_property var component property)
  325. cmake_parse_arguments(_ "GENERATOR_EXPRESSION" "" "" ${ARGN})
  326. __component_get_target(component_target ${component})
  327. if(__GENERATOR_EXPRESSION)
  328. set(val "$<TARGET_PROPERTY:${component_target},${property}>")
  329. else()
  330. __component_get_property(val ${component_target} ${property})
  331. endif()
  332. set(${var} "${val}" PARENT_SCOPE)
  333. endfunction()
  334. # idf_component_set_property
  335. #
  336. # @brief Set the value of the specified component property related. The property is
  337. # also added to the internal list of component properties if it isn't there already.
  338. #
  339. # @param[in] component component name or alias of the component to set the property of
  340. # @param[in] property the property to set the value of
  341. # @param[out] value value of the property to set to
  342. #
  343. # @param[in, optional] APPEND (option) append the value to the current value of the
  344. # property instead of replacing it
  345. function(idf_component_set_property component property val)
  346. cmake_parse_arguments(_ "APPEND" "" "" ${ARGN})
  347. __component_get_target(component_target ${component})
  348. if(__APPEND)
  349. __component_set_property(${component_target} ${property} "${val}" APPEND)
  350. else()
  351. __component_set_property(${component_target} ${property} "${val}")
  352. endif()
  353. endfunction()
  354. # idf_component_register
  355. #
  356. # @brief Register a component to the build, creating component library targets etc.
  357. #
  358. # @param[in, optional] SRCS (multivalue) list of source files for the component
  359. # @param[in, optional] SRC_DIRS (multivalue) list of source directories to look for source files
  360. # in (.c, .cpp. .S); ignored when SRCS is specified.
  361. # @param[in, optional] EXCLUDE_SRCS (multivalue) used to exclude source files for the specified
  362. # SRC_DIRS
  363. # @param[in, optional] INCLUDE_DIRS (multivalue) public include directories for the created component library
  364. # @param[in, optional] PRIV_INCLUDE_DIRS (multivalue) private include directories for the created component library
  365. # @param[in, optional] LDFRAGMENTS (multivalue) linker script fragments for the component
  366. # @param[in, optional] REQUIRES (multivalue) publicly required components in terms of usage requirements
  367. # @param[in, optional] PRIV_REQUIRES (multivalue) privately required components in terms of usage requirements
  368. # or components only needed for functions/values defined in its project_include.cmake
  369. # @param[in, optional] REQUIRED_IDF_TARGETS (multivalue) the list of IDF build targets that the component only supports
  370. # @param[in, optional] EMBED_FILES (multivalue) list of binary files to embed with the component
  371. # @param[in, optional] EMBED_TXTFILES (multivalue) list of text files to embed with the component
  372. # @param[in, optional] KCONFIG (single value) override the default Kconfig
  373. # @param[in, optional] KCONFIG_PROJBUILD (single value) override the default Kconfig
  374. # @param[in, optional] WHOLE_ARCHIVE (option) link the component as --whole-archive
  375. function(idf_component_register)
  376. set(options WHOLE_ARCHIVE)
  377. set(single_value KCONFIG KCONFIG_PROJBUILD)
  378. set(multi_value SRCS SRC_DIRS EXCLUDE_SRCS
  379. INCLUDE_DIRS PRIV_INCLUDE_DIRS LDFRAGMENTS REQUIRES
  380. PRIV_REQUIRES REQUIRED_IDF_TARGETS EMBED_FILES EMBED_TXTFILES)
  381. cmake_parse_arguments(_ "${options}" "${single_value}" "${multi_value}" ${ARGN})
  382. if(NOT __idf_component_context)
  383. message(FATAL_ERROR "Called idf_component_register from a non-component directory.")
  384. endif()
  385. __component_check_target()
  386. __component_add_sources(sources)
  387. # Add component manifest to the list of dependencies
  388. set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${COMPONENT_DIR}/idf_component.yml")
  389. # Create the final target for the component. This target is the target that is
  390. # visible outside the build system.
  391. __component_get_target(component_target ${COMPONENT_ALIAS})
  392. __component_get_property(component_lib ${component_target} COMPONENT_LIB)
  393. # Use generator expression so that users can append/override flags even after call to
  394. # idf_build_process
  395. idf_build_get_property(include_directories INCLUDE_DIRECTORIES GENERATOR_EXPRESSION)
  396. idf_build_get_property(compile_options COMPILE_OPTIONS GENERATOR_EXPRESSION)
  397. idf_build_get_property(compile_definitions COMPILE_DEFINITIONS GENERATOR_EXPRESSION)
  398. idf_build_get_property(c_compile_options C_COMPILE_OPTIONS GENERATOR_EXPRESSION)
  399. idf_build_get_property(cxx_compile_options CXX_COMPILE_OPTIONS GENERATOR_EXPRESSION)
  400. idf_build_get_property(asm_compile_options ASM_COMPILE_OPTIONS GENERATOR_EXPRESSION)
  401. idf_build_get_property(common_reqs ___COMPONENT_REQUIRES_COMMON)
  402. include_directories("${include_directories}")
  403. add_compile_options("${compile_options}")
  404. add_compile_definitions("${compile_definitions}")
  405. add_c_compile_options("${c_compile_options}")
  406. add_cxx_compile_options("${cxx_compile_options}")
  407. add_asm_compile_options("${asm_compile_options}")
  408. if(common_reqs) # check whether common_reqs exists, this may be the case in minimalistic host unit test builds
  409. list(REMOVE_ITEM common_reqs ${component_lib})
  410. endif()
  411. link_libraries(${common_reqs})
  412. idf_build_get_property(config_dir CONFIG_DIR)
  413. # The contents of 'sources' is from the __component_add_sources call
  414. if(sources OR __EMBED_FILES OR __EMBED_TXTFILES)
  415. add_library(${component_lib} STATIC ${sources})
  416. __component_set_property(${component_target} COMPONENT_TYPE LIBRARY)
  417. __component_add_include_dirs(${component_lib} "${__INCLUDE_DIRS}" PUBLIC)
  418. __component_add_include_dirs(${component_lib} "${__PRIV_INCLUDE_DIRS}" PRIVATE)
  419. __component_add_include_dirs(${component_lib} "${config_dir}" PUBLIC)
  420. set_target_properties(${component_lib} PROPERTIES OUTPUT_NAME ${COMPONENT_NAME} LINKER_LANGUAGE C)
  421. __ldgen_add_component(${component_lib})
  422. else()
  423. add_library(${component_lib} INTERFACE)
  424. __component_set_property(${component_target} COMPONENT_TYPE CONFIG_ONLY)
  425. __component_add_include_dirs(${component_lib} "${__INCLUDE_DIRS}" INTERFACE)
  426. __component_add_include_dirs(${component_lib} "${config_dir}" INTERFACE)
  427. endif()
  428. # Alias the static/interface library created for linking to external targets.
  429. # The alias is the <prefix>::<component name> name.
  430. __component_get_property(component_alias ${component_target} COMPONENT_ALIAS)
  431. add_library(${component_alias} ALIAS ${component_lib})
  432. # Perform other component processing, such as embedding binaries and processing linker
  433. # script fragments
  434. foreach(file ${__EMBED_FILES})
  435. target_add_binary_data(${component_lib} "${file}" "BINARY")
  436. endforeach()
  437. foreach(file ${__EMBED_TXTFILES})
  438. target_add_binary_data(${component_lib} "${file}" "TEXT")
  439. endforeach()
  440. if(__LDFRAGMENTS)
  441. __ldgen_add_fragment_files("${__LDFRAGMENTS}")
  442. endif()
  443. # Set dependencies
  444. __component_set_all_dependencies()
  445. # Make the COMPONENT_LIB variable available in the component CMakeLists.txt
  446. set(COMPONENT_LIB ${component_lib} PARENT_SCOPE)
  447. # COMPONENT_TARGET is deprecated but is made available with same function
  448. # as COMPONENT_LIB for compatibility.
  449. set(COMPONENT_TARGET ${component_lib} PARENT_SCOPE)
  450. __component_set_properties()
  451. endfunction()
  452. # idf_component_mock
  453. #
  454. # @brief Create mock component with CMock and register it to IDF build system.
  455. #
  456. # @param[in, optional] INCLUDE_DIRS (multivalue) list include directories which belong to the header files
  457. # provided in MOCK_HEADER_FILES. If any other include directories are necessary, they need
  458. # to be passed here, too.
  459. # @param[in, optional] MOCK_HEADER_FILES (multivalue) list of header files from which the mocks shall be generated.
  460. # @param[in, optional] REQUIRES (multivalue) any other components required by the mock component.
  461. #
  462. function(idf_component_mock)
  463. set(options)
  464. set(single_value)
  465. set(multi_value MOCK_HEADER_FILES INCLUDE_DIRS REQUIRES)
  466. cmake_parse_arguments(_ "${options}" "${single_value}" "${multi_value}" ${ARGN})
  467. list(APPEND __REQUIRES "cmock")
  468. set(MOCK_GENERATED_HEADERS "")
  469. set(MOCK_GENERATED_SRCS "")
  470. set(MOCK_FILES "")
  471. set(IDF_PATH $ENV{IDF_PATH})
  472. set(CMOCK_DIR "${IDF_PATH}/components/cmock/CMock")
  473. set(MOCK_GEN_DIR "${CMAKE_CURRENT_BINARY_DIR}")
  474. list(APPEND __INCLUDE_DIRS "${MOCK_GEN_DIR}/mocks")
  475. foreach(header_file ${__MOCK_HEADER_FILES})
  476. get_filename_component(file_without_dir ${header_file} NAME_WE)
  477. list(APPEND MOCK_GENERATED_HEADERS "${MOCK_GEN_DIR}/mocks/Mock${file_without_dir}.h")
  478. list(APPEND MOCK_GENERATED_SRCS "${MOCK_GEN_DIR}/mocks/Mock${file_without_dir}.c")
  479. endforeach()
  480. file(MAKE_DIRECTORY "${MOCK_GEN_DIR}/mocks")
  481. idf_component_register(SRCS "${MOCK_GENERATED_SRCS}"
  482. INCLUDE_DIRS ${__INCLUDE_DIRS}
  483. REQUIRES ${__REQUIRES})
  484. set(COMPONENT_LIB ${COMPONENT_LIB} PARENT_SCOPE)
  485. add_custom_command(
  486. OUTPUT ruby_found SYMBOLIC
  487. COMMAND "ruby" "-v"
  488. COMMENT "Try to find ruby. If this fails, you need to install ruby"
  489. )
  490. # This command builds the mocks.
  491. # First, environment variable UNITY_DIR is set. This is necessary to prevent unity from looking in its own submodule
  492. # which doesn't work in our CI yet...
  493. # The rest is a straight forward call to cmock.rb, consult cmock's documentation for more information.
  494. add_custom_command(
  495. OUTPUT ${MOCK_GENERATED_SRCS} ${MOCK_GENERATED_HEADERS}
  496. DEPENDS ruby_found
  497. COMMAND ${CMAKE_COMMAND} -E env "UNITY_DIR=${IDF_PATH}/components/unity/unity"
  498. ruby
  499. ${CMOCK_DIR}/lib/cmock.rb
  500. -o${CMAKE_CURRENT_SOURCE_DIR}/mock/mock_config.yaml
  501. ${__MOCK_HEADER_FILES}
  502. )
  503. endfunction()
  504. # idf_component_optional_requires
  505. #
  506. # @brief Add a dependency on a given component only if it is included in the build.
  507. #
  508. # Calling idf_component_optional_requires(PRIVATE dependency_name) has the similar effect to
  509. # target_link_libraries(${COMPONENT_LIB} PRIVATE idf::dependency_name), only if 'dependency_name'
  510. # component is part of the build. Otherwise, no dependency gets added. Multiple names may be given.
  511. #
  512. # @param[in] type of the dependency, one of: PRIVATE, PUBLIC, INTERFACE
  513. # @param[in, multivalue] list of component names which should be added as dependencies
  514. #
  515. function(idf_component_optional_requires req_type)
  516. set(optional_reqs ${ARGN})
  517. idf_build_get_property(build_components BUILD_COMPONENTS)
  518. foreach(req ${optional_reqs})
  519. if(req IN_LIST build_components)
  520. idf_component_get_property(req_lib ${req} COMPONENT_LIB)
  521. target_link_libraries(${COMPONENT_LIB} ${req_type} ${req_lib})
  522. endif()
  523. endforeach()
  524. endfunction()
  525. # idf_component_add_link_dependency
  526. #
  527. # @brief Specify than an ESP-IDF component library depends on another component
  528. # library at link time only.
  529. #
  530. # @note Almost always it's better to use idf_component_register() REQUIRES or
  531. # PRIV_REQUIRES for this. However using this function allows adding a dependency
  532. # from inside a different component, as a last resort.
  533. #
  534. # @param[in, required] FROM Component the dependency is from (this component depends on the other component)
  535. # @param[in, optional] TO Component the dependency is to (this component is depended on by FROM). If omitted
  536. # then the current component is assumed. For this default value to work, this function must be called after
  537. # idf_component_register() in the component CMakeLists.txt file.
  538. function(idf_component_add_link_dependency)
  539. set(single_value FROM TO)
  540. cmake_parse_arguments(_ "" "${single_value}" "" ${ARGN})
  541. idf_component_get_property(from_lib ${__FROM} COMPONENT_LIB)
  542. if(__TO)
  543. idf_component_get_property(to_lib ${__TO} COMPONENT_LIB)
  544. else()
  545. set(to_lib ${COMPONENT_LIB})
  546. endif()
  547. set_property(TARGET ${from_lib} APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<LINK_ONLY:${to_lib}>)
  548. endfunction()
  549. #
  550. # Deprecated functions
  551. #
  552. # register_component
  553. #
  554. # Compatibility function for registering 3.xx style components.
  555. macro(register_component)
  556. spaces2list(COMPONENT_SRCS)
  557. spaces2list(COMPONENT_SRCDIRS)
  558. spaces2list(COMPONENT_ADD_INCLUDEDIRS)
  559. spaces2list(COMPONENT_PRIV_INCLUDEDIRS)
  560. spaces2list(COMPONENT_REQUIRES)
  561. spaces2list(COMPONENT_PRIV_REQUIRES)
  562. spaces2list(COMPONENT_ADD_LDFRAGMENTS)
  563. spaces2list(COMPONENT_EMBED_FILES)
  564. spaces2list(COMPONENT_EMBED_TXTFILES)
  565. spaces2list(COMPONENT_SRCEXCLUDE)
  566. idf_component_register(SRCS "${COMPONENT_SRCS}"
  567. SRC_DIRS "${COMPONENT_SRCDIRS}"
  568. INCLUDE_DIRS "${COMPONENT_ADD_INCLUDEDIRS}"
  569. PRIV_INCLUDE_DIRS "${COMPONENT_PRIV_INCLUDEDIRS}"
  570. REQUIRES "${COMPONENT_REQUIRES}"
  571. PRIV_REQUIRES "${COMPONENT_PRIV_REQUIRES}"
  572. LDFRAGMENTS "${COMPONENT_ADD_LDFRAGMENTS}"
  573. EMBED_FILES "${COMPONENT_EMBED_FILES}"
  574. EMBED_TXTFILES "${COMPONENT_EMBED_TXTFILES}"
  575. EXCLUDE_SRCS "${COMPONENT_SRCEXCLUDE}")
  576. endmacro()
  577. # require_idf_targets
  578. #
  579. # Compatibility function for requiring IDF build targets for 3.xx style components.
  580. function(require_idf_targets)
  581. set(__REQUIRED_IDF_TARGETS "${ARGN}")
  582. __component_check_target()
  583. endfunction()
  584. # register_config_only_component
  585. #
  586. # Compatibility function for registering 3.xx style config components.
  587. macro(register_config_only_component)
  588. register_component()
  589. endmacro()
  590. # component_compile_options
  591. #
  592. # Wrapper around target_compile_options that passes the component name
  593. function(component_compile_options)
  594. target_compile_options(${COMPONENT_LIB} PRIVATE ${ARGV})
  595. endfunction()
  596. # component_compile_definitions
  597. #
  598. # Wrapper around target_compile_definitions that passes the component name
  599. function(component_compile_definitions)
  600. target_compile_definitions(${COMPONENT_LIB} PRIVATE ${ARGV})
  601. endfunction()