d604da8e4c9c391f8b836cbc4f944a0e7bd00162
[lldb.git] / libc / cmake / modules / LLVMLibCRules.cmake
1 include(LLVMLibCTargetNameUtils)
2
3 # A rule for self contained header file targets.
4 # This rule merely copies the header file from the current source directory to
5 # the current binary directory.
6 # Usage:
7 #     add_header(
8 #       <target name>
9 #       HDR <header file>
10 #     )
11 function(add_header target_name)
12   cmake_parse_arguments(
13     "ADD_HEADER"
14     ""    # No optional arguments
15     "HDR" # Single value arguments
16     "DEPENDS"
17     ${ARGN}
18   )
19   if(NOT ADD_HEADER_HDR)
20     message(FATAL_ERROR "'add_header' rules requires the HDR argument specifying a headef file.")
21   endif()
22
23   set(dest_file ${CMAKE_CURRENT_BINARY_DIR}/${ADD_HEADER_HDR})
24   set(src_file ${CMAKE_CURRENT_SOURCE_DIR}/${ADD_HEADER_HDR})
25
26   add_custom_command(
27     OUTPUT ${dest_file}
28     COMMAND cp ${src_file} ${dest_file}
29     DEPENDS ${src_file}
30   )
31
32   get_fq_target_name(${target_name} fq_target_name)
33   add_custom_target(
34     ${fq_target_name}
35     DEPENDS ${dest_file}
36   )
37
38   if(ADD_HEADER_DEPENDS)
39     get_fq_deps_list(fq_deps_list ${ADD_HEADER_DEPENDS})
40     add_dependencies(
41       ${fq_target_name} ${fq_deps_list}
42     )
43   endif()
44 endfunction(add_header)
45
46 # A rule for generated header file targets.
47 # Usage:
48 #     add_gen_header(
49 #       <target name>
50 #       DEF_FILE <.h.def file>
51 #       GEN_HDR <generated header file name>
52 #       PARAMS <list of name=value pairs>
53 #       DATA_FILES <list input data files>
54 #     )
55 function(add_gen_header target_name)
56   cmake_parse_arguments(
57     "ADD_GEN_HDR"
58     "" # No optional arguments
59     "DEF_FILE;GEN_HDR" # Single value arguments
60     "PARAMS;DATA_FILES;DEPENDS"     # Multi value arguments
61     ${ARGN}
62   )
63   if(NOT ADD_GEN_HDR_DEF_FILE)
64     message(FATAL_ERROR "`add_gen_hdr` rule requires DEF_FILE to be specified.")
65   endif()
66   if(NOT ADD_GEN_HDR_GEN_HDR)
67     message(FATAL_ERROR "`add_gen_hdr` rule requires GEN_HDR to be specified.")
68   endif()
69
70   set(out_file ${CMAKE_CURRENT_BINARY_DIR}/${ADD_GEN_HDR_GEN_HDR})
71   set(in_file ${CMAKE_CURRENT_SOURCE_DIR}/${ADD_GEN_HDR_DEF_FILE})
72
73   set(fq_data_files "")
74   if(ADD_GEN_HDR_DATA_FILES)
75     foreach(data_file IN LISTS ADD_GEN_HDR_DATA_FILES)
76       list(APPEND fq_data_files "${CMAKE_CURRENT_SOURCE_DIR}/${data_file}")
77     endforeach(data_file)
78   endif()
79
80   set(replacement_params "")
81   if(ADD_GEN_HDR_PARAMS)
82     list(APPEND replacement_params "--args" ${ADD_GEN_HDR_PARAMS})
83   endif()
84
85   set(gen_hdr_script "${LIBC_BUILD_SCRIPTS_DIR}/gen_hdr.py")
86
87   add_custom_command(
88     OUTPUT ${out_file}
89     COMMAND $<TARGET_FILE:libc-hdrgen> -o ${out_file} --header ${ADD_GEN_HDR_GEN_HDR} --def ${in_file} ${replacement_params} -I ${LIBC_SOURCE_DIR} ${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}/api.td
90     WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
91     DEPENDS ${in_file} ${fq_data_files} ${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}/api.td libc-hdrgen
92   )
93
94   get_fq_target_name(${target_name} fq_target_name)
95   if(ADD_GEN_HDR_DEPENDS)
96     get_fq_deps_list(fq_deps_list ${ADD_GEN_HDR_DEPENDS})
97   endif()
98   add_custom_target(
99     ${fq_target_name}
100     DEPENDS ${out_file} ${fq_deps_list}
101   )
102 endfunction(add_gen_header)
103
104 set(OBJECT_LIBRARY_TARGET_TYPE "OBJECT_LIBRARY")
105
106 # Rule which is essentially a wrapper over add_library to compile a set of
107 # sources to object files.
108 # Usage:
109 #     add_object_library(
110 #       <target_name>
111 #       HDRS <list of header files>
112 #       SRCS <list of source files>
113 #       DEPENDS <list of dependencies>
114 #       COMPILE_OPTIONS <optional list of special compile options for this target>
115 function(add_object_library target_name)
116   cmake_parse_arguments(
117     "ADD_OBJECT"
118     "" # No option arguments
119     "" # Single value arguments
120     "SRCS;HDRS;COMPILE_OPTIONS;DEPENDS" # Multivalue arguments
121     ${ARGN}
122   )
123
124   if(NOT ADD_OBJECT_SRCS)
125     message(FATAL_ERROR "'add_object_library' rule requires SRCS to be specified.")
126   endif()
127
128   get_fq_target_name(${target_name} fq_target_name)
129   add_library(
130     ${fq_target_name}
131     OBJECT
132     ${ADD_OBJECT_SRCS}
133     ${ADD_OBJECT_HDRS}
134   )
135   target_include_directories(
136     ${fq_target_name}
137     PRIVATE
138       "${LIBC_BUILD_DIR}/include;${LIBC_SOURCE_DIR};${LIBC_BUILD_DIR}"
139   )
140   if(ADD_OBJECT_COMPILE_OPTIONS)
141     target_compile_options(
142       ${fq_target_name}
143       PRIVATE ${ADD_OBJECT_COMPILE_OPTIONS}
144     )
145   endif()
146
147   set(all_object_files $<TARGET_OBJECTS:${fq_target_name}>)
148   if(ADD_OBJECT_DEPENDS)
149     get_fq_deps_list(fq_deps_list ${ADD_OBJECT_DEPENDS})
150     add_dependencies(
151       ${fq_target_name}
152       ${fq_deps_list}
153     )
154     foreach(obj_target IN LISTS fq_deps_list)
155       if(NOT TARGET obj_target)
156         # Not all targets will be visible. So, we will ignore those which aren't
157         # visible yet.
158         continue()
159       endif()
160       get_target_property(obj_type ${obj_target} "TARGET_TYPE")
161       if((NOT obj_type) OR (NOT (${obj_type} STREQUAL ${OBJECT_LIBRARY_TARGET_TYPE})))
162         continue()
163       endif()
164       # If a dependency is also a object file library, we will collect the list of
165       # object files from it.
166       get_target_property(obj_files ${obj_target} "OBJECT_FILES")
167       list(APPEND all_object_files ${obj_files})
168     endforeach(obj_target)
169   endif()
170   list(REMOVE_DUPLICATES all_object_files)
171
172   set_target_properties(
173     ${fq_target_name}
174     PROPERTIES
175       "TARGET_TYPE" ${OBJECT_LIBRARY_TARGET_TYPE}
176       "OBJECT_FILES" "${all_object_files}"
177   )
178 endfunction(add_object_library)
179
180 set(ENTRYPOINT_OBJ_TARGET_TYPE "ENTRYPOINT_OBJ")
181
182 # A rule for entrypoint object targets.
183 # Usage:
184 #     add_entrypoint_object(
185 #       <target_name>
186 #       [ALIAS|REDIRECTED] # Specified if the entrypoint is redirected or an alias.
187 #       [NAME] <the C name of the entrypoint if different from target_name>
188 #       SRCS <list of .cpp files>
189 #       HDRS <list of .h files>
190 #       DEPENDS <list of dependencies>
191 #       COMPILE_OPTIONS <optional list of special compile options for this target>
192 #       SPECIAL_OBJECTS <optional list of special object targets added by the rule `add_object`>
193 #     )
194 function(add_entrypoint_object target_name)
195   cmake_parse_arguments(
196     "ADD_ENTRYPOINT_OBJ"
197     "ALIAS;REDIRECTED" # Optional argument
198     "NAME" # Single value arguments
199     "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS"  # Multi value arguments
200     ${ARGN}
201   )
202
203   get_fq_target_name(${target_name} fq_target_name)
204
205   if(ADD_ENTRYPOINT_OBJ_ALIAS)
206     # Alias targets help one add aliases to other entrypoint object targets.
207     # One can use alias targets setup OS/machine independent entrypoint targets.
208     list(LENGTH ADD_ENTRYPOINT_OBJ_DEPENDS deps_size)
209     if(NOT (${deps_size} EQUAL "1"))
210       message(FATAL_ERROR "An entrypoint alias should have exactly one dependency.")
211     endif()
212     list(GET ADD_ENTRYPOINT_OBJ_DEPENDS 0 dep_target)
213     get_fq_dep_name(fq_dep_name ${dep_target})
214     if(NOT TARGET ${fq_dep_name})
215       message(WARNING "Aliasee ${fq_dep_name} for entrypoint alias ${target_name} missing; "
216                       "Target ${target_name} will be ignored.")
217       return()
218     endif()
219
220     get_target_property(obj_type ${fq_dep_name} "TARGET_TYPE")
221     if((NOT obj_type) OR (NOT (${obj_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE})))
222       message(FATAL_ERROR "The aliasee of an entrypoint alias should be an entrypoint.")
223     endif()
224
225     add_custom_target(${fq_target_name})
226     add_dependencies(${fq_target_name} ${fq_dep_name})
227     get_target_property(all_objects ${fq_dep_name} "OBJECT_FILES")
228     get_target_property(all_objects_raw ${fq_dep_name} "OBJECT_FILES_RAW")
229     set_target_properties(
230       ${fq_target_name}
231       PROPERTIES
232         "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE}
233         "OBJECT_FILES" "${all_objects}"
234         "OBJECT_FILES_RAW" "${all_objects_raw}"
235     )
236     return()
237   endif()
238
239   if(NOT ADD_ENTRYPOINT_OBJ_SRCS)
240     message(FATAL_ERROR "`add_entrypoint_object` rule requires SRCS to be specified.")
241   endif()
242   if(NOT ADD_ENTRYPOINT_OBJ_HDRS)
243     message(FATAL_ERROR "`add_entrypoint_object` rule requires HDRS to be specified.")
244   endif()
245
246   set(entrypoint_name ${target_name})
247   if(ADD_ENTRYPOINT_OBJ_NAME)
248     set(entrypoint_name ${ADD_ENTRYPOINT_OBJ_NAME})
249   endif()
250
251   set(objects_target_name "${fq_target_name}_objects")
252
253   add_library(
254     ${objects_target_name}
255     # We want an object library as the objects will eventually get packaged into
256     # an archive (like libc.a).
257     OBJECT
258     ${ADD_ENTRYPOINT_OBJ_SRCS}
259     ${ADD_ENTRYPOINT_OBJ_HDRS}
260   )
261   target_compile_options(
262     ${objects_target_name}
263     BEFORE
264     PRIVATE
265       -fpie ${LLVM_CXX_STD_default}
266   )
267   target_include_directories(
268     ${objects_target_name}
269     PRIVATE
270       "${LIBC_BUILD_DIR}/include;${LIBC_SOURCE_DIR};${LIBC_BUILD_DIR}"
271   )
272   add_dependencies(
273     ${objects_target_name}
274     libc.src.__support.common
275   )
276   set(dep_objects "")
277   if(ADD_ENTRYPOINT_OBJ_DEPENDS)
278     get_fq_deps_list(fq_deps_list ${ADD_ENTRYPOINT_OBJ_DEPENDS})
279     add_dependencies(
280       ${objects_target_name}
281       ${fq_deps_list}
282     )
283     foreach(dep_target IN LISTS fq_deps_list)
284       if(NOT TARGET ${dep_target})
285         # Not all targets will be visible. So, we will ignore those which aren't
286         # visible yet.
287         continue()
288       endif()
289       get_target_property(obj_type ${dep_target} "TARGET_TYPE")
290       if((NOT obj_type) OR (NOT (${obj_type} STREQUAL ${OBJECT_LIBRARY_TARGET_TYPE})))
291         # Even from among the visible targets, we will collect object files
292         # only from add_object_library targets.
293         continue()
294       endif()
295       # Calling get_target_property requires that the target be visible at this
296       # point. For object library dependencies, this is a reasonable requirement.
297       # We can revisit this in future if we need cases which break under this
298       # requirement.
299       get_target_property(obj_files ${dep_target} "OBJECT_FILES")
300       list(APPEND dep_objects ${obj_files})
301     endforeach(dep_target)
302   endif()
303   list(REMOVE_DUPLICATES dep_objects)
304
305   if(ADD_ENTRYPOINT_OBJ_COMPILE_OPTIONS)
306     target_compile_options(
307       ${objects_target_name}
308       PRIVATE ${ADD_ENTRYPOINT_OBJ_COMPILE_OPTIONS}
309     )
310   endif()
311
312   set(object_file_raw "${CMAKE_CURRENT_BINARY_DIR}/${target_name}_raw.o")
313   set(object_file "${CMAKE_CURRENT_BINARY_DIR}/${target_name}.o")
314
315   set(input_objects $<TARGET_OBJECTS:${objects_target_name}>)
316   add_custom_command(
317     OUTPUT ${object_file_raw}
318     DEPENDS ${input_objects}
319     COMMAND ${CMAKE_LINKER} -r ${input_objects} -o ${object_file_raw}
320   )
321
322   set(alias_attributes "0,function,global")
323   if(ADD_ENTRYPOINT_OBJ_REDIRECTED)
324     set(alias_attributes "${alias_attributes},hidden")
325   endif()
326
327   add_custom_command(
328     OUTPUT ${object_file}
329     # We llvm-objcopy here as GNU-binutils objcopy does not support the 'hidden' flag.
330     DEPENDS ${object_file_raw} ${llvm-objcopy}
331     COMMAND $<TARGET_FILE:llvm-objcopy> --add-symbol "${entrypoint_name}=.llvm.libc.entrypoint.${entrypoint_name}:${alias_attributes}" ${object_file_raw} ${object_file}
332   )
333
334   add_custom_target(
335     ${fq_target_name}
336     ALL
337     DEPENDS ${object_file}
338   )
339   set(all_objects ${object_file})
340   list(APPEND all_objects ${dep_objects})
341   set(all_objects_raw ${object_file_raw})
342   list(APPEND all_objects_raw ${dep_objects})
343   set_target_properties(
344     ${fq_target_name}
345     PROPERTIES
346       "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE}
347       "OBJECT_FILES" "${all_objects}"
348       "OBJECT_FILES_RAW" "${all_objects_raw}"
349   )
350 endfunction(add_entrypoint_object)
351
352 # A rule to build a library from a collection of entrypoint objects.
353 # Usage:
354 #     add_entrypoint_library(
355 #       DEPENDS <list of add_entrypoint_object targets>
356 #     )
357 function(add_entrypoint_library target_name)
358   cmake_parse_arguments(
359     "ENTRYPOINT_LIBRARY"
360     "" # No optional arguments
361     "" # No single value arguments
362     "DEPENDS" # Multi-value arguments
363     ${ARGN}
364   )
365   if(NOT ENTRYPOINT_LIBRARY_DEPENDS)
366     message(FATAL_ERROR "'add_entrypoint_library' target requires a DEPENDS list of 'add_entrypoint_object' targets.")
367   endif()
368
369   set(obj_list "")
370   foreach(dep IN LISTS ENTRYPOINT_LIBRARY_DEPENDS)
371     get_target_property(dep_type ${dep} "TARGET_TYPE")
372     if(NOT (${dep_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE}))
373       message(FATAL_ERROR "Dependency '${dep}' of 'add_entrypoint_collection' is not an 'add_entrypoint_object' target.")
374     endif()
375     get_target_property(target_obj_files ${dep} "OBJECT_FILES")
376     list(APPEND obj_list "${target_obj_files}")
377   endforeach(dep)
378   list(REMOVE_DUPLICATES obj_list)
379
380   set(library_file "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${target_name}${CMAKE_STATIC_LIBRARY_SUFFIX}")
381   add_custom_command(
382     OUTPUT ${library_file}
383     COMMAND ${CMAKE_AR} -r ${library_file} ${obj_list}
384     DEPENDS ${obj_list}
385   )
386   add_custom_target(
387     ${target_name}
388     ALL
389     DEPENDS ${library_file}
390   )
391 endfunction(add_entrypoint_library)
392
393 # Rule build a redirector object file.
394 function(add_redirector_object target_name)
395   cmake_parse_arguments(
396     "REDIRECTOR_OBJECT"
397     "" # No optional arguments
398     "SRC" # The cpp file in which the redirector is defined.
399     "" # No multivalue arguments
400     ${ARGN}
401   )
402   if(NOT REDIRECTOR_OBJECT_SRC)
403     message(FATAL_ERROR "'add_redirector_object' rule requires SRC option listing one source file.")
404   endif()
405
406   add_library(
407     ${target_name}
408     OBJECT
409     ${REDIRECTOR_OBJECT_SRC}
410   )
411   target_compile_options(
412     ${target_name}
413     BEFORE PRIVATE -fPIC
414   )
415 endfunction(add_redirector_object)
416
417 # Rule to build a shared library of redirector objects.
418 function(add_redirector_library target_name)
419   cmake_parse_arguments(
420     "REDIRECTOR_LIBRARY"
421     ""
422     ""
423     "DEPENDS"
424     ${ARGN}
425   )
426
427   set(obj_files "")
428   foreach(dep IN LISTS REDIRECTOR_LIBRARY_DEPENDS)
429     # TODO: Ensure that each dep is actually a add_redirector_object target.
430     list(APPEND obj_files $<TARGET_OBJECTS:${dep}>)
431   endforeach(dep)
432
433   # TODO: Call the linker explicitly instead of calling the compiler driver to
434   # prevent DT_NEEDED on C++ runtime.
435   add_library(
436     ${target_name}
437     SHARED
438     ${obj_files}
439   )
440   set_target_properties(${target_name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
441
442   target_link_libraries(
443     ${target_name}
444     -nostdlib -lc -lm
445   )
446
447   set_target_properties(
448     ${target_name}
449     PROPERTIES
450       LINKER_LANGUAGE "C"
451   )
452 endfunction(add_redirector_library)
453
454 # Rule to add a libc unittest.
455 # Usage
456 #    add_libc_unittest(
457 #      <target name>
458 #      SUITE <name of the suite this test belongs to>
459 #      SRCS  <list of .cpp files for the test>
460 #      HDRS  <list of .h files for the test>
461 #      DEPENDS <list of dependencies>
462 #      COMPILE_OPTIONS <list of special compile options for this target>
463 #    )
464 function(add_libc_unittest target_name)
465   if(NOT LLVM_INCLUDE_TESTS)
466     return()
467   endif()
468   
469   cmake_parse_arguments(
470     "LIBC_UNITTEST"
471     "" # No optional arguments
472     "SUITE" # Single value arguments
473     "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS" # Multi-value arguments
474     ${ARGN}
475   )
476   if(NOT LIBC_UNITTEST_SRCS)
477     message(FATAL_ERROR "'add_libc_unittest' target requires a SRCS list of .cpp files.")
478   endif()
479   if(NOT LIBC_UNITTEST_DEPENDS)
480     message(FATAL_ERROR "'add_libc_unittest' target requires a DEPENDS list of 'add_entrypoint_object' targets.")
481   endif()
482
483   set(library_deps "")
484   get_fq_deps_list(fq_deps_list ${LIBC_UNITTEST_DEPENDS})
485   foreach(dep IN LISTS fq_deps_list)
486     get_target_property(dep_type ${dep} "TARGET_TYPE")
487     if(${dep_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE})
488       get_target_property(obj_files ${dep} "OBJECT_FILES_RAW")
489       list(APPEND library_deps ${obj_files})
490     elseif(${dep_type} STREQUAL ${OBJECT_LIBRARY_TARGET_TYPE})
491       get_target_property(obj_files ${dep} "OBJECT_FILES")
492       list(APPEND library_deps ${obj_files})
493     endif()
494     # TODO: Check if the dep is a normal CMake library target. If yes, then add it
495     # to the list of library_deps.
496   endforeach(dep)
497   list(REMOVE_DUPLICATES library_deps)
498
499   get_fq_target_name(${target_name} fq_target_name)
500   add_executable(
501     ${fq_target_name}
502     EXCLUDE_FROM_ALL
503     ${LIBC_UNITTEST_SRCS}
504     ${LIBC_UNITTEST_HDRS}
505   )
506   target_include_directories(
507     ${fq_target_name}
508     PRIVATE
509       ${LIBC_SOURCE_DIR}
510       ${LIBC_BUILD_DIR}
511       ${LIBC_BUILD_DIR}/include
512   )
513   if(LIBC_UNITTEST_COMPILE_OPTIONS)
514     target_compile_options(
515       ${target_name}
516       PRIVATE ${LIBC_UNITTEST_COMPILE_OPTIONS}
517     )
518   endif()
519
520   if(library_deps)
521     target_link_libraries(${fq_target_name} PRIVATE ${library_deps})
522   endif()
523
524   set_target_properties(${fq_target_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
525
526   add_dependencies(
527     ${fq_target_name}
528     ${fq_deps_list}
529   )
530
531   target_link_libraries(${fq_target_name} PRIVATE LibcUnitTest libc_test_utils)
532
533   add_custom_command(
534     TARGET ${fq_target_name}
535     POST_BUILD
536     COMMAND $<TARGET_FILE:${fq_target_name}>
537   )
538   if(LIBC_UNITTEST_SUITE)
539     add_dependencies(
540       ${LIBC_UNITTEST_SUITE}
541       ${fq_target_name}
542     )
543   endif()
544 endfunction(add_libc_unittest)
545
546 function(add_libc_testsuite suite_name)
547   add_custom_target(${suite_name})
548   add_dependencies(check-libc ${suite_name})
549 endfunction(add_libc_testsuite)
550
551 # Rule to add a fuzzer test.
552 # Usage
553 #    add_libc_fuzzer(
554 #      <target name>
555 #      SRCS  <list of .cpp files for the test>
556 #      HDRS  <list of .h files for the test>
557 #      DEPENDS <list of dependencies>
558 #    )
559 function(add_libc_fuzzer target_name)
560   cmake_parse_arguments(
561     "LIBC_FUZZER"
562     "" # No optional arguments
563     "" # Single value arguments
564     "SRCS;HDRS;DEPENDS" # Multi-value arguments
565     ${ARGN}
566   )
567   if(NOT LIBC_FUZZER_SRCS)
568     message(FATAL_ERROR "'add_libc_fuzzer' target requires a SRCS list of .cpp files.")
569   endif()
570   if(NOT LIBC_FUZZER_DEPENDS)
571     message(FATAL_ERROR "'add_libc_fuzzer' target requires a DEPENDS list of 'add_entrypoint_object' targets.")
572   endif()
573
574   get_fq_deps_list(fq_deps_list ${LIBC_FUZZER_DEPENDS})
575   set(library_deps "")
576   foreach(dep IN LISTS fq_deps_list)
577     get_target_property(dep_type ${dep} "TARGET_TYPE")
578     if (dep_type)
579       string(COMPARE EQUAL ${dep_type} ${ENTRYPOINT_OBJ_TARGET_TYPE} dep_is_entrypoint)
580       if(dep_is_entrypoint)
581         get_target_property(obj_file ${dep} "OBJECT_FILES_RAW")
582         list(APPEND library_deps ${obj_file})
583         continue()
584       endif()
585     endif()
586     # TODO: Check if the dep is a normal CMake library target. If yes, then add it
587     # to the list of library_deps.
588   endforeach(dep)
589
590   get_fq_target_name(${target_name} fq_target_name)
591   add_executable(
592     ${fq_target_name}
593     EXCLUDE_FROM_ALL
594     ${LIBC_FUZZER_SRCS}
595     ${LIBC_FUZZER_HDRS}
596   )
597   target_include_directories(
598     ${fq_target_name}
599     PRIVATE
600       ${LIBC_SOURCE_DIR}
601       ${LIBC_BUILD_DIR}
602       ${LIBC_BUILD_DIR}/include
603   )
604
605   if(library_deps)
606     target_link_libraries(${fq_target_name} PRIVATE ${library_deps})
607   endif()
608
609   set_target_properties(${fq_target_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
610
611   add_dependencies(
612     ${fq_target_name}
613     ${fq_deps_list}
614   )
615   add_dependencies(libc-fuzzer ${fq_target_name})
616 endfunction(add_libc_fuzzer)
617
618 # Rule to add header only libraries.
619 # Usage
620 #    add_header_library(
621 #      <target name>
622 #      HDRS  <list of .h files part of the library>
623 #      DEPENDS <list of dependencies>
624 #    )
625 function(add_header_library target_name)
626   cmake_parse_arguments(
627     "ADD_HEADER"
628     "" # No optional arguments
629     "" # No Single value arguments
630     "HDRS;DEPENDS" # Multi-value arguments
631     ${ARGN}
632   )
633
634   if(NOT ADD_HEADER_HDRS)
635     message(FATAL_ERROR "'add_header_library' target requires a HDRS list of .h files.")
636   endif()
637
638   get_fq_target_name(${target_name} fq_target_name)
639
640   set(FULL_HDR_PATHS "")
641   # TODO: Remove this foreach block when we can switch to the new
642   # version of the CMake policy CMP0076.
643   foreach(hdr IN LISTS ADD_HEADER_HDRS)
644     list(APPEND FULL_HDR_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/${hdr})
645   endforeach()
646
647   set(interface_target_name "${fq_target_name}_header_library__")
648
649   add_library(${interface_target_name} INTERFACE)
650   target_sources(${interface_target_name} INTERFACE ${FULL_HDR_PATHS})
651   if(ADD_HEADER_DEPENDS)
652     get_fq_deps_list(fq_deps_list ${ADD_HEADER_DEPENDS})
653     add_dependencies(${interface_target_name} ${fq_deps_list})
654   endif()
655
656   add_custom_target(${fq_target_name})
657   add_dependencies(${fq_target_name} ${interface_target_name})
658   set_target_properties(
659     ${fq_target_name}
660     PROPERTIES
661       "TARGET_TYPE" "HDR_LIBRARY"
662   )
663 endfunction(add_header_library)