diff --git a/libc/src/__support/CPP/CMakeLists.txt b/libc/src/__support/CPP/CMakeLists.txt --- a/libc/src/__support/CPP/CMakeLists.txt +++ b/libc/src/__support/CPP/CMakeLists.txt @@ -78,6 +78,15 @@ libc.src.__support.integer_to_string ) +add_header_library( + cstring + HDRS + cstring.h + DEPENDS + libc.src.__support.common + .string +) + add_header_library( optional HDRS diff --git a/libc/src/__support/CPP/cstring.h b/libc/src/__support/CPP/cstring.h new file mode 100644 --- /dev/null +++ b/libc/src/__support/CPP/cstring.h @@ -0,0 +1,41 @@ +//===-- 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_CPP_CSTRING_H +#define LLVM_LIBC_SRC_SUPPORT_CPP_CSTRING_H + +#include "src/__support/CPP/string.h" + +namespace __llvm_libc::cpp { + +// 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 { + string str; + const char *cstr; + +public: + // These constructors can be implemented iff required. + CString() = delete; + CString(const CString &) = delete; + CString(CString &&) = delete; + + inline CString(string in_str) { + str = in_str; + cstr = str.c_str(); + } + + inline CString(const char *in_cstr) { cstr = in_cstr; } + + inline operator const char *() const { return cstr; } +}; + +} // namespace __llvm_libc::cpp + +#endif // LLVM_LIBC_SRC_SUPPORT_CPP_CSTRING_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/cstring.h" +#include "src/__support/CPP/string.h" + +namespace __llvm_libc::testing { + +cpp::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 @@ -2,6 +2,7 @@ ExecuteFunction.h Test.h LibcTest.cpp + CmakeFilePath.cpp LibcTest.h TestLogger.cpp TestLogger.h @@ -20,6 +21,7 @@ add_dependencies( LibcUnitTest libc.src.__support.CPP.string + libc.src.__support.CPP.cstring libc.src.__support.CPP.string_view libc.src.__support.CPP.type_traits libc.src.__support.OSUtil.osutil 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/cstring.h" +#include "src/__support/CPP/string.h" + +namespace __llvm_libc::testing { + +cpp::CString libc_make_test_file_path_func(const char *file_name) { + return 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,11 +9,23 @@ #ifndef LLVM_LIBC_UTILS_UNITTEST_LIBCTEST_H #define LLVM_LIBC_UTILS_UNITTEST_LIBCTEST_H +// 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/CPP/ or // utils/testutils. No other headers should be included. #include "PlatformDefs.h" +#include "src/__support/CPP/cstring.h" #include "src/__support/CPP/string.h" #include "src/__support/CPP/string_view.h" #include "src/__support/CPP/type_traits.h" @@ -245,6 +257,8 @@ // Make TypeList visible in __llvm_libc::testing. template using TypeList = internal::TypeList; +cpp::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"], @@ -165,6 +179,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"], @@ -203,6 +227,15 @@ ], ) +libc_support_library( + name = "__support_cpp_c_string", + hdrs = ["src/__support/CPP/cstring.h"], + deps = [ + ":__support_cpp_string", + ":libc_root", + ], +) + libc_support_library( name = "__support_cpp_type_traits", hdrs = ["src/__support/CPP/type_traits.h"], @@ -238,6 +271,16 @@ ], ) +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 = [ @@ -392,6 +435,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"], @@ -695,6 +752,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( @@ -2073,6 +2147,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", @@ -2083,6 +2158,7 @@ libc_support_library( name = "printf_config", hdrs = ["src/stdio/printf_core/printf_config.h"], + defines = PRINTF_COPTS, deps = [ ":libc_root", ], @@ -2092,6 +2168,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", @@ -2113,7 +2190,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", @@ -2134,6 +2211,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", @@ -2142,10 +2220,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", @@ -2168,6 +2259,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", @@ -2190,6 +2282,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", @@ -2204,6 +2297,7 @@ name = "sprintf", srcs = ["src/stdio/sprintf.cpp"], hdrs = ["src/stdio/sprintf.h"], + defines = PRINTF_COPTS, deps = [ ":__support_arg_list", ":errno", @@ -2217,6 +2311,7 @@ name = "snprintf", srcs = ["src/stdio/snprintf.cpp"], hdrs = ["src/stdio/snprintf.h"], + defines = PRINTF_COPTS, deps = [ ":__support_arg_list", ":errno", @@ -2225,3 +2320,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", @@ -37,6 +38,7 @@ ":test_logger", "//libc:__support_cpp_bit", "//libc:__support_cpp_bitset", + "//libc:__support_cpp_c_string", "//libc:__support_cpp_span", "//libc:__support_cpp_string", "//libc:__support_cpp_string_view", 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", + ], +)