p-ranav / structopt Goto Github PK
View Code? Open in Web Editor NEWParse command line arguments by defining a struct
License: MIT License
Parse command line arguments by defining a struct
License: MIT License
With the current implementation, the option handling/parsing only works with a lot of allocations. If the implementation would use string_view
internally and can save arguments as viewer structs, that could be neat.
If excess positional arguments are provided the parser does not raise an exception.
struct FileOptions {
// Positional arguments
// ./main <input_file> <output_file>
std::string input_file;
std::string output_file;
};
STRUCTOPT(FileOptions, input_file, output_file);
Executing ./main file1 file2 file3
does not raise an exception.
Hi, do you plan to add ability of setting up a custom help message? structopt adds --help command line flag unconditionally, without ability to override built-in help message format, so I think it makes sense even if you add a help description per argument in the future.
It requires only a small change, I made it to the structopt bundled in my project, you can see how it looks here
Ran into Neargye/magic_enum#69 while building. The issue has already been fixed upstream, need to update it here.
When including structopt in my custom project which adds strong compilation flags for GCC (-pedantic -Wall -Werror -Wextra -Wformat
) the following errors appear:
In file included from [...]/structopt/include/structopt/parser.hpp:13,
from [...]/structopt/include/structopt/app.hpp:8,
from [...]/main.cpp:1:
[...]/structopt/include/structopt/is_number.hpp:9:8: error: type qualifiers ignored on function return type [-Werror=ignored-qualifiers]
9 | static const bool is_binary_notation(std::string const &input) {
| ^~~~~
[...]/structopt/include/structopt/is_number.hpp:14:8: error: type qualifiers ignored on function return type [-Werror=ignored-qualifiers]
14 | static const bool is_hex_notation(std::string const &input) {
| ^~~~~
[...]/structopt/include/structopt/is_number.hpp:19:8: error: type qualifiers ignored on function return type [-Werror=ignored-qualifiers]
19 | static const bool is_octal_notation(std::string const &input) {
| ^~~~~
[...]/structopt/include/structopt/is_number.hpp: In function ‘bool structopt::details::is_valid_number(const string&)’:
[...]/structopt/include/structopt/is_number.hpp:34:12: error: comparison of unsigned expression in ‘>= 0’ is always true [-Werror=type-limits]
34 | while (j >= 0 && input[j] == ' ')
| ~~^~~~
My main.cpp
:
#include <structopt/app.hpp>
int main()
{
std::cout << "Test" << std::endl;
}
My CMakeLists.txt
:
# Set minimum CMake version
cmake_minimum_required(VERSION 3.14)
# Set project name and the programming language
project("test" LANGUAGES CXX)
# Set path to project root
set(VENDOR_DIR "${CMAKE_CURRENT_SOURCE_DIR}/vendor")
option(STRUCTOPT_TESTS "Don't build structopt tests" OFF)
option(STRUCTOPT_SAMPLES "Don't build structopt examples" OFF)
add_subdirectory("${VENDOR_DIR}/structopt" build_extern_structopt)
# Create executable with all provided sources
add_executable(${PROJECT_NAME} main.cpp)
# Link structopt
target_link_libraries(${PROJECT_NAME} PRIVATE structopt::structopt)
# Set library source files compilation flags for different compilers
target_compile_options(${PROJECT_NAME}
PRIVATE $<$<CXX_COMPILER_ID:GNU>:
-pedantic
-Wall
-Werror
-Wextra
-Wformat
>
$<$<CXX_COMPILER_ID:MSCV>:
/W4
/Wall
/WX
>)
# Set C++ version for the local source files
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20)
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_20)
My build commands build.sh
:
#!/usr/bin/env bash
rm -rf build && mkdir -p build && cd build
cmake .. -G "Unix Makefiles"
cmake --build .
The complete log:
-- The CXX compiler identification is GNU 10.1.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: PROJECT_ROOT/build
Scanning dependencies of target test
[ 50%] Building CXX object CMakeFiles/test.dir/main.cpp.o
In file included from PROJECT_ROOT/vendor/structopt/include/structopt/parser.hpp:13,
from PROJECT_ROOT/vendor/structopt/include/structopt/app.hpp:8,
from PROJECT_ROOT/main.cpp:1:
PROJECT_ROOT/vendor/structopt/include/structopt/is_number.hpp:9:8: error: type qualifiers ignored on function return type [-Werror=ignored-qualifiers]
9 | static const bool is_binary_notation(std::string const &input) {
| ^~~~~
PROJECT_ROOT/vendor/structopt/include/structopt/is_number.hpp:14:8: error: type qualifiers ignored on function return type [-Werror=ignored-qualifiers]
14 | static const bool is_hex_notation(std::string const &input) {
| ^~~~~
PROJECT_ROOT/vendor/structopt/include/structopt/is_number.hpp:19:8: error: type qualifiers ignored on function return type [-Werror=ignored-qualifiers]
19 | static const bool is_octal_notation(std::string const &input) {
| ^~~~~
PROJECT_ROOT/vendor/structopt/include/structopt/is_number.hpp: In function ‘bool structopt::details::is_valid_number(const string&)’:
PROJECT_ROOT/vendor/structopt/include/structopt/is_number.hpp:34:12: error: comparison of unsigned expression in ‘>= 0’ is always true [-Werror=type-limits]
34 | while (j >= 0 && input[j] == ' ')
| ~~^~~~
cc1plus: all warnings being treated as errors
make[2]: *** [CMakeFiles/test.dir/build.make:82: CMakeFiles/test.dir/main.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:115: CMakeFiles/test.dir/all] Error 2
make: *** [Makefile:103: all] Error 2
This was tested on a Linux PC (Kernel: 5.8.1-2-MANJARO, Architecture: x86_64 GNU/Linux) with c++
(GCC) 10.1.0 and cmake
3.18.1.
It is just a minor issue I just removed the const
qualifiers and the j >= 0
as described in the warnings and then everything worked for me (my main.cpp
was at one point more advanced but I trimmed it for this issue - --help
and the other features were working fine).
If you only have optional arguments in the structure no error will be produced when unknown optional or positional arguments are provided.
struct Options {
std::optional<std::string> directory;
};
STRUCTOPT(Options, directory);
Executing ./a.out --bad
or ./a.out bad
will not raise an exception. If you add a positional argument, you will get the expected result.
struct Options {
std::optional<std::string> directory;
std::string dummy;
};
STRUCTOPT(Options, directory, dummy);
I seems that first character of long-name is used in a short-name.
In case:
struct Options
{
// oositional flags
// ./main [--bar] [--baz]
std::optional<bool> bar = false;
std::optional<bool> baz = false;
};
STRUCTOPT(Options, bar, baz);
Help prints:
USAGE: my_app [FLAGS] [OPTIONS]
FLAGS:
-b, --bar
-b, --baz
OPTIONS:
-h, --help <help>
-v, --version <version>
There are -b
twice. Ii can be confusing, specially with many another options between duplicates.
BTW, it's possible (or is planned) to set flag name (short name)?
Maybe something like
std::optional<bool> baz = false;
...
STRUCTOPT(Options, bar, structopt::short(baz, "z"));
#include <iostream>
#include <optional>
#include <string>
#include <structopt/app.hpp>
struct Options {
std::string db_name;
std::string path_files;
std::string path_archive;
enum class LogLevel { trace, debug, info, warn, err, critical, off };
std::optional<LogLevel> log_level = LogLevel::debug;
};
STRUCTOPT(Options, db_name, path_files, path_archive, log_level);
int main(int argc, char* argv[]) {
auto opts = structopt::app("test", "1.0.0.1").parse<Options>(argc, argv);
std::cout << "Hello World!\n";
}
without parameters
./test.exe
Microsoft Visual Studio Community 2019
Version 16.7.2
VisualStudio.16.Release/16.7.2+30413.136
In the current beta release of boost, boost::pfr
comes with a new feature for extracting the struct name from a given type. This way structopt
could get rid of the library visit_struct
and fully rely on boost::pfr
. Or, since the new boost::pfr
feature requries C++20, to still support older C++ standards , the current reflection mechanism might stay as fallback.
Hello,
I would like to add some help strings for the arguments / subcommands defined in the options struct.
i.e. - provide an explanation for what each subcommand does or for the arguments in the help usage.
Is it currently possible?
Thanks for the great work!
Hello and first of all, thanks for this nice piece of software !
When STRUCTOPT(...)
is used inside a namespace, I encounter the following error:
/home/chybz/dev/zap/build/root/include/structopt/third_party/visit_struct/visit_struct.hpp:839:22: error: ‘visitable’ is not a class template
839 | template <> struct visitable<STRUCT_NAME, void> { \
| ^~~~~~~~~
/home/chybz/dev/zap/build/root/include/structopt/app.hpp:13:19: note: in expansion of macro ‘VISITABLE_STRUCT’
13 | #define STRUCTOPT VISITABLE_STRUCT
| ^~~~~~~~~~~~~~~~
so.cpp:16:1: note: in expansion of macro ‘STRUCTOPT’
16 | STRUCTOPT(Options, config_file, bind_address, verbose, user, files);
| ^~~~~~~~~
/home/chybz/dev/zap/build/root/include/structopt/third_party/visit_struct/visit_struct.hpp:839:51: error: explicit specialization of non-template ‘foo::visit_struct::traits::visitable’
839 | template <> struct visitable<STRUCT_NAME, void> {
Here's the minimal example I used, compiled with gcc (Debian 10.2.1-6) 10.2.1 20210110
:
g++ -Wall -std=c++20 -o test test.cpp
#include <iostream>
#include <optional>
#include <vector>
#include <structopt/app.hpp>
namespace foo {
struct Options {
std::string config_file;
std::optional<std::string> bind_address;
std::optional<bool> verbose = false;
std::optional<std::pair<std::string, std::string>> user;
std::vector<std::string> files;
};
STRUCTOPT(Options, config_file, bind_address, verbose, user, files);
}
int main(int argc, char *argv[]) {
try {
auto options = structopt::app("my_app").parse<foo::Options>(argc, argv);
std::cout << "config_file = " << options.config_file << "\n";
} catch (structopt::exception& e) {
std::cout << e.what() << "\n";
std::cout << e.help();
}
}
If I remove namespace foo { ... }
, it compiles without error.
Could you please have a look ?
Thank you !
The examples don't make clear, if all arguments can be passed from within a config file imho. Can this be done?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.