[libc-commits] [libc] 9b8ca3c - [libc] Add global stdout and stderr objects.

Siva Chandra Reddy via libc-commits libc-commits at lists.llvm.org
Thu May 26 22:44:37 PDT 2022


Author: Siva Chandra Reddy
Date: 2022-05-27T05:43:49Z
New Revision: 9b8ca3c1f18c6c906c8ba8d5ac7a082f2d3b5bd4

URL: https://github.com/llvm/llvm-project/commit/9b8ca3c1f18c6c906c8ba8d5ac7a082f2d3b5bd4
DIFF: https://github.com/llvm/llvm-project/commit/9b8ca3c1f18c6c906c8ba8d5ac7a082f2d3b5bd4.diff

LOG: [libc] Add global stdout and stderr objects.

They are added as entrypoint object targets. The header-gen
infrastructure has been extended to enable handling standard required
global objects. The libc-api-test has also been extended to verify the
global object declarations.

Reviewed By: lntue

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

Added: 
    libc/src/stdio/stderr.cpp
    libc/src/stdio/stderr.h
    libc/src/stdio/stdout.cpp
    libc/src/stdio/stdout.h

Modified: 
    libc/config/linux/api.td
    libc/config/linux/x86_64/entrypoints.txt
    libc/config/public_api.td
    libc/spec/spec.td
    libc/spec/stdc.td
    libc/src/__support/File/file.h
    libc/src/__support/File/linux_file.cpp
    libc/src/stdio/CMakeLists.txt
    libc/test/src/CMakeLists.txt
    libc/test/src/__support/File/platform_file_test.cpp
    libc/utils/HdrGen/PrototypeTestGen/PrototypeTestGen.cpp
    libc/utils/HdrGen/PublicAPICommand.cpp
    libc/utils/LibcTableGenUtil/APIIndexer.cpp
    libc/utils/LibcTableGenUtil/APIIndexer.h

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index 6862139d66c31..f8ca32133eea8 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -147,6 +147,10 @@ def StringAPI : PublicAPI<"string.h"> {
 }
 
 def StdIOAPI : PublicAPI<"stdio.h"> {
+  let Macros = [
+    SimpleMacroDef<"stderr", "stderr">,
+    SimpleMacroDef<"stdout", "stdout">,
+  ];
   let Types = ["size_t", "FILE", "cookie_io_functions_t"];
 }
 

diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 99937c7ebe592..300d94761f701 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -276,6 +276,8 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.stdio.fwrite_unlocked
     libc.src.stdio.sprintf
     libc.src.stdio.snprintf
+    libc.src.stdio.stderr
+    libc.src.stdio.stdout
 
     # signal.h entrypoints
     # TODO: Enable signal.h entrypoints after fixing signal.h

diff  --git a/libc/config/public_api.td b/libc/config/public_api.td
index 6d2f534f5a593..1b34506c643c3 100644
--- a/libc/config/public_api.td
+++ b/libc/config/public_api.td
@@ -22,4 +22,5 @@ class PublicAPI<string name> {
   list<string> Enumerations = [];
   list<string> Structs = [];
   list<string> Functions = [];
+  list<string> Objects = [];
 }

diff  --git a/libc/spec/spec.td b/libc/spec/spec.td
index fe5b2005650d4..d609f8e04ea3e 100644
--- a/libc/spec/spec.td
+++ b/libc/spec/spec.td
@@ -138,16 +138,23 @@ class FunctionSpec<string name, RetValSpec return, list<ArgSpec> args> {
   list<ArgSpec> Args = args;
 }
 
+class ObjectSpec<string name, string type> {
+  string Name = name;
+  string Type = type;
+}
+
 class HeaderSpec<string name,
                 list<Macro> macros = [],
                 list<Type> types = [],
                 list<EnumeratedNameValue> enumerations = [],
