1 # This is a helper function and not a build rule. It is to be used by the
2 # various test rules to generate the full list of object files
3 # recursively produced by "add_entrypoint_object" and "add_object_library"
6 # get_object_files_for_test(<result var>
7 # <skipped_entrypoints_var>
8 # <target0> [<target1> ...])
10 # The list of object files is collected in <result_var>.
11 # If skipped entrypoints were found, then <skipped_entrypoints_var> is
12 # set to a true value.
13 # targetN is either an "add_entrypoint_target" target or an
14 # "add_object_library" target.
15 function(get_object_files_for_test result skipped_entrypoints_list)
18 foreach(dep IN LISTS ARGN)
19 if (NOT TARGET ${dep})
20 # Skip any tests whose dependencies have not been defined.
21 list(APPEND skipped_list ${dep})
24 get_target_property(dep_type ${dep} "TARGET_TYPE")
26 # Target for which TARGET_TYPE property is not set do not
27 # provide any object files.
31 if(${dep_type} STREQUAL ${OBJECT_LIBRARY_TARGET_TYPE})
32 get_target_property(dep_object_files ${dep} "OBJECT_FILES")
34 list(APPEND object_files ${dep_object_files})
36 elseif(${dep_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE})
37 get_target_property(is_skipped ${dep} "SKIPPED")
39 list(APPEND skipped_list ${dep})
42 get_target_property(object_file_raw ${dep} "OBJECT_FILE_RAW")
44 list(APPEND object_files ${object_file_raw})
46 elseif(${dep_type} STREQUAL ${ENTRYPOINT_OBJ_VENDOR_TARGET_TYPE})
47 # We skip tests for all externally implemented entrypoints.
48 list(APPEND skipped_list ${dep})
52 get_target_property(indirect_deps ${dep} "DEPS")
53 get_object_files_for_test(
54 indirect_objfiles indirect_skipped_list ${indirect_deps})
55 list(APPEND object_files ${indirect_objfiles})
56 if(indirect_skipped_list)
57 list(APPEND skipped_list ${indirect_skipped_list})
60 list(REMOVE_DUPLICATES object_files)
61 set(${result} ${object_files} PARENT_SCOPE)
62 list(REMOVE_DUPLICATES skipped_list)
63 set(${skipped_entrypoints_list} ${skipped_list} PARENT_SCOPE)
64 endfunction(get_object_files_for_test)
66 # Rule to add a libc unittest.
70 # SUITE <name of the suite this test belongs to>
71 # SRCS <list of .cpp files for the test>
72 # HDRS <list of .h files for the test>
73 # DEPENDS <list of dependencies>
74 # COMPILE_OPTIONS <list of special compile options for this target>
75 # LINK_LIBRARIES <list of linking libraries for this target>
77 function(create_libc_unittest fq_target_name)
78 if(NOT LLVM_INCLUDE_TESTS)
82 cmake_parse_arguments(
84 "NO_RUN_POSTBUILD" # Optional arguments
85 "SUITE;CXX_STANDARD" # Single value arguments
86 "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS;LINK_LIBRARIES;FLAGS" # Multi-value arguments
89 if(NOT LIBC_UNITTEST_SRCS)
90 message(FATAL_ERROR "'add_libc_unittest' target requires a SRCS list of .cpp "
93 if(NOT LIBC_UNITTEST_DEPENDS)
94 message(FATAL_ERROR "'add_libc_unittest' target requires a DEPENDS list of "
95 "'add_entrypoint_object' targets.")
98 get_fq_deps_list(fq_deps_list ${LIBC_UNITTEST_DEPENDS})
99 list(APPEND fq_deps_list libc.src.__support.StringUtil.error_to_string
100 libc.test.UnitTest.ErrnoSetterMatcher)
101 list(REMOVE_DUPLICATES fq_deps_list)
102 get_object_files_for_test(
103 link_object_files skipped_entrypoints_list ${fq_deps_list})
104 if(skipped_entrypoints_list)
105 # If a test is OS/target machine independent, it has to be skipped if the
106 # OS/target machine combination does not provide any dependent entrypoints.
107 # If a test is OS/target machine specific, then such a test will live is a
108 # OS/target machine specific directory and will be skipped at the directory
111 # There can potentially be a setup like this: A unittest is setup for a
112 # OS/target machine independent object library, which in turn depends on a
113 # machine specific object library. Such a test would be testing internals of
114 # the libc and it is assumed that they will be rare in practice. So, they
115 # can be skipped in the corresponding CMake files using platform specific
116 # logic. This pattern is followed in the startup tests for example.
118 # Another pattern that is present currently is to detect machine
119 # capabilities and add entrypoints and tests accordingly. That approach is
120 # much lower level approach and is independent of the kind of skipping that
121 # is happening here at the entrypoint level.
122 if(LIBC_CMAKE_VERBOSE_LOGGING)
123 set(msg "Skipping unittest ${fq_target_name} as it has missing deps: "
124 "${skipped_entrypoints_list}.")
125 message(STATUS ${msg})
130 if(SHOW_INTERMEDIATE_OBJECTS)
131 message(STATUS "Adding unit test ${fq_target_name}")
132 if(${SHOW_INTERMEDIATE_OBJECTS} STREQUAL "DEPS")
133 foreach(dep IN LISTS ADD_OBJECT_DEPENDS)
134 message(STATUS " ${fq_target_name} depends on ${dep}")
139 if(LIBC_UNITTEST_NO_RUN_POSTBUILD)
140 set(fq_build_target_name ${fq_target_name})
142 set(fq_build_target_name ${fq_target_name}.__build__)
146 ${fq_build_target_name}
148 ${LIBC_UNITTEST_SRCS}
149 ${LIBC_UNITTEST_HDRS}
151 target_include_directories(${fq_build_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})
152 target_include_directories(${fq_build_target_name} PRIVATE ${LIBC_SOURCE_DIR})
153 target_compile_options(
154 ${fq_build_target_name}
155 PRIVATE -fpie ${LIBC_COMPILE_OPTIONS_DEFAULT}
157 if(LLVM_LIBC_FULL_BUILD)
158 target_compile_options(
159 ${fq_build_target_name}
160 PRIVATE -ffreestanding
163 if(LIBC_UNITTEST_COMPILE_OPTIONS)
164 target_compile_options(
165 ${fq_build_target_name}
166 PRIVATE ${LIBC_UNITTEST_COMPILE_OPTIONS}
169 if(NOT LIBC_UNITTEST_CXX_STANDARD)
170 set(LIBC_UNITTEST_CXX_STANDARD ${CMAKE_CXX_STANDARD})
172 set_target_properties(
173 ${fq_build_target_name}
175 CXX_STANDARD ${LIBC_UNITTEST_CXX_STANDARD}
178 set(link_libraries ${link_object_files})
179 # Test object files will depend on LINK_LIBRARIES passed down from `add_fp_unittest`
180 foreach(lib IN LISTS LIBC_UNITTEST_LINK_LIBRARIES)
181 if(TARGET ${lib}.unit)
182 list(APPEND link_libraries ${lib}.unit)
184 list(APPEND link_libraries ${lib})
188 set_target_properties(${fq_build_target_name}
189 PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
192 ${fq_build_target_name}
196 # LibcUnitTest should not depend on anything in LINK_LIBRARIES.
197 list(APPEND link_libraries LibcDeathTestExecutors.unit LibcTest.unit)
199 target_link_libraries(${fq_build_target_name} PRIVATE ${link_libraries})
201 if(NOT LIBC_UNITTEST_NO_RUN_POSTBUILD)
204 COMMAND ${fq_build_target_name}
205 COMMENT "Running unit test ${fq_target_name}"
209 if(LIBC_UNITTEST_SUITE)
211 ${LIBC_UNITTEST_SUITE}
215 add_dependencies(libc-unit-tests ${fq_target_name})
216 endfunction(create_libc_unittest)
218 # Internal function, used by `add_libc_unittest`.
219 function(expand_flags_for_libc_unittest target_name flags)
220 cmake_parse_arguments(
222 "IGNORE_MARKER" # No Optional arguments
223 "" # No Single-value arguments
224 "DEPENDS;FLAGS" # Multi-value arguments
228 list(LENGTH flags nflags)
230 create_libc_unittest(
232 DEPENDS "${EXPAND_FLAGS_DEPENDS}"
233 FLAGS "${EXPAND_FLAGS_FLAGS}"
234 "${EXPAND_FLAGS_UNPARSED_ARGUMENTS}"
239 list(GET flags 0 flag)
240 list(REMOVE_AT flags 0)
241 extract_flag_modifier(${flag} real_flag modifier)
243 if(NOT "${modifier}" STREQUAL "NO")
244 expand_flags_for_libc_unittest(
247 DEPENDS "${EXPAND_FLAGS_DEPENDS}" IGNORE_MARKER
248 FLAGS "${EXPAND_FLAGS_FLAGS}" IGNORE_MARKER
249 "${EXPAND_FLAGS_UNPARSED_ARGUMENTS}"
253 if("${real_flag}" STREQUAL "" OR "${modifier}" STREQUAL "ONLY")
257 set(NEW_FLAGS ${EXPAND_FLAGS_FLAGS})
258 list(REMOVE_ITEM NEW_FLAGS ${flag})
259 get_fq_dep_list_without_flag(NEW_DEPS ${real_flag} ${EXPAND_FLAGS_DEPENDS})
261 # Only target with `flag` has `.__NO_flag` target, `flag__NO` and
262 # `flag__ONLY` do not.
263 if("${modifier}" STREQUAL "")
264 set(TARGET_NAME "${target_name}.__NO_${flag}")
266 set(TARGET_NAME "${target_name}")
269 expand_flags_for_libc_unittest(
272 DEPENDS "${NEW_DEPS}" IGNORE_MARKER
273 FLAGS "${NEW_FLAGS}" IGNORE_MARKER
274 "${EXPAND_FLAGS_UNPARSED_ARGUMENTS}"
276 endfunction(expand_flags_for_libc_unittest)
278 function(add_libc_unittest target_name)
279 cmake_parse_arguments(
281 "" # Optional arguments
282 "" # Single value arguments
283 "DEPENDS;FLAGS" # Multi-value arguments
287 get_fq_target_name(${target_name} fq_target_name)
289 if(ADD_TO_EXPAND_DEPENDS AND ("${SHOW_INTERMEDIATE_OBJECTS}" STREQUAL "DEPS"))
290 message(STATUS "Gathering FLAGS from dependencies for ${fq_target_name}")
293 get_fq_deps_list(fq_deps_list ${ADD_TO_EXPAND_DEPENDS})
294 get_flags_from_dep_list(deps_flag_list ${fq_deps_list})
296 list(APPEND ADD_TO_EXPAND_FLAGS ${deps_flag_list})
297 remove_duplicated_flags("${ADD_TO_EXPAND_FLAGS}" flags)
300 if(SHOW_INTERMEDIATE_OBJECTS AND flags)
301 message(STATUS "Unit test ${fq_target_name} has FLAGS: ${flags}")
304 expand_flags_for_libc_unittest(
307 DEPENDS ${fq_deps_list} IGNORE_MARKER
308 FLAGS ${flags} IGNORE_MARKER
309 ${ADD_TO_EXPAND_UNPARSED_ARGUMENTS}
311 endfunction(add_libc_unittest)
313 function(add_libc_exhaustive_testsuite suite_name)
314 add_custom_target(${suite_name})
315 add_dependencies(exhaustive-check-libc ${suite_name})
316 endfunction(add_libc_exhaustive_testsuite)
318 function(add_libc_long_running_testsuite suite_name)
319 add_custom_target(${suite_name})
320 add_dependencies(libc-long-running-tests ${suite_name})
321 endfunction(add_libc_long_running_testsuite)
323 # Rule to add a fuzzer test.
327 # SRCS <list of .cpp files for the test>
328 # HDRS <list of .h files for the test>
329 # DEPENDS <list of dependencies>
331 function(add_libc_fuzzer target_name)
332 cmake_parse_arguments(
334 "NEED_MPFR" # Optional arguments
335 "" # Single value arguments
336 "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS" # Multi-value arguments
339 if(NOT LIBC_FUZZER_SRCS)
340 message(FATAL_ERROR "'add_libc_fuzzer' target requires a SRCS list of .cpp "
343 if(NOT LIBC_FUZZER_DEPENDS)
344 message(FATAL_ERROR "'add_libc_fuzzer' target requires a DEPENDS list of "
345 "'add_entrypoint_object' targets.")
348 list(APPEND LIBC_FUZZER_LINK_LIBRARIES "")
349 if(LIBC_FUZZER_NEED_MPFR)
350 if(NOT LIBC_TESTS_CAN_USE_MPFR)
351 message(VERBOSE "Fuzz test ${name} will be skipped as MPFR library is not available.")
354 list(APPEND LIBC_FUZZER_LINK_LIBRARIES mpfr gmp)
358 get_fq_target_name(${target_name} fq_target_name)
359 get_fq_deps_list(fq_deps_list ${LIBC_FUZZER_DEPENDS})
360 get_object_files_for_test(
361 link_object_files skipped_entrypoints_list ${fq_deps_list})
362 if(skipped_entrypoints_list)
363 if(LIBC_CMAKE_VERBOSE_LOGGING)
364 set(msg "Skipping fuzzer target ${fq_target_name} as it has missing deps: "
365 "${skipped_entrypoints_list}.")
366 message(STATUS ${msg})
368 add_custom_target(${fq_target_name})
370 # A post build custom command is used to avoid running the command always.
372 TARGET ${fq_target_name}
374 COMMAND ${CMAKE_COMMAND} -E echo ${msg}
385 target_include_directories(${fq_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})
386 target_include_directories(${fq_target_name} PRIVATE ${LIBC_SOURCE_DIR})
388 target_link_libraries(${fq_target_name} PRIVATE
390 ${LIBC_FUZZER_LINK_LIBRARIES}
393 set_target_properties(${fq_target_name}
394 PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
400 add_dependencies(libc-fuzzer ${fq_target_name})
402 target_compile_options(${fq_target_name}
404 ${LIBC_FUZZER_COMPILE_OPTIONS})
406 endfunction(add_libc_fuzzer)
408 # DEPRECATED: Use add_hermetic_test instead.
410 # Rule to add an integration test. An integration test is like a unit test
411 # but does not use the system libc. Not even the startup objects from the
412 # system libc are linked in to the final executable. The final exe is fully
413 # statically linked. The libc that the final exe links to consists of only
414 # the object files of the DEPENDS targets.
417 # add_integration_test(
419 # SUITE <the suite to which the test should belong>
420 # SRCS <src1.cpp> [src2.cpp ...]
421 # HDRS [hdr1.cpp ...]
422 # DEPENDS <list of entrypoint or other object targets>
423 # ARGS <list of command line arguments to be passed to the test>
424 # ENV <list of environment variables to set before running the test>
425 # COMPILE_OPTIONS <list of special compile options for this target>
428 # The DEPENDS list can be empty. If not empty, it should be a list of
429 # targets added with add_entrypoint_object or add_object_library.
430 function(add_integration_test test_name)
431 get_fq_target_name(${test_name} fq_target_name)
432 set(supported_targets gpu linux)
433 if(NOT (${LIBC_TARGET_OS} IN_LIST supported_targets))
434 message(STATUS "Skipping ${fq_target_name} as it is not available on ${LIBC_TARGET_OS}.")
437 cmake_parse_arguments(
439 "" # No optional arguments
440 "SUITE" # Single value arguments
441 "SRCS;HDRS;DEPENDS;ARGS;ENV;COMPILE_OPTIONS;LOADER_ARGS" # Multi-value arguments
445 if(NOT INTEGRATION_TEST_SUITE)
446 message(FATAL_ERROR "SUITE not specified for ${fq_target_name}")
448 if(NOT INTEGRATION_TEST_SRCS)
449 message(FATAL_ERROR "The SRCS list for add_integration_test is missing.")
451 if(NOT TARGET libc.startup.${LIBC_TARGET_OS}.crt1)
452 message(FATAL_ERROR "The 'crt1' target for the integration test is missing.")
455 get_fq_target_name(${test_name}.libc fq_libc_target_name)
457 get_fq_deps_list(fq_deps_list ${INTEGRATION_TEST_DEPENDS})
458 list(APPEND fq_deps_list
459 # All integration tests use the operating system's startup object with the
460 # integration test object and need to inherit the same dependencies.
461 libc.startup.${LIBC_TARGET_OS}.crt1
462 libc.test.IntegrationTest.test
463 # We always add the memory functions objects. This is because the
464 # compiler's codegen can emit calls to the C memory functions.
466 libc.src.string.bzero
467 libc.src.string.memcmp
468 libc.src.string.memcpy
469 libc.src.string.memmove
470 libc.src.string.memset
472 list(REMOVE_DUPLICATES fq_deps_list)
474 # TODO: Instead of gathering internal object files from entrypoints,
475 # collect the object files with public names of entrypoints.
476 get_object_files_for_test(
477 link_object_files skipped_entrypoints_list ${fq_deps_list})
478 if(skipped_entrypoints_list)
479 if(LIBC_CMAKE_VERBOSE_LOGGING)
480 set(msg "Skipping unittest ${fq_target_name} as it has missing deps: "
481 "${skipped_entrypoints_list}.")
482 message(STATUS ${msg})
486 list(REMOVE_DUPLICATES link_object_files)
488 # Make a library of all deps
490 ${fq_target_name}.__libc__
495 set_target_properties(${fq_target_name}.__libc__
496 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
497 set_target_properties(${fq_target_name}.__libc__
498 PROPERTIES ARCHIVE_OUTPUT_NAME ${fq_target_name}.libc)
500 set(fq_build_target_name ${fq_target_name}.__build__)
502 ${fq_build_target_name}
504 # The NVIDIA 'nvlink' linker does not currently support static libraries.
505 $<$<BOOL:${LIBC_GPU_TARGET_ARCHITECTURE_IS_NVPTX}>:${link_object_files}>
506 ${INTEGRATION_TEST_SRCS}
507 ${INTEGRATION_TEST_HDRS}
509 set_target_properties(${fq_build_target_name}
510 PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
511 target_include_directories(${fq_build_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})
512 target_include_directories(${fq_build_target_name} PRIVATE ${LIBC_SOURCE_DIR})
513 target_compile_options(${fq_build_target_name}
514 PRIVATE -fpie -ffreestanding -fno-exceptions -fno-rtti ${INTEGRATION_TEST_COMPILE_OPTIONS})
515 # The GPU build requires overriding the default CMake triple and architecture.
516 if(LIBC_GPU_TARGET_ARCHITECTURE_IS_AMDGPU)
517 target_compile_options(${fq_build_target_name} PRIVATE
518 -nogpulib -mcpu=${LIBC_GPU_TARGET_ARCHITECTURE}
519 -flto --target=${LIBC_GPU_TARGET_TRIPLE}
520 -mcode-object-version=${LIBC_GPU_CODE_OBJECT_VERSION})
521 elseif(LIBC_GPU_TARGET_ARCHITECTURE_IS_NVPTX)
522 get_nvptx_compile_options(nvptx_options ${LIBC_GPU_TARGET_ARCHITECTURE})
523 target_compile_options(${fq_build_target_name} PRIVATE
524 -nogpulib ${nvptx_options} -fno-use-cxa-atexit
525 --target=${LIBC_GPU_TARGET_TRIPLE})
528 if(LIBC_TARGET_ARCHITECTURE_IS_GPU)
529 target_link_options(${fq_build_target_name} PRIVATE -nostdlib -static)
531 target_link_options(${fq_build_target_name} PRIVATE -nolibc -nostartfiles -nostdlib++ -static)
533 target_link_libraries(
534 ${fq_build_target_name}
535 # The NVIDIA 'nvlink' linker does not currently support static libraries.
536 $<$<NOT:$<BOOL:${LIBC_GPU_TARGET_ARCHITECTURE_IS_NVPTX}>>:${fq_target_name}.__libc__>
537 libc.startup.${LIBC_TARGET_OS}.crt1
538 libc.test.IntegrationTest.test)
539 add_dependencies(${fq_build_target_name}
540 libc.test.IntegrationTest.test
541 ${INTEGRATION_TEST_DEPENDS})
543 # Tests on the GPU require an external loader utility to launch the kernel.
544 if(TARGET libc.utils.gpu.loader)
545 add_dependencies(${fq_build_target_name} libc.utils.gpu.loader)
546 get_target_property(gpu_loader_exe libc.utils.gpu.loader "EXECUTABLE")
549 # We have to use a separate var to store the command as a list because
550 # the COMMAND option of `add_custom_target` cannot handle empty vars in the
551 # command. For example, if INTEGRATION_TEST_ENV is empty, the actual
552 # command also will not run. So, we use this list and tell `add_custom_target`
553 # to expand the list (by including the option COMMAND_EXPAND_LISTS). This
554 # makes `add_custom_target` construct the correct command and execute it.
556 ${INTEGRATION_TEST_ENV}
557 $<$<BOOL:${LIBC_TARGET_ARCHITECTURE_IS_GPU}>:${gpu_loader_exe}>
558 ${CMAKE_CROSSCOMPILING_EMULATOR}
559 ${INTEGRATION_TEST_LOADER_ARGS}
560 $<TARGET_FILE:${fq_build_target_name}> ${INTEGRATION_TEST_ARGS})
565 COMMENT "Running integration test ${fq_target_name}"
567 add_dependencies(${INTEGRATION_TEST_SUITE} ${fq_target_name})
568 endfunction(add_integration_test)
570 set(LIBC_HERMETIC_TEST_COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_DEFAULT}
571 -fpie -ffreestanding -fno-exceptions -fno-rtti)
572 # The GPU build requires overriding the default CMake triple and architecture.
573 if(LIBC_GPU_TARGET_ARCHITECTURE_IS_AMDGPU)
574 list(APPEND LIBC_HERMETIC_TEST_COMPILE_OPTIONS
575 -nogpulib -mcpu=${LIBC_GPU_TARGET_ARCHITECTURE} -flto
576 --target=${LIBC_GPU_TARGET_TRIPLE}
577 -mcode-object-version=${LIBC_GPU_CODE_OBJECT_VERSION})
578 elseif(LIBC_GPU_TARGET_ARCHITECTURE_IS_NVPTX)
579 get_nvptx_compile_options(nvptx_options ${LIBC_GPU_TARGET_ARCHITECTURE})
580 list(APPEND LIBC_HERMETIC_TEST_COMPILE_OPTIONS
581 -nogpulib ${nvptx_options} -fno-use-cxa-atexit --target=${LIBC_GPU_TARGET_TRIPLE})
584 # Rule to add a hermetic test. A hermetic test is one whose executable is fully
585 # statically linked and consists of pieces drawn only from LLVM's libc. Nothing,
586 # including the startup objects, come from the system libc.
589 # add_libc_hermetic_test(
591 # SUITE <the suite to which the test should belong>
592 # SRCS <src1.cpp> [src2.cpp ...]
593 # HDRS [hdr1.cpp ...]
594 # DEPENDS <list of entrypoint or other object targets>
595 # ARGS <list of command line arguments to be passed to the test>
596 # ENV <list of environment variables to set before running the test>
597 # COMPILE_OPTIONS <list of special compile options for the test>
598 # LINK_LIBRARIES <list of linking libraries for this target>
599 # LOADER_ARGS <list of special args to loaders (like the GPU loader)>
601 function(add_libc_hermetic_test test_name)
602 if(NOT TARGET libc.startup.${LIBC_TARGET_OS}.crt1)
603 message(VERBOSE "Skipping ${fq_target_name} as it is not available on ${LIBC_TARGET_OS}.")
606 cmake_parse_arguments(
608 "" # No optional arguments
609 "SUITE" # Single value arguments
610 "SRCS;HDRS;DEPENDS;ARGS;ENV;COMPILE_OPTIONS;LINK_LIBRARIES;LOADER_ARGS" # Multi-value arguments
614 if(NOT HERMETIC_TEST_SUITE)
615 message(FATAL_ERROR "SUITE not specified for ${fq_target_name}")
617 if(NOT HERMETIC_TEST_SRCS)
618 message(FATAL_ERROR "The SRCS list for add_integration_test is missing.")
621 get_fq_target_name(${test_name} fq_target_name)
622 get_fq_target_name(${test_name}.libc fq_libc_target_name)
624 get_fq_deps_list(fq_deps_list ${HERMETIC_TEST_DEPENDS})
625 list(APPEND fq_deps_list
626 # Hermetic tests use the platform's startup object. So, their deps also
627 # have to be collected.
628 libc.startup.${LIBC_TARGET_OS}.crt1
629 # We always add the memory functions objects. This is because the
630 # compiler's codegen can emit calls to the C memory functions.
632 libc.src.string.bzero
633 libc.src.string.memcmp
634 libc.src.string.memcpy
635 libc.src.string.memmove
636 libc.src.string.memset
637 libc.src.__support.StringUtil.error_to_string
639 list(REMOVE_DUPLICATES fq_deps_list)
641 # TODO: Instead of gathering internal object files from entrypoints,
642 # collect the object files with public names of entrypoints.
643 get_object_files_for_test(
644 link_object_files skipped_entrypoints_list ${fq_deps_list})
645 if(skipped_entrypoints_list)
646 set(msg "Skipping unittest ${fq_target_name} as it has missing deps: "
647 "${skipped_entrypoints_list}.")
648 message(STATUS ${msg})
651 list(REMOVE_DUPLICATES link_object_files)
653 # Make a library of all deps
655 ${fq_target_name}.__libc__
660 set_target_properties(${fq_target_name}.__libc__
661 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
662 set_target_properties(${fq_target_name}.__libc__
663 PROPERTIES ARCHIVE_OUTPUT_NAME ${fq_target_name}.libc)
665 set(fq_build_target_name ${fq_target_name}.__build__)
667 ${fq_build_target_name}
669 # The NVIDIA 'nvlink' linker does not currently support static libraries.
670 $<$<BOOL:${LIBC_GPU_TARGET_ARCHITECTURE_IS_NVPTX}>:${link_object_files}>
671 ${HERMETIC_TEST_SRCS}
672 ${HERMETIC_TEST_HDRS}
674 set_target_properties(${fq_build_target_name}
676 RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
677 #OUTPUT_NAME ${fq_target_name}
679 target_include_directories(${fq_build_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})
680 target_include_directories(${fq_build_target_name} PRIVATE ${LIBC_SOURCE_DIR})
681 target_compile_options(${fq_build_target_name}
682 PRIVATE ${LIBC_HERMETIC_TEST_COMPILE_OPTIONS} ${HERMETIC_TEST_COMPILE_OPTIONS})
684 set(link_libraries "")
685 foreach(lib IN LISTS HERMETIC_TEST_LINK_LIBRARIES)
686 if(TARGET ${lib}.hermetic)
687 list(APPEND link_libraries ${lib}.hermetic)
689 list(APPEND link_libraries ${lib})
693 if(LIBC_TARGET_ARCHITECTURE_IS_GPU)
694 target_link_options(${fq_build_target_name} PRIVATE -nostdlib -static)
696 target_link_options(${fq_build_target_name} PRIVATE -nolibc -nostartfiles -nostdlib++ -static)
698 target_link_libraries(
699 ${fq_build_target_name}
701 libc.startup.${LIBC_TARGET_OS}.crt1
704 LibcHermeticTestSupport.hermetic
705 # The NVIDIA 'nvlink' linker does not currently support static libraries.
706 $<$<NOT:$<BOOL:${LIBC_GPU_TARGET_ARCHITECTURE_IS_NVPTX}>>:${fq_target_name}.__libc__>)
707 add_dependencies(${fq_build_target_name}
709 libc.test.UnitTest.ErrnoSetterMatcher
712 # Tests on the GPU require an external loader utility to launch the kernel.
713 if(TARGET libc.utils.gpu.loader)
714 add_dependencies(${fq_build_target_name} libc.utils.gpu.loader)
715 get_target_property(gpu_loader_exe libc.utils.gpu.loader "EXECUTABLE")
718 set(test_cmd ${HERMETIC_TEST_ENV}
719 $<$<BOOL:${LIBC_TARGET_ARCHITECTURE_IS_GPU}>:${gpu_loader_exe}> ${CMAKE_CROSSCOMPILING_EMULATOR} ${HERMETIC_TEST_LOADER_ARGS}
720 $<TARGET_FILE:${fq_build_target_name}> ${HERMETIC_TEST_ARGS})
725 COMMENT "Running hermetic test ${fq_target_name}"
726 ${LIBC_HERMETIC_TEST_JOB_POOL}
729 add_dependencies(${HERMETIC_TEST_SUITE} ${fq_target_name})
730 add_dependencies(libc-hermetic-tests ${fq_target_name})
731 endfunction(add_libc_hermetic_test)
733 # A convenience function to add both a unit test as well as a hermetic test.
734 function(add_libc_test test_name)
735 cmake_parse_arguments(
737 "UNIT_TEST_ONLY;HERMETIC_TEST_ONLY" # Optional arguments
738 "" # Single value arguments
739 "" # Multi-value arguments
742 if(LIBC_ENABLE_UNITTESTS AND NOT LIBC_TEST_HERMETIC_TEST_ONLY)
743 add_libc_unittest(${test_name}.__unit__ ${LIBC_TEST_UNPARSED_ARGUMENTS})
745 if(LIBC_ENABLE_HERMETIC_TESTS AND NOT LIBC_TEST_UNIT_TEST_ONLY)
746 add_libc_hermetic_test(${test_name}.__hermetic__ ${LIBC_TEST_UNPARSED_ARGUMENTS})
747 get_fq_target_name(${test_name} fq_test_name)
748 if(TARGET ${fq_test_name}.__hermetic__ AND TARGET ${fq_test_name}.__unit__)
749 # Tests like the file tests perform file operations on disk file. If we
750 # don't chain up the unit test and hermetic test, then those tests will
751 # step on each other's files.
752 add_dependencies(${fq_test_name}.__hermetic__ ${fq_test_name}.__unit__)
755 endfunction(add_libc_test)