[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