[libc][bazel] add file printf targets and support
authorMichael Jones <michaelrj@google.com>
Mon, 27 Mar 2023 22:14:17 +0000 (15:14 -0700)
committerMichael Jones <michaelrj@google.com>
Wed, 26 Apr 2023 21:30:48 +0000 (14:30 -0700)
This patch adds targets for printf and fprintf to the bazel build.
Additionally, it adds support for the build system to specify where
files should be written for testing purposes. This was necessary to
enable the fprintf test under bazel.

Reviewed By: sivachandra

Differential Revision: https://reviews.llvm.org/D147008

13 files changed:
libc/src/__support/CMakeLists.txt
libc/src/__support/c_string.h [new file with mode: 0644]
libc/src/stdio/fprintf.cpp
libc/test/UnitTest/BazelFilePath.cpp [new file with mode: 0644]
libc/test/UnitTest/CMakeLists.txt
libc/test/UnitTest/CmakeFilePath.cpp [new file with mode: 0644]
libc/test/UnitTest/LibcTest.h
libc/test/UnitTest/Test.h
libc/test/src/stdio/fprintf_test.cpp
utils/bazel/llvm-project-overlay/libc/BUILD.bazel
utils/bazel/llvm-project-overlay/libc/libc_build_rules.bzl
utils/bazel/llvm-project-overlay/libc/test/UnitTest/BUILD.bazel
utils/bazel/llvm-project-overlay/libc/test/src/stdio/BUILD.bazel

index 7f60e5d..469d81d 100644 (file)
@@ -46,6 +46,15 @@ add_header_library(
 )
 
 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
     ctype_utils.h
diff --git a/libc/src/__support/c_string.h b/libc/src/__support/c_string.h
new file mode 100644 (file)
index 0000000..eaac4e7
--- /dev/null
@@ -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
index da8fabf..900e18f 100644 (file)
@@ -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 (file)
index 0000000..7bee46c
--- /dev/null
@@ -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 <stdlib.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) {
+  // 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
index 389a59c..d905766 100644 (file)
@@ -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 @@ foreach(lib LibcUnitTest LibcHermeticTest)
   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 (file)
index 0000000..1e89167
--- /dev/null
@@ -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
index 7368377..c802b23 100644 (file)
@@ -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 @@ template <typename... Types> struct TypeList {
 // Make TypeList visible in __llvm_libc::testing.
 template <typename... Types> using TypeList = internal::TypeList<Types...>;
 
+CString libc_make_test_file_path_func(const char *file_name);
+
 } // namespace testing
 } // namespace __llvm_libc
 
index 19c4149..7fd6f02 100644 (file)
@@ -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)
index 20b3c0f..a521bb4 100644 (file)
@@ -34,8 +34,10 @@ using ::fread;
 } // 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 @@ TEST(LlvmLibcFPrintfTest, WriteToFile) {
 
   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];
index e156614..6e6953e 100644 (file)
@@ -20,6 +20,12 @@ package(
 
 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=<disable|external|system>`.
 # Flag documentation: https://bazel.build/extending/config
@@ -154,6 +160,14 @@ libc_support_library(
 )
 
 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"],
     deps = [
@@ -171,6 +185,16 @@ libc_support_library(
 )
 
 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"],
     deps = [":libc_root"],
@@ -245,6 +269,25 @@ libc_support_library(
 )
 
 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 = [
         "src/__support/float_to_string.h",
@@ -399,6 +442,20 @@ libc_support_library(
 )
 
 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"],
     deps = [":libc_root"],
@@ -701,6 +758,23 @@ libc_support_library(
     ],
 )
 
+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_function(
 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(
 libc_support_library(
     name = "printf_config",
     hdrs = ["src/stdio/printf_core/printf_config.h"],
+    defines = PRINTF_COPTS,
     deps = [
         ":libc_root",
     ],
@@ -2099,6 +2175,7 @@ libc_support_library(
     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 @@ libc_support_library(
     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 @@ libc_support_library(
     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",
@@ -2150,9 +2228,22 @@ libc_support_library(
 )
 
 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 @@ libc_support_library(
         "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 @@ libc_support_library(
     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 @@ libc_function(
     name = "sprintf",
     srcs = ["src/stdio/sprintf.cpp"],
     hdrs = ["src/stdio/sprintf.h"],
+    defines = PRINTF_COPTS,
     deps = [
         ":__support_arg_list",
         ":errno",
@@ -2224,6 +2318,7 @@ libc_function(
     name = "snprintf",
     srcs = ["src/stdio/snprintf.cpp"],
     hdrs = ["src/stdio/snprintf.h"],
+    defines = PRINTF_COPTS,
     deps = [
         ":__support_arg_list",
         ":errno",
@@ -2232,3 +2327,41 @@ libc_function(
         ":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",
+    ],
+)
index b4506c3..83dff3f 100644 (file)
@@ -23,7 +23,7 @@ def _libc_library(name, copts = None, **kwargs):
     # 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 @@ def libc_function(
       **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 @@ def libc_function(
 
     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,
index 319f60b..7ab3fe1 100644 (file)
@@ -23,6 +23,7 @@ cc_library(
 cc_library(
     name = "LibcUnitTest",
     srcs = [
+        "BazelFilePath.cpp",
         "ExecuteFunctionUnix.cpp",
         "LibcTest.cpp",
         "LibcTestMain.cpp",
@@ -35,6 +36,7 @@ cc_library(
     ],
     deps = [
         ":test_logger",
+        "//libc:__support_c_string",
         "//libc:__support_cpp_bit",
         "//libc:__support_cpp_bitset",
         "//libc:__support_cpp_span",
index f646079..07ffd21 100644 (file)
@@ -31,11 +31,11 @@ libc_test(
     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_test(
     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_test(
         "//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",
+    ],
+)