Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / pigweed / repo / pw_build / pigweed.cmake
1 # Copyright 2020 The Pigweed Authors
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 # use this file except in compliance with the License. You may obtain a copy of
5 # the License at
6 #
7 #     https://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 # License for the specific language governing permissions and limitations under
13 # the License.
14 include_guard(GLOBAL)
15
16 # Wrapper around cmake_parse_arguments that fails with an error if any arguments
17 # remained unparsed.
18 macro(_pw_parse_argv_strict function start_arg options one multi)
19   cmake_parse_arguments(PARSE_ARGV
20       "${start_arg}" arg "${options}" "${one}" "${multi}"
21   )
22   if(NOT "${arg_UNPARSED_ARGUMENTS}" STREQUAL "")
23     set(_all_args ${options} ${one} ${multi})
24     message(FATAL_ERROR
25         "Unexpected arguments to ${function}: ${arg_UNPARSED_ARGUMENTS}\n"
26         "Valid arguments: ${_all_args}"
27     )
28   endif()
29 endmacro()
30
31 # Automatically creates a library and test targets for the files in a module.
32 # This function is only suitable for simple modules that meet the following
33 # requirements:
34 #
35 #  - The module exposes exactly one library.
36 #  - All source files in the module directory are included in the library.
37 #  - Each test in the module has
38 #    - exactly one source .cc file,
39 #    - optionally, one .c source with the same base name as the .cc file,
40 #    - only a dependency on the main module library.
41 #  - The module is not a facade.
42 #
43 # Modules that do not meet these requirements may not use
44 # pw_auto_add_simple_module. Instead, define the module's libraries and tests
45 # with pw_add_module_library, pw_add_facade, pw_add_test, and the standard CMake
46 # functions, such as add_library, target_link_libraries, etc.
47 #
48 # This function does the following:
49 #
50 #   1. Find all .c and .cc files in the module's root directory.
51 #   2. Create a library with the module name using pw_add_module_library with
52 #      all source files that do not end with _test.cc.
53 #   3. Declare a test for each source file that ends with _test.cc.
54 #
55 # Args:
56 #
57 #   IMPLEMENTS_FACADE - this module implements the specified facade
58 #   PUBLIC_DEPS - public target_link_libraries arguments
59 #   PRIVATE_DEPS - private target_link_libraries arguments
60 #
61 function(pw_auto_add_simple_module MODULE)
62   _pw_parse_argv_strict(pw_auto_add_simple_module 1
63       ""
64       "IMPLEMENTS_FACADE"
65       "PUBLIC_DEPS;PRIVATE_DEPS;TEST_DEPS"
66   )
67
68   file(GLOB all_sources *.cc *.c)
69
70   # Create a library with all source files not ending in _test.
71   set(sources "${all_sources}")
72   list(FILTER sources EXCLUDE REGEX "_test(\\.cc|(_c)?\\.c)$")
73   list(FILTER sources EXCLUDE REGEX "_fuzzer\\.cc$")
74
75   file(GLOB_RECURSE headers *.h)
76
77   if(arg_IMPLEMENTS_FACADE)
78     set(groups backends)
79   else()
80     set(groups modules "${MODULE}")
81   endif()
82
83   pw_add_module_library("${MODULE}"
84     IMPLEMENTS_FACADES
85       ${arg_IMPLEMENTS_FACADE}
86     PUBLIC_DEPS
87       ${arg_PUBLIC_DEPS}
88     PRIVATE_DEPS
89       ${arg_PRIVATE_DEPS}
90     SOURCES
91       ${sources}
92     HEADERS
93       ${headers}
94   )
95
96   if(arg_IMPLEMENTS_FACADE)
97     target_include_directories("${MODULE}" PUBLIC public_overrides)
98   endif()
99
100   pw_auto_add_module_tests("${MODULE}"
101     PRIVATE_DEPS
102       ${arg_PUBLIC_DEPS}
103       ${arg_PRIVATE_DEPS}
104       ${arg_TEST_DEPS}
105     GROUPS
106       ${groups}
107   )
108 endfunction(pw_auto_add_simple_module)
109
110 # Creates a test for each source file ending in _test. Tests with mutliple .cc
111 # files or different dependencies than the module will not work correctly.
112 #
113 # Args:
114 #
115 #  PRIVATE_DEPS - dependencies to apply to all tests
116 #  GROUPS - groups in addition to MODULE to which to add these tests
117 #
118 function(pw_auto_add_module_tests MODULE)
119   _pw_parse_argv_strict(pw_auto_add_module_tests 1
120       ""
121       ""
122       "PRIVATE_DEPS;GROUPS"
123   )
124
125   file(GLOB cc_tests *_test.cc)
126
127   foreach(test IN LISTS cc_tests)
128     get_filename_component(test_name "${test}" NAME_WE)
129
130     # Find a .c test corresponding with the test .cc file, if any.
131     file(GLOB c_test "${test_name}.c" "${test_name}_c.c")
132
133     pw_add_test("${MODULE}.${test_name}"
134       SOURCES
135         "${test}"
136         ${c_test}
137       DEPS
138         "$<TARGET_NAME_IF_EXISTS:${MODULE}>"
139         ${arg_PRIVATE_DEPS}
140       GROUPS
141         "${MODULE}"
142         ${arg_GROUPS}
143     )
144   endforeach()
145 endfunction(pw_auto_add_module_tests)
146
147 # Sets the provided variable to the common library arguments.
148 macro(_pw_library_args variable)
149   set("${variable}" SOURCES HEADERS PUBLIC_DEPS PRIVATE_DEPS ${ARGN})
150 endmacro()
151
152 # Creates a library in a module. The library has access to the public/ include
153 # directory.
154 #
155 # Args:
156 #
157 #   SOURCES - source files for this library
158 #   HEADERS - header files for this library
159 #   PUBLIC_DEPS - public target_link_libraries arguments
160 #   PRIVATE_DEPS - private target_link_libraries arguments
161 #   IMPLEMENTS_FACADES - which facades this library implements
162 #
163 function(pw_add_module_library NAME)
164   _pw_library_args(list_args IMPLEMENTS_FACADES)
165   _pw_parse_argv_strict(pw_add_module_library 1 "" "" "${list_args}")
166
167   # Check that the library's name is prefixed by the module name.
168   get_filename_component(module "${CMAKE_CURRENT_SOURCE_DIR}" NAME)
169
170   if(NOT "${NAME}" MATCHES "${module}(\\.[^\\.]+)?(\\.facade)?$")
171     message(FATAL_ERROR
172         "Module libraries must match the module name or be in the form "
173         "'MODULE_NAME.LIBRARY_NAME'. The library '${NAME}' does not match."
174     )
175   endif()
176
177   add_library("${NAME}" EXCLUDE_FROM_ALL ${arg_HEADERS} ${arg_SOURCES})
178   target_include_directories("${NAME}" PUBLIC public)
179   target_link_libraries("${NAME}"
180     PUBLIC
181       pw_build
182       ${arg_PUBLIC_DEPS}
183     PRIVATE
184       pw_build.strict_warnings
185       pw_build.extra_strict_warnings
186       ${arg_PRIVATE_DEPS}
187   )
188
189   if(NOT "${arg_IMPLEMENTS_FACADES}" STREQUAL "")
190     target_include_directories("${NAME}" PUBLIC public_overrides)
191     set(facades ${arg_IMPLEMENTS_FACADES})
192     list(TRANSFORM facades APPEND ".facade")
193     target_link_libraries("${NAME}" PUBLIC ${facades})
194   endif()
195
196   # Libraries require at least one source file.
197   if(NOT arg_SOURCES)
198     target_sources("${NAME}" PRIVATE $<TARGET_PROPERTY:pw_build.empty,SOURCES>)
199   endif()
200 endfunction(pw_add_module_library)
201
202 # Declares a module as a facade.
203 #
204 # Facades are declared as two libraries to avoid circular dependencies.
205 # Libraries that use the facade depend on a library named for the module. The
206 # module that implements the facade depends on a library named
207 # MODULE_NAME.facade.
208 #
209 # pw_add_facade accepts the same arguments as pw_add_module_library, except for
210 # IMPLEMENTS_FACADES. It also accepts the following argument:
211 #
212 #  DEFAULT_BACKEND - which backend to use by default
213 #
214 function(pw_add_facade NAME)
215   _pw_library_args(list_args)
216   _pw_parse_argv_strict(pw_add_facade 1 "" "DEFAULT_BACKEND" "${list_args}")
217
218   # If no backend is set, a script that displays an error message is used
219   # instead. If the facade is used in the build, it fails with this error.
220   add_custom_target("${NAME}._no_backend_set_message"
221     COMMAND
222       python "$ENV{PW_ROOT}/pw_build/py/pw_build/null_backend.py" "${NAME}"
223   )
224   add_library("${NAME}.NO_BACKEND_SET" INTERFACE)
225   add_dependencies("${NAME}.NO_BACKEND_SET" "${NAME}._no_backend_set_message")
226
227   # Set the default backend to the error message if no default is specified.
228   if("${arg_DEFAULT_BACKEND}" STREQUAL "")
229     set(arg_DEFAULT_BACKEND "${NAME}.NO_BACKEND_SET")
230   endif()
231
232   # Declare the backend variable for this facade.
233   set("${NAME}_BACKEND" "${arg_DEFAULT_BACKEND}" CACHE STRING
234       "Backend for ${NAME}")
235
236   # Define the facade library, which is used by the backend to avoid circular
237   # dependencies.
238   add_library("${NAME}.facade" INTERFACE)
239   target_include_directories("${NAME}.facade" INTERFACE public)
240   target_link_libraries("${NAME}.facade" INTERFACE ${arg_PUBLIC_DEPS})
241
242   # Define the public-facing library for this facade, which depends on the
243   # header files in .facade target and exposes the dependency on the backend.
244   pw_add_module_library("${NAME}"
245     SOURCES
246       ${arg_SOURCES}
247     HEADERS
248       ${arg_HEADERS}
249     PUBLIC_DEPS
250       "${NAME}.facade"
251       "${${NAME}_BACKEND}"
252   )
253 endfunction(pw_add_facade)
254
255 # Sets which backend to use for the given facade.
256 function(pw_set_backend FACADE BACKEND)
257   set("${FACADE}_BACKEND" "${BACKEND}" CACHE STRING "Backend for ${NAME}" FORCE)
258 endfunction(pw_set_backend)
259
260 # Declares a unit test. Creates two targets:
261 #
262 #  * <TEST_NAME> - the test executable
263 #  * <TEST_NAME>.run - builds and runs the test
264 #
265 # Args:
266 #
267 #   NAME: name to use for the target
268 #   SOURCES: source files for this test
269 #   DEPS: libraries on which this test depends
270 #   GROUPS: groups to which to add this test; if none are specified, the test is
271 #       added to the 'default' and 'all' groups
272 #
273 function(pw_add_test NAME)
274   _pw_parse_argv_strict(pw_add_test 1 "" "" "SOURCES;DEPS;GROUPS")
275
276   add_executable("${NAME}" EXCLUDE_FROM_ALL ${arg_SOURCES})
277   target_link_libraries("${NAME}"
278     PRIVATE
279       pw_unit_test
280       pw_unit_test.main
281       ${arg_DEPS}
282   )
283
284   # Define a target for running the test. The target creates a stamp file to
285   # indicate successful test completion. This allows running tests in parallel
286   # with Ninja's full dependency resolution.
287   add_custom_command(
288     COMMAND
289       # TODO(hepler): This only runs local test binaries. Execute a test runner
290       #     instead to support device test runs.
291       "$<TARGET_FILE:${NAME}>"
292     COMMAND
293       "${CMAKE_COMMAND}" -E touch "${NAME}.stamp"
294     DEPENDS
295       "${NAME}"
296     OUTPUT
297       "${NAME}.stamp"
298   )
299   add_custom_target("${NAME}.run" DEPENDS "${NAME}.stamp")
300
301   # Always add tests to the "all" group. If no groups are provided, add the
302   # test to the "default" group.
303   if(arg_GROUPS)
304     set(groups all ${arg_GROUPS})
305   else()
306     set(groups all default)
307   endif()
308
309   list(REMOVE_DUPLICATES groups)
310   pw_add_test_to_groups("${NAME}" ${groups})
311 endfunction(pw_add_test)
312
313 # Adds a test target to the specified test groups. Test groups can be built with
314 # the pw_tests_GROUP_NAME target or executed with the pw_run_tests_GROUP_NAME
315 # target.
316 function(pw_add_test_to_groups TEST_NAME)
317   foreach(group IN LISTS ARGN)
318     if(NOT TARGET "pw_tests.${group}")
319       add_custom_target("pw_tests.${group}")
320       add_custom_target("pw_run_tests.${group}")
321     endif()
322
323     add_dependencies("pw_tests.${group}" "${TEST_NAME}")
324     add_dependencies("pw_run_tests.${group}" "${TEST_NAME}.run")
325   endforeach()
326 endfunction(pw_add_test_to_groups)