components.cmake 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. # Given a list of components in 'component_paths', filter only paths to the components
  2. # mentioned in 'components' and return as a list in 'result_paths'
  3. function(components_get_paths component_paths components result_paths)
  4. set(result "")
  5. foreach(path ${component_paths})
  6. get_filename_component(name "${path}" NAME)
  7. if("${name}" IN_LIST components)
  8. list(APPEND result "${name}")
  9. endif()
  10. endforeach()
  11. set("${result_path}" "${result}" PARENT_SCOPE)
  12. endfunction()
  13. # Add a component to the build, using the COMPONENT variables defined
  14. # in the parent
  15. #
  16. function(register_component)
  17. get_filename_component(component_dir ${CMAKE_CURRENT_LIST_FILE} DIRECTORY)
  18. spaces2list(COMPONENT_SRCS)
  19. spaces2list(COMPONENT_SRCDIRS)
  20. spaces2list(COMPONENT_ADD_INCLUDEDIRS)
  21. spaces2list(COMPONENT_SRCEXCLUDE)
  22. if(COMPONENT_SRCDIRS)
  23. # Warn user if both COMPONENT_SRCDIRS and COMPONENT_SRCS are set
  24. if(COMPONENT_SRCS)
  25. message(WARNING "COMPONENT_SRCDIRS and COMPONENT_SRCS are both set, COMPONENT_SRCS will be ignored")
  26. endif()
  27. set(COMPONENT_SRCS "")
  28. foreach(dir ${COMPONENT_SRCDIRS})
  29. get_filename_component(abs_dir ${dir} ABSOLUTE BASE_DIR ${component_dir})
  30. if(NOT IS_DIRECTORY ${abs_dir})
  31. message(FATAL_ERROR "${CMAKE_CURRENT_LIST_FILE}: COMPONENT_SRCDIRS entry '${dir}' does not exist")
  32. endif()
  33. file(GLOB matches "${abs_dir}/*.c" "${abs_dir}/*.cpp" "${abs_dir}/*.S")
  34. if(matches)
  35. list(SORT matches)
  36. set(COMPONENT_SRCS "${COMPONENT_SRCS};${matches}")
  37. else()
  38. message(FATAL_ERROR "${CMAKE_CURRENT_LIST_FILE}: COMPONENT_SRCDIRS entry '${dir}' has no source files")
  39. endif()
  40. endforeach()
  41. endif()
  42. # Remove COMPONENT_SRCEXCLUDE matches
  43. foreach(exclude ${COMPONENT_SRCEXCLUDE})
  44. get_filename_component(exclude "${exclude}" ABSOLUTE ${component_dir})
  45. foreach(src ${COMPONENT_SRCS})
  46. get_filename_component(abs_src "${src}" ABSOLUTE ${component_dir})
  47. if("${exclude}" STREQUAL "${abs_src}") # compare as canonical paths
  48. list(REMOVE_ITEM COMPONENT_SRCS "${src}")
  49. endif()
  50. endforeach()
  51. endforeach()
  52. # add as a PUBLIC library (if there are source files) or INTERFACE (if header only)
  53. if(COMPONENT_SRCS OR embed_binaries)
  54. add_library(${COMPONENT_TARGET} STATIC ${COMPONENT_SRCS})
  55. set(include_type PUBLIC)
  56. set_property(TARGET ${COMPONENT_TARGET} PROPERTY OUTPUT_NAME ${COMPONENT_NAME})
  57. ldgen_generate_sections_info(${COMPONENT_TARGET})
  58. else()
  59. add_library(${COMPONENT_TARGET} INTERFACE) # header-only component
  60. set(include_type INTERFACE)
  61. endif()
  62. # binaries to embed directly in library
  63. spaces2list(COMPONENT_EMBED_FILES)
  64. spaces2list(COMPONENT_EMBED_TXTFILES)
  65. foreach(embed_data ${COMPONENT_EMBED_FILES} ${COMPONENT_EMBED_TXTFILES})
  66. if(embed_data IN_LIST COMPONENT_EMBED_TXTFILES)
  67. set(embed_type "TEXT")
  68. else()
  69. set(embed_type "BINARY")
  70. endif()
  71. target_add_binary_data("${COMPONENT_TARGET}" "${embed_data}" "${embed_type}")
  72. endforeach()
  73. # add component public includes
  74. foreach(include_dir ${COMPONENT_ADD_INCLUDEDIRS})
  75. get_filename_component(abs_dir ${include_dir} ABSOLUTE BASE_DIR ${component_dir})
  76. if(NOT IS_DIRECTORY ${abs_dir})
  77. message(FATAL_ERROR "${CMAKE_CURRENT_LIST_FILE}: "
  78. "COMPONENT_ADD_INCLUDEDIRS entry '${include_dir}' not found")
  79. endif()
  80. target_include_directories(${COMPONENT_TARGET} ${include_type} ${abs_dir})
  81. endforeach()
  82. # add component private includes
  83. foreach(include_dir ${COMPONENT_PRIV_INCLUDEDIRS})
  84. if(${include_type} STREQUAL INTERFACE)
  85. message(FATAL_ERROR "${CMAKE_CURRENT_LIST_FILE} "
  86. "sets no component source files but sets COMPONENT_PRIV_INCLUDEDIRS")
  87. endif()
  88. get_filename_component(abs_dir ${include_dir} ABSOLUTE BASE_DIR ${component_dir})
  89. if(NOT IS_DIRECTORY ${abs_dir})
  90. message(FATAL_ERROR "${CMAKE_CURRENT_LIST_FILE}: "
  91. "COMPONENT_PRIV_INCLUDEDIRS entry '${include_dir}' does not exist")
  92. endif()
  93. target_include_directories(${COMPONENT_TARGET} PRIVATE ${abs_dir})
  94. endforeach()
  95. if(${COMPONENT_NAME} IN_LIST BUILD_TEST_COMPONENTS)
  96. set_property(TARGET ${IDF_PROJECT_EXECUTABLE} APPEND PROPERTY
  97. LINK_LIBRARIES "-L${CMAKE_CURRENT_BINARY_DIR}")
  98. set_property(TARGET ${IDF_PROJECT_EXECUTABLE} APPEND PROPERTY
  99. LINK_LIBRARIES "-Wl,--whole-archive -l${COMPONENT_NAME} -Wl,--no-whole-archive")
  100. endif()
  101. if(COMPONENT_SRCS OR embed_binaries)
  102. target_include_directories(${COMPONENT_TARGET} PUBLIC ${IDF_INCLUDE_DIRECTORIES})
  103. target_compile_options(${COMPONENT_TARGET} PUBLIC ${IDF_COMPILE_OPTIONS})
  104. target_compile_options(${COMPONENT_TARGET} PUBLIC $<$<COMPILE_LANGUAGE:C>:${IDF_C_COMPILE_OPTIONS}>)
  105. target_compile_options(${COMPONENT_TARGET} PUBLIC $<$<COMPILE_LANGUAGE:CXX>:${IDF_CXX_COMPILE_OPTIONS}>)
  106. target_compile_definitions(${COMPONENT_TARGET} PUBLIC ${IDF_COMPILE_DEFINITIONS})
  107. endif()
  108. if(COMPONENT_ADD_LDFRAGMENTS)
  109. spaces2list(COMPONENT_ADD_LDFRAGMENTS)
  110. ldgen_add_fragment_files(${COMPONENT_TARGET} "${COMPONENT_ADD_LDFRAGMENTS}")
  111. endif()
  112. endfunction()
  113. function(register_config_only_component)
  114. get_filename_component(component_dir ${CMAKE_CURRENT_LIST_FILE} DIRECTORY)
  115. get_filename_component(component ${component_dir} NAME)
  116. # No-op for now...
  117. endfunction()
  118. function(add_component_dependencies target dep dep_type)
  119. get_target_property(target_type ${target} TYPE)
  120. get_target_property(target_imported ${target} IMPORTED)
  121. if(${target_type} STREQUAL STATIC_LIBRARY OR ${target_type} STREQUAL EXECUTABLE)
  122. if(TARGET ${dep})
  123. # Add all compile options exported by dep into target
  124. target_include_directories(${target} ${dep_type}
  125. $<TARGET_PROPERTY:${dep},INTERFACE_INCLUDE_DIRECTORIES>)
  126. target_compile_definitions(${target} ${dep_type}
  127. $<TARGET_PROPERTY:${dep},INTERFACE_COMPILE_DEFINITIONS>)
  128. target_compile_options(${target} ${dep_type}
  129. $<TARGET_PROPERTY:${dep},INTERFACE_COMPILE_OPTIONS>)
  130. endif()
  131. endif()
  132. endfunction()
  133. function(require_idf_targets)
  134. if(NOT ${IDF_TARGET} IN_LIST ARGN)
  135. message(FATAL_ERROR "Component ${COMPONENT_NAME} only supports targets: ${ARGN}")
  136. endif()
  137. endfunction()
  138. # component_compile_options
  139. #
  140. # Wrapper around target_compile_options that passes the component name
  141. function(component_compile_options)
  142. target_compile_options(${COMPONENT_TARGET} PRIVATE ${ARGV})
  143. endfunction()
  144. # component_compile_definitions
  145. #
  146. # Wrapper around target_compile_definitions that passes the component name
  147. function(component_compile_definitions)
  148. target_compile_definitions(${COMPONENT_TARGET} PRIVATE ${ARGV})
  149. endfunction()
  150. # component_get_target
  151. #
  152. # Get the library target created for the given component
  153. function(component_get_target var component)
  154. get_property(prefix GLOBAL PROPERTY __IDF_COMPONENTS_PREFIX)
  155. set(${var} ${prefix}_${component} PARENT_SCOPE)
  156. endfunction()