]> granicus.if.org Git - esp-idf/blob - tools/cmake/components.cmake
Merge branch 'bugfix/regression_in_light_sleep_mode' into 'master'
[esp-idf] / tools / cmake / components.cmake
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
14 # Add a component to the build, using the COMPONENT variables defined
15 # in the parent
16 #
17 function(register_component)
18     get_filename_component(component_dir ${CMAKE_CURRENT_LIST_FILE} DIRECTORY)
19     get_filename_component(component ${component_dir} NAME)
20
21     spaces2list(COMPONENT_SRCDIRS)
22     spaces2list(COMPONENT_ADD_INCLUDEDIRS)
23     spaces2list(COMPONENT_SRCEXCLUDE)
24
25     if(COMPONENT_SRCDIRS)
26         # Warn user if both COMPONENT_SRCDIRS and COMPONENT_SRCS are set
27         if(COMPONENT_SRCS)
28             message(WARNING "COMPONENT_SRCDIRS and COMPONENT_SRCS are both set, COMPONENT_SRCS will be ignored")
29         endif()
30
31         set(COMPONENT_SRCS "")
32
33         foreach(dir ${COMPONENT_SRCDIRS})
34             get_filename_component(abs_dir ${dir} ABSOLUTE BASE_DIR ${component_dir})
35             if(NOT IS_DIRECTORY ${abs_dir})
36                 message(FATAL_ERROR "${CMAKE_CURRENT_LIST_FILE}: COMPONENT_SRCDIRS entry '${dir}' does not exist")
37             endif()
38
39             file(GLOB matches "${abs_dir}/*.c" "${abs_dir}/*.cpp" "${abs_dir}/*.S")
40             if(matches)
41                 list(SORT matches)
42                 set(COMPONENT_SRCS "${COMPONENT_SRCS};${matches}")
43             else()
44                 message(FATAL_ERROR "${CMAKE_CURRENT_LIST_FILE}: COMPONENT_SRCDIRS entry '${dir}' has no source files")
45             endif()
46         endforeach()
47     endif()
48
49     # Remove COMPONENT_SRCEXCLUDE matches
50     foreach(exclude ${COMPONENT_SRCEXCLUDE})
51         get_filename_component(exclude "${exclude}" ABSOLUTE ${component_dir})
52         foreach(src ${COMPONENT_SRCS})
53             get_filename_component(abs_src "${src}" ABSOLUTE ${component_dir})
54             if("${exclude}" STREQUAL "${abs_src}")  # compare as canonical paths
55                 list(REMOVE_ITEM COMPONENT_SRCS "${src}")
56             endif()
57         endforeach()
58     endforeach()
59
60     # add as a PUBLIC library (if there are source files) or INTERFACE (if header only)
61     if(COMPONENT_SRCS OR embed_binaries)
62         add_library(${component} STATIC ${COMPONENT_SRCS})
63         set(include_type PUBLIC)
64     else()
65         add_library(${component} INTERFACE) # header-only component
66         set(include_type INTERFACE)
67     endif()
68
69     # binaries to embed directly in library
70     spaces2list(COMPONENT_EMBED_FILES)
71     spaces2list(COMPONENT_EMBED_TXTFILES)
72     foreach(embed_data ${COMPONENT_EMBED_FILES} ${COMPONENT_EMBED_TXTFILES})
73         if(embed_data IN_LIST COMPONENT_EMBED_TXTFILES)
74             set(embed_type "TEXT")
75         else()
76             set(embed_type "BINARY")
77         endif()
78         target_add_binary_data("${component}" "${embed_data}" "${embed_type}")
79     endforeach()
80
81     # add component public includes
82     foreach(include_dir ${COMPONENT_ADD_INCLUDEDIRS})
83         get_filename_component(abs_dir ${include_dir} ABSOLUTE BASE_DIR ${component_dir})
84         if(NOT IS_DIRECTORY ${abs_dir})
85             message(FATAL_ERROR "${CMAKE_CURRENT_LIST_FILE}: "
86                 "COMPONENT_ADD_INCLUDEDIRS entry '${include_dir}' not found")
87         endif()
88         target_include_directories(${component} ${include_type} ${abs_dir})
89     endforeach()
90
91     # add component private includes
92     foreach(include_dir ${COMPONENT_PRIV_INCLUDEDIRS})
93         if(${include_type} STREQUAL INTERFACE)
94             message(FATAL_ERROR "${CMAKE_CURRENT_LIST_FILE} "
95                 "sets no component source files but sets COMPONENT_PRIV_INCLUDEDIRS")
96         endif()
97
98         get_filename_component(abs_dir ${include_dir} ABSOLUTE BASE_DIR ${component_dir})
99         if(NOT IS_DIRECTORY ${abs_dir})
100             message(FATAL_ERROR "${CMAKE_CURRENT_LIST_FILE}: "
101                 "COMPONENT_PRIV_INCLUDEDIRS entry '${include_dir}' does not exist")
102         endif()
103         target_include_directories(${component} PRIVATE ${abs_dir})
104     endforeach()
105 endfunction()
106
107 function(register_config_only_component)
108     get_filename_component(component_dir ${CMAKE_CURRENT_LIST_FILE} DIRECTORY)
109     get_filename_component(component ${component_dir} NAME)
110
111     # No-op for now...
112 endfunction()
113
114 function(add_component_dependencies target dep dep_type)
115     get_target_property(target_type ${target} TYPE)
116     get_target_property(target_imported ${target} IMPORTED)
117
118     if(${target_type} STREQUAL STATIC_LIBRARY OR ${target_type} STREQUAL EXECUTABLE)
119         if(TARGET ${dep})
120             # Add all compile options exported by dep into target
121             target_include_directories(${target} ${dep_type}
122                 $<TARGET_PROPERTY:${dep},INTERFACE_INCLUDE_DIRECTORIES>)
123             target_compile_definitions(${target} ${dep_type}
124                 $<TARGET_PROPERTY:${dep},INTERFACE_COMPILE_DEFINITIONS>)
125             target_compile_options(${target} ${dep_type}
126                 $<TARGET_PROPERTY:${dep},INTERFACE_COMPILE_OPTIONS>)
127         endif()
128     endif()
129 endfunction()
130
131 function(components_finish_registration)
132
133     # have the executable target depend on all components in the build
134     set_target_properties(${CMAKE_PROJECT_NAME}.elf PROPERTIES INTERFACE_COMPONENT_REQUIRES "${BUILD_COMPONENTS}")
135
136     spaces2list(COMPONENT_REQUIRES_COMMON)
137
138     # each component should see the include directories of its requirements
139     #
140     # (we can't do this until all components are registered and targets exist in cmake, as we have
141     # a circular requirements graph...)
142     foreach(a ${BUILD_COMPONENTS})
143         if(TARGET ${a})
144             get_component_requirements("${a}" a_deps a_priv_deps)
145             list(APPEND a_priv_deps ${COMPONENT_REQUIRES_COMMON})
146             foreach(b ${a_deps})
147                 add_component_dependencies(${a} ${b} PUBLIC)
148             endforeach()
149
150             foreach(b ${a_priv_deps})
151                 add_component_dependencies(${a} ${b} PRIVATE)
152             endforeach()
153
154             get_target_property(a_type ${a} TYPE)
155             if(${a_type} MATCHES .+_LIBRARY)
156                 set(COMPONENT_LIBRARIES "${COMPONENT_LIBRARIES};${a}")
157             endif()
158         endif()
159     endforeach()
160
161     # Add each component library's link-time dependencies (which are otherwise ignored) to the executable
162     # LINK_DEPENDS in order to trigger a re-link when needed (on Ninja/Makefile generators at least).
163     # (maybe this should probably be something CMake does, but it doesn't do it...)
164     foreach(component ${BUILD_COMPONENTS})
165         if(TARGET ${component})
166             get_target_property(imported ${component} IMPORTED)
167             get_target_property(type ${component} TYPE)
168             if(NOT imported)
169                 if(${type} STREQUAL STATIC_LIBRARY OR ${type} STREQUAL EXECUTABLE)
170                     get_target_property(link_depends "${component}" LINK_DEPENDS)
171                     if(link_depends)
172                         set_property(TARGET ${CMAKE_PROJECT_NAME}.elf APPEND PROPERTY LINK_DEPENDS "${link_depends}")
173                     endif()
174                 endif()
175             endif()
176         endif()
177     endforeach()
178
179     target_link_libraries(${CMAKE_PROJECT_NAME}.elf ${COMPONENT_LIBRARIES})
180
181     message(STATUS "Component libraries: ${COMPONENT_LIBRARIES}")
182
183 endfunction()