Branch | MSVC 2015, 2017, 2019, 2022 / CLANG 6, 9-17 / GCC 7-13 | Test Coverage |
---|---|---|
master | ||
dev |
C++ command line parser toolkit for kids of all ages.
- GNU style command lines (-o, --output=FILE, etc.)
- Parses directly to any supplied (or implicitly created) variable that is:
- Default constructible
- Copyable
- Either assignable or constructible from string, has an istream extraction operator, or has a specialization of Cli::Convert::fromString<T>().
- Render help text
- Option definitions can be scattered across multiple files.
- Git style subcommands.
- Response files (requires
<filesystem>
support). - Convert argv to/from command line with Windows, Posix, or GNU semantics.
- Wordwrap arbitrary paragraphs and simple text tables for console.
- Works whether or not exceptions and RTTI are disabled.
- Distributed under the Boost Software License, Version 1.0.
Check out the complete documentation, contains many examples, and the quick reference.
#include "dimcli/cli.h"
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char * argv[]) {
Dim::Cli cli;
// Define option that populates an existing variable.
int count;
cli.opt(&count, "c n count", 1).desc("Times to say hello.");
// Or, define option without referencing an existing variable. The variable
// to populate is then implicitly allocated and the returned object is used
// like a smart pointer to access it.
auto & name = cli.opt<string>("name", "Unknown")
.desc("Who to greet.");
// Parse command line.
if (!cli.parse(argc, argv))
return cli.printError(cerr);
// Access the options.
if (!name)
cout << "Greeting the unknown." << endl;
for (int i = 0; i < count; ++i)
cout << "Hello " << *name << "!" << endl;
return 0;
}
What it does when run:
$ a.out -x
Error: Unknown option: -x
$ a.out --help
Usage: a.out [OPTIONS]
Options:
-c, -n, --count=NUM Times to say hello. (default: 1)
--name=STRING Who to greet. (default: Unknown)
--help Show this message and exit.
$ a.out --count=2
Greeting the unknown.
Hello Unknown!
Hello Unknown!
$ a.out --name John
Hello John!
All you need is:
- libs/dimcli/cli.h
- libs/dimcli/cli.cpp
Using vcpkg
- vcpkg install dimcli
Get the latest dimcli release.
Build it (this example uses Visual C++ 2015 to install a 64-bit build to c:\dimcli on a windows machine):
- md build & cd build
- cmake .. -DCMAKE_INSTALL_PREFIX=c:\dimcli -G "Visual Studio 14 2015 Win64"
- cmake --build .
- ctest -C Debug
- cmake --build . --target install
- Prerequisites
- install cmake >= 3.6
- install Visual Studio >= 2015
- include the "Github Extension for Visual Studio" (if you care)
- include git
- Make the library (assuming VS 2015)
- git clone https://github.com/gknowles/dimcli.git
- cd dimcli
- git submodule update --init
- md build & cd build
- cmake .. -G "Visual Studio 14 2015 Win64"
- cmake . --build
- Test
- ctest -C Debug
- Visual Studio
- open dimcli\build\dimcli.sln
Why not a single header file?
- On large projects with many binaries (tests, utilities, etc) it's good for compile times to move as much stuff out of the headers as you easily can.
- Inflicting <Windows.h> (and to a much lesser extent <termios.h> & <unistd.h>) on all clients seems a bridge too far.
Sources of inspiration:
- LLVM CommandLine module
- click - Python command line interface creation kit
- My own bad experiences
Things that were harder than expected:
- Parsing command lines with bash style quoting
- Response files - because of the need to transcode UTF-16 on Windows
- Password prompting - there's no standard way to disable console echo :(
- Build system - you can do a lot with CMake, but it's not always easy
Other interesting C++ command line parsers: