CLI framework for C++: cppcli — creating powerful console applications
Developing console interfaces (CLI) in C++ often requires manual argument parsing, flag handling, and command organization. The cppcli library provides a ready-made framework for quickly creating professional CLI applications. It allows you to focus on business logic rather than input/output infrastructure. In this article, we will break down the key features of cppcli, provide code examples, and show how to integrate it into your project.
Key features of cppcli
- Declarative command definition — each command is described as a separate class or lambda function.
- Automatic argument parsing — support for positional, named arguments, and flags.
- Colored output and formatting — built-in utilities for styled output (ANSI colors, tables, progress bars).
- Validation and help — automatic generation of help messages and validation of required arguments.
- Extensibility — support for custom argument types and middleware.
Quick start: installation and first example
cppcli is distributed as a header-only library. To install, clone the repository or use CMake FetchContent. Integration into a project:
#include <cppcli/cli.h>#include <iostream>
int main(int argc, char* argv[]) { cppcli::App app("My application", "1.0.0"); app.run(argc, argv); return 0;}This is the minimal skeleton. Now let's add a greet command that takes a user name.
Example: command with arguments
#include <cppcli/cli.h>
int main(int argc, char* argv[]) { cppcli::App app("Greeter", "1.0.0");
app.command("greet", "Greets the user") .argument<std::string>("name", "User name") .action([](const cppcli::Args& args) { std::string name = args.get<std::string>("name"); std::cout << "Hello, " << name << "!"; });
app.run(argc, argv); return 0;}Run: ./app greet Ivan will output Hello, Ivan!. If the argument is not specified, cppcli will output an error and help.
Flags and optional parameters
Let's add a --formal flag for a formal greeting:
app.command("greet", "Greets the user") .argument<std::string>("name", "Name") .flag("--formal", "-f", "Formal greeting") .action([](const cppcli::Args& args) { std::string name = args.get<std::string>("name"); bool formal = args.get<bool>("formal"); if (formal) std::cout << "Greetings, " << name << "!"; else std::cout << "Hello, " << name << "!"; });Now ./app greet Ivan --formal will output Greetings, Ivan!.
Nested commands and subcommands
cppcli supports a tree-like command structure. For example, for a project management utility:
app.command("project", "Project management") .command("create", "Create a project") .argument<std::string>("name", "Project name") .action([](const cppcli::Args& args) { std::cout << "Project created: " << args.get<std::string>("name") << ""; }) .command("delete", "Delete a project") .argument<std::string>("name", "Project name") .flag("--force", "Without confirmation") .action([](const cppcli::Args& args) { // deletion logic });Call: ./app project