diff --git a/llvm/tools/llvm-debuginfod/CMakeLists.txt b/llvm/tools/llvm-debuginfod/CMakeLists.txt index 72f2c19848489..d32c6826d7687 100644 --- a/llvm/tools/llvm-debuginfod/CMakeLists.txt +++ b/llvm/tools/llvm-debuginfod/CMakeLists.txt @@ -1,8 +1,16 @@ set(LLVM_LINK_COMPONENTS + Option Support ) +set(LLVM_TARGET_DEFINITIONS Opts.td) +tablegen(LLVM Opts.inc -gen-opt-parser-defs) +add_public_tablegen_target(DebugInfodOptsTableGen) + add_llvm_tool(llvm-debuginfod llvm-debuginfod.cpp + + DEPENDS + DebugInfodOptsTableGen ) target_link_libraries(llvm-debuginfod PRIVATE LLVMDebuginfod) if(LLVM_INSTALL_BINUTILS_SYMLINKS) diff --git a/llvm/tools/llvm-debuginfod/Opts.td b/llvm/tools/llvm-debuginfod/Opts.td new file mode 100644 index 0000000000000..1de241a3fc2a1 --- /dev/null +++ b/llvm/tools/llvm-debuginfod/Opts.td @@ -0,0 +1,20 @@ +include "llvm/Option/OptParser.td" + +class F : Flag<["-"], name>, HelpText; +class FF: Flag<["--"], name>, HelpText; +class S: Separate<["-"], name>, HelpText, MetaVarName; + +def help : FF<"help", "Display available options">; +def : F<"h", "Alias for --help">, Alias; +def max_concurrency : + S<"c", "", "Maximum number of files to scan concurrently. " + "If 0, use the hardware concurrency.">; +def host_interface : S<"i", "", "Host interface to bind to.">; +def min_interval : + S<"m", "", "Minimum number of seconds to wait before an on-demand update can be" + "triggered by a request for a buildid which is not in the collection.">; +def port : S<"p", "", "Port to listen on. Set to 0 to bind to any available port.">; +def scan_interval : + S<"t", "", "Number of seconds to wait between subsequent " + "automated scans of the filesystem.">; +def verbose_logging : F<"v", "Enable verbose logging.">; diff --git a/llvm/tools/llvm-debuginfod/llvm-debuginfod.cpp b/llvm/tools/llvm-debuginfod/llvm-debuginfod.cpp index c64d4dbb3155f..7edc78e7f3f2a 100644 --- a/llvm/tools/llvm-debuginfod/llvm-debuginfod.cpp +++ b/llvm/tools/llvm-debuginfod/llvm-debuginfod.cpp @@ -15,60 +15,120 @@ /// //===----------------------------------------------------------------------===// +#include "llvm/ADT/StringRef.h" #include "llvm/Debuginfod/Debuginfod.h" #include "llvm/Debuginfod/HTTPClient.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/ThreadPool.h" using namespace llvm; -cl::OptionCategory DebuginfodCategory("llvm-debuginfod Options"); - -static cl::list ScanPaths(cl::Positional, - cl::desc(""), - cl::cat(DebuginfodCategory)); - -static cl::opt - Port("p", cl::init(0), - cl::desc("Port to listen on. Set to 0 to bind to any available port."), - cl::cat(DebuginfodCategory)); - -static cl::opt - HostInterface("i", cl::init("0.0.0.0"), - cl::desc("Host interface to bind to."), - cl::cat(DebuginfodCategory)); - -static cl::opt - ScanInterval("t", cl::init(300), - cl::desc("Number of seconds to wait between subsequent " - "automated scans of the filesystem."), - cl::cat(DebuginfodCategory)); - -static cl::opt MinInterval( - "m", cl::init(10), - cl::desc( - "Minimum number of seconds to wait before an on-demand update can be " - "triggered by a request for a buildid which is not in the collection."), - cl::cat(DebuginfodCategory)); - -static cl::opt - MaxConcurrency("c", cl::init(0), - cl::desc("Maximum number of files to scan concurrently. If " - "0, use the hardware concurrency."), - cl::cat(DebuginfodCategory)); - -static cl::opt VerboseLogging("v", cl::init(false), - cl::desc("Enable verbose logging."), - cl::cat(DebuginfodCategory)); +// Command-line option boilerplate. +namespace { +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) \ + static constexpr StringLiteral NAME##_init[] = VALUE; \ + static constexpr ArrayRef NAME(NAME##_init, \ + std::size(NAME##_init) - 1); +#include "Opts.inc" +#undef PREFIX + +static constexpr 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 DebuginfodOptTable : public opt::GenericOptTable { +public: + DebuginfodOptTable() : GenericOptTable(InfoTable) {} +}; +} // end anonymous namespace + +// Options +static unsigned Port; +static std::string HostInterface; +static int ScanInterval; +static double MinInterval; +static size_t MaxConcurrency; +static bool VerboseLogging; +static std::vector ScanPaths; ExitOnError ExitOnErr; +template +static void parseIntArg(const opt::InputArgList &Args, int ID, T &Value, + T Default) { + if (const opt::Arg *A = Args.getLastArg(ID)) { + StringRef V(A->getValue()); + if (!llvm::to_integer(V, Value, 0)) { + errs() << A->getSpelling() + ": expected an integer, but got '" + V + "'"; + exit(1); + } + } else { + Value = Default; + } +} + +static void parseArgs(int argc, char **argv) { + DebuginfodOptTable Tbl; + llvm::StringRef ToolName = argv[0]; + llvm::BumpPtrAllocator A; + llvm::StringSaver Saver{A}; + opt::InputArgList Args = + Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) { + llvm::errs() << Msg << '\n'; + std::exit(1); + }); + + if (Args.hasArg(OPT_help)) { + Tbl.printHelp(llvm::outs(), + "llvm-debuginfod [options] ", + ToolName.str().c_str()); + std::exit(0); + } + + VerboseLogging = Args.hasArg(OPT_verbose_logging); + ScanPaths = Args.getAllArgValues(OPT_INPUT); + + parseIntArg(Args, OPT_port, Port, 0u); + parseIntArg(Args, OPT_scan_interval, ScanInterval, 300); + parseIntArg(Args, OPT_max_concurrency, MaxConcurrency, 0ul); + + if (const opt::Arg *A = Args.getLastArg(OPT_min_interval)) { + StringRef V(A->getValue()); + if (!llvm::to_float(V, MinInterval)) { + errs() << A->getSpelling() + ": expected a number, but got '" + V + "'"; + exit(1); + } + } else { + MinInterval = 10.0; + } + + HostInterface = Args.getLastArgValue(OPT_host_interface, "0.0.0.0"); +} + int main(int argc, char **argv) { InitLLVM X(argc, argv); HTTPClient::initialize(); - cl::HideUnrelatedOptions({&DebuginfodCategory}); - cl::ParseCommandLineOptions(argc, argv); + parseArgs(argc, argv); SmallVector Paths; for (const std::string &Path : ScanPaths) diff --git a/llvm/utils/gn/secondary/llvm/tools/llvm-debuginfod/BUILD.gn b/llvm/utils/gn/secondary/llvm/tools/llvm-debuginfod/BUILD.gn index c8ee330a867cb..236124f351bf7 100644 --- a/llvm/utils/gn/secondary/llvm/tools/llvm-debuginfod/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/tools/llvm-debuginfod/BUILD.gn @@ -1,6 +1,12 @@ import("//llvm/tools/binutils_symlinks.gni") +import("//llvm/utils/TableGen/tablegen.gni") import("//llvm/utils/gn/build/symlink_or_copy.gni") +tablegen("Opts") { + visibility = [ ":llvm-debuginfod" ] + args = [ "-gen-opt-parser-defs" ] +} + if (llvm_install_binutils_symlinks) { symlink_or_copy("debuginfod") { deps = [ ":llvm-debuginfod" ] @@ -19,7 +25,9 @@ group("symlinks") { executable("llvm-debuginfod") { deps = [ + ":Opts", "//llvm/lib/Debuginfod", + "//llvm/lib/Option", "//llvm/lib/Support", ] sources = [ "llvm-debuginfod.cpp" ]