diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt --- a/libc/src/__support/CMakeLists.txt +++ b/libc/src/__support/CMakeLists.txt @@ -45,6 +45,15 @@ libc.src.__support.CPP.expected ) +add_header_library( + c_string + HDRS + c_string.h + DEPENDS + libc.src.__support.common + libc.src.__support.CPP.string +) + add_header_library( ctype_utils HDRS diff --git a/libc/src/__support/c_string.h b/libc/src/__support/c_string.h new file mode 100644 --- /dev/null +++ b/libc/src/__support/c_string.h @@ -0,0 +1,36 @@ +//===-- Implementation of a struct to hold a string in menory -------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_SUPPORT_C_STRING_H +#define LLVM_LIBC_SRC_SUPPORT_C_STRING_H + +#include "src/__support/CPP/string.h" +#include "src/__support/macros/attributes.h" // for LIBC_INLINE + +namespace __llvm_libc { + +// The CString class is a companion to the cpp::string class. Its use case is as +// a return value for a function that in C would return a char* and a flag for +// if that char* needs to be freed. +class CString { + cpp::string str; + +public: + // These constructors can be implemented iff required. + CString() = delete; + CString(const CString &) = delete; + CString(CString &&) = delete; + + LIBC_INLINE CString(cpp::string in_str) : str(in_str) {} + + LIBC_INLINE operator const char *() const { return str.c_str(); } +}; + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SUPPORT_C_STRING_H diff --git a/libc/src/stdio/fprintf.cpp b/libc/src/stdio/fprintf.cpp --- a/libc/src/stdio/fprintf.cpp +++ b/libc/src/stdio/fprintf.cpp @@ -8,7 +8,6 @@ #include "src/stdio/fprintf.h" -#include "src/__support/File/file.h" #include "src/__support/arg_list.h" #include "src/stdio/printf_core/vfprintf_internal.h" @@ -18,6 +17,7 @@ namespace __llvm_libc { #ifndef LIBC_COPT_PRINTF_USE_SYSTEM_FILE +#include "src/__support/File/file.h" using FileT = __llvm_libc::File; #else // defined(LIBC_COPT_PRINTF_USE_SYSTEM_FILE) using FileT = ::FILE; diff --git a/libc/test/UnitTest/BazelFilePath.cpp b/libc/test/UnitTest/BazelFilePath.cpp new file mode 100644 --- /dev/null +++ b/libc/test/UnitTest/BazelFilePath.cpp @@ -0,0 +1,25 @@ +//===-- Implementation of the file path generator for bazel ---------------===// +// +// 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 + +#include "src/__support/CPP/string.h" +#include "src/__support/c_string.h" + +namespace __llvm_libc::testing { + +CString libc_make_test_file_path_func(const char *file_name) { + // This is the path to the folder bazel wants the test outputs written to. + const char *UNDECLARED_OUTPUTS_PATH = getenv("TEST_UNDECLARED_OUTPUTS_DIR"); + + return cpp::string(UNDECLARED_OUTPUTS_PATH) + file_name; +} + +} // namespace __llvm_libc::testing 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,6 +1,7 @@ set(libc_test_srcs_common Test.h LibcTest.cpp + CmakeFilePath.cpp LibcTest.h TestLogger.cpp TestLogger.h @@ -29,6 +30,7 @@ target_compile_options(${lib} PRIVATE ${LIBC_HERMETIC_TEST_COMPILE_OPTIONS} -fno-exceptions -fno-rtti) add_dependencies(${lib} + libc.src.__support.c_string libc.src.__support.CPP.string libc.src.__support.CPP.string_view libc.src.__support.CPP.type_traits diff --git a/libc/test/UnitTest/CmakeFilePath.cpp b/libc/test/UnitTest/CmakeFilePath.cpp new file mode 100644 --- /dev/null +++ b/libc/test/UnitTest/CmakeFilePath.cpp @@ -0,0 +1,20 @@ +//===-- Implementation of the file path generator for cmake ---------------===// +// +// 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 "src/__support/CPP/string.h" +#include "src/__support/c_string.h" + +namespace __llvm_libc::testing { + +CString libc_make_test_file_path_func(const char *file_name) { + return cpp::string(file_name); +} + +} // namespace __llvm_libc::testing 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 @@ -9,14 +9,26 @@ #ifndef LLVM_LIBC_UTILS_UNITTEST_LIBCTEST_H #define LLVM_LIBC_UTILS_UNITTEST_LIBCTEST_H -// This file can only include headers from src/__support/CPP/ or -// utils/testutils. No other headers should be included. +// This is defined as a simple macro in test.h so that it exists for platforms +// that don't use our test infrastructure. It's defined as a proper function +// below. +#ifdef libc_make_test_file_path +#undef libc_make_test_file_path +#endif // libc_make_test_file_path + +// This is defined as a macro here to avoid namespace issues. +#define libc_make_test_file_path(file_name) \ + (__llvm_libc::testing::libc_make_test_file_path_func(file_name)) + +// This file can only include headers from src/__support/ or test/UnitTest. No +// other headers should be included. #include "PlatformDefs.h" #include "src/__support/CPP/string.h" #include "src/__support/CPP/string_view.h" #include "src/__support/CPP/type_traits.h" +#include "src/__support/c_string.h" #include "test/UnitTest/ExecuteFunction.h" #include "test/UnitTest/TestLogger.h" @@ -259,6 +271,8 @@ // Make TypeList visible in __llvm_libc::testing. template using TypeList = internal::TypeList; +CString libc_make_test_file_path_func(const char *file_name); + } // namespace testing } // namespace __llvm_libc diff --git a/libc/test/UnitTest/Test.h b/libc/test/UnitTest/Test.h --- a/libc/test/UnitTest/Test.h +++ b/libc/test/UnitTest/Test.h @@ -9,6 +9,13 @@ #ifndef LLVM_LIBC_UTILS_UNITTEST_TEST_H #define LLVM_LIBC_UTILS_UNITTEST_TEST_H +// This macro takes a file name and returns a value implicitly castable to +// a const char*. That const char* is the path to a file with the provided name +// in a directory where the test is allowed to write. By default it writes +// directly to the filename provided, but implementations are allowed to +// redefine it as necessary. +#define libc_make_test_file_path(file_name) (file_name) + #ifdef LIBC_COPT_TEST_USE_FUCHSIA #include "FuchsiaTest.h" #elif defined(LIBC_COPT_TEST_USE_PIGWEED) diff --git a/libc/test/src/stdio/fprintf_test.cpp b/libc/test/src/stdio/fprintf_test.cpp --- a/libc/test/src/stdio/fprintf_test.cpp +++ b/libc/test/src/stdio/fprintf_test.cpp @@ -34,8 +34,10 @@ } // namespace printf_test TEST(LlvmLibcFPrintfTest, WriteToFile) { - constexpr char FILENAME[] = "testdata/fprintf_output.test"; - ::FILE *file = printf_test::fopen(FILENAME, "w"); + const char *FILENAME = "fprintf_output.test"; + auto FILE_PATH = libc_make_test_file_path(FILENAME); + + ::FILE *file = printf_test::fopen(FILE_PATH, "w"); ASSERT_FALSE(file == nullptr); int written; @@ -55,7 +57,7 @@ ASSERT_EQ(0, printf_test::fclose(file)); - file = printf_test::fopen(FILENAME, "r"); + file = printf_test::fopen(FILE_PATH, "r"); ASSERT_FALSE(file == nullptr); char data[50]; diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel --- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel @@ -20,6 +20,12 @@ licenses(["notice"]) +PRINTF_COPTS = [ + "LIBC_COPT_PRINTF_USE_SYSTEM_FILE", + "LIBC_COPT_PRINTF_DISABLE_INDEX_MODE", + "LIBC_COPT_PRINTF_DISABLE_WRITE_INT", +] + # A flag to pick which `mpfr` to use for math tests. # Usage: `--@llvm-project//libc:mpfr=`. # Flag documentation: https://bazel.build/extending/config @@ -153,6 +159,14 @@ ], ) +libc_support_library( + name = "__support_cpp_expected", + hdrs = ["src/__support/CPP/expected.h"], + deps = [ + ":libc_root", + ], +) + libc_support_library( name = "__support_cpp_functional", hdrs = ["src/__support/CPP/functional.h"], @@ -170,6 +184,16 @@ deps = [":libc_root"], ) +libc_support_library( + name = "__support_cpp_new", + srcs = ["src/__support/CPP/new.cpp"], + hdrs = ["src/__support/CPP/new.h"], + deps = [ + ":__support_common", + ":libc_root", + ], +) + libc_support_library( name = "__support_cpp_optional", hdrs = ["src/__support/CPP/optional.h"], @@ -244,6 +268,25 @@ ], ) +libc_support_library( + name = "__support_c_string", + hdrs = ["src/__support/c_string.h"], + deps = [ + ":__support_cpp_string", + ":libc_root", + ], +) + +libc_support_library( + name = "__support_error_or", + hdrs = ["src/__support/error_or.h"], + deps = [ + ":__support_common", + ":__support_cpp_expected", + ":libc_root", + ], +) + libc_support_library( name = "__support_float_to_string", hdrs = [ @@ -398,6 +441,20 @@ ], ) +libc_support_library( + name = "__support_file_file", + srcs = ["src/__support/File/file.cpp"], + hdrs = ["src/__support/File/file.h"], + deps = [ + ":__support_cpp_new", + ":__support_cpp_span", + ":__support_error_or", + ":__support_threads_mutex", + ":errno", + ":libc_root", + ], +) + libc_support_library( name = "__support_named_pair", hdrs = ["src/__support/named_pair.h"], @@ -701,6 +758,23 @@ ], ) +libc_support_library( + name = "__support_threads_mutex", + hdrs = [ + "src/__support/threads/mutex.h", + "src/__support/threads/mutex_common.h", + ], + textual_hdrs = [ + "src/__support/threads/linux/mutex.h", + "src/__support/threads/linux/futex_word.h", + ], + deps = [ + ":__support_cpp_atomic", + ":__support_osutil_syscall", + ":libc_root", + ], +) + ############################### errno targets ################################ libc_function( @@ -2080,6 +2154,7 @@ libc_support_library( name = "printf_core_structs", hdrs = ["src/stdio/printf_core/core_structs.h"], + defines = PRINTF_COPTS, deps = [ ":__support_cpp_string_view", ":__support_fputil_fp_bits", @@ -2090,6 +2165,7 @@ libc_support_library( name = "printf_config", hdrs = ["src/stdio/printf_core/printf_config.h"], + defines = PRINTF_COPTS, deps = [ ":libc_root", ], @@ -2099,6 +2175,7 @@ name = "printf_parser", srcs = ["src/stdio/printf_core/parser.cpp"], hdrs = ["src/stdio/printf_core/parser.h"], + defines = PRINTF_COPTS, deps = [ ":__support_arg_list", ":__support_common", @@ -2120,7 +2197,7 @@ name = "printf_mock_parser", srcs = ["src/stdio/printf_core/parser.cpp"], hdrs = ["src/stdio/printf_core/parser.h"], - copts = ["-DLIBC_COPT_MOCK_ARG_LIST"], + defines = PRINTF_COPTS + ["LIBC_COPT_MOCK_ARG_LIST"], deps = [ ":__support_arg_list", ":__support_common", @@ -2141,6 +2218,7 @@ name = "printf_string_writer", srcs = ["src/stdio/printf_core/string_writer.cpp"], hdrs = ["src/stdio/printf_core/string_writer.h"], + defines = PRINTF_COPTS, deps = [ ":__support_cpp_string_view", ":libc_root", @@ -2149,10 +2227,23 @@ ], ) +libc_support_library( + name = "printf_file_writer", + hdrs = ["src/stdio/printf_core/file_writer.h"], + defines = PRINTF_COPTS, + deps = [ + ":__support_cpp_string_view", + ":__support_file_file", + ":libc_root", + ":printf_core_structs", + ], +) + libc_support_library( name = "printf_writer", srcs = ["src/stdio/printf_core/writer.cpp"], hdrs = ["src/stdio/printf_core/writer.h"], + defines = PRINTF_COPTS, deps = [ ":__support_cpp_string_view", ":libc_root", @@ -2175,6 +2266,7 @@ "src/stdio/printf_core/string_converter.h", "src/stdio/printf_core/write_int_converter.h", ], + defines = PRINTF_COPTS, deps = [ ":__support_common", ":__support_cpp_limits", @@ -2197,6 +2289,7 @@ name = "printf_main", srcs = ["src/stdio/printf_core/printf_main.cpp"], hdrs = ["src/stdio/printf_core/printf_main.h"], + defines = PRINTF_COPTS, deps = [ ":__support_arg_list", ":libc_root", @@ -2211,6 +2304,7 @@ name = "sprintf", srcs = ["src/stdio/sprintf.cpp"], hdrs = ["src/stdio/sprintf.h"], + defines = PRINTF_COPTS, deps = [ ":__support_arg_list", ":errno", @@ -2224,6 +2318,7 @@ name = "snprintf", srcs = ["src/stdio/snprintf.cpp"], hdrs = ["src/stdio/snprintf.h"], + defines = PRINTF_COPTS, deps = [ ":__support_arg_list", ":errno", @@ -2232,3 +2327,41 @@ ":printf_writer", ], ) + +libc_support_library( + name = "vfprintf_internal", + hdrs = ["src/stdio/printf_core/vfprintf_internal.h"], + defines = PRINTF_COPTS, + deps = [ + ":__support_arg_list", + ":__support_file_file", + ":__support_macros_attributes", + ":printf_file_writer", + ":printf_main", + ":printf_writer", + ], +) + +libc_function( + name = "printf", + srcs = ["src/stdio/printf.cpp"], + hdrs = ["src/stdio/printf.h"], + defines = PRINTF_COPTS, + deps = [ + ":__support_arg_list", + ":errno", + ":vfprintf_internal", + ], +) + +libc_function( + name = "fprintf", + srcs = ["src/stdio/fprintf.cpp"], + hdrs = ["src/stdio/fprintf.h"], + defines = PRINTF_COPTS, + deps = [ + ":__support_arg_list", + ":errno", + ":vfprintf_internal", + ], +) diff --git a/utils/bazel/llvm-project-overlay/libc/libc_build_rules.bzl b/utils/bazel/llvm-project-overlay/libc/libc_build_rules.bzl --- a/utils/bazel/llvm-project-overlay/libc/libc_build_rules.bzl +++ b/utils/bazel/llvm-project-overlay/libc/libc_build_rules.bzl @@ -23,7 +23,7 @@ # We want all libc sources to be compiled with "hidden" visibility. # The public symbols will be given "default" visibility explicitly. # See src/__support/common.h for more information. - copts.append("-fvisibility=hidden") + copts = copts + ["-fvisibility=hidden"] native.cc_library( name = name, copts = copts, @@ -65,11 +65,11 @@ **kwargs: Other attributes relevant for a cc_library. For example, deps. """ deps = deps or [] - deps.append(LIBC_ROOT_TARGET) + # We use the explicit equals pattern here because append and += mutate the + # original list, where this creates a new list and stores it in deps. + deps = deps + [LIBC_ROOT_TARGET] copts = copts or [] - copts.append("-O3") - copts.append("-fno-builtin") - copts.append("-fno-lax-vector-conversions") + copts = copts + ["-O3", "-fno-builtin", "-fno-lax-vector-conversions"] # We compile the code twice, the first target is suffixed with ".__internal__" and contains the # C++ functions in the "__llvm_libc" namespace. This allows us to test the function in the @@ -87,9 +87,9 @@ func_attrs = ["__attribute__((visibility(\"default\")))"] if weak: - func_attrs.append("__attribute__((weak))") + func_attrs = func_attrs + ["__attribute__((weak))"] local_defines = local_defines or ["LIBC_COPT_PUBLIC_PACKAGING"] - local_defines.append("LLVM_LIBC_FUNCTION_ATTR='%s'" % " ".join(func_attrs)) + local_defines = local_defines + ["LLVM_LIBC_FUNCTION_ATTR='%s'" % " ".join(func_attrs)] _libc_library( name = name, srcs = srcs, diff --git a/utils/bazel/llvm-project-overlay/libc/test/UnitTest/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/test/UnitTest/BUILD.bazel --- a/utils/bazel/llvm-project-overlay/libc/test/UnitTest/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/test/UnitTest/BUILD.bazel @@ -23,6 +23,7 @@ cc_library( name = "LibcUnitTest", srcs = [ + "BazelFilePath.cpp", "ExecuteFunctionUnix.cpp", "LibcTest.cpp", "LibcTestMain.cpp", @@ -35,6 +36,7 @@ ], deps = [ ":test_logger", + "//libc:__support_c_string", "//libc:__support_cpp_bit", "//libc:__support_cpp_bitset", "//libc:__support_cpp_span", diff --git a/utils/bazel/llvm-project-overlay/libc/test/src/stdio/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/test/src/stdio/BUILD.bazel --- a/utils/bazel/llvm-project-overlay/libc/test/src/stdio/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/test/src/stdio/BUILD.bazel @@ -31,11 +31,11 @@ libc_function_deps = [ ], deps = [ - "//libc:printf_string_writer", - "//libc:printf_writer", - "//libc:printf_core_structs", - "//libc:__support_cpp_string_view", - "//libc:__support_arg_list", + "//libc:__support_arg_list", + "//libc:__support_cpp_string_view", + "//libc:printf_core_structs", + "//libc:printf_string_writer", + "//libc:printf_writer", ], ) @@ -45,12 +45,12 @@ libc_function_deps = [ ], deps = [ - "//libc:printf_converter", - "//libc:printf_string_writer", - "//libc:printf_writer", - "//libc:printf_core_structs", - "//libc:__support_cpp_string_view", - "//libc:__support_arg_list", + "//libc:__support_arg_list", + "//libc:__support_cpp_string_view", + "//libc:printf_converter", + "//libc:printf_core_structs", + "//libc:printf_string_writer", + "//libc:printf_writer", ], ) @@ -74,3 +74,19 @@ "//libc:snprintf", ], ) + +libc_test( + name = "printf_test", + srcs = ["printf_test.cpp"], + libc_function_deps = [ + "//libc:printf", + ], +) + +libc_test( + name = "fprintf_test", + srcs = ["fprintf_test.cpp"], + libc_function_deps = [ + "//libc:fprintf", + ], +)