948 lines · plain
1function(_get_common_test_compile_options output_var c_test flags)2 _get_compile_options_from_flags(compile_flags ${flags})3 _get_compile_options_from_config(config_flags)4 _get_compile_options_from_arch(arch_flags)5 6 # Death test executor is only available in Linux for now.7 if(NOT ${LIBC_TARGET_OS} STREQUAL "linux")8 list(REMOVE_ITEM config_flags "-DLIBC_ADD_NULL_CHECKS")9 endif()10 11 set(compile_options12 ${LIBC_COMPILE_OPTIONS_DEFAULT}13 ${LIBC_TEST_COMPILE_OPTIONS_DEFAULT}14 ${compile_flags}15 ${config_flags}16 ${arch_flags})17 18 if(LLVM_LIBC_COMPILER_IS_GCC_COMPATIBLE)19 list(APPEND compile_options "-fpie")20 21 if(LLVM_LIBC_FULL_BUILD)22 list(APPEND compile_options "-DLIBC_FULL_BUILD")23 # Only add -ffreestanding flag in full build mode.24 list(APPEND compile_options "-ffreestanding")25 list(APPEND compile_options "-fno-exceptions")26 list(APPEND compile_options "-fno-unwind-tables")27 list(APPEND compile_options "-fno-asynchronous-unwind-tables")28 if(NOT c_test)29 list(APPEND compile_options "-fno-rtti")30 endif()31 endif()32 33 if(LIBC_COMPILER_HAS_FIXED_POINT)34 list(APPEND compile_options "-ffixed-point")35 endif()36 37 list(APPEND compile_options "-Wall")38 list(APPEND compile_options "-Wextra")39 # -DLIBC_WNO_ERROR=ON if you can't build cleanly with -Werror.40 if(NOT LIBC_WNO_ERROR)41 # list(APPEND compile_options "-Werror")42 endif()43 list(APPEND compile_options "-Wconversion")44 # FIXME: convert to -Wsign-conversion45 list(APPEND compile_options "-Wno-sign-conversion")46 list(APPEND compile_options "-Wimplicit-fallthrough")47 list(APPEND compile_options "-Wwrite-strings")48 # Silence this warning because _Complex is a part of C99.49 if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")50 if(NOT c_test)51 list(APPEND compile_options "-fext-numeric-literals")52 endif()53 else()54 list(APPEND compile_options "-Wno-c99-extensions")55 list(APPEND compile_options "-Wno-gnu-imaginary-constant")56 endif()57 list(APPEND compile_options "-Wno-pedantic")58 if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")59 list(APPEND compile_options "-Wstrict-prototypes")60 list(APPEND compile_options "-Wextra-semi")61 list(APPEND compile_options "-Wnewline-eof")62 list(APPEND compile_options "-Wnonportable-system-include-path")63 list(APPEND compile_options "-Wthread-safety")64 endif()65 endif()66 set(${output_var} ${compile_options} PARENT_SCOPE)67endfunction()68 69function(_get_hermetic_test_compile_options output_var)70 _get_common_test_compile_options(compile_options "" "")71 list(APPEND compile_options "-DLIBC_TEST=HERMETIC")72 73 # null check tests are death tests, remove from hermetic tests for now.74 if(LIBC_ADD_NULL_CHECKS)75 list(REMOVE_ITEM compile_options "-DLIBC_ADD_NULL_CHECKS")76 endif()77 78 # The GPU build requires overriding the default CMake triple and architecture.79 if(LIBC_TARGET_ARCHITECTURE_IS_AMDGPU)80 list(APPEND compile_options81 -Wno-multi-gpu -nogpulib -mcpu=${LIBC_GPU_TARGET_ARCHITECTURE} -flto82 -mcode-object-version=${LIBC_GPU_CODE_OBJECT_VERSION})83 elseif(LIBC_TARGET_ARCHITECTURE_IS_NVPTX)84 list(APPEND compile_options85 "SHELL:-mllvm -nvptx-emit-init-fini-kernel=false"86 -Wno-multi-gpu --cuda-path=${LIBC_CUDA_ROOT}87 -nogpulib -march=${LIBC_GPU_TARGET_ARCHITECTURE} -fno-use-cxa-atexit)88 endif()89 90 set(${output_var} ${compile_options} PARENT_SCOPE)91endfunction()92 93# This is a helper function and not a build rule. It is to be used by the94# various test rules to generate the full list of object files95# recursively produced by "add_entrypoint_object" and "add_object_library"96# targets.97# Usage:98# get_object_files_for_test(<result var>99# <skipped_entrypoints_var>100# <target0> [<target1> ...])101#102# The list of object files is collected in <result_var>.103# If skipped entrypoints were found, then <skipped_entrypoints_var> is104# set to a true value.105# targetN is either an "add_entrypoint_target" target or an106# "add_object_library" target.107function(get_object_files_for_test result skipped_entrypoints_list)108 set(object_files "")109 set(skipped_list "")110 set(checked_list "")111 set(unchecked_list "${ARGN}")112 list(REMOVE_DUPLICATES unchecked_list)113 114 foreach(dep IN LISTS unchecked_list)115 if (NOT TARGET ${dep})116 # Skip tests with undefined dependencies.117 # Compiler-RT targets are added only if they are enabled. However, such targets may not be defined118 # at the time of the libc build. We should skip checking such targets.119 if (NOT ${dep} MATCHES "^RTScudo.*|^RTGwp.*")120 list(APPEND skipped_list ${dep})121 endif()122 continue()123 endif()124 get_target_property(aliased_target ${dep} "ALIASED_TARGET")125 if(aliased_target)126 # If the target is just an alias, switch to the real target.127 set(dep ${aliased_target})128 endif()129 130 get_target_property(dep_type ${dep} "TARGET_TYPE")131 if(NOT dep_type)132 # Skip tests with no object dependencies.133 continue()134 endif()135 136 get_target_property(dep_checked ${dep} "CHECK_OBJ_FOR_TESTS")137 138 if(dep_checked)139 # Target full dependency has already been checked. Just use the results.140 get_target_property(dep_obj ${dep} "OBJECT_FILES_FOR_TESTS")141 get_target_property(dep_skip ${dep} "SKIPPED_LIST_FOR_TESTS")142 else()143 # Target full dependency hasn't been checked. Recursively check its DEPS.144 set(dep_obj "${dep}")145 set(dep_skip "")146 147 get_target_property(indirect_deps ${dep} "DEPS")148 get_object_files_for_test(dep_obj dep_skip ${indirect_deps})149 150 if(${dep_type} STREQUAL ${OBJECT_LIBRARY_TARGET_TYPE})151 get_target_property(dep_object_files ${dep} "OBJECT_FILES")152 if(dep_object_files)153 list(APPEND dep_obj ${dep_object_files})154 endif()155 elseif(${dep_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE})156 get_target_property(is_skipped ${dep} "SKIPPED")157 if(is_skipped)158 list(APPEND dep_skip ${dep})159 list(REMOVE_ITEM dep_obj ${dep})160 endif()161 get_target_property(object_file_raw ${dep} "OBJECT_FILE_RAW")162 if(object_file_raw)163 # TODO: Remove this once we stop suffixing the target with ".__internal__"164 if(fq_target_name STREQUAL "libc.test.include.issignaling_c_test.__unit__" OR fq_target_name STREQUAL "libc.test.include.iscanonical_c_test.__unit__")165 string(REPLACE ".__internal__" "" object_file_raw ${object_file_raw})166 endif()167 list(APPEND dep_obj ${object_file_raw})168 endif()169 endif()170 171 set_target_properties(${dep} PROPERTIES172 OBJECT_FILES_FOR_TESTS "${dep_obj}"173 SKIPPED_LIST_FOR_TESTS "${dep_skip}"174 CHECK_OBJ_FOR_TESTS "YES"175 )176 177 endif()178 179 list(APPEND object_files ${dep_obj})180 list(APPEND skipped_list ${dep_skip})181 182 endforeach(dep)183 184 list(REMOVE_DUPLICATES object_files)185 set(${result} ${object_files} PARENT_SCOPE)186 list(REMOVE_DUPLICATES skipped_list)187 set(${skipped_entrypoints_list} ${skipped_list} PARENT_SCOPE)188 189endfunction(get_object_files_for_test)190 191# Rule to add a libc unittest.192# Usage193# add_libc_unittest(194# <target name>195# SUITE <name of the suite this test belongs to>196# SRCS <list of .cpp files for the test>197# HDRS <list of .h files for the test>198# DEPENDS <list of dependencies>199# ENV <list of environment variables to set before running the test>200# COMPILE_OPTIONS <list of special compile options for this target>201# LINK_LIBRARIES <list of linking libraries for this target>202# )203function(create_libc_unittest fq_target_name)204 if(NOT LLVM_INCLUDE_TESTS)205 return()206 endif()207 208 cmake_parse_arguments(209 "LIBC_UNITTEST"210 "NO_RUN_POSTBUILD;C_TEST" # Optional arguments211 "SUITE;CXX_STANDARD" # Single value arguments212 "SRCS;HDRS;DEPENDS;ENV;COMPILE_OPTIONS;LINK_LIBRARIES;FLAGS" # Multi-value arguments213 ${ARGN}214 )215 if(NOT LIBC_UNITTEST_SRCS)216 message(FATAL_ERROR "'add_libc_unittest' target requires a SRCS list of .cpp "217 "files.")218 endif()219 if(NOT LIBC_UNITTEST_DEPENDS)220 message(FATAL_ERROR "'add_libc_unittest' target requires a DEPENDS list of "221 "'add_entrypoint_object' targets.")222 endif()223 224 get_fq_deps_list(fq_deps_list ${LIBC_UNITTEST_DEPENDS})225 if(NOT LIBC_UNITTEST_C_TEST)226 list(APPEND fq_deps_list libc.src.__support.StringUtil.error_to_string227 libc.test.UnitTest.ErrnoSetterMatcher)228 endif()229 list(REMOVE_DUPLICATES fq_deps_list)230 231 _get_common_test_compile_options(compile_options "${LIBC_UNITTEST_C_TEST}"232 "${LIBC_UNITTEST_FLAGS}")233 list(APPEND compile_options "-DLIBC_TEST=UNIT")234 # TODO: Ideally we would have a separate function for link options.235 set(link_options236 ${compile_options}237 ${LIBC_LINK_OPTIONS_DEFAULT}238 ${LIBC_TEST_LINK_OPTIONS_DEFAULT}239 )240 list(APPEND compile_options ${LIBC_UNITTEST_COMPILE_OPTIONS})241 242 if(SHOW_INTERMEDIATE_OBJECTS)243 message(STATUS "Adding unit test ${fq_target_name}")244 if(${SHOW_INTERMEDIATE_OBJECTS} STREQUAL "DEPS")245 foreach(dep IN LISTS LIBC_UNITTEST_DEPENDS)246 message(STATUS " ${fq_target_name} depends on ${dep}")247 endforeach()248 endif()249 endif()250 251 get_object_files_for_test(252 link_object_files skipped_entrypoints_list ${fq_deps_list})253 if(skipped_entrypoints_list)254 # If a test is OS/target machine independent, it has to be skipped if the255 # OS/target machine combination does not provide any dependent entrypoints.256 # If a test is OS/target machine specific, then such a test will live is a257 # OS/target machine specific directory and will be skipped at the directory258 # level if required.259 #260 # There can potentially be a setup like this: A unittest is setup for a261 # OS/target machine independent object library, which in turn depends on a262 # machine specific object library. Such a test would be testing internals of263 # the libc and it is assumed that they will be rare in practice. So, they264 # can be skipped in the corresponding CMake files using platform specific265 # logic. This pattern is followed in the startup tests for example.266 #267 # Another pattern that is present currently is to detect machine268 # capabilities and add entrypoints and tests accordingly. That approach is269 # much lower level approach and is independent of the kind of skipping that270 # is happening here at the entrypoint level.271 if(LIBC_CMAKE_VERBOSE_LOGGING)272 set(msg "Skipping unittest ${fq_target_name} as it has missing deps: "273 "${skipped_entrypoints_list}.")274 message(STATUS ${msg})275 endif()276 return()277 endif()278 279 if(LIBC_UNITTEST_NO_RUN_POSTBUILD)280 set(fq_build_target_name ${fq_target_name})281 else()282 set(fq_build_target_name ${fq_target_name}.__build__)283 endif()284 285 add_executable(286 ${fq_build_target_name}287 EXCLUDE_FROM_ALL288 ${LIBC_UNITTEST_SRCS}289 ${LIBC_UNITTEST_HDRS}290 )291 target_include_directories(${fq_build_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})292 target_include_directories(${fq_build_target_name} PRIVATE ${LIBC_SOURCE_DIR})293 target_compile_options(${fq_build_target_name} PRIVATE ${compile_options})294 target_link_options(${fq_build_target_name} PRIVATE ${link_options})295 296 if(NOT LIBC_UNITTEST_CXX_STANDARD)297 set(LIBC_UNITTEST_CXX_STANDARD ${CMAKE_CXX_STANDARD})298 endif()299 set_target_properties(300 ${fq_build_target_name}301 PROPERTIES302 CXX_STANDARD ${LIBC_UNITTEST_CXX_STANDARD}303 )304 305 set(link_libraries ${link_object_files})306 # Test object files will depend on LINK_LIBRARIES passed down from `add_fp_unittest`307 foreach(lib IN LISTS LIBC_UNITTEST_LINK_LIBRARIES)308 if(TARGET ${lib}.unit)309 list(APPEND link_libraries ${lib}.unit)310 else()311 list(APPEND link_libraries ${lib})312 endif()313 endforeach()314 315 set_target_properties(${fq_build_target_name}316 PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})317 318 add_dependencies(319 ${fq_build_target_name}320 ${fq_deps_list}321 )322 323 # LibcUnitTest should not depend on anything in LINK_LIBRARIES.324 if(NOT LIBC_UNITTEST_C_TEST)325 list(APPEND link_libraries LibcDeathTestExecutors.unit LibcTest.unit)326 endif()327 328 target_link_libraries(${fq_build_target_name} PRIVATE ${link_libraries})329 330 if(NOT LIBC_UNITTEST_NO_RUN_POSTBUILD)331 add_custom_target(332 ${fq_target_name}333 COMMAND ${LIBC_UNITTEST_ENV} ${CMAKE_CROSSCOMPILING_EMULATOR} ${CMAKE_CURRENT_BINARY_DIR}/${fq_build_target_name}334 COMMENT "Running unit test ${fq_target_name}"335 DEPENDS ${fq_build_target_name}336 )337 endif()338 339 if(LIBC_UNITTEST_SUITE)340 add_dependencies(341 ${LIBC_UNITTEST_SUITE}342 ${fq_target_name}343 )344 endif()345 add_dependencies(libc-unit-tests ${fq_target_name})346endfunction(create_libc_unittest)347 348function(add_libc_unittest target_name)349 add_target_with_flags(350 ${target_name}351 CREATE_TARGET create_libc_unittest352 ${ARGN}353 )354endfunction(add_libc_unittest)355 356function(add_libc_exhaustive_testsuite suite_name)357 add_custom_target(${suite_name})358 add_dependencies(exhaustive-check-libc ${suite_name})359endfunction(add_libc_exhaustive_testsuite)360 361function(add_libc_long_running_testsuite suite_name)362 add_custom_target(${suite_name})363 add_dependencies(libc-long-running-tests ${suite_name})364endfunction(add_libc_long_running_testsuite)365 366# Rule to add a fuzzer test.367# Usage368# add_libc_fuzzer(369# <target name>370# SRCS <list of .cpp files for the test>371# HDRS <list of .h files for the test>372# DEPENDS <list of dependencies>373# )374function(add_libc_fuzzer target_name)375 cmake_parse_arguments(376 "LIBC_FUZZER"377 "NEED_MPFR" # Optional arguments378 "" # Single value arguments379 "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS" # Multi-value arguments380 ${ARGN}381 )382 if(NOT LIBC_FUZZER_SRCS)383 message(FATAL_ERROR "'add_libc_fuzzer' target requires a SRCS list of .cpp "384 "files.")385 endif()386 if(NOT LIBC_FUZZER_DEPENDS)387 message(FATAL_ERROR "'add_libc_fuzzer' target requires a DEPENDS list of "388 "'add_entrypoint_object' targets.")389 endif()390 391 list(APPEND LIBC_FUZZER_LINK_LIBRARIES "")392 if(LIBC_FUZZER_NEED_MPFR)393 if(NOT LIBC_TESTS_CAN_USE_MPFR)394 message(VERBOSE "Fuzz test ${name} will be skipped as MPFR library is not available.")395 return()396 endif()397 list(APPEND LIBC_FUZZER_LINK_LIBRARIES mpfr gmp)398 endif()399 400 401 get_fq_target_name(${target_name} fq_target_name)402 get_fq_deps_list(fq_deps_list ${LIBC_FUZZER_DEPENDS})403 get_object_files_for_test(404 link_object_files skipped_entrypoints_list ${fq_deps_list})405 if(skipped_entrypoints_list)406 if(LIBC_CMAKE_VERBOSE_LOGGING)407 set(msg "Skipping fuzzer target ${fq_target_name} as it has missing deps: "408 "${skipped_entrypoints_list}.")409 message(STATUS ${msg})410 endif()411 add_custom_target(${fq_target_name})412 413 # A post build custom command is used to avoid running the command always.414 add_custom_command(415 TARGET ${fq_target_name}416 POST_BUILD417 COMMAND ${CMAKE_COMMAND} -E echo ${msg}418 )419 return()420 endif()421 422 add_executable(423 ${fq_target_name}424 EXCLUDE_FROM_ALL425 ${LIBC_FUZZER_SRCS}426 ${LIBC_FUZZER_HDRS}427 )428 target_include_directories(${fq_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})429 target_include_directories(${fq_target_name} PRIVATE ${LIBC_SOURCE_DIR})430 431 target_link_libraries(${fq_target_name} PRIVATE432 ${link_object_files}433 ${LIBC_FUZZER_LINK_LIBRARIES}434 )435 436 set_target_properties(${fq_target_name}437 PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})438 439 add_dependencies(440 ${fq_target_name}441 ${fq_deps_list}442 )443 add_dependencies(libc-fuzzer ${fq_target_name})444 445 target_compile_options(${fq_target_name}446 PRIVATE447 ${LIBC_FUZZER_COMPILE_OPTIONS})448 449endfunction(add_libc_fuzzer)450 451# Get libgcc_s to be used in hermetic and integration tests.452if(NOT MSVC AND NOT LIBC_CC_SUPPORTS_NOSTDLIBPP)453 execute_process(COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=libgcc_s.so.1454 OUTPUT_VARIABLE LIBGCC_S_LOCATION)455 string(STRIP ${LIBGCC_S_LOCATION} LIBGCC_S_LOCATION)456endif()457 458# DEPRECATED: Use add_hermetic_test instead.459#460# Rule to add an integration test. An integration test is like a unit test461# but does not use the system libc. Not even the startup objects from the462# system libc are linked in to the final executable. The final exe is fully463# statically linked. The libc that the final exe links to consists of only464# the object files of the DEPENDS targets.465#466# Usage:467# add_integration_test(468# <target name>469# SUITE <the suite to which the test should belong>470# SRCS <src1.cpp> [src2.cpp ...]471# HDRS [hdr1.cpp ...]472# DEPENDS <list of entrypoint or other object targets>473# ARGS <list of command line arguments to be passed to the test>474# ENV <list of environment variables to set before running the test>475# COMPILE_OPTIONS <list of special compile options for this target>476# )477#478# The DEPENDS list can be empty. If not empty, it should be a list of479# targets added with add_entrypoint_object or add_object_library.480function(add_integration_test test_name)481 get_fq_target_name(${test_name} fq_target_name)482 set(supported_targets gpu linux)483 if(NOT (${LIBC_TARGET_OS} IN_LIST supported_targets))484 message(STATUS "Skipping ${fq_target_name} as it is not available on ${LIBC_TARGET_OS}.")485 return()486 endif()487 cmake_parse_arguments(488 "INTEGRATION_TEST"489 "" # No optional arguments490 "SUITE" # Single value arguments491 "SRCS;HDRS;DEPENDS;ARGS;ENV;COMPILE_OPTIONS;LOADER_ARGS" # Multi-value arguments492 ${ARGN}493 )494 495 if(NOT INTEGRATION_TEST_SUITE)496 message(FATAL_ERROR "SUITE not specified for ${fq_target_name}")497 endif()498 if(NOT INTEGRATION_TEST_SRCS)499 message(FATAL_ERROR "The SRCS list for add_integration_test is missing.")500 endif()501 if(NOT LLVM_LIBC_FULL_BUILD AND NOT TARGET libc.startup.${LIBC_TARGET_OS}.crt1)502 message(FATAL_ERROR "The 'crt1' target for the integration test is missing.")503 endif()504 505 get_fq_target_name(${test_name}.libc fq_libc_target_name)506 507 get_fq_deps_list(fq_deps_list ${INTEGRATION_TEST_DEPENDS})508 list(APPEND fq_deps_list509 # All integration tests use the operating system's startup object with the510 # integration test object and need to inherit the same dependencies.511 libc.startup.${LIBC_TARGET_OS}.crt1512 libc.test.IntegrationTest.test513 # We always add the memory functions objects. This is because the514 # compiler's codegen can emit calls to the C memory functions.515 libc.src.string.memcmp516 libc.src.string.memcpy517 libc.src.string.memmove518 libc.src.string.memset519 libc.src.strings.bcmp520 libc.src.strings.bzero521 )522 523 if(libc.src.compiler.__stack_chk_fail IN_LIST TARGET_LLVMLIBC_ENTRYPOINTS)524 # __stack_chk_fail should always be included if supported to allow building525 # libc with the stack protector enabled.526 list(APPEND fq_deps_list libc.src.compiler.__stack_chk_fail)527 endif()528 529 list(REMOVE_DUPLICATES fq_deps_list)530 531 # TODO: Instead of gathering internal object files from entrypoints,532 # collect the object files with public names of entrypoints.533 get_object_files_for_test(534 link_object_files skipped_entrypoints_list ${fq_deps_list})535 if(skipped_entrypoints_list)536 if(LIBC_CMAKE_VERBOSE_LOGGING)537 set(msg "Skipping integration test ${fq_target_name} as it has missing deps: "538 "${skipped_entrypoints_list}.")539 message(STATUS ${msg})540 endif()541 return()542 endif()543 list(REMOVE_DUPLICATES link_object_files)544 545 # Make a library of all deps546 add_library(547 ${fq_target_name}.__libc__548 STATIC549 EXCLUDE_FROM_ALL550 ${link_object_files}551 )552 set_target_properties(${fq_target_name}.__libc__553 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})554 set_target_properties(${fq_target_name}.__libc__555 PROPERTIES ARCHIVE_OUTPUT_NAME ${fq_target_name}.libc)556 557 set(fq_build_target_name ${fq_target_name}.__build__)558 add_executable(559 ${fq_build_target_name}560 EXCLUDE_FROM_ALL561 ${INTEGRATION_TEST_SRCS}562 ${INTEGRATION_TEST_HDRS}563 )564 set_target_properties(${fq_build_target_name}565 PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})566 target_include_directories(${fq_build_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})567 target_include_directories(${fq_build_target_name} PRIVATE ${LIBC_SOURCE_DIR})568 569 _get_hermetic_test_compile_options(compile_options "")570 target_compile_options(${fq_build_target_name} PRIVATE571 ${compile_options} ${INTEGRATION_TEST_COMPILE_OPTIONS})572 573 set(compiler_runtime "")574 575 if(LIBC_TARGET_ARCHITECTURE_IS_AMDGPU)576 target_link_options(${fq_build_target_name} PRIVATE577 ${LIBC_COMPILE_OPTIONS_DEFAULT} ${INTEGRATION_TEST_COMPILE_OPTIONS}578 -Wno-multi-gpu -mcpu=${LIBC_GPU_TARGET_ARCHITECTURE} -flto -nostdlib -static579 "-Wl,-mllvm,-amdhsa-code-object-version=${LIBC_GPU_CODE_OBJECT_VERSION}")580 elseif(LIBC_TARGET_ARCHITECTURE_IS_NVPTX)581 target_link_options(${fq_build_target_name} PRIVATE582 ${LIBC_COMPILE_OPTIONS_DEFAULT} ${INTEGRATION_TEST_COMPILE_OPTIONS}583 "-Wl,--suppress-stack-size-warning" -Wno-multi-gpu584 "-Wl,-mllvm,-nvptx-emit-init-fini-kernel"585 -march=${LIBC_GPU_TARGET_ARCHITECTURE} -nostdlib -static586 "--cuda-path=${LIBC_CUDA_ROOT}")587 elseif(LIBC_CC_SUPPORTS_NOSTDLIBPP)588 set(link_options589 -nolibc590 -nostartfiles591 -nostdlib++592 -static593 ${LIBC_LINK_OPTIONS_DEFAULT}594 ${LIBC_TEST_LINK_OPTIONS_DEFAULT}595 )596 target_link_options(${fq_build_target_name} PRIVATE ${link_options})597 else()598 # Older version of gcc does not support `nostdlib++` flag. We use599 # `nostdlib` and link against libgcc_s, which cannot be linked statically.600 set(link_options601 -nolibc602 -nostartfiles603 -nostdlib604 ${LIBC_LINK_OPTIONS_DEFAULT}605 ${LIBC_TEST_LINK_OPTIONS_DEFAULT}606 )607 target_link_options(${fq_build_target_name} PRIVATE ${link_options})608 list(APPEND compiler_runtime ${LIBGCC_S_LOCATION})609 endif()610 target_link_libraries(611 ${fq_build_target_name}612 libc.startup.${LIBC_TARGET_OS}.crt1613 libc.test.IntegrationTest.test614 ${fq_target_name}.__libc__615 ${compiler_runtime}616 )617 add_dependencies(${fq_build_target_name}618 libc.test.IntegrationTest.test619 ${INTEGRATION_TEST_DEPENDS})620 621 # Tests on the GPU require an external loader utility to launch the kernel.622 if(TARGET libc.utils.gpu.loader)623 add_dependencies(${fq_build_target_name} libc.utils.gpu.loader)624 get_target_property(gpu_loader_exe libc.utils.gpu.loader "EXECUTABLE")625 endif()626 627 # We have to use a separate var to store the command as a list because628 # the COMMAND option of `add_custom_target` cannot handle empty vars in the629 # command. For example, if INTEGRATION_TEST_ENV is empty, the actual630 # command also will not run. So, we use this list and tell `add_custom_target`631 # to expand the list (by including the option COMMAND_EXPAND_LISTS). This632 # makes `add_custom_target` construct the correct command and execute it.633 set(test_cmd634 ${INTEGRATION_TEST_ENV}635 $<$<BOOL:${LIBC_TARGET_OS_IS_GPU}>:${gpu_loader_exe}>636 ${CMAKE_CROSSCOMPILING_EMULATOR}637 ${INTEGRATION_TEST_LOADER_ARGS}638 $<TARGET_FILE:${fq_build_target_name}> ${INTEGRATION_TEST_ARGS})639 add_custom_target(640 ${fq_target_name}641 COMMAND ${test_cmd}642 COMMAND_EXPAND_LISTS643 COMMENT "Running integration test ${fq_target_name}"644 )645 add_dependencies(${INTEGRATION_TEST_SUITE} ${fq_target_name})646endfunction(add_integration_test)647 648# Rule to add a hermetic program. A hermetic program is one whose executable is fully649# statically linked and consists of pieces drawn only from LLVM's libc. Nothing,650# including the startup objects, come from the system libc.651#652# For the GPU, these can be either tests or benchmarks, depending on the value653# of the LINK_LIBRARIES arg.654#655# Usage:656# add_libc_hermetic(657# <target name>658# SUITE <the suite to which the test should belong>659# SRCS <src1.cpp> [src2.cpp ...]660# HDRS [hdr1.cpp ...]661# DEPENDS <list of entrypoint or other object targets>662# ARGS <list of command line arguments to be passed to the test>663# ENV <list of environment variables to set before running the test>664# COMPILE_OPTIONS <list of special compile options for the test>665# LINK_LIBRARIES <list of linking libraries for this target>666# LOADER_ARGS <list of special args to loaders (like the GPU loader)>667# )668function(add_libc_hermetic test_name)669 if(NOT TARGET libc.startup.${LIBC_TARGET_OS}.crt1)670 message(VERBOSE "Skipping ${fq_target_name} as it is not available on ${LIBC_TARGET_OS}.")671 return()672 endif()673 cmake_parse_arguments(674 "HERMETIC_TEST"675 "IS_GPU_BENCHMARK;NO_RUN_POSTBUILD" # Optional arguments676 "SUITE;CXX_STANDARD" # Single value arguments677 "SRCS;HDRS;DEPENDS;ARGS;ENV;COMPILE_OPTIONS;LINK_LIBRARIES;LOADER_ARGS" # Multi-value arguments678 ${ARGN}679 )680 681 if(NOT HERMETIC_TEST_SUITE)682 message(FATAL_ERROR "SUITE not specified for ${fq_target_name}")683 endif()684 if(NOT HERMETIC_TEST_SRCS)685 message(FATAL_ERROR "The SRCS list for add_integration_test is missing.")686 endif()687 688 get_fq_target_name(${test_name} fq_target_name)689 get_fq_target_name(${test_name}.libc fq_libc_target_name)690 691 get_fq_deps_list(fq_deps_list ${HERMETIC_TEST_DEPENDS})692 list(APPEND fq_deps_list693 # Hermetic tests use the platform's startup object. So, their deps also694 # have to be collected.695 libc.startup.${LIBC_TARGET_OS}.crt1696 # We always add the memory functions objects. This is because the697 # compiler's codegen can emit calls to the C memory functions.698 libc.src.__support.StringUtil.error_to_string699 libc.src.string.memcmp700 libc.src.string.memcpy701 libc.src.string.memmove702 libc.src.string.memset703 libc.src.strings.bcmp704 libc.src.strings.bzero705 )706 707 if(libc.src.compiler.__stack_chk_fail IN_LIST TARGET_LLVMLIBC_ENTRYPOINTS)708 # __stack_chk_fail should always be included if supported to allow building709 # libc with the stack protector enabled.710 list(APPEND fq_deps_list libc.src.compiler.__stack_chk_fail)711 endif()712 713 if(libc.src.time.clock IN_LIST TARGET_LLVMLIBC_ENTRYPOINTS)714 # We will link in the 'clock' implementation if it exists for test timing.715 list(APPEND fq_deps_list libc.src.time.clock)716 endif()717 718 list(REMOVE_DUPLICATES fq_deps_list)719 720 # TODO: Instead of gathering internal object files from entrypoints,721 # collect the object files with public names of entrypoints.722 get_object_files_for_test(723 link_object_files skipped_entrypoints_list ${fq_deps_list})724 if(skipped_entrypoints_list)725 if(LIBC_CMAKE_VERBOSE_LOGGING)726 set(msg "Skipping hermetic test ${fq_target_name} as it has missing deps: "727 "${skipped_entrypoints_list}.")728 message(STATUS ${msg})729 endif()730 return()731 endif()732 list(REMOVE_DUPLICATES link_object_files)733 734 # Make a library of all deps735 add_library(736 ${fq_target_name}.__libc__737 STATIC738 EXCLUDE_FROM_ALL739 ${link_object_files}740 )741 set_target_properties(${fq_target_name}.__libc__742 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})743 set_target_properties(${fq_target_name}.__libc__744 PROPERTIES ARCHIVE_OUTPUT_NAME ${fq_target_name}.libc)745 746 if(HERMETIC_TEST_NO_RUN_POSTBUILD)747 set(fq_build_target_name ${fq_target_name})748 else()749 set(fq_build_target_name ${fq_target_name}.__build__)750 endif()751 752 add_executable(753 ${fq_build_target_name}754 EXCLUDE_FROM_ALL755 ${HERMETIC_TEST_SRCS}756 ${HERMETIC_TEST_HDRS}757 )758 759 if(NOT HERMETIC_TEST_CXX_STANDARD)760 set(HERMETIC_TEST_CXX_STANDARD ${CMAKE_CXX_STANDARD})761 endif()762 set_target_properties(${fq_build_target_name}763 PROPERTIES764 RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}765 CXX_STANDARD ${HERMETIC_TEST_CXX_STANDARD}766 )767 768 target_include_directories(${fq_build_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})769 target_include_directories(${fq_build_target_name} PRIVATE ${LIBC_SOURCE_DIR})770 _get_hermetic_test_compile_options(compile_options "")771 target_compile_options(${fq_build_target_name} PRIVATE772 ${compile_options}773 ${HERMETIC_TEST_COMPILE_OPTIONS})774 775 set(link_libraries "")776 set(compiler_runtime "")777 foreach(lib IN LISTS HERMETIC_TEST_LINK_LIBRARIES)778 if(TARGET ${lib}.hermetic)779 list(APPEND link_libraries ${lib}.hermetic)780 else()781 list(APPEND link_libraries ${lib})782 endif()783 endforeach()784 785 if(LIBC_TARGET_ARCHITECTURE_IS_AMDGPU)786 target_link_options(${fq_build_target_name} PRIVATE787 ${LIBC_COMPILE_OPTIONS_DEFAULT} -Wno-multi-gpu788 -mcpu=${LIBC_GPU_TARGET_ARCHITECTURE} -flto789 "-Wl,-mllvm,-amdgpu-lower-global-ctor-dtor=0" -nostdlib -static790 "-Wl,-mllvm,-amdhsa-code-object-version=${LIBC_GPU_CODE_OBJECT_VERSION}")791 elseif(LIBC_TARGET_ARCHITECTURE_IS_NVPTX)792 target_link_options(${fq_build_target_name} PRIVATE793 ${LIBC_COMPILE_OPTIONS_DEFAULT} -Wno-multi-gpu794 "-Wl,--suppress-stack-size-warning"795 "-Wl,-mllvm,-nvptx-emit-init-fini-kernel"796 -march=${LIBC_GPU_TARGET_ARCHITECTURE} -nostdlib -static797 "--cuda-path=${LIBC_CUDA_ROOT}")798 elseif(LIBC_CC_SUPPORTS_NOSTDLIBPP)799 set(link_options800 -nolibc801 -nostartfiles802 -nostdlib++803 -static804 ${LIBC_LINK_OPTIONS_DEFAULT}805 ${LIBC_TEST_LINK_OPTIONS_DEFAULT}806 )807 target_link_options(${fq_build_target_name} PRIVATE ${link_options})808 else()809 # Older version of gcc does not support `nostdlib++` flag. We use810 # `nostdlib` and link against libgcc_s, which cannot be linked statically.811 set(link_options812 -nolibc813 -nostartfiles814 -nostdlib815 ${LIBC_LINK_OPTIONS_DEFAULT}816 ${LIBC_TEST_LINK_OPTIONS_DEFAULT}817 )818 target_link_options(${fq_build_target_name} PRIVATE ${link_options})819 list(APPEND compiler_runtime ${LIBGCC_S_LOCATION})820 endif()821 target_link_libraries(822 ${fq_build_target_name}823 PRIVATE824 libc.startup.${LIBC_TARGET_OS}.crt1825 ${link_libraries}826 LibcHermeticTestSupport.hermetic827 ${fq_target_name}.__libc__828 ${compiler_runtime}829 )830 add_dependencies(${fq_build_target_name}831 LibcTest.hermetic832 libc.test.UnitTest.ErrnoSetterMatcher833 ${fq_deps_list})834 # TODO: currently the dependency chain is broken such that getauxval cannot properly835 # propagate to hermetic tests. This is a temporary workaround.836 if (LIBC_TARGET_ARCHITECTURE_IS_AARCH64 AND NOT(LIBC_TARGET_OS_IS_BAREMETAL))837 target_link_libraries(838 ${fq_build_target_name}839 PRIVATE840 libc.src.sys.auxv.getauxval841 )842 endif()843 844 # Tests on the GPU require an external loader utility to launch the kernel.845 if(TARGET libc.utils.gpu.loader)846 add_dependencies(${fq_build_target_name} libc.utils.gpu.loader)847 get_target_property(gpu_loader_exe libc.utils.gpu.loader "EXECUTABLE")848 endif()849 850 if(NOT HERMETIC_TEST_NO_RUN_POSTBUILD)851 if (LIBC_TEST_CMD)852 # In the form of "<command> binary=@BINARY@", e.g. "qemu-system-arm -loader$<COMMA>file=@BINARY@"853 string(REPLACE "@BINARY@" "$<TARGET_FILE:${fq_build_target_name}>" test_cmd_parsed ${LIBC_TEST_CMD})854 string(REPLACE " " ";" test_cmd "${test_cmd_parsed}")855 else()856 set(test_cmd ${HERMETIC_TEST_ENV}857 $<$<BOOL:${LIBC_TARGET_OS_IS_GPU}>:${gpu_loader_exe}> ${CMAKE_CROSSCOMPILING_EMULATOR} ${HERMETIC_TEST_LOADER_ARGS}858 $<TARGET_FILE:${fq_build_target_name}> ${HERMETIC_TEST_ARGS})859 endif()860 861 add_custom_target(862 ${fq_target_name}863 DEPENDS ${fq_target_name}.__cmd__864 )865 866 add_custom_command(867 OUTPUT ${fq_target_name}.__cmd__868 COMMAND ${test_cmd}869 COMMAND_EXPAND_LISTS870 COMMENT "Running hermetic test ${fq_target_name}"871 ${LIBC_HERMETIC_TEST_JOB_POOL}872 )873 874 set_source_files_properties(${fq_target_name}.__cmd__875 PROPERTIES876 SYMBOLIC "TRUE"877 )878 endif()879 880 add_dependencies(${HERMETIC_TEST_SUITE} ${fq_target_name})881 if(NOT ${HERMETIC_TEST_IS_GPU_BENCHMARK})882 # If it is a benchmark, it will already have been added to the883 # gpu-benchmark target884 add_dependencies(libc-hermetic-tests ${fq_target_name})885 endif()886endfunction(add_libc_hermetic)887 888# A convenience function to add both a unit test as well as a hermetic test.889function(add_libc_test test_name)890 cmake_parse_arguments(891 "LIBC_TEST"892 "UNIT_TEST_ONLY;HERMETIC_TEST_ONLY" # Optional arguments893 "" # Single value arguments894 "" # Multi-value arguments895 ${ARGN}896 )897 if(LIBC_ENABLE_UNITTESTS AND NOT LIBC_TEST_HERMETIC_TEST_ONLY)898 add_libc_unittest(${test_name}.__unit__ ${LIBC_TEST_UNPARSED_ARGUMENTS})899 endif()900 if(LIBC_ENABLE_HERMETIC_TESTS AND NOT LIBC_TEST_UNIT_TEST_ONLY)901 add_libc_hermetic(902 ${test_name}.__hermetic__903 LINK_LIBRARIES904 LibcTest.hermetic905 ${LIBC_TEST_UNPARSED_ARGUMENTS}906 )907 get_fq_target_name(${test_name} fq_test_name)908 if(TARGET ${fq_test_name}.__hermetic__ AND TARGET ${fq_test_name}.__unit__)909 # Tests like the file tests perform file operations on disk file. If we910 # don't chain up the unit test and hermetic test, then those tests will911 # step on each other's files.912 if(NOT LIBC_TEST_HERMETIC_ONLY)913 add_dependencies(${fq_test_name}.__hermetic__ ${fq_test_name}.__unit__)914 endif()915 endif()916 endif()917endfunction(add_libc_test)918 919# Tests all implementations that can run on the target CPU.920function(add_libc_multi_impl_test name suite)921 get_property(fq_implementations GLOBAL PROPERTY ${name}_implementations)922 foreach(fq_config_name IN LISTS fq_implementations)923 get_target_property(required_cpu_features ${fq_config_name} REQUIRE_CPU_FEATURES)924 cpu_supports(can_run "${required_cpu_features}")925 if(can_run)926 string(FIND ${fq_config_name} "." last_dot_loc REVERSE)927 math(EXPR name_loc "${last_dot_loc} + 1")928 string(SUBSTRING ${fq_config_name} ${name_loc} -1 target_name)929 add_libc_test(930 ${target_name}_test931 SUITE932 ${suite}933 COMPILE_OPTIONS934 ${LIBC_COMPILE_OPTIONS_NATIVE}935 LINK_LIBRARIES936 LibcMemoryHelpers937 ${ARGN}938 DEPENDS939 ${fq_config_name}940 libc.src.__support.macros.sanitizer941 )942 get_fq_target_name(${fq_config_name}_test fq_target_name)943 else()944 message(STATUS "Skipping test for '${fq_config_name}' insufficient host cpu features '${required_cpu_features}'")945 endif()946 endforeach()947endfunction()948