cxxopts

A lightweight C++ option parser library. Supports POSIX syntax with a header-only, easy-to-use design.

cppclicommand-lineheader-only

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)