1 include(LLVMLibCTargetNameUtils)
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.
11 function(add_header target_name)
12 cmake_parse_arguments(
14 "" # No optional arguments
15 "HDR" # Single value arguments
19 if(NOT ADD_HEADER_HDR)
20 message(FATAL_ERROR "'add_header' rules requires the HDR argument specifying a headef file.")
23 set(dest_file ${CMAKE_CURRENT_BINARY_DIR}/${ADD_HEADER_HDR})
24 set(src_file ${CMAKE_CURRENT_SOURCE_DIR}/${ADD_HEADER_HDR})
28 COMMAND cp ${src_file} ${dest_file}
32 get_fq_target_name(${target_name} fq_target_name)
38 if(ADD_HEADER_DEPENDS)
39 get_fq_deps_list(fq_deps_list ${ADD_HEADER_DEPENDS})
41 ${fq_target_name} ${fq_deps_list}
44 endfunction(add_header)
46 # A rule for generated header file targets.
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>
55 function(add_gen_header target_name)
56 cmake_parse_arguments(
58 "" # No optional arguments
59 "DEF_FILE;GEN_HDR" # Single value arguments
60 "PARAMS;DATA_FILES;DEPENDS" # Multi value arguments
63 if(NOT ADD_GEN_HDR_DEF_FILE)
64 message(FATAL_ERROR "`add_gen_hdr` rule requires DEF_FILE to be specified.")
66 if(NOT ADD_GEN_HDR_GEN_HDR)
67 message(FATAL_ERROR "`add_gen_hdr` rule requires GEN_HDR to be specified.")
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})
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}")
80 set(replacement_params "")
81 if(ADD_GEN_HDR_PARAMS)
82 list(APPEND replacement_params "--args" ${ADD_GEN_HDR_PARAMS})
85 set(gen_hdr_script "${LIBC_BUILD_SCRIPTS_DIR}/gen_hdr.py")
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
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})
100 DEPENDS ${out_file} ${fq_deps_list}
102 endfunction(add_gen_header)
104 set(OBJECT_LIBRARY_TARGET_TYPE "OBJECT_LIBRARY")
106 # Rule which is essentially a wrapper over add_library to compile a set of
107 # sources to object files.
109 # add_object_library(
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(
118 "" # No option arguments
119 "" # Single value arguments
120 "SRCS;HDRS;COMPILE_OPTIONS;DEPENDS" # Multivalue arguments
124 if(NOT ADD_OBJECT_SRCS)
125 message(FATAL_ERROR "'add_object_library' rule requires SRCS to be specified.")
128 get_fq_target_name(${target_name} fq_target_name)
135 target_include_directories(
138 "${LIBC_BUILD_DIR}/include;${LIBC_SOURCE_DIR};${LIBC_BUILD_DIR}"
140 if(ADD_OBJECT_COMPILE_OPTIONS)
141 target_compile_options(
143 PRIVATE ${ADD_OBJECT_COMPILE_OPTIONS}
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})
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
160 get_target_property(obj_type ${obj_target} "TARGET_TYPE")
161 if((NOT obj_type) OR (NOT (${obj_type} STREQUAL ${OBJECT_LIBRARY_TARGET_TYPE})))
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)
170 list(REMOVE_DUPLICATES all_object_files)
172 set_target_properties(
175 "TARGET_TYPE" ${OBJECT_LIBRARY_TARGET_TYPE}
176 "OBJECT_FILES" "${all_object_files}"
178 endfunction(add_object_library)
180 set(ENTRYPOINT_OBJ_TARGET_TYPE "ENTRYPOINT_OBJ")
182 # A rule for entrypoint object targets.
184 # add_entrypoint_object(
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`>
194 function(add_entrypoint_object target_name)
195 cmake_parse_arguments(
197 "ALIAS;REDIRECTED" # Optional argument
198 "NAME" # Single value arguments
199 "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS" # Multi value arguments
203 get_fq_target_name(${target_name} fq_target_name)
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.")
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.")
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.")
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(
232 "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE}
233 "OBJECT_FILES" "${all_objects}"
234 "OBJECT_FILES_RAW" "${all_objects_raw}"
239 if(NOT ADD_ENTRYPOINT_OBJ_SRCS)
240 message(FATAL_ERROR "`add_entrypoint_object` rule requires SRCS to be specified.")
242 if(NOT ADD_ENTRYPOINT_OBJ_HDRS)
243 message(FATAL_ERROR "`add_entrypoint_object` rule requires HDRS to be specified.")
246 set(entrypoint_name ${target_name})
247 if(ADD_ENTRYPOINT_OBJ_NAME)
248 set(entrypoint_name ${ADD_ENTRYPOINT_OBJ_NAME})
251 set(objects_target_name "${fq_target_name}_objects")
254 ${objects_target_name}
255 # We want an object library as the objects will eventually get packaged into
256 # an archive (like libc.a).
258 ${ADD_ENTRYPOINT_OBJ_SRCS}
259 ${ADD_ENTRYPOINT_OBJ_HDRS}
261 target_compile_options(
262 ${objects_target_name}
265 -fpie ${LLVM_CXX_STD_default}
267 target_include_directories(
268 ${objects_target_name}
270 "${LIBC_BUILD_DIR}/include;${LIBC_SOURCE_DIR};${LIBC_BUILD_DIR}"
273 ${objects_target_name}
274 libc.src.__support.common
277 if(ADD_ENTRYPOINT_OBJ_DEPENDS)
278 get_fq_deps_list(fq_deps_list ${ADD_ENTRYPOINT_OBJ_DEPENDS})
280 ${objects_target_name}
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
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.
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
299 get_target_property(obj_files ${dep_target} "OBJECT_FILES")
300 list(APPEND dep_objects ${obj_files})
301 endforeach(dep_target)
303 list(REMOVE_DUPLICATES dep_objects)
305 if(ADD_ENTRYPOINT_OBJ_COMPILE_OPTIONS)
306 target_compile_options(
307 ${objects_target_name}
308 PRIVATE ${ADD_ENTRYPOINT_OBJ_COMPILE_OPTIONS}
312 set(object_file_raw "${CMAKE_CURRENT_BINARY_DIR}/${target_name}_raw.o")
313 set(object_file "${CMAKE_CURRENT_BINARY_DIR}/${target_name}.o")
315 set(input_objects $<TARGET_OBJECTS:${objects_target_name}>)
317 OUTPUT ${object_file_raw}
318 DEPENDS ${input_objects}
319 COMMAND ${CMAKE_LINKER} -r ${input_objects} -o ${object_file_raw}
322 set(alias_attributes "0,function,global")
323 if(ADD_ENTRYPOINT_OBJ_REDIRECTED)
324 set(alias_attributes "${alias_attributes},hidden")
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}
337 DEPENDS ${object_file}
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(
346 "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE}
347 "OBJECT_FILES" "${all_objects}"
348 "OBJECT_FILES_RAW" "${all_objects_raw}"
350 endfunction(add_entrypoint_object)
352 # A rule to build a library from a collection of entrypoint objects.
354 # add_entrypoint_library(
355 # DEPENDS <list of add_entrypoint_object targets>
357 function(add_entrypoint_library target_name)
358 cmake_parse_arguments(
360 "" # No optional arguments
361 "" # No single value arguments
362 "DEPENDS" # Multi-value arguments
365 if(NOT ENTRYPOINT_LIBRARY_DEPENDS)
366 message(FATAL_ERROR "'add_entrypoint_library' target requires a DEPENDS list of 'add_entrypoint_object' targets.")
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.")
375 get_target_property(target_obj_files ${dep} "OBJECT_FILES")
376 list(APPEND obj_list "${target_obj_files}")
378 list(REMOVE_DUPLICATES obj_list)
380 set(library_file "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${target_name}${CMAKE_STATIC_LIBRARY_SUFFIX}")
382 OUTPUT ${library_file}
383 COMMAND ${CMAKE_AR} -r ${library_file} ${obj_list}
389 DEPENDS ${library_file}
391 endfunction(add_entrypoint_library)
393 # Rule build a redirector object file.
394 function(add_redirector_object target_name)
395 cmake_parse_arguments(
397 "" # No optional arguments
398 "SRC" # The cpp file in which the redirector is defined.
399 "" # No multivalue arguments
402 if(NOT REDIRECTOR_OBJECT_SRC)
403 message(FATAL_ERROR "'add_redirector_object' rule requires SRC option listing one source file.")
409 ${REDIRECTOR_OBJECT_SRC}
411 target_compile_options(
415 endfunction(add_redirector_object)
417 # Rule to build a shared library of redirector objects.
418 function(add_redirector_library target_name)
419 cmake_parse_arguments(
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}>)
433 # TODO: Call the linker explicitly instead of calling the compiler driver to
434 # prevent DT_NEEDED on C++ runtime.
440 set_target_properties(${target_name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
442 target_link_libraries(
447 set_target_properties(
452 endfunction(add_redirector_library)
454 # Rule to add a libc unittest.
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>
464 function(add_libc_unittest target_name)
465 if(NOT LLVM_INCLUDE_TESTS)
469 cmake_parse_arguments(
471 "" # No optional arguments
472 "SUITE" # Single value arguments
473 "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS" # Multi-value arguments
476 if(NOT LIBC_UNITTEST_SRCS)
477 message(FATAL_ERROR "'add_libc_unittest' target requires a SRCS list of .cpp files.")
479 if(NOT LIBC_UNITTEST_DEPENDS)
480 message(FATAL_ERROR "'add_libc_unittest' target requires a DEPENDS list of 'add_entrypoint_object' targets.")
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})
494 # TODO: Check if the dep is a normal CMake library target. If yes, then add it
495 # to the list of library_deps.
497 list(REMOVE_DUPLICATES library_deps)
499 get_fq_target_name(${target_name} fq_target_name)
503 ${LIBC_UNITTEST_SRCS}
504 ${LIBC_UNITTEST_HDRS}
506 target_include_directories(
511 ${LIBC_BUILD_DIR}/include
513 if(LIBC_UNITTEST_COMPILE_OPTIONS)
514 target_compile_options(
516 PRIVATE ${LIBC_UNITTEST_COMPILE_OPTIONS}
521 target_link_libraries(${fq_target_name} PRIVATE ${library_deps})
524 set_target_properties(${fq_target_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
531 target_link_libraries(${fq_target_name} PRIVATE LibcUnitTest libc_test_utils)
534 TARGET ${fq_target_name}
536 COMMAND $<TARGET_FILE:${fq_target_name}>
538 if(LIBC_UNITTEST_SUITE)
540 ${LIBC_UNITTEST_SUITE}
544 endfunction(add_libc_unittest)
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)
551 # Rule to add a fuzzer test.
555 # SRCS <list of .cpp files for the test>
556 # HDRS <list of .h files for the test>
557 # DEPENDS <list of dependencies>
559 function(add_libc_fuzzer target_name)
560 cmake_parse_arguments(
562 "" # No optional arguments
563 "" # Single value arguments
564 "SRCS;HDRS;DEPENDS" # Multi-value arguments
567 if(NOT LIBC_FUZZER_SRCS)
568 message(FATAL_ERROR "'add_libc_fuzzer' target requires a SRCS list of .cpp files.")
570 if(NOT LIBC_FUZZER_DEPENDS)
571 message(FATAL_ERROR "'add_libc_fuzzer' target requires a DEPENDS list of 'add_entrypoint_object' targets.")
574 get_fq_deps_list(fq_deps_list ${LIBC_FUZZER_DEPENDS})
576 foreach(dep IN LISTS fq_deps_list)
577 get_target_property(dep_type ${dep} "TARGET_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})
586 # TODO: Check if the dep is a normal CMake library target. If yes, then add it
587 # to the list of library_deps.
590 get_fq_target_name(${target_name} fq_target_name)
597 target_include_directories(
602 ${LIBC_BUILD_DIR}/include
606 target_link_libraries(${fq_target_name} PRIVATE ${library_deps})
609 set_target_properties(${fq_target_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
615 add_dependencies(libc-fuzzer ${fq_target_name})
616 endfunction(add_libc_fuzzer)
618 # Rule to add header only libraries.
620 # add_header_library(
622 # HDRS <list of .h files part of the library>
623 # DEPENDS <list of dependencies>
625 function(add_header_library target_name)
626 cmake_parse_arguments(
628 "" # No optional arguments
629 "" # No Single value arguments
630 "HDRS;DEPENDS" # Multi-value arguments
634 if(NOT ADD_HEADER_HDRS)
635 message(FATAL_ERROR "'add_header_library' target requires a HDRS list of .h files.")
638 get_fq_target_name(${target_name} fq_target_name)
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})
647 set(interface_target_name "${fq_target_name}_header_library__")
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})
656 add_custom_target(${fq_target_name})
657 add_dependencies(${fq_target_name} ${interface_target_name})
658 set_target_properties(
661 "TARGET_TYPE" "HDR_LIBRARY"
663 endfunction(add_header_library)