diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -75,11 +75,15 @@ option(LIBC_GPU_BUILD "Build libc for the GPU. All CPU build options will be ignored." OFF) set(LIBC_TARGET_TRIPLE "" CACHE STRING "The target triple for the libc build.") +set(LIBC_ENABLE_UNITTESTS ON) +set(LIBC_ENABLE_HERMETIC_TESTS ON) + # Defines LIBC_TARGET_ARCHITECTURE and associated macros. include(LLVMLibCArchitectures) if(LIBC_TARGET_ARCHITECTURE_IS_GPU) include(prepare_libc_gpu_build) + set(LIBC_ENABLE_UNITTESTS OFF) endif() include(LLVMLibCCheckMPFR) diff --git a/libc/cmake/modules/LLVMLibCTestRules.cmake b/libc/cmake/modules/LLVMLibCTestRules.cmake --- a/libc/cmake/modules/LLVMLibCTestRules.cmake +++ b/libc/cmake/modules/LLVMLibCTestRules.cmake @@ -77,7 +77,7 @@ cmake_parse_arguments( "LIBC_UNITTEST" - "NO_RUN_POSTBUILD;NO_LIBC_UNITTEST_TEST_MAIN" # Optional arguments + "NO_RUN_POSTBUILD" # Optional arguments "SUITE;CXX_STANDARD" # Single value arguments "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS;LINK_LIBRARIES;FLAGS" # Multi-value arguments ${ARGN} @@ -179,11 +179,7 @@ ) # LibcUnitTest should not depend on anything in LINK_LIBRARIES. - if(NO_LIBC_UNITTEST_TEST_MAIN) - list(APPEND link_libraries LibcUnitTest) - else() - list(APPEND link_libraries LibcUnitTest LibcUnitTestMain) - endif() + list(APPEND link_libraries LibcTestMain LibcUnitTest) target_link_libraries(${fq_build_target_name} PRIVATE ${link_libraries}) @@ -386,6 +382,8 @@ endfunction(add_libc_fuzzer) +# DEPRECATED: Use add_hermetic_test instead. +# # Rule to add an integration test. An integration test is like a unit test # but does not use the system libc. Not even the startup objects from the # system libc are linked in to the final executable. The final exe is fully @@ -544,3 +542,158 @@ ) add_dependencies(${INTEGRATION_TEST_SUITE} ${fq_target_name}) endfunction(add_integration_test) + +set(LIBC_HERMETIC_TEST_COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_DEFAULT} + -fpie -ffreestanding -fno-exceptions -fno-rtti) +# The GPU build requires overriding the default CMake triple and architecture. +if(LIBC_GPU_TARGET_ARCHITECTURE_IS_AMDGPU) + list(APPEND LIBC_HERMETIC_TEST_COMPILE_OPTIONS + -mcpu=${LIBC_GPU_TARGET_ARCHITECTURE} -flto --target=${LIBC_GPU_TARGET_TRIPLE}) +elseif(LIBC_GPU_TARGET_ARCHITECTURE_IS_NVPTX) + get_nvptx_compile_options(nvptx_options ${LIBC_GPU_TARGET_ARCHITECTURE}) + list(APPEND ${nvptx_options} --target=${LIBC_GPU_TARGET_TRIPLE}) +endif() + +# Rule to add a hermetic test. A hermetic test is one whose executable is fully +# statically linked and consists of pieces drawn only from LLVM's libc. Nothing, +# including the startup objects, come from the system libc. +# +# Usage: +# add_libc_hermetic_test( +# +# SUITE +# SRCS [src2.cpp ...] +# HDRS [hdr1.cpp ...] +# DEPENDS +# ARGS +# ENV +# COMPILE_OPTIONS +# LOADER_ARGS +# ) +function(add_libc_hermetic_test test_name) + if(NOT TARGET libc.startup.${LIBC_TARGET_OS}.crt1) + message(VERBOSE "Skipping ${fq_target_name} as it is not available on ${LIBC_TARGET_OS}.") + return() + endif() + cmake_parse_arguments( + "HERMETIC_TEST" + "" # No optional arguments + "SUITE" # Single value arguments + "SRCS;HDRS;DEPENDS;ARGS;ENV;COMPILE_OPTIONS;LOADER_ARGS" # Multi-value arguments + ${ARGN} + ) + + if(NOT HERMETIC_TEST_SUITE) + message(FATAL_ERROR "SUITE not specified for ${fq_target_name}") + endif() + if(NOT HERMETIC_TEST_SRCS) + message(FATAL_ERROR "The SRCS list for add_integration_test is missing.") + endif() + + get_fq_target_name(${test_name} fq_target_name) + get_fq_target_name(${test_name}.libc fq_libc_target_name) + + get_fq_deps_list(fq_deps_list ${HERMETIC_TEST_DEPENDS}) + list(APPEND fq_deps_list + # Hermetic tests use the platform's startup object. So, their deps also + # have to be collected. + libc.startup.${LIBC_TARGET_OS}.crt1 + # We always add the memory functions objects. This is because the + # compiler's codegen can emit calls to the C memory functions. + libc.src.string.bcmp + libc.src.string.bzero + libc.src.string.memcmp + libc.src.string.memcpy + libc.src.string.memmove + libc.src.string.memset + ) + list(REMOVE_DUPLICATES fq_deps_list) + + # TODO: Instead of gathering internal object files from entrypoints, + # collect the object files with public names of entrypoints. + get_object_files_for_test( + link_object_files skipped_entrypoints_list ${fq_deps_list}) + if(skipped_entrypoints_list) + set(msg "Skipping unittest ${fq_target_name} as it has missing deps: " + "${skipped_entrypoints_list}.") + message(STATUS ${msg}) + return() + endif() + list(REMOVE_DUPLICATES link_object_files) + + # Make a library of all deps + add_library( + ${fq_target_name}.__libc__ + STATIC + EXCLUDE_FROM_ALL + ${link_object_files} + ) + set_target_properties(${fq_target_name}.__libc__ + PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + set_target_properties(${fq_target_name}.__libc__ + PROPERTIES ARCHIVE_OUTPUT_NAME ${fq_target_name}.libc) + + set(fq_build_target_name ${fq_target_name}.__build__) + add_executable( + ${fq_build_target_name} + EXCLUDE_FROM_ALL + # The NVIDIA 'nvlink' linker does not currently support static libraries. + $<$:${link_object_files}> + ${HERMETIC_TEST_SRCS} + ${HERMETIC_TEST_HDRS} + ) + set_target_properties(${fq_build_target_name} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + #OUTPUT_NAME ${fq_target_name} + ) + target_include_directories( + ${fq_build_target_name} + PRIVATE + ${LIBC_SOURCE_DIR} + ${LIBC_BUILD_DIR} + ${LIBC_BUILD_DIR}/include + ) + target_compile_options(${fq_build_target_name} + PRIVATE ${LIBC_HERMETIC_TEST_COMPILE_OPTIONS} ${HERMETIC_TEST_COMPILE_OPTIONS}) + + target_link_options(${fq_build_target_name} PRIVATE -nostdlib -static) + target_link_libraries( + ${fq_build_target_name} + libc.startup.${LIBC_TARGET_OS}.crt1 + LibcTestMain LibcHermeticTest + # The NVIDIA 'nvlink' linker does not currently support static libraries. + $<$>:${fq_target_name}.__libc__>) + add_dependencies(${fq_build_target_name} + LibcHermeticTest + ${HERMETIC_TEST_DEPENDS}) + + # Tests on the GPU require an external loader utility to launch the kernel. + if(TARGET libc.utils.gpu.loader) + add_dependencies(${fq_build_target_name} libc.utils.gpu.loader) + get_target_property(gpu_loader_exe libc.utils.gpu.loader "EXECUTABLE") + endif() + + set(test_cmd ${HERMETIC_TEST_ENV} + $<$:${gpu_loader_exe}> ${HERMETIC_TEST_LOADER_ARGS} + $ ${HERMETIC_TEST_ARGS}) + add_custom_target( + ${fq_target_name} + COMMAND ${test_cmd} + COMMAND_EXPAND_LISTS + COMMENT "Running hermetic test ${fq_target_name}" + ) + + add_dependencies(${HERMETIC_TEST_SUITE} ${fq_target_name}) + add_dependencies(libc-hermetic-tests ${fq_target_name}) +endfunction(add_libc_hermetic_test) + +# A convenience function to add both a unit test as well as a hermetic test. +function(add_libc_test test_name) + if(LIBC_ENABLE_UNITTESTS) + add_libc_unittest(${test_name}.__unit__ ${ARGN}) + endif() + if(LIBC_ENABLE_HERMETIC_TESTS) + add_libc_hermetic_test(${test_name}.__hermetic__ ${ARGN}) + endif() +endfunction(add_libc_test) diff --git a/libc/test/CMakeLists.txt b/libc/test/CMakeLists.txt --- a/libc/test/CMakeLists.txt +++ b/libc/test/CMakeLists.txt @@ -1,6 +1,7 @@ add_custom_target(check-libc) add_custom_target(libc-unit-tests) -add_dependencies(check-libc libc-unit-tests) +add_custom_target(libc-hermetic-tests) +add_dependencies(check-libc libc-unit-tests libc-hermetic-tests) add_custom_target(exhaustive-check-libc) add_custom_target(libc-long-running-tests) diff --git a/libc/test/UnitTest/CMakeLists.txt b/libc/test/UnitTest/CMakeLists.txt --- a/libc/test/UnitTest/CMakeLists.txt +++ b/libc/test/UnitTest/CMakeLists.txt @@ -1,5 +1,4 @@ -set(libc_unit_test_srcs - ExecuteFunction.h +set(libc_test_srcs_common Test.h LibcTest.cpp LibcTest.h @@ -7,32 +6,47 @@ TestLogger.h ) +set(libc_death_test_srcs ExecuteFunction.h) if(${LIBC_TARGET_OS} STREQUAL "linux") - list(APPEND libc_unit_test_srcs ExecuteFunctionUnix.cpp) + list(APPEND libc_death_test_srcs + LibcDeathTestExecutors.cpp ExecuteFunctionUnix.cpp) endif() add_library( LibcUnitTest - ${libc_unit_test_srcs} + ${libc_test_srcs_common} + ${libc_death_test_srcs} ) -target_include_directories(LibcUnitTest PUBLIC ${LIBC_SOURCE_DIR}) -add_dependencies( - LibcUnitTest - libc.src.__support.CPP.string - libc.src.__support.CPP.string_view - libc.src.__support.CPP.type_traits - libc.src.__support.OSUtil.osutil - libc.src.__support.uint128) +add_library( + LibcHermeticTest + ${libc_test_srcs_common} + HermeticTestUtils.cpp +) + +foreach(lib LibcUnitTest LibcHermeticTest) + target_include_directories(${lib} PUBLIC ${LIBC_SOURCE_DIR}) + target_compile_options(${lib} PRIVATE ${LIBC_HERMETIC_TEST_COMPILE_OPTIONS} + -fno-exceptions -fno-rtti) + add_dependencies(${lib} + libc.src.__support.CPP.string + libc.src.__support.CPP.string_view + libc.src.__support.CPP.type_traits + libc.src.__support.OSUtil.osutil + libc.src.__support.uint128 + ) +endforeach() + +target_compile_options(LibcHermeticTest PRIVATE -ffreestanding -nostdlib -nostdlib++) add_library( - LibcUnitTestMain + LibcTestMain LibcTestMain.cpp ) -target_include_directories(LibcUnitTestMain PUBLIC ${LIBC_SOURCE_DIR}) -add_dependencies(LibcUnitTestMain LibcUnitTest) -target_link_libraries(LibcUnitTestMain PUBLIC LibcUnitTest) +target_include_directories(LibcTestMain PUBLIC ${LIBC_SOURCE_DIR}) +target_compile_options(LibcTestMain PRIVATE -fno-exceptions -fno-rtti) +add_dependencies(LibcTestMain LibcUnitTest) add_header_library( string_utils diff --git a/libc/test/UnitTest/HermeticTestUtils.cpp b/libc/test/UnitTest/HermeticTestUtils.cpp new file mode 100644 --- /dev/null +++ b/libc/test/UnitTest/HermeticTestUtils.cpp @@ -0,0 +1,91 @@ +//===-- Implementation of libc death test executors -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include +#include + +namespace __llvm_libc { + +int bcmp(const void *lhs, const void *rhs, size_t count); +void bzero(void *ptr, size_t count); +int memcmp(const void *lhs, const void *rhs, size_t count); +void *memcpy(void *__restrict, const void *__restrict, size_t); +void *memmove(void *dst, const void *src, size_t count); +void *memset(void *ptr, int value, size_t count); + +} // namespace __llvm_libc + +namespace { + +// Integration tests cannot use the SCUDO standalone allocator as SCUDO pulls +// various other parts of the libc. Since SCUDO development does not use +// LLVM libc build rules, it is very hard to keep track or pull all that SCUDO +// requires. Hence, as a work around for this problem, we use a simple allocator +// which just hands out continuous blocks from a statically allocated chunk of +// memory. +static uint8_t memory[16384]; +static uint8_t *ptr = memory; + +} // anonymous namespace + +extern "C" { + +// Hermetic tests rely on the following memory functions. This is because the +// compiler code generation can emit calls to them. We want to map the external +// entrypoint to the internal implementation of the function used for testing. +// This is done manually as not all targets support aliases. + +int bcmp(const void *lhs, const void *rhs, size_t count) { + return __llvm_libc::bcmp(lhs, rhs, count); +} +void bzero(void *ptr, size_t count) { __llvm_libc::bzero(ptr, count); } +int memcmp(const void *lhs, const void *rhs, size_t count) { + return __llvm_libc::memcmp(lhs, rhs, count); +} +void *memcpy(void *__restrict dst, const void *__restrict src, size_t count) { + return __llvm_libc::memcpy(dst, src, count); +} +void *memmove(void *dst, const void *src, size_t count) { + return __llvm_libc::memmove(dst, src, count); +} +void *memset(void *ptr, int value, size_t count) { + return __llvm_libc::memset(ptr, value, count); +} + +void *malloc(size_t s) { + void *mem = ptr; + ptr += s; + return mem; +} + +void free(void *) {} + +void *realloc(void *ptr, size_t s) { + free(ptr); + return malloc(s); +} + +// The unit test framework uses pure virtual functions. Since hermetic tests +// cannot depend C++ runtime libraries, implement dummy functions to support +// the virtual function runtime. +void __cxa_pure_virtual() { + // A pure virtual being called is an error so we just trap. + __builtin_trap(); +} + +// Integration tests are linked with -nostdlib. BFD linker expects +// __dso_handle when -nostdlib is used. +void *__dso_handle = nullptr; + +} // extern "C" + +void operator delete(void *) { + // The libc runtime should not use the global delete operator. Hence, + // we just trap here to catch any such accidental usages. + __builtin_trap(); +} diff --git a/libc/test/UnitTest/LibcDeathTestExecutors.cpp b/libc/test/UnitTest/LibcDeathTestExecutors.cpp new file mode 100644 --- /dev/null +++ b/libc/test/UnitTest/LibcDeathTestExecutors.cpp @@ -0,0 +1,102 @@ +//===-- Implementation of libc death test executors -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "LibcTest.h" + +#include "test/UnitTest/ExecuteFunction.h" +#include "test/UnitTest/TestLogger.h" + +#include + +namespace __llvm_libc { +namespace testing { + +bool Test::testProcessKilled(testutils::FunctionCaller *Func, int Signal, + const char *LHSStr, const char *RHSStr, + const char *File, unsigned long Line) { + testutils::ProcessStatus Result = testutils::invoke_in_subprocess(Func, 500); + + if (const char *error = Result.get_error()) { + Ctx->markFail(); + tlog << File << ":" << Line << ": FAILURE\n" << error << '\n'; + return false; + } + + if (Result.timed_out()) { + Ctx->markFail(); + tlog << File << ":" << Line << ": FAILURE\n" + << "Process timed out after " << 500 << " milliseconds.\n"; + return false; + } + + if (Result.exited_normally()) { + Ctx->markFail(); + tlog << File << ":" << Line << ": FAILURE\n" + << "Expected " << LHSStr + << " to be killed by a signal\nBut it exited normally!\n"; + return false; + } + + int KilledBy = Result.get_fatal_signal(); + assert(KilledBy != 0 && "Not killed by any signal"); + if (Signal == -1 || KilledBy == Signal) + return true; + + using testutils::signal_as_string; + Ctx->markFail(); + tlog << File << ":" << Line << ": FAILURE\n" + << " Expected: " << LHSStr << '\n' + << "To be killed by signal: " << Signal << '\n' + << " Which is: " << signal_as_string(Signal) << '\n' + << " But it was killed by: " << KilledBy << '\n' + << " Which is: " << signal_as_string(KilledBy) << '\n'; + return false; +} + +bool Test::testProcessExits(testutils::FunctionCaller *Func, int ExitCode, + const char *LHSStr, const char *RHSStr, + const char *File, unsigned long Line) { + testutils::ProcessStatus Result = testutils::invoke_in_subprocess(Func, 500); + + if (const char *error = Result.get_error()) { + Ctx->markFail(); + tlog << File << ":" << Line << ": FAILURE\n" << error << '\n'; + return false; + } + + if (Result.timed_out()) { + Ctx->markFail(); + tlog << File << ":" << Line << ": FAILURE\n" + << "Process timed out after " << 500 << " milliseconds.\n"; + return false; + } + + if (!Result.exited_normally()) { + Ctx->markFail(); + tlog << File << ":" << Line << ": FAILURE\n" + << "Expected " << LHSStr << '\n' + << "to exit with exit code " << ExitCode << '\n' + << "But it exited abnormally!\n"; + return false; + } + + int ActualExit = Result.get_exit_code(); + if (ActualExit == ExitCode) + return true; + + Ctx->markFail(); + tlog << File << ":" << Line << ": FAILURE\n" + << "Expected exit code of: " << LHSStr << '\n' + << " Which is: " << ActualExit << '\n' + << " To be equal to: " << RHSStr << '\n' + << " Which is: " << ExitCode << '\n'; + return false; +} + +} // namespace testing +} // namespace __llvm_libc diff --git a/libc/test/UnitTest/LibcTest.h b/libc/test/UnitTest/LibcTest.h --- a/libc/test/UnitTest/LibcTest.h +++ b/libc/test/UnitTest/LibcTest.h @@ -23,8 +23,6 @@ namespace __llvm_libc { namespace testing { -class RunContext; - // Only the following conditions are supported. Notice that we do not have // a TRUE or FALSE condition. That is because, C library funtions do not // return boolean values, but use integral return values to indicate true or @@ -42,6 +40,18 @@ namespace internal { +class RunContext { +public: + enum RunResult { Result_Pass = 1, Result_Fail = 2 }; + + RunResult status() const { return Status; } + + void markFail() { Status = Result_Fail; } + +private: + RunResult Status = Result_Pass; +}; + template bool test(RunContext *Ctx, TestCondition Cond, ValType LHS, ValType RHS, const char *LHSStr, const char *RHSStr, const char *File, @@ -65,9 +75,9 @@ class Test { private: Test *Next = nullptr; - RunContext *Ctx = nullptr; + internal::RunContext *Ctx = nullptr; - void setContext(RunContext *C) { Ctx = C; } + void setContext(internal::RunContext *C) { Ctx = C; } public: virtual ~Test() {} @@ -161,6 +171,10 @@ static Test *End; }; +extern int argc; +extern char **argv; +extern char **envp; + namespace internal { constexpr bool same_prefix(char const *lhs, char const *rhs, int const len) { diff --git a/libc/test/UnitTest/LibcTest.cpp b/libc/test/UnitTest/LibcTest.cpp --- a/libc/test/UnitTest/LibcTest.cpp +++ b/libc/test/UnitTest/LibcTest.cpp @@ -11,28 +11,11 @@ #include "src/__support/CPP/string.h" #include "src/__support/CPP/string_view.h" #include "src/__support/UInt128.h" -#include "test/UnitTest/ExecuteFunction.h" #include "test/UnitTest/TestLogger.h" -#include namespace __llvm_libc { namespace testing { -// This need not be a class as all it has is a single read-write state variable. -// But, we make it class as then its implementation can be hidden from the -// header file. -class RunContext { -public: - enum RunResult { Result_Pass = 1, Result_Fail = 2 }; - - RunResult status() const { return Status; } - - void markFail() { Status = Result_Fail; } - -private: - RunResult Status = Result_Pass; -}; - namespace internal { // When the value is UInt128 or __uint128_t, show its hexadecimal digits. @@ -149,6 +132,12 @@ Test *Test::Start = nullptr; Test *Test::End = nullptr; +int argc = 0; +char **argv = nullptr; +char **envp = nullptr; + +using internal::RunContext; + void Test::addTest(Test *T) { if (End == nullptr) { Start = T; @@ -326,90 +315,5 @@ return false; } -#ifdef ENABLE_SUBPROCESS_TESTS - -bool Test::testProcessKilled(testutils::FunctionCaller *Func, int Signal, - const char *LHSStr, const char *RHSStr, - const char *File, unsigned long Line) { - testutils::ProcessStatus Result = testutils::invoke_in_subprocess(Func, 500); - - if (const char *error = Result.get_error()) { - Ctx->markFail(); - tlog << File << ":" << Line << ": FAILURE\n" << error << '\n'; - return false; - } - - if (Result.timed_out()) { - Ctx->markFail(); - tlog << File << ":" << Line << ": FAILURE\n" - << "Process timed out after " << 500 << " milliseconds.\n"; - return false; - } - - if (Result.exited_normally()) { - Ctx->markFail(); - tlog << File << ":" << Line << ": FAILURE\n" - << "Expected " << LHSStr - << " to be killed by a signal\nBut it exited normally!\n"; - return false; - } - - int KilledBy = Result.get_fatal_signal(); - assert(KilledBy != 0 && "Not killed by any signal"); - if (Signal == -1 || KilledBy == Signal) - return true; - - using testutils::signal_as_string; - Ctx->markFail(); - tlog << File << ":" << Line << ": FAILURE\n" - << " Expected: " << LHSStr << '\n' - << "To be killed by signal: " << Signal << '\n' - << " Which is: " << signal_as_string(Signal) << '\n' - << " But it was killed by: " << KilledBy << '\n' - << " Which is: " << signal_as_string(KilledBy) << '\n'; - return false; -} - -bool Test::testProcessExits(testutils::FunctionCaller *Func, int ExitCode, - const char *LHSStr, const char *RHSStr, - const char *File, unsigned long Line) { - testutils::ProcessStatus Result = testutils::invoke_in_subprocess(Func, 500); - - if (const char *error = Result.get_error()) { - Ctx->markFail(); - tlog << File << ":" << Line << ": FAILURE\n" << error << '\n'; - return false; - } - - if (Result.timed_out()) { - Ctx->markFail(); - tlog << File << ":" << Line << ": FAILURE\n" - << "Process timed out after " << 500 << " milliseconds.\n"; - return false; - } - - if (!Result.exited_normally()) { - Ctx->markFail(); - tlog << File << ":" << Line << ": FAILURE\n" - << "Expected " << LHSStr << '\n' - << "to exit with exit code " << ExitCode << '\n' - << "But it exited abnormally!\n"; - return false; - } - - int ActualExit = Result.get_exit_code(); - if (ActualExit == ExitCode) - return true; - - Ctx->markFail(); - tlog << File << ":" << Line << ": FAILURE\n" - << "Expected exit code of: " << LHSStr << '\n' - << " Which is: " << ActualExit << '\n' - << " To be equal to: " << RHSStr << '\n' - << " Which is: " << ExitCode << '\n'; - return false; -} - -#endif // ENABLE_SUBPROCESS_TESTS } // namespace testing } // namespace __llvm_libc diff --git a/libc/test/UnitTest/LibcTestMain.cpp b/libc/test/UnitTest/LibcTestMain.cpp --- a/libc/test/UnitTest/LibcTestMain.cpp +++ b/libc/test/UnitTest/LibcTestMain.cpp @@ -12,7 +12,11 @@ return argc > 1 ? argv[1] : nullptr; } -int main(int argc, char *argv[]) { +extern "C" int main(int argc, char **argv, char **envp) { + __llvm_libc::testing::argc = argc; + __llvm_libc::testing::argv = argv; + __llvm_libc::testing::envp = envp; + const char *TestFilter = getTestFilter(argc, argv); return __llvm_libc::testing::Test::runTests(TestFilter); } diff --git a/libc/test/src/ctype/CMakeLists.txt b/libc/test/src/ctype/CMakeLists.txt --- a/libc/test/src/ctype/CMakeLists.txt +++ b/libc/test/src/ctype/CMakeLists.txt @@ -1,159 +1,159 @@ -add_custom_target(libc_ctype_unittests) +add_custom_target(libc-ctype-tests) -add_libc_unittest( +add_libc_test( isalnum_test SUITE - libc_ctype_unittests + libc-ctype-tests SRCS isalnum_test.cpp DEPENDS libc.src.ctype.isalnum ) -add_libc_unittest( +add_libc_test( isalpha_test SUITE - libc_ctype_unittests + libc-ctype-tests SRCS isalpha_test.cpp DEPENDS libc.src.ctype.isalpha ) -add_libc_unittest( +add_libc_test( isascii_test SUITE - libc_ctype_unittests + libc-ctype-tests SRCS isascii_test.cpp DEPENDS libc.src.ctype.isascii ) -add_libc_unittest( +add_libc_test( isblank_test SUITE - libc_ctype_unittests + libc-ctype-tests SRCS isblank_test.cpp DEPENDS libc.src.ctype.isblank ) -add_libc_unittest( +add_libc_test( iscntrl_test SUITE - libc_ctype_unittests + libc-ctype-tests SRCS iscntrl_test.cpp DEPENDS libc.src.ctype.iscntrl ) -add_libc_unittest( +add_libc_test( isdigit_test SUITE - libc_ctype_unittests + libc-ctype-tests SRCS isdigit_test.cpp DEPENDS libc.src.ctype.isdigit ) -add_libc_unittest( +add_libc_test( isgraph_test SUITE - libc_ctype_unittests + libc-ctype-tests SRCS isgraph_test.cpp DEPENDS libc.src.ctype.isgraph ) -add_libc_unittest( +add_libc_test( islower_test SUITE - libc_ctype_unittests + libc-ctype-tests SRCS islower_test.cpp DEPENDS libc.src.ctype.islower ) -add_libc_unittest( +add_libc_test( isprint_test SUITE - libc_ctype_unittests + libc-ctype-tests SRCS isprint_test.cpp DEPENDS libc.src.ctype.isprint ) -add_libc_unittest( +add_libc_test( ispunct_test SUITE - libc_ctype_unittests + libc-ctype-tests SRCS ispunct_test.cpp DEPENDS libc.src.ctype.ispunct ) -add_libc_unittest( +add_libc_test( isspace_test SUITE - libc_ctype_unittests + libc-ctype-tests SRCS isspace_test.cpp DEPENDS libc.src.ctype.isspace ) -add_libc_unittest( +add_libc_test( isupper_test SUITE - libc_ctype_unittests + libc-ctype-tests SRCS isupper_test.cpp DEPENDS libc.src.ctype.isupper ) -add_libc_unittest( +add_libc_test( isxdigit_test SUITE - libc_ctype_unittests + libc-ctype-tests SRCS isxdigit_test.cpp DEPENDS libc.src.ctype.isxdigit ) -add_libc_unittest( +add_libc_test( toascii_test SUITE - libc_ctype_unittests + libc-ctype-tests SRCS toascii_test.cpp DEPENDS libc.src.ctype.toascii ) -add_libc_unittest( +add_libc_test( tolower_test SUITE - libc_ctype_unittests + libc-ctype-tests SRCS tolower_test.cpp DEPENDS libc.src.ctype.tolower ) -add_libc_unittest( +add_libc_test( toupper_test SUITE - libc_ctype_unittests + libc-ctype-tests SRCS toupper_test.cpp DEPENDS