magic_args is a C++23 header-only library for command-line argument handling. Its primary goal is ease of use, while also aiming to be full-featured.
#include <magic_args/magic_args.hpp>
struct MyArgs {
bool mFoo {false};
std::string mBar;
int mBaz {0};
};
int main(int argc, char** argv) {
// This gets you an
// std::expected<MyArgs, magic_args::incomplete_parse_reason>
const auto args = magic_args::parse<MyArgs>(argc, argv);
if (!args.has_value()) {
if (args.error() == magic_args::HelpRequested) {
return EXIT_SUCCESS;
}
return EXIT_FAILURE;
}
magic_args::dump(*args);
return EXIT_SUCCESS;
}
> minimal.exe --help
Usage: minimal [OPTIONS...]
Options:
--foo
--bar=VALUE
--baz=VALUE
-?, --help show this message
> minimal.exe --foo --baz=123 --bar SomeString
mFoo `true`
mBar `SomeString`
mBaz `123`
Help text, short flags, and positional arguments are also supported.
Long names are inferred for struct members in the following forms:
struct MyArgs {
std::string mEmUpperCamel;
std::string m_EmUnderscoreUpperCamel;
std::string _UnderscoreUpperCamel;
std::string _underscoreLowerCamel;
std::string UpperCamel;
std::string lowerCamel;
std::string m_em_snake_case;
std::string snake_case;
};
To disable inference and use property names as option names verbatim, use the verbatim_names<>
helper:
const auto args = magic_args::parse<
MyArgs,
magic_args::verbatim_names<magic_args::gnu_style_parsing_traits>>(argv);
// ... or ...
const auto args = magic_args::parse<
MyArgs,
magic_args::verbatim_names<magic_args::powershell_style_parsing_traits>>(argv);
magic_args requires C++23, and is tested with:
- latest Visual Studio cl.exe and clang-cl.exe
- latest Apple Clang (XCode)
- GCC 13 on Ubuntu 24.04
The magic_args library has no other dependencies; CMake, Catch2, and vcpkg are used for the examples and unit tests.
Add the magic_args
directory to your project and include path, using your preferred method. Options include:
- a git submodule
- CMake
FetchContent
andExternalProject_Add
- adding the files manually
A single-header-file version is also available from the releases page.
If you want to use using namespace
, use using namespace magic_args::public_api
; this avoids pulling in the
magic_args::detail
namespace.
As the project is very new, I wouldn't recommend contributing it to a package manager; however, if you wish to integrate
it with one (for example, via vcpkg's overlay ports feature), cmake --install
is supported.
--foo
and-f
for flags (bool options that default to false and can be set to false)--foo=bar
,--foo bar
, and-f bar
syntax for options with values--version
and--help
- examples and descriptive text can be added to
--help
- alternative powershell-style syntax
- compatible with
std::optional<>
used when the difference between 'not provided' and 'default value' is important - positional arguments
- mandatory positional arguments
- positional arguments with multiple values
--
, treating all later arguments as positional arguments, even if they match an option- support for
WinMain
andwWinMain
Long arguments are automatically inferred for struct members; if you want to use a different argument name, help text,
or to support short flags, use the magic_args::option<>
and magic_args::flag<>
types:
struct MyArgs {
magic_args::flag mMyFlag {
.mName = "long-name", // --my-flag
.mHelp = "documentation here",
.mShortName = "m", // -m
};
magic_args::option<std::string> mOpt1 {
.mValue = "default",
.mName = "option", // --option
.mHelp = "documentation here",
.mShortName = "o", // -m
};
magic_args::option<std::string> mOpt2 { {}, "option-2", "documentation", "p" };
};
Option and flag members are implicitly convertible to their template type (or bool
for flags). has_value()
,
value()
, operator*()
, and operator->()
are supported for std::optional<>
types.
struct MyArgs {
magic_args::mandatory_positional_argument<std::string> mPos1;
magic_args::optional_positional_argument<std::string> mPos2;
magic_args::optional_positional_argument<std::vector<std::string>> mPos3;
};
- multiple
std::vector<>
arguments are not permitted - if present, an
std::vector<>
argument must be the last argument - if both mandatory and optional positional arguments are present, all optional positional arguments must be after all mandatory positional arguments
Default values, names, and documentation can be specified in the same way as flags and options:
struct MyArgs {
magic_args::mandatory_positional_argument<std::string> mPos1 {
.mValue = "default",
.mName = "POSITIONAL",
.mHelp = "help text here",
};
};
A description, examples, and version information can be provided; description and examples will be shown in --help
,
and version information will be used for --version
:
const magic_args::program_info programInfo {
.mDescription = "My program does something",
.mVersion = "HerpDerp v1.0.0",
.mExamples = {
"myprog FOO",
"myprog FOO --bar",
},
};
const auto args = magic_args::parse<MyArgs>(argc, argv, programInfo);
> foo --help
Usage: foo [OPTIONS...] INPUT
My program does something.
Examples:
myprog FOO
myprog FOO --bar
Options:
-b, --bar help text here
-?, --help show this message
--version print program version
Arguments:
INPUT help text here
If you provide a version, parse<>()
can result in std::unexpected{ magic_args::VersionRequested }
; like
HelpRequested
, you will probably want to return EXIT_SUCCESS
from main()
for this.
Types can be supported by implementing support for operator >>
from a stream; alternatively, implement the following
functions in the same namespace as your type:
// Used by `magic_args::parse()`
void from_string_argument(T& v, std::string_view arg);
// Used by `magic_args::dump()`; alternatively, implement `std::formatter<>`
auto formattable_argument_value(const T& v);
If possible, use a standard main
function instead. magic_args includes helpers for when that is impractical:
#define MAGIC_ARGS_ENABLE_WINDOWS_EXTENSIONS
#include <magic_args/magic_args.hpp>
// If you're not using the single-header version, you can do this instead of using the macro:
#include <magic_args/windows.hpp>
...
magic_args::attach_to_parent_terminal();
const auto args = magic_args::parse<MyArgs>(GetCommandLineW());
When using these helpers, arguments are converted to UTF-8; using UTF-8 as your process code page is strongly recommended.
GetCommandLineW()
should be used instead of the lpCmdLine
parameter as it includes the program path (argv[0]
);
using lpCmdLine
leads to inconsistent results, as the behavior of CommandLineToArgvW()
varies when using
lpCmdLine
.
The Windows helpers are not enabled by default as they include <Windows.h>
.
You can choose to use powershell-like syntax instead of the default GNU-like syntax:
const auto args = magic_args::parse<
MyArgs,
magic_args::powershell_style_parsing_traits>(argc, argv);
This will use single dashes for arguments, and UpperCamelCase
for inferred names:
Usage: minimal-powershell-style [OPTIONS...]
Options:
-Foo
-Bar=VALUE
-Baz=VALUE
-?, -Help show this message
Currently, only up to 16 struct members are supported; this limit can be increased by extending
magic_args::detail::tie_struct()
.
magic_args is MIT-licensed.