diff --git a/llvm/test/tools/llvm-libtool-darwin/invalid-input-output-args.test b/llvm/test/tools/llvm-libtool-darwin/invalid-input-output-args.test --- a/llvm/test/tools/llvm-libtool-darwin/invalid-input-output-args.test +++ b/llvm/test/tools/llvm-libtool-darwin/invalid-input-output-args.test @@ -10,7 +10,7 @@ # RUN: not llvm-libtool-darwin -static %t.input 2>&1 | \ # RUN: FileCheck %s --check-prefix=NO-OUTPUT -# NO-OUTPUT: for the -o option: must be specified at least once! +# NO-OUTPUT: for the -o option: must be specified ## Missing argument to -o: # RUN: not llvm-libtool-darwin -static %t.input -o 2>&1 | \ @@ -22,7 +22,7 @@ # RUN: not llvm-libtool-darwin -static %t.input -o %t.lib1 -o %t.lib2 2>&1 | \ # RUN: FileCheck %s --check-prefix=DOUBLE-OUTPUT -# DOUBLE-OUTPUT: for the -o option: must occur exactly one time! +# DOUBLE-OUTPUT: for the -o option: may only occur zero or one times! ## Input file not found: # RUN: not llvm-libtool-darwin -static -o %t.lib %t.missing 2>&1 | \ diff --git a/llvm/test/tools/llvm-libtool-darwin/missing-library-type.test b/llvm/test/tools/llvm-libtool-darwin/missing-library-type.test --- a/llvm/test/tools/llvm-libtool-darwin/missing-library-type.test +++ b/llvm/test/tools/llvm-libtool-darwin/missing-library-type.test @@ -2,4 +2,4 @@ # RUN: not llvm-libtool-darwin -o %t.lib %t.input 2>&1 | \ # RUN: FileCheck %s --check-prefix=MISSING-OPERATION -# MISSING-OPERATION: Library Type: option: must be specified at least once! +# MISSING-OPERATION: Library Type: option: must be specified diff --git a/llvm/test/tools/llvm-libtool-darwin/version.test b/llvm/test/tools/llvm-libtool-darwin/version.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-libtool-darwin/version.test @@ -0,0 +1,25 @@ +## Test the -V flag, which prints the version number to stdout. It also allows +## for no operation to be specified, but if an operation is specified, it should +## still occur and regular argument parsing errors should be surfaced (unlike +## cctools libtool, which silences all argument parsing errors when -V is +## specified). + +## Test -V by itself +# RUN: llvm-libtool-darwin -V | FileCheck %s +## The specific version number, vendor string, etc. will differ across +## environments, so this is the most specific we can get. +# CHECK: LLVM version + +## Parsing errors should not be surfaced when no operation is specified +# RUN: llvm-libtool-darwin -V -D -U | FileCheck %s + +## Regular errors should occur when an operation is specified +# RUN: not llvm-libtool-darwin -V -static 2>&1 | FileCheck --check-prefix=ERROR %s +# ERROR: for the -o option: must be specified + +## A valid command line should print the version and perform the operation +# RUN: yaml2obj %S/Inputs/input1.yaml -o %t-input1.o +# RUN: yaml2obj %S/Inputs/input2.yaml -o %t-input2.o +# RUN: llvm-libtool-darwin -static -o %t.lib %t-input1.o %t-input2.o -V | FileCheck %s +# RUN: llvm-libtool-darwin -static -o %t2.lib %t-input1.o %t-input2.o +# RUN: cmp %t.lib %t2.lib diff --git a/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp b/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp --- a/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp +++ b/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp @@ -32,7 +32,7 @@ cl::OptionCategory LibtoolCategory("llvm-libtool-darwin Options"); static cl::opt OutputFile("o", cl::desc("Specify output filename"), - cl::value_desc("filename"), cl::Required, + cl::value_desc("filename"), cl::cat(LibtoolCategory)); static cl::list InputFiles(cl::Positional, @@ -44,14 +44,14 @@ "arch_only", cl::desc("Specify architecture type for output library"), cl::value_desc("arch_type"), cl::ZeroOrMore, cl::cat(LibtoolCategory)); -enum class Operation { Static }; +enum class Operation { None, Static }; static cl::opt LibraryOperation( cl::desc("Library Type: "), cl::values( clEnumValN(Operation::Static, "static", "Produce a statically linked library from the input files")), - cl::Required, cl::cat(LibtoolCategory)); + cl::init(Operation::None), cl::cat(LibtoolCategory)); static cl::opt DeterministicOption( "D", cl::desc("Use zero for timestamps and UIDs/GIDs (Default)"), @@ -81,6 +81,10 @@ " libraries"), cl::ZeroOrMore, cl::Prefix, cl::cat(LibtoolCategory)); +static cl::opt + VersionOption("V", cl::desc("Print the version number and exit"), + cl::cat(LibtoolCategory)); + static const std::array StandardSearchDirs{ "/lib", "/usr/lib", @@ -444,6 +448,23 @@ Config C; cl::ParseCommandLineOptions(Argc, Argv, "llvm-libtool-darwin\n"); + if (LibraryOperation == Operation::None) { + if (!VersionOption) { + std::string Error; + raw_string_ostream Stream(Error); + LibraryOperation.error("must be specified", "", Stream); + return createStringError(std::errc::invalid_argument, Error.c_str()); + } + return C; + } + + if (OutputFile.empty()) { + std::string Error; + raw_string_ostream Stream(Error); + OutputFile.error("must be specified", "o", Stream); + return createStringError(std::errc::invalid_argument, Error.c_str()); + } + if (DeterministicOption && NonDeterministicOption) return createStringError(std::errc::invalid_argument, "cannot specify both -D and -U flags"); @@ -483,8 +504,13 @@ return EXIT_FAILURE; } + if (VersionOption) + cl::PrintVersionMessage(); + Config C = *ConfigOrErr; switch (LibraryOperation) { + case Operation::None: + break; case Operation::Static: if (Error E = createStaticLibrary(C)) { WithColor::defaultErrorHandler(std::move(E));