brintos

brintos / llvm-project-archived public Read only

0
0
Text · 34.2 KiB · 933b81b Raw
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