#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"
llvm::cl::opt<std::string>
FunctionName("name", llvm::cl::desc("Name of the function to be wrapped."),
llvm::cl::value_desc("<function name>"), llvm::cl::Required);
+llvm::cl::opt<std::string>
+ AliaseeString("aliasee",
+ llvm::cl::desc("Declare as an alias to this C name."),
+ llvm::cl::value_desc("<aliasee string>"));
+llvm::cl::opt<std::string>
+ AliaseeFile("aliasee-file",
+ llvm::cl::desc("Declare as an alias to the C name read from "
+ "this file."),
+ llvm::cl::value_desc("<path to a file containing alias name>"));
+llvm::cl::opt<std::string>
+ AppendToFile("append-to-file",
+ llvm::cl::desc("Append the generated content at the end of "
+ "the contents of this file."),
+ llvm::cl::value_desc("<path to a file>"));
+
+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()) {
"' 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;
}
}
- // 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;
}