cxxopts
A lightweight C++ option parser library. Supports POSIX syntax with a header-only, easy-to-use design.
Framework
cxxopts
Overview
cxxopts is a lightweight C++ option parser library that supports POSIX syntax with a header-only, easy-to-use design. It is supported by developers who value simplicity and portability, and has been adopted in many open source projects.
Details
cxxopts supports modern C++11 and later, providing command-line argument parsing with minimal dependencies. It offers a GNU getopt-like API while achieving C++-like type safety and ease of use.
Key Features
- Header-Only: Can be used by including a single header file
- Lightweight Design: Achieves command-line parsing with minimal code
- POSIX Compliant: Supports GNU getopt-compatible syntax
- Type Safe: Safe argument processing using C++ type system
- Automatic Help Generation: Automatically generates help messages from option definitions
- Exception-Based: Clear error handling using exceptions
- C++11 Support: Works in a wide range of environments while utilizing modern C++ features
Pros and Cons
Pros
- Easy Integration: Header-only with minimal dependencies
- Lightweight: Low overhead and fast operation
- Familiar API: Intuitive for developers familiar with GNU getopt
- Type Safe: Compile-time type checking
- Portable: Works on various platforms
- Minimal Learning Curve: Easy to learn with simple API
Cons
- Feature Limitations: Advanced features are inferior to other libraries
- No Subcommand Support: Not suitable for complex CLI applications
- No Configuration File Support: No external configuration file loading functionality
- Limited Customization: Limited customization of help format, etc.
Key Links
Usage Examples
Basic Usage
#include <cxxopts.hpp>
#include <iostream>
int main(int argc, char* argv[]) {
cxxopts::Options options("MyApp", "Simple command-line application");
options.add_options()
("f,file", "File to process", cxxopts::value<std::string>()->default_value("default.txt"))
("v,verbose", "Verbose output", cxxopts::value<bool>()->default_value("false"))
("h,help", "Show help");
auto result = options.parse(argc, argv);
if (result.count("help")) {
std::cout << options.help() << std::endl;
return 0;
}
auto filename = result["file"].as<std::string>();
auto verbose = result["verbose"].as<bool>();
std::cout << "Processing file: " << filename << std::endl;
if (verbose) {
std::cout << "Verbose mode enabled" << std::endl;
}
return 0;
}
Multiple Argument Types
#include <cxxopts.hpp>
#include <iostream>
#include <vector>
int main(int argc, char* argv[]) {
cxxopts::Options options("DataProcessor", "Data processing tool");
options.add_options()
("i,input", "Input files", cxxopts::value<std::vector<std::string>>())
("o,output", "Output file", cxxopts::value<std::string>())
("t,threads", "Number of threads", cxxopts::value<int>()->default_value("1"))
("r,recursive", "Recursive processing", cxxopts::value<bool>()->default_value("false"))
("f,format", "Output format", cxxopts::value<std::string>()->default_value("json"))
("h,help", "Show help");
try {
auto result = options.parse(argc, argv);
if (result.count("help")) {
std::cout << options.help() << std::endl;
return 0;
}
if (result.count("input")) {
auto inputs = result["input"].as<std::vector<std::string>>();
std::cout << "Input files:" << std::endl;
for (const auto& file : inputs) {
std::cout << " - " << file << std::endl;
}
}
if (result.count("output")) {
auto output = result["output"].as<std::string>();
std::cout << "Output file: " << output << std::endl;
}
auto threads = result["threads"].as<int>();
auto recursive = result["recursive"].as<bool>();
auto format = result["format"].as<std::string>();
std::cout << "Threads: " << threads << std::endl;
std::cout << "Recursive: " << (recursive ? "enabled" : "disabled") << std::endl;
std::cout << "Format: " << format << std::endl;
} catch (const cxxopts::OptionException& e) {
std::cout << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}
Positional Arguments
#include <cxxopts.hpp>
#include <iostream>
int main(int argc, char* argv[]) {
cxxopts::Options options("FileUtil", "File utility");
options.add_options()
("c,command", "Command to execute", cxxopts::value<std::string>())
("v,verbose", "Verbose output")
("d,dry-run", "Show only, don't actually execute")
("h,help", "Show help");
// Set positional arguments
options.parse_positional({"command"});
options.positional_help("COMMAND [OPTIONS]");
try {
auto result = options.parse(argc, argv);
if (result.count("help")) {
std::cout << options.help() << std::endl;
return 0;
}
if (!result.count("command")) {
std::cout << "Error: No command specified" << std::endl;
std::cout << options.help() << std::endl;
return 1;
}
auto command = result["command"].as<std::string>();
auto verbose = result.count("verbose") > 0;
auto dry_run = result.count("dry-run") > 0;
std::cout << "Command: " << command << std::endl;
if (verbose) {
std::cout << "Verbose mode: enabled" << std::endl;
}
if (dry_run) {
std::cout << "Dry-run mode: enabled (won't actually execute)" << std::endl;
}
// Command execution logic
if (command == "list") {
std::cout << "Listing files..." << std::endl;
} else if (command == "clean") {
std::cout << "Running cleanup..." << std::endl;
} else {
std::cout << "Unknown command: " << command << std::endl;
return 1;
}
} catch (const cxxopts::OptionException& e) {
std::cout << "Option parsing error: " << e.what() << std::endl;
return 1;
}
return 0;
}
Error Handling
#include <cxxopts.hpp>
#include <iostream>
int main(int argc, char* argv[]) {
cxxopts::Options options("SecureApp", "Secure application");
options.add_options()
("u,user", "Username", cxxopts::value<std::string>())
("p,port", "Port number", cxxopts::value<int>())
("s,ssl", "Use SSL connection")
("t,timeout", "Timeout (seconds)", cxxopts::value<int>()->default_value("30"))
("h,help", "Show help");
try {
auto result = options.parse(argc, argv);
if (result.count("help")) {
std::cout << options.help() << std::endl;
return 0;
}
// Check required parameters
if (!result.count("user")) {
throw cxxopts::OptionException("Username is required");
}
if (!result.count("port")) {
throw cxxopts::OptionException("Port number is required");
}
auto user = result["user"].as<std::string>();
auto port = result["port"].as<int>();
auto ssl = result.count("ssl") > 0;
auto timeout = result["timeout"].as<int>();
// Value validation
if (port < 1 || port > 65535) {
throw cxxopts::OptionException("Port number must be in range 1-65535");
}
if (timeout <= 0) {
throw cxxopts::OptionException("Timeout must be a positive value");
}
std::cout << "Connection settings:" << std::endl;
std::cout << " User: " << user << std::endl;
std::cout << " Port: " << port << std::endl;
std::cout << " SSL: " << (ssl ? "enabled" : "disabled") << std::endl;
std::cout << " Timeout: " << timeout << " seconds" << std::endl;
} catch (const cxxopts::OptionException& e) {
std::cerr << "Error: " << e.what() << std::endl;
std::cerr << std::endl << options.help() << std::endl;
return 1;
} catch (const cxxopts::argument_incorrect_type& e) {
std::cerr << "Type error: " << e.what() << std::endl;
return 1;
} catch (const std::exception& e) {
std::cerr << "Unexpected error: " << e.what() << std::endl;
return 1;
}
return 0;
}
CMake Usage
# CMakeLists.txt
cmake_minimum_required(VERSION 3.11)
project(MyCxxoptsApp)
# Get cxxopts (using FetchContent)
include(FetchContent)
FetchContent_Declare(
cxxopts
GIT_REPOSITORY https://github.com/jarro2783/cxxopts.git
GIT_TAG v3.1.1
)
FetchContent_MakeAvailable(cxxopts)
add_executable(my_app main.cpp)
target_link_libraries(my_app cxxopts::cxxopts)
target_compile_features(my_app PRIVATE cxx_std_11)