diff --git a/libc/utils/tools/WrapperGen/Main.cpp b/libc/utils/tools/WrapperGen/Main.cpp --- a/libc/utils/tools/WrapperGen/Main.cpp +++ b/libc/utils/tools/WrapperGen/Main.cpp @@ -10,6 +10,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Main.h" @@ -19,8 +20,37 @@ llvm::cl::opt FunctionName("name", llvm::cl::desc("Name of the function to be wrapped."), llvm::cl::value_desc(""), llvm::cl::Required); +llvm::cl::opt + AliaseeString("aliasee", + llvm::cl::desc("Declare as an alias to this C name."), + llvm::cl::value_desc("")); +llvm::cl::opt + AliaseeFile("aliasee-file", + llvm::cl::desc("Declare as an alias to the C name read from " + "this file."), + llvm::cl::value_desc("")); +llvm::cl::opt + AppendToFile("append-to-file", + llvm::cl::desc("Append the generated content at the end of " + "the contents of this file."), + llvm::cl::value_desc("")); + +static std::string GetAliaseeName() { + if (AliaseeString.size() > 0) + return AliaseeString; + + auto ErrorOrBuf = llvm::MemoryBuffer::getFile(AliaseeFile); + if (!ErrorOrBuf) + llvm::PrintFatalError("Unable to read the aliasee file " + AliaseeFile); + return std::string(ErrorOrBuf.get()->getBuffer().trim()); +} static bool WrapperGenMain(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) { + if (!AliaseeString.empty() && !AliaseeFile.empty()) { + llvm::PrintFatalError("The options 'aliasee' and 'aliasee-file' cannot " + "be specified simultaniously."); + } + llvm_libc::APIIndexer Indexer(Records); auto Iter = Indexer.FunctionSpecMap.find(FunctionName); if (Iter == Indexer.FunctionSpecMap.end()) { @@ -28,11 +58,27 @@ "' not found in any standard spec."); } - // To avoid all confusion, we include the implementation header using the - // full path (relative the libc directory.) - std::string Header = Indexer.FunctionToHeaderMap[FunctionName]; - auto RelPath = llvm::StringRef(Header).drop_back(2); // Drop the ".h" suffix. - OS << "#include \"src/" << RelPath << "/" << FunctionName << ".h\"\n"; + bool EmitAlias = !(AliaseeString.empty() && AliaseeFile.empty()); + + if (!EmitAlias && AppendToFile.empty()) { + // If not emitting an alias, and not appending to another file, + // we should include the implementation header to ensure the wrapper + // compiles. + // To avoid all confusion, we include the implementation header using the + // full path (relative to the libc directory.) + std::string Header = Indexer.FunctionToHeaderMap[FunctionName]; + auto RelPath = + llvm::StringRef(Header).drop_back(2); // Drop the ".h" suffix. + OS << "#include \"src/" << RelPath << "/" << FunctionName << ".h\"\n"; + } + if (!AppendToFile.empty()) { + auto ErrorOrBuf = llvm::MemoryBuffer::getFile(AppendToFile); + if (!ErrorOrBuf) { + llvm::PrintFatalError("Unable to read the file '" + AppendToFile + + "' to append to."); + } + OS << ErrorOrBuf.get()->getBuffer().trim() << '\n'; + } auto &NameSpecPair = *Iter; llvm::Record *FunctionSpec = NameSpecPair.second; @@ -79,14 +125,17 @@ } } - // TODO: Arg types of the C++ implementation functions need not - // match the standard types. Either handle such differences here, or - // avoid such a thing in the implementations. - OS << ") {\n" - << " " << (ShouldReturn ? "return " : "") - << "__llvm_libc::" << FunctionName << "(" << CallArgs.str() << ");\n" - << "}\n"; - + if (EmitAlias) { + OS << ") __attribute__((alias(\"" << GetAliaseeName() << "\")));\n"; + } else { + // TODO: Arg types of the C++ implementation functions need not + // match the standard types. Either handle such differences here, or + // avoid such a thing in the implementations. + OS << ") {\n" + << " " << (ShouldReturn ? "return " : "") + << "__llvm_libc::" << FunctionName << "(" << CallArgs.str() << ");\n" + << "}\n"; + } return false; }