forked from OSchip/llvm-project
[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
This commit is contained in:
parent
827fa2c419
commit
9b8ca3c1f1
libc
config
spec
src
test/src
utils
HdrGen
LibcTableGenUtil
|
@ -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"];
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -22,4 +22,5 @@ class PublicAPI<string name> {
|
|||
list<string> Enumerations = [];
|
||||
list<string> Structs = [];
|
||||
list<string> Functions = [];
|
||||
list<string> Objects = [];
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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 *"
|
||||
>,
|
||||
]
|
||||
>;
|
||||
|
||||
|
|
|
@ -223,6 +223,9 @@ public:
|
|||
// 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
|
||||
|
|
|
@ -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 different 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#include "src/__support/File/file.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
extern FILE *stderr = reinterpret_cast<FILE *>(__llvm_libc::stderr);
|
|
@ -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."
|
|
@ -0,0 +1,5 @@
|
|||
#include "src/__support/File/file.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
extern FILE *stdout = reinterpret_cast<FILE *>(__llvm_libc::stdout);
|
|
@ -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."
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -63,13 +63,16 @@ public:
|
|||
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);
|
||||
|
|
Loading…
Reference in New Issue