[llvm] [readtapi] Use OptParser.td for options (PR #72183)
Cyndy Ishida via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 13 16:59:05 PST 2023
https://github.com/cyndyishida created https://github.com/llvm/llvm-project/pull/72183
This includes revamping how --compare was handled and adds `-o` ontop of tablegen approach.
This will be used to add more complex options.
>From d76ba9eb001ca03b98f167509107c6e8add179a1 Mon Sep 17 00:00:00 2001
From: Cyndy Ishida <cyndy_ishida at apple.com>
Date: Mon, 13 Nov 2023 16:52:13 -0800
Subject: [PATCH] [readtapi] Use OptParser.td for options
This includes revamping how --compare was handled and adds `-o` ontop of
tablegen approach.
This will be used to add more complex options.
---
llvm/include/llvm/TextAPI/TextAPIError.h | 3 +
llvm/lib/TextAPI/TextAPIError.cpp | 11 +-
.../tools/llvm-readtapi/command-line.test | 7 +
.../tools/llvm-readtapi/compare-flags.test | 23 +--
llvm/tools/llvm-readtapi/CMakeLists.txt | 8 +
llvm/tools/llvm-readtapi/Opts.td | 16 ++
llvm/tools/llvm-readtapi/llvm-readtapi.cpp | 144 ++++++++++++------
7 files changed, 153 insertions(+), 59 deletions(-)
create mode 100644 llvm/test/tools/llvm-readtapi/command-line.test
create mode 100644 llvm/tools/llvm-readtapi/Opts.td
diff --git a/llvm/include/llvm/TextAPI/TextAPIError.h b/llvm/include/llvm/TextAPI/TextAPIError.h
index a8484063d7948de..de19f7894d35986 100644
--- a/llvm/include/llvm/TextAPI/TextAPIError.h
+++ b/llvm/include/llvm/TextAPI/TextAPIError.h
@@ -28,8 +28,11 @@ class TextAPIError : public llvm::ErrorInfo<TextAPIError> {
public:
static char ID;
TextAPIErrorCode EC;
+ std::string Msg;
TextAPIError(TextAPIErrorCode EC) : EC(EC) {}
+ TextAPIError(TextAPIErrorCode EC, std::string Msg)
+ : EC(EC), Msg(std::move(Msg)) {}
void log(raw_ostream &OS) const override;
std::error_code convertToErrorCode() const override;
diff --git a/llvm/lib/TextAPI/TextAPIError.cpp b/llvm/lib/TextAPI/TextAPIError.cpp
index dd97381ce094c2f..23954a9e3466de2 100644
--- a/llvm/lib/TextAPI/TextAPIError.cpp
+++ b/llvm/lib/TextAPI/TextAPIError.cpp
@@ -21,14 +21,17 @@ char TextAPIError::ID = 0;
void TextAPIError::log(raw_ostream &OS) const {
switch (EC) {
case TextAPIErrorCode::NoSuchArchitecture:
- OS << "no such architecture\n";
- return;
+ OS << "no such architecture";
+ break;
case TextAPIErrorCode::InvalidInputFormat:
- OS << "invalid input format\n";
- return;
+ OS << "invalid input format";
+ break;
default:
llvm_unreachable("unhandled TextAPIErrorCode");
}
+ if (!Msg.empty())
+ OS << ": " << Msg;
+ OS << "\n";
}
std::error_code TextAPIError::convertToErrorCode() const {
diff --git a/llvm/test/tools/llvm-readtapi/command-line.test b/llvm/test/tools/llvm-readtapi/command-line.test
new file mode 100644
index 000000000000000..3b17194a7c14792
--- /dev/null
+++ b/llvm/test/tools/llvm-readtapi/command-line.test
@@ -0,0 +1,7 @@
+; RUN: llvm-readtapi --help 2>&1 | FileCheck %s
+; RUN: llvm-readtapi -help 2>&1 | FileCheck %s
+
+CHECK: OVERVIEW: LLVM TAPI file reader and manipulator
+CHECK: USAGE: llvm-readtapi [options] <inputs>
+CHECK: OPTIONS:
+CHECK: -help display this help
diff --git a/llvm/test/tools/llvm-readtapi/compare-flags.test b/llvm/test/tools/llvm-readtapi/compare-flags.test
index 06184eeb7661e10..82e0230d4cd898d 100644
--- a/llvm/test/tools/llvm-readtapi/compare-flags.test
+++ b/llvm/test/tools/llvm-readtapi/compare-flags.test
@@ -1,16 +1,21 @@
; RUN: rm -rf %t
; RUN: split-file %s %t
-; RUN: not llvm-readtapi --compare %t/tbdv4.tbd %t/tbdv5.tbd 2>&1 | FileCheck %s
+; RUN: not llvm-readtapi --compare %t/tbdv4.tbd %t/tbdv5.tbd -o %t/output.txt 2>&1 | FileCheck %s --allow-empty
+; RUN: FileCheck %s --check-prefix FILEOUT < %t/output.txt
-; CHECK: < {{.*}}tbdv4.tbd
-; CHECK: > {{.*}}tbdv5.tbd
+; CHECK-NOT: error:
+; CHECK-NOT: warning:
+
+; FILEOUT: < {{.*}}tbdv4.tbd
+; FILEOUT: > {{.*}}tbdv5.tbd
+
+; FILEOUT: Two Level Namespace
+; FILEOUT-NEXT: < true
+; FILEOUT-NEXT: > false
+; FILEOUT-NEXT: Shared Cache Ineligible
+; FILEOUT-NEXT: < true
+; FILEOUT-NEXT: > false
-CHECK: Two Level Namespace
-CHECK-NEXT: < true
-CHECK-NEXT: > false
-CHECK-NEXT: Shared Cache Ineligible
-CHECK-NEXT: < true
-CHECK-NEXT: > false
//--- tbdv4.tbd
diff --git a/llvm/tools/llvm-readtapi/CMakeLists.txt b/llvm/tools/llvm-readtapi/CMakeLists.txt
index 277011cf13c8e41..b4d6c9959ec1a62 100644
--- a/llvm/tools/llvm-readtapi/CMakeLists.txt
+++ b/llvm/tools/llvm-readtapi/CMakeLists.txt
@@ -1,12 +1,20 @@
set(LLVM_LINK_COMPONENTS
Object
Support
+ Option
TextAPI
)
+set(LLVM_TARGET_DEFINITIONS Opts.td)
+tablegen(LLVM Opts.inc -gen-opt-parser-defs)
+add_public_tablegen_target(ReadTAPIOptsTableGen)
+
add_llvm_tool(llvm-readtapi
llvm-readtapi.cpp
DiffEngine.cpp
+
+ DEPENDS
+ ReadTAPIOptsTableGen
)
if(LLVM_INSTALL_BINUTILS_SYMLINKS)
diff --git a/llvm/tools/llvm-readtapi/Opts.td b/llvm/tools/llvm-readtapi/Opts.td
new file mode 100644
index 000000000000000..40701658fb3e8f9
--- /dev/null
+++ b/llvm/tools/llvm-readtapi/Opts.td
@@ -0,0 +1,16 @@
+// Include the common option parsing interfaces.
+include "llvm/Option/OptParser.td"
+
+class FF<string name, string help>: Flag<["-", "--"], name>, HelpText<help>;
+class JS<string name, string help, string var = ""> : JoinedOrSeparate<["-", "--"], name>, HelpText<help>, MetaVarName<var>;
+
+//
+// General Driver options
+//
+def help : FF<"help", "display this help">;
+def output: JS<"o", "Write output to <file>","<file>">;
+
+//
+// Compare options
+//
+def compare : FF<"compare", "compare tapi files for library differences">;
diff --git a/llvm/tools/llvm-readtapi/llvm-readtapi.cpp b/llvm/tools/llvm-readtapi/llvm-readtapi.cpp
index 1a3a66e2a7a1c3c..2aba59033e25cff 100644
--- a/llvm/tools/llvm-readtapi/llvm-readtapi.cpp
+++ b/llvm/tools/llvm-readtapi/llvm-readtapi.cpp
@@ -11,12 +11,16 @@
//===----------------------------------------------------------------------===//
#include "DiffEngine.h"
#include "llvm/Object/TapiUniversal.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/TextAPI/TextAPIError.h"
#include <cstdlib>
using namespace llvm;
@@ -24,26 +28,41 @@ using namespace MachO;
using namespace object;
namespace {
-cl::OptionCategory TapiCat("llvm-readtapi options");
-cl::OptionCategory CompareCat("llvm-readtapi --compare options");
-
-cl::opt<std::string> InputFileName(cl::Positional, cl::desc("<tapi file>"),
- cl::Required, cl::cat(TapiCat));
-cl::opt<std::string> CompareInputFileName(cl::Positional,
- cl::desc("<comparison file>"),
- cl::Required, cl::cat(CompareCat));
-enum OutputKind {
- Compare,
+using namespace llvm::opt;
+enum ID {
+ OPT_INVALID = 0, // This is not an option ID.
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
+#include "Opts.inc"
+#undef OPTION
};
-cl::opt<OutputKind>
- Output(cl::desc("choose command action:"),
- cl::values(clEnumValN(Compare, "compare",
- "compare tapi file for library differences")),
- cl::init(OutputKind::Compare), cl::cat(TapiCat));
-} // anonymous namespace
+#define PREFIX(NAME, VALUE) \
+ static constexpr StringLiteral NAME##_init[] = VALUE; \
+ static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
+ std::size(NAME##_init) - 1);
+#include "Opts.inc"
+#undef PREFIX
+
+static constexpr opt::OptTable::Info InfoTable[] = {
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#include "Opts.inc"
+#undef OPTION
+};
+
+class TAPIOptTable : public opt::GenericOptTable {
+public:
+ TAPIOptTable() : opt::GenericOptTable(InfoTable) {
+ setGroupedShortOptions(true);
+ }
+};
+
+struct Context {
+ std::vector<std::string> Inputs;
+ std::unique_ptr<llvm::raw_fd_stream> OutStream;
+};
-Expected<std::unique_ptr<Binary>> convertFileToBinary(std::string &Filename) {
+Expected<std::unique_ptr<Binary>>
+convertFileToBinary(const StringRef Filename) {
ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
MemoryBuffer::getFileOrSTDIN(Filename);
if (BufferOrErr.getError())
@@ -51,40 +70,73 @@ Expected<std::unique_ptr<Binary>> convertFileToBinary(std::string &Filename) {
return createBinary(BufferOrErr.get()->getMemBufferRef());
}
-int main(int Argc, char **Argv) {
- InitLLVM X(Argc, Argv);
- cl::HideUnrelatedOptions(TapiCat);
- cl::ParseCommandLineOptions(Argc, Argv,
- "TAPI File Reader and Manipulator Tool");
-
- if (Output == OutputKind::Compare) {
- if (InputFileName.empty() || CompareInputFileName.empty()) {
- cl::PrintHelpMessage();
- return EXIT_FAILURE;
- }
+const int NON_TAPI_EXIT_CODE = 2;
- ExitOnError ExitOnErr("error: '" + InputFileName + "' ",
- /*DefaultErrorExitCode=*/2);
- auto BinLHS = ExitOnErr(convertFileToBinary(InputFileName));
+bool handleCompareAction(const Context &Ctx) {
+ ExitOnError ExitOnErr("error: ", /*DefaultErrorExitCode=*/NON_TAPI_EXIT_CODE);
+ if (Ctx.Inputs.size() != 2) {
+ ExitOnErr(make_error<TextAPIError>(TextAPIErrorCode::InvalidInputFormat,
+ "compare only supports 2 input files"));
+ }
+ StringRef InputFileName = Ctx.Inputs.front();
+ ExitOnErr.setBanner("error: '" + InputFileName.str() + "' ");
+ auto BinLHS = ExitOnErr(convertFileToBinary(InputFileName));
- TapiUniversal *FileLHS = dyn_cast<TapiUniversal>(BinLHS.get());
- if (!FileLHS) {
- ExitOnErr(createStringError(std::errc::executable_format_error,
- "unsupported file format"));
- }
+ TapiUniversal *FileLHS = dyn_cast<TapiUniversal>(BinLHS.get());
+ if (!FileLHS) {
+ ExitOnErr(createStringError(std::errc::executable_format_error,
+ "unsupported file format"));
+ }
- ExitOnErr.setBanner("error: '" + CompareInputFileName + "' ");
- auto BinRHS = ExitOnErr(convertFileToBinary(CompareInputFileName));
+ StringRef CompareInputFileName = Ctx.Inputs.at(1);
+ ExitOnErr.setBanner("error: '" + CompareInputFileName.str() + "' ");
+ auto BinRHS = ExitOnErr(convertFileToBinary(CompareInputFileName));
- TapiUniversal *FileRHS = dyn_cast<TapiUniversal>(BinRHS.get());
- if (!FileRHS) {
- ExitOnErr(createStringError(std::errc::executable_format_error,
- "unsupported file format"));
- }
+ TapiUniversal *FileRHS = dyn_cast<TapiUniversal>(BinRHS.get());
+ if (!FileRHS) {
+ ExitOnErr(createStringError(std::errc::executable_format_error,
+ "unsupported file format"));
+ }
+
+ raw_ostream &OS = Ctx.OutStream ? *Ctx.OutStream : outs();
+ return DiffEngine(FileLHS, FileRHS).compareFiles(OS);
+}
- raw_ostream &OS = outs();
- return DiffEngine(FileLHS, FileRHS).compareFiles(OS);
+} // anonymous namespace
+
+int main(int Argc, char **Argv) {
+ InitLLVM X(Argc, Argv);
+ BumpPtrAllocator A;
+ StringSaver Saver(A);
+ TAPIOptTable Tbl;
+ Context Ctx;
+ opt::InputArgList Args =
+ Tbl.parseArgs(Argc, Argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {
+ WithColor::error(errs(), "llvm-readtapi") << Msg << "\n";
+ exit(1);
+ });
+ if (Args.hasArg(OPT_help)) {
+ Tbl.printHelp(outs(), "llvm-readtapi [options] <inputs>",
+ "LLVM TAPI file reader and manipulator");
+ return EXIT_SUCCESS;
+ }
+
+ for (opt::Arg *A : Args.filtered(OPT_INPUT))
+ Ctx.Inputs.push_back(A->getValue());
+
+ if (opt::Arg *A = Args.getLastArg(OPT_output)) {
+ std::string OutputLoc = std::move(A->getValue());
+ std::error_code EC;
+ Ctx.OutStream = std::make_unique<llvm::raw_fd_stream>(OutputLoc, EC);
+ if (EC) {
+ llvm::errs() << "error opening the file '" << OutputLoc
+ << "': " << EC.message() << "\n";
+ return NON_TAPI_EXIT_CODE;
+ }
}
- return 0;
+ if (Args.hasArg(OPT_compare))
+ return handleCompareAction(Ctx);
+
+ return EXIT_SUCCESS;
}
More information about the llvm-commits
mailing list