Skip to content

Ookii.CommandLine for C++ is a powerful and flexible header-only command line argument parsing library, supporting PowerShell-like and POSIX-like conventions, as well as subcommands.

License

Notifications You must be signed in to change notification settings

SvenGroot/Ookii.CommandLine.Cpp

Repository files navigation

Ookii.CommandLine for C++ NuGet

Ookii.CommandLine for C++ is a powerful and flexible command line argument parsing library for C++ applications.

  • Easily define strongly-typed arguments, with a simple builder API or using code-generation.
  • Create applications with multiple subcommands.
  • Generate fully customizable usage help.
  • Supports PowerShell-like and POSIX-like parsing rules.
  • Header-only library.

Ookii.CommandLine for C++ is a port of Ookii.CommandLine for .Net, providing the same argument parsing semantics, but using an API that is suitable for C++. It has feature parity with Ookii.CommandLine 2.4 for .Net, with the exception of dictionary argument, and some features from Ookii.CommandLine 3.0 for .Net.

Overview

Ookii.CommandLine is a library that lets you parse the command line arguments for your application into a set of strongly-typed, named values. You can easily define the accepted arguments, and then parse the command line supplied to your application for those arguments. In addition, you can generate usage help that can be displayed to the user.

Ookii.CommandLine can be used with any kind of C++ application, whether console or GUI. Some functions, such as creating usage help, are primarily designed for console applications, but even those can be easily adapted for use with other styles of applications.

Two styles of command line parsing rules are supported: the default mode uses rules similar to those used by PowerShell, and the alternative long/short mode uses a style influenced by POSIX conventions, where arguments have separate long and short names with different prefixes. Many aspects of the parsing rules are configurable.

To determine which arguments are accepted, first you create variables that will hold their values. Then, you use the ookii::parser_builder class to specify things such as the argument names, whether or not an argument is required, and descriptions used to customize the usage help, among other options. This creates an an ookii::command_line_parser, which can parse those arguments.

For example, the following code defines four arguments: a required positional argument, an optional positional argument, a named-only argument, and a switch argument (sometimes also called a flag):

std::string required_argument;
int optional_argument;
float named_argument;
bool switch_argument;

// argv[0] is used for the application executable name.
auto name = ookii::command_line_parser::get_executable_name(argc, argv);
auto parser = ookii::parser_builder{name}
    .add_argument(required_argument, "Required").required().positional()
        .description("A required positional argument.")
    .add_argument(optional_argument, "Optional").positional()
        .description("An optional positional argument.")
    .add_argument(named_argument, "Named")
        .description("An argument that can only supplied by name.")
    .add_argument(switch_argument, "Switch")
        .description("A switch argument, which doesn't require a value.")
    .build();

Each argument has a different type that determines the kinds of values it can accept.

To parse these arguments, all you have to do is call the following on the generated parser.

ookii::parse_result result = parser.parse(argc, argv, {});

This code will parse the arguments in the argv array, will handle and print errors to the console, and will print usage help if needed. It returns an ookii::parse_result that indicates if the operation was successful (it can be converted to bool for this purpose).

If the arguments are invalid, or help is requested, this application will print the following usage help:

Usage: sample_app [-Required] <string> [[-Optional] <int>] [-Help] [-Named <float>]
   [-Switch] [-Version]

    -Required <string>
        A required positional argument.

    -Optional <int>
        An optional positional argument.

    -Help [<bool>] (-?, -h)
        Displays this help message.

    -Named <float>
        An argument that can only supplied by name.

    -Switch [<bool>]
        A switch argument, which doesn't require a value.

The usage help includes the descriptions given for the arguments.

See the documentation for the samples for more examples of usage help generated by Ookii.CommandLine. The usage help format can also be fully customized.

The application also has one argument that wasn't explicitly defined, -Help, which is automatically added by default. You can also easily add a default -Version argument.

An example invocation of this application, specifying all the arguments, would look like this (argument names are case insensitive by default):

./MyApplication foo 42 -switch -named 5.6

Ookii.CommandLine also provides code generation scripts that can generate the above code using a specially annotated struct or class. For example, the below generates the same arguments as above:

// [arguments]
// [name_transform: PascalCase]
struct arguments
{
    // [argument, required, positional]
    // A required positional argument.
    std::string required;
    // [argument, positional]
    // An optional positional argument.
    int optional;
    // [argument]
    // An argument that can only supplied by name.
    float named;
    // [argument: Switch]
    // A switch argument, which doesn't require a value.
    bool switch_argument;

    OOKII_GENERATED_METHODS(arguments);
};

In addition, Ookii.CommandLine can be used to create applications that have multiple subcommands, each with their own arguments.

Requirements

Ookii.CommandLine for C++ requires the following:

  • A compiler supporting C++20 (tested with Visual C++ 2022, g++ 11, and Clang 14 and 15).
  • A standard C++ library supporting the <format> header, or;
    • libfmt if <format> is not available.
  • line_wrapping_ostream, used to generate usage help, relies on dynamic_cast and will require RTTI to be enabled to function correctly.

Ookii.CommandLine for C++ should support any operating system (tested on Windows and Linux). If you want to make sure your platform is supported, you can run the tests.

To use Ookii.CommandLine in your project, the easiest way is to use CMake. If you use Visual Studio, you can also use the NuGet package.

Alternatively, you can clone this repository to get the header files and add the "include" folder to your include path. Since Ookii.CommandLine is entirely implemented in the headers, there are no linking requirements.

Although Ookii.CommandLine is split out into several header files, you typically want to include just the following:

#include <ookii/command_line.h>

This gets you all the library functionality, including subcommands.

CMake usage

Ookii.CommandLine provides a Config file for CMake. After installing the library, you can use:

find_package(Ookii.CommandLine CONFIG)

This will add a library called Ookii.CommandLine::OOKIICL, which you can use with target_link_libraries.

You can also use FetchContent to easily incorporate Ookii.CommandLine:

cmake_minimum_required(VERSION 3.15)

include(FetchContent)

# C++ 20 or later is required for Ookii.CommandLine
set(CMAKE_CXX_STANDARD 20)

FetchContent_Declare(OOKIICL
    GIT_REPOSITORY "https:://github.com/SvenGroot/Ookii.CommandLine.Cpp"
    GIT_TAG "v2.0")

FetchContent_MakeAvailable(OOKIICL)

# Add the header only library to a project.
add_executable(foo)
target_link_libraries(foo PRIVATE Ookii.CommandLine::OOKIICL)

Wide character support

On Windows, you probably want to treat your arguments as wide characters (wchar_t), since that is the native character type used by Windows. For instance, that is the case if you're using the int wmain() entry point, or the CommandLineToArgvW function if you're using WinMain.

The entire Ookii.CommandLine library is implemented using templates which allow the selection of the character type, so they can support both char and wchar_t. The ookii::command_line_parser class is actually a typedef for ookii::basic_command_line_parser<char>, and there is a similar typedef ookii::wcommand_line_parser that translates to ookii::basic_command_line_parser<wchar_t>.

The same is true of ookii::parser_builder, ookii::usage_writer, ookii::command, ookii::command_manager, ookii::localized_string_provider, and ookii::line_wrapping_ostream, which all have wide character versions starting with w.

If you wish to test out Unicode support on Windows, you can compile the unit tests for Unicode by passing -DOOKIICL_UNICODE=1 to CMake. This has no effect on platforms other than Windows, and only applies to the unit tests; no special define is needed for the library itself to use Unicode, except for the <ookii/command_line_generated.h> header (used in conjunction with the code-generation scripts), which requires the _UNICODE define.

Due to limitations of some of the libraries used (in particular, <format>), character types other than char and wchar_t are not supported.

Conditional compilation options

Use the following macros to control the behavior of Ookii.CommandLine, either using #define or the appropriate compiler switch.

Macro Description
_UNICODE If defined, certain templates will default to wchar_t for the character type. The <ookii/command_line_generated.h> header (used in conjunction with the code-generation scripts), uses wchar_t for its declarations. Use on Windows to support Unicode arguments.
_WIN32 If defined, the Windows-specific parser_builder::add_win32_version_argument() and command_manager::add_win32_version_command() methods will be available. These methods create a version command that reads information from the VERSIONINFO resource.
OOKII_PLATFORM_DEFINITION See OOKII_PLATFORM_NOT_INLINE.
OOKII_PLATFORM_NOT_INLINE Do not provide an inline definition of platform-specific functionality. This avoids the need to include platform headers such as <windows.h> in every file that uses the <ookii/command_line.h> header. You must have exactly one C++ file where both OOKII_PLATFORM_NOT_INLINE and OOKII_PLATFORM_DEFINITION are defined prior to including <ookii/command_line.h>, to provide a definition to the linker. See the unit tests project for an example how to do this. Implies OOKII_NO_PLATFORM_HEADERS unless OOKII_PLATFORM_DEFINITION is defined.
OOKII_FORCE_LIBFMT Use the libfmt library even if the <format> header is available.
OOKII_NO_PLATFORM_HEADERS Do not include platform headers such as <windows.h>. Use this if you have already included them manually with different settings than the <ookii/platform_helper.h> header uses. If you want to avoid including them at all, use OOKII_PLATFORM_NOT_INLINE.

Building and running tests and samples

Building the tests and samples requires the following:

  • CMake 3.15 or later.
  • (optional) PowerShell 6 or later for the samples and tests using the code-generation scripts (tested using PowerShell 7.3 on both Windows and Linux).
    • The Pester module is required to run the script tests.

To build the included tests and samples, clone the repository to a local directory, create a folder to hold the build output, and run CMake to configure the project:

mkdir build
cd build
cmake ..
cmake --build .

A script is provided to aid building on Linux: scripts/build.sh. You can use the --compiler argument to use a C++ compiler other than the default on your system (specify only the binary name, e.g "clang++"), the --clean argument to reconfigure and rebuild, and the --docs argument to build documentation instead of the tests and samples (requires doxygen and dot)

Running tests

The unit tests require the existence of the nl_NL.UTF-8 locale. If this locale does not exist, you will see one test failure. In Linux, you can generate this locale using the following command:

sudo locale-gen nl_NL.UTF-8

To run the tests, use the following command:

ctest --output-on-failure

If everything passes, your environment is supported. If you want to see more detailed output, you can run the unittests binary directly.

You can also use scripts/build.sh --test to build and run the tests.

Running samples

After building, you will find several samples in the output. These samples are described in detail, with samples of their usage help output, in the samples documentation.

More information

Please check out the following to get started:

About

Ookii.CommandLine for C++ is a powerful and flexible header-only command line argument parsing library, supporting PowerShell-like and POSIX-like conventions, as well as subcommands.

Resources

License

Stars

Watchers

Forks

Packages

No packages published