diff --git a/llvm/test/tools/llvm-size/help.test b/llvm/test/tools/llvm-size/help.test
--- a/llvm/test/tools/llvm-size/help.test
+++ b/llvm/test/tools/llvm-size/help.test
@@ -1,15 +1,10 @@
## Show that help text is printed correctly when requested.
-RUN: llvm-size -h | FileCheck %s --check-prefixes=CHECK,CATEG
-RUN: llvm-size --help | FileCheck %s --check-prefixes=CHECK,CATEG
-RUN: llvm-size --help-list \
-RUN: | FileCheck %s --check-prefixes=CHECK,LIST
+RUN: llvm-size -h | FileCheck %s
+RUN: llvm-size --help | FileCheck %s
-CHECK: OVERVIEW: llvm object size dumper
-CHECK: USAGE: llvm-size{{(.exe)?}} [options] {{$}}
+CHECK: OVERVIEW: LLVM object size dumper
+CHECK: USAGE: {{.*}}llvm-size{{(.exe)?}} [options] {{$}}
CHECK: OPTIONS:
-CATEG: Generic Options:
-LIST-NOT: Generic Options:
-CATEG: llvm-size Options:
-LIST-NOT: llvm-size Options:
+CHECK: OPTIONS (Mach-O specific):
CHECK: @FILE
diff --git a/llvm/test/tools/llvm-size/radix.test b/llvm/test/tools/llvm-size/radix.test
--- a/llvm/test/tools/llvm-size/radix.test
+++ b/llvm/test/tools/llvm-size/radix.test
@@ -121,7 +121,7 @@
# RUN: not llvm-size %t1.o --radix=bad 2>&1 \
# RUN: | FileCheck %s --check-prefix=BAD-VAL -DNUM=bad
-# BAD-VAL: {{.*}}llvm-size{{.*}}: for the --radix option: Cannot find option named '[[NUM]]'!
+# BAD-VAL: {{.*}}llvm-size{{.*}}: --radix value should be one of: 8, 10, 16
--- !ELF
FileHeader:
diff --git a/llvm/test/tools/llvm-size/unknown-format.test b/llvm/test/tools/llvm-size/unknown-format.test
--- a/llvm/test/tools/llvm-size/unknown-format.test
+++ b/llvm/test/tools/llvm-size/unknown-format.test
@@ -1,4 +1,4 @@
## Show that the an error is emitted if an unknown value is passed to --format.
# RUN: not llvm-size --format=unknown 2>&1 | FileCheck %s
-# CHECK: {{.*}}llvm-size{{.*}}: for the --format option: Cannot find option named 'unknown'!
+# CHECK: {{.*}}llvm-size{{.*}}: error: --format value should be one of: 'berkeley', 'darwin', 'sysv'
diff --git a/llvm/tools/llvm-size/CMakeLists.txt b/llvm/tools/llvm-size/CMakeLists.txt
--- a/llvm/tools/llvm-size/CMakeLists.txt
+++ b/llvm/tools/llvm-size/CMakeLists.txt
@@ -1,10 +1,17 @@
set(LLVM_LINK_COMPONENTS
Object
+ Option
Support
)
+set(LLVM_TARGET_DEFINITIONS Opts.td)
+tablegen(LLVM Opts.inc -gen-opt-parser-defs)
+add_public_tablegen_target(SizeOptsTableGen)
+
add_llvm_tool(llvm-size
llvm-size.cpp
+ DEPENDS
+ SizeOptsTableGen
)
if(LLVM_INSTALL_BINUTILS_SYMLINKS)
diff --git a/llvm/tools/llvm-size/llvm-size.cpp b/llvm/tools/llvm-size/llvm-size.cpp
--- a/llvm/tools/llvm-size/llvm-size.cpp
+++ b/llvm/tools/llvm-size/llvm-size.cpp
@@ -18,6 +18,9 @@
#include "llvm/Object/MachO.h"
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
@@ -33,23 +36,56 @@
using namespace llvm;
using namespace object;
-cl::OptionCategory SizeCat("llvm-size Options");
+namespace {
+using namespace llvm::opt; // for HelpHidden in Opts.inc
+enum ID {
+ OPT_INVALID = 0, // This is not an option ID.
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ OPT_##ID,
+#include "Opts.inc"
+#undef OPTION
+};
+
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "Opts.inc"
+#undef PREFIX
+
+const opt::OptTable::Info InfoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ { \
+ PREFIX, NAME, HELPTEXT, \
+ METAVAR, OPT_##ID, opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, \
+ OPT_##ALIAS, ALIASARGS, VALUES},
+#include "Opts.inc"
+#undef OPTION
+};
+
+class SizeOptTable : public opt::OptTable {
+public:
+ SizeOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
+};
enum OutputFormatTy { berkeley, sysv, darwin };
-static cl::opt
- OutputFormat("format", cl::desc("Specify output format"),
- cl::values(clEnumVal(sysv, "System V format"),
- clEnumVal(berkeley, "Berkeley format"),
- clEnumVal(darwin, "Darwin -m format")),
- cl::init(berkeley), cl::cat(SizeCat));
-
-static cl::opt
- OutputFormatShort(cl::desc("Specify output format"),
- cl::values(clEnumValN(sysv, "A", "System V format"),
- clEnumValN(berkeley, "B", "Berkeley format"),
- clEnumValN(darwin, "m", "Darwin -m format")),
- cl::init(berkeley), cl::cat(SizeCat));
+enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 };
+} // namespace
+static bool ArchAll = false;
+static std::vector ArchFlags;
+static bool ELFCommons;
+static OutputFormatTy OutputFormat;
+static bool DarwinLongFormat;
+static RadixTy Radix;
+static bool TotalSizes;
+
+static std::vector InputFilenames;
+
+static std::string ToolName;
+
+// States
+static bool HadError = false;
static bool BerkeleyHeaderPrinted = false;
static bool MoreThanOneFile = false;
static uint64_t TotalObjectText = 0;
@@ -57,59 +93,13 @@
static uint64_t TotalObjectBss = 0;
static uint64_t TotalObjectTotal = 0;
-cl::opt
- DarwinLongFormat("l",
- cl::desc("When format is darwin, use long format "
- "to include addresses and offsets."),
- cl::cat(SizeCat));
-
-cl::opt
- ELFCommons("common",
- cl::desc("Print common symbols in the ELF file. When using "
- "Berkeley format, this is added to bss."),
- cl::init(false), cl::cat(SizeCat));
-
-static cl::list
- ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
- cl::ZeroOrMore, cl::cat(SizeCat));
-static bool ArchAll = false;
-
-enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 };
-static cl::opt Radix(
- "radix", cl::desc("Print size in radix"), cl::init(decimal),
- cl::values(clEnumValN(octal, "8", "Print size in octal"),
- clEnumValN(decimal, "10", "Print size in decimal"),
- clEnumValN(hexadecimal, "16", "Print size in hexadecimal")),
- cl::cat(SizeCat));
-
-static cl::opt RadixShort(
- cl::desc("Print size in radix:"),
- cl::values(clEnumValN(octal, "o", "Print size in octal"),
- clEnumValN(decimal, "d", "Print size in decimal"),
- clEnumValN(hexadecimal, "x", "Print size in hexadecimal")),
- cl::init(decimal), cl::cat(SizeCat));
-
-static cl::opt
- TotalSizes("totals",
- cl::desc("Print totals of all objects - Berkeley format only"),
- cl::init(false), cl::cat(SizeCat));
-
-static cl::alias TotalSizesShort("t", cl::desc("Short for --totals"),
- cl::aliasopt(TotalSizes));
-
-static cl::list
- InputFilenames(cl::Positional, cl::desc(""), cl::ZeroOrMore);
-
-static cl::extrahelp
- HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
-
-static bool HadError = false;
-
-static std::string ToolName;
-
-static void error(const Twine &Message, StringRef File) {
+static void error(const Twine &Message, StringRef File = "") {
HadError = true;
- WithColor::error(errs(), ToolName) << "'" << File << "': " << Message << "\n";
+ if (File.empty())
+ WithColor::error(errs(), ToolName) << Message << '\n';
+ else
+ WithColor::error(errs(), ToolName)
+ << "'" << File << "': " << Message << '\n';
}
// This version of error() prints the archive name and member name, for example:
@@ -874,27 +864,66 @@
int main(int argc, char **argv) {
InitLLVM X(argc, argv);
- cl::HideUnrelatedOptions(SizeCat);
- cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n");
-
+ BumpPtrAllocator A;
+ StringSaver Saver(A);
+ SizeOptTable Tbl;
ToolName = argv[0];
- if (OutputFormatShort.getNumOccurrences())
- OutputFormat = static_cast(OutputFormatShort);
- if (RadixShort.getNumOccurrences())
- Radix = RadixShort.getValue();
+ opt::InputArgList Args = Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver,
+ [&](StringRef Msg) { error(Msg); });
+ if (Args.hasArg(OPT_help)) {
+ Tbl.printHelp(
+ outs(),
+ (Twine(ToolName) + " [options] ").str().c_str(),
+ "LLVM object size dumper");
+ // TODO Replace this with OptTable API once it adds extrahelp support.
+ outs() << "\nPass @FILE as argument to read options from FILE.\n";
+ return 0;
+ }
+ if (Args.hasArg(OPT_version)) {
+ outs() << ToolName << '\n';
+ cl::PrintVersionMessage();
+ return 0;
+ }
- for (StringRef Arch : ArchFlags) {
- if (Arch == "all") {
- ArchAll = true;
- } else {
- if (!MachOObjectFile::isValidArch(Arch)) {
+ ELFCommons = Args.hasArg(OPT_common);
+ DarwinLongFormat = Args.hasArg(OPT_l);
+ TotalSizes = Args.hasArg(OPT_totals);
+ StringRef V = Args.getLastArgValue(OPT_format_EQ, "berkeley");
+ if (V == "berkeley")
+ OutputFormat = berkeley;
+ else if (V == "darwin")
+ OutputFormat = darwin;
+ else if (V == "sysv")
+ OutputFormat = sysv;
+ else
+ error("--format value should be one of: 'berkeley', 'darwin', 'sysv'");
+ V = Args.getLastArgValue(OPT_radix_EQ, "10");
+ if (V == "8")
+ Radix = RadixTy::octal;
+ else if (V == "10")
+ Radix = RadixTy::decimal;
+ else if (V == "16")
+ Radix = RadixTy::hexadecimal;
+ else
+ error("--radix value should be one of: 8, 10, 16 ");
+
+ for (const auto *A : Args.filtered(OPT_arch_EQ)) {
+ SmallVector Values;
+ llvm::SplitString(A->getValue(), Values, ",");
+ for (StringRef V : Values) {
+ if (V == "all")
+ ArchAll = true;
+ else if (MachOObjectFile::isValidArch(V))
+ ArchFlags.push_back(V);
+ else {
outs() << ToolName << ": for the -arch option: Unknown architecture "
- << "named '" << Arch << "'";
+ << "named '" << V << "'";
return 1;
}
}
}
+ InputFilenames = Args.getAllArgValues(OPT_INPUT);
if (InputFilenames.empty())
InputFilenames.push_back("a.out");