-                list<FunctionSpec> functions = []> {
+                list<FunctionSpec> functions = [],
+                list<ObjectSpec> objects = []> {
   string Name = name;
   list<FunctionSpec> Functions = functions;
   list<Type> Types = types;
   list<Macro> Macros = macros;
   list<EnumeratedNameValue> Enumerations = enumerations;
+  list<ObjectSpec> Objects = objects;
 }
 
 class StandardSpec<string name> {

diff  --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index aa09bc36a25da..f173e4b54eeab 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -471,7 +471,10 @@ def StdC : StandardSpec<"stdc"> {
 
   HeaderSpec StdIO = HeaderSpec<
       "stdio.h",
-      [], // Macros
+      [
+          Macro<"stderr">,
+          Macro<"stdout">,
+      ], // Macros
       [ // Types
           SizeTType,
           FILE,
@@ -560,6 +563,16 @@ def StdC : StandardSpec<"stdc"> {
                ArgSpec<ConstCharRestrictedPtr>,
                ArgSpec<VarArgType>]
           >,
+      ],
+      [
+          ObjectSpec<
+              "stdout",
+              "FILE *"
+          >,
+          ObjectSpec<
+              "stderr",
+              "FILE *"
+          >,
       ]
   >;
 

diff  --git a/libc/src/__support/File/file.h b/libc/src/__support/File/file.h
index a62aa7f2e72d3..49a5779c2f322 100644
--- a/libc/src/__support/File/file.h
+++ b/libc/src/__support/File/file.h
@@ -223,6 +223,9 @@ class File {
 // library.
 File *openfile(const char *path, const char *mode);
 
+extern File *stdout;
+extern File *stderr;
+
 } // namespace __llvm_libc
 
 #endif // LLVM_LIBC_SRC_SUPPORT_OSUTIL_FILE_H

diff  --git a/libc/src/__support/File/linux_file.cpp b/libc/src/__support/File/linux_file.cpp
index b1a58d94e7207..fc706c2e7ac11 100644
--- a/libc/src/__support/File/linux_file.cpp
+++ b/libc/src/__support/File/linux_file.cpp
@@ -165,4 +165,18 @@ File *openfile(const char *path, const char *mode) {
   return file;
 }
 
+// TODO: Use the appropriate buffering modes for the standard streams below
+// the 
diff erent buffering modes are available.
+constexpr size_t STDOUT_BUFFER_SIZE = 1024;
+char stdout_buffer[STDOUT_BUFFER_SIZE];
+static LinuxFile StdOut(1, stdout_buffer, STDOUT_BUFFER_SIZE, 0, false,
+                        File::ModeFlags(File::OpenMode::APPEND));
+File *stdout = &StdOut;
+
+constexpr size_t STDERR_BUFFER_SIZE = 1024;
+char stderr_buffer[STDERR_BUFFER_SIZE];
+static LinuxFile StdErr(2, stderr_buffer, STDERR_BUFFER_SIZE, 0, false,
+                        File::ModeFlags(File::OpenMode::APPEND));
+File *stderr = &StdErr;
+
 } // namespace __llvm_libc

diff  --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index 2abb5091b1cb1..f4684c6b371f4 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -203,6 +203,29 @@ add_entrypoint_object(
     libc.src.__support.File.file
 )
 
+add_entrypoint_object(
+  stdout
+  SRCS
+    stdout.cpp
+  HDRS
+    stdout.h
+  DEPENDS
+    libc.include.stdio
+    libc.src.__support.File.file
+    libc.src.__support.File.platform_file
+)
+
+add_entrypoint_object(
+  stderr
+  SRCS
+    stderr.cpp
+  HDRS
+    stderr.h
+  DEPENDS
+    libc.include.stdio
+    libc.src.__support.File.file
+    libc.src.__support.File.platform_file
+)
 
 add_entrypoint_object(
   sprintf

diff  --git a/libc/src/stdio/stderr.cpp b/libc/src/stdio/stderr.cpp
new file mode 100644
index 0000000000000..60e9d94d7ecd4
--- /dev/null
+++ b/libc/src/stdio/stderr.cpp
@@ -0,0 +1,5 @@
+#include "src/__support/File/file.h"
+
+#include <stdio.h>
+
+extern FILE *stderr = reinterpret_cast<FILE *>(__llvm_libc::stderr);

diff  --git a/libc/src/stdio/stderr.h b/libc/src/stdio/stderr.h
new file mode 100644
index 0000000000000..ee4e6bfb6a2b0
--- /dev/null
+++ b/libc/src/stdio/stderr.h
@@ -0,0 +1,9 @@
+//===------------------------------------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#error "Do not include this file. Instead include __support/File/file.h."

diff  --git a/libc/src/stdio/stdout.cpp b/libc/src/stdio/stdout.cpp
new file mode 100644
index 0000000000000..66fed5d0c35d2
--- /dev/null
+++ b/libc/src/stdio/stdout.cpp
@@ -0,0 +1,5 @@
+#include "src/__support/File/file.h"
+
+#include <stdio.h>
+
+extern FILE *stdout = reinterpret_cast<FILE *>(__llvm_libc::stdout);

diff  --git a/libc/src/stdio/stdout.h b/libc/src/stdio/stdout.h
new file mode 100644
index 0000000000000..ee4e6bfb6a2b0
--- /dev/null
+++ b/libc/src/stdio/stdout.h
@@ -0,0 +1,9 @@
+//===------------------------------------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#error "Do not include this file. Instead include __support/File/file.h."

diff  --git a/libc/test/src/CMakeLists.txt b/libc/test/src/CMakeLists.txt
index 49f7bc0774dcf..50ccc9e68b633 100644
--- a/libc/test/src/CMakeLists.txt
+++ b/libc/test/src/CMakeLists.txt
@@ -96,6 +96,8 @@ set_target_properties(
   PROPERTIES
   INCLUDE_DIRECTORIES ""
 )
+target_link_libraries(libc-api-test llvmlibc)
+
 # Only include we need is the include for cpp::IsSame and our generated
 # public headers.
 target_include_directories(

diff  --git a/libc/test/src/__support/File/platform_file_test.cpp b/libc/test/src/__support/File/platform_file_test.cpp
index 0ad0efc19cf59..fe04b6f643e5a 100644
--- a/libc/test/src/__support/File/platform_file_test.cpp
+++ b/libc/test/src/__support/File/platform_file_test.cpp
@@ -195,3 +195,8 @@ TEST(LlvmLibcPlatformFileTest, IncorrectOperation) {
   ASSERT_TRUE(file->error());
   ASSERT_EQ(file->close(), 0);
 }
+
+TEST(LlvmLibcPlatformFileTest, StdOutStdErrSmokeTest) {
+  EXPECT_FALSE(__llvm_libc::stdout == nullptr);
+  EXPECT_FALSE(__llvm_libc::stderr == nullptr);
+}

diff  --git a/libc/utils/HdrGen/PrototypeTestGen/PrototypeTestGen.cpp b/libc/utils/HdrGen/PrototypeTestGen/PrototypeTestGen.cpp
index e6b4353ca8d24..ca35dde7237d1 100644
--- a/libc/utils/HdrGen/PrototypeTestGen/PrototypeTestGen.cpp
+++ b/libc/utils/HdrGen/PrototypeTestGen/PrototypeTestGen.cpp
@@ -28,6 +28,12 @@ bool TestGeneratorMain(llvm::raw_ostream &OS, llvm::RecordKeeper &records) {
   for (const auto &entrypoint : EntrypointNamesOption) {
     auto match = G.FunctionToHeaderMap.find(entrypoint);
     if (match == G.FunctionToHeaderMap.end()) {
+      auto objectMatch = G.ObjectToHeaderMap.find(entrypoint);
+      if (objectMatch != G.ObjectToHeaderMap.end()) {
+        headerFileSet.insert(objectMatch->second);
+        continue;
+      }
+
       llvm::errs() << "ERROR: entrypoint '" << entrypoint
                    << "' could not be found in spec in any public header\n";
       return true;
@@ -43,6 +49,17 @@ bool TestGeneratorMain(llvm::raw_ostream &OS, llvm::RecordKeeper &records) {
   for (const auto &entrypoint : EntrypointNamesOption) {
     auto match = G.FunctionSpecMap.find(entrypoint);
     if (match == G.FunctionSpecMap.end()) {
+      auto objectMatch = G.ObjectSpecMap.find(entrypoint);
+      if (objectMatch != G.ObjectSpecMap.end()) {
+        auto entrypointPtr = entrypoint + "_ptr";
+        llvm::Record *objectSpec = G.ObjectSpecMap[entrypoint];
+        auto objectType = objectSpec->getValueAsString("Type");
+        // We just make sure that the global object is present.
+        OS << "  " << objectType << " *" << entrypointPtr << " = &"
+           << entrypoint << ";\n";
+        OS << "  ++" << entrypointPtr << ";\n"; // To avoid unused var warning.
+        continue;
+      }
       llvm::errs() << "ERROR: entrypoint '" << entrypoint
                    << "' could not be found in spec in any public header\n";
       return true;
@@ -74,6 +91,11 @@ bool TestGeneratorMain(llvm::raw_ostream &OS, llvm::RecordKeeper &records) {
   OS << "  return 0;\n";
   OS << "}\n\n";
 
+  // We provide dummy malloc and free implementations to support the case
+  // when LLVM libc does to include them.
+  OS << "void *malloc(size_t) { return nullptr; }\n";
+  OS << "void free(void *) {}\n";
+
   return false;
 }
 

diff  --git a/libc/utils/HdrGen/PublicAPICommand.cpp b/libc/utils/HdrGen/PublicAPICommand.cpp
index 8f036f7a6d56e..e1e8f4ee42b9e 100644
--- a/libc/utils/HdrGen/PublicAPICommand.cpp
+++ b/libc/utils/HdrGen/PublicAPICommand.cpp
@@ -114,6 +114,15 @@ void writeAPIFromIndex(APIIndexer &G,
 
     OS << ");\n\n";
   }
+
+  // Make another pass over entrypoints to emit object declarations.
+  for (const auto &Name : EntrypointNameList) {
+    if (G.ObjectSpecMap.find(Name) == G.ObjectSpecMap.end())
+      continue;
+    llvm::Record *ObjectSpec = G.ObjectSpecMap[Name];
+    auto Type = ObjectSpec->getValueAsString("Type");
+    OS << "extern " << Type << " " << Name << ";\n";
+  }
   OS << "__END_C_DECLS\n";
 }
 

diff  --git a/libc/utils/LibcTableGenUtil/APIIndexer.cpp b/libc/utils/LibcTableGenUtil/APIIndexer.cpp
index fd3f53c4150fc..2630797517f77 100644
--- a/libc/utils/LibcTableGenUtil/APIIndexer.cpp
+++ b/libc/utils/LibcTableGenUtil/APIIndexer.cpp
@@ -108,6 +108,13 @@ void APIIndexer::indexStandardSpecDef(llvm::Record *StandardSpec) {
         EnumerationSpecMap[std::string(
             EnumerationSpec->getValueAsString("Name"))] = EnumerationSpec;
       }
+
+      auto ObjectSpecList = HeaderSpec->getValueAsListOfDefs("Objects");
+      for (llvm::Record *ObjectSpec : ObjectSpecList) {
+        auto ObjectName = std::string(ObjectSpec->getValueAsString("Name"));
+        ObjectSpecMap[ObjectName] = ObjectSpec;
+        ObjectToHeaderMap[ObjectName] = std::string(Header);
+      }
     }
   }
 }
@@ -135,6 +142,10 @@ void APIIndexer::indexPublicAPIDef(llvm::Record *PublicAPI) {
   auto EnumerationList = PublicAPI->getValueAsListOfStrings("Enumerations");
   for (llvm::StringRef EnumerationName : EnumerationList)
     Enumerations.insert(std::string(EnumerationName));
+
+  auto ObjectList = PublicAPI->getValueAsListOfStrings("Objects");
+  for (llvm::StringRef ObjectName : ObjectList)
+    Objects.insert(std::string(ObjectName));
 }
 
 void APIIndexer::index(llvm::RecordKeeper &Records) {

diff  --git a/libc/utils/LibcTableGenUtil/APIIndexer.h b/libc/utils/LibcTableGenUtil/APIIndexer.h
index cbb7ac2e66dcf..26c813075a7ba 100644
--- a/libc/utils/LibcTableGenUtil/APIIndexer.h
+++ b/libc/utils/LibcTableGenUtil/APIIndexer.h
@@ -63,13 +63,16 @@ class APIIndexer {
   NameToRecordMapping EnumerationSpecMap;
   NameToRecordMapping FunctionSpecMap;
   NameToRecordMapping MacroDefsMap;
+  NameToRecordMapping ObjectSpecMap;
 
   std::unordered_map<std::string, std::string> FunctionToHeaderMap;
+  std::unordered_map<std::string, std::string> ObjectToHeaderMap;
 
   NameSet RequiredTypes;
   NameSet Structs;
   NameSet Enumerations;
   NameSet Functions;
+  NameSet Objects;
   NameSet PublicHeaders;
 
   std::string getTypeAsString(llvm::Record *TypeRecord);


        


More information about the libc-commits mailing list