mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-01-16 07:08:01 +00:00
Compare commits
12 Commits
d8a5bdc294
...
04054ad1fa
Author | SHA1 | Date | |
---|---|---|---|
|
04054ad1fa | ||
|
b4bb084e38 | ||
|
de117cf1e5 | ||
|
5188ede219 | ||
|
ccb1ccaa0a | ||
|
a8185bb499 | ||
|
0cee321ef9 | ||
|
6f589b8443 | ||
|
eb1150d6be | ||
|
543e7f1577 | ||
|
7e6ff84c69 | ||
|
023bf54282 |
@ -359,6 +359,15 @@
|
||||
"contributions": [
|
||||
"platform"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "certik",
|
||||
"name": "Ondřej Čertík",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/20568?v=4",
|
||||
"profile": "https://ondrejcertik.com/",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
14
.clang-tidy
14
.clang-tidy
@ -6,26 +6,16 @@ FormatStyle: file
|
||||
Checks: '
|
||||
-*,
|
||||
google-*,
|
||||
-google-runtime-int,
|
||||
-google-runtime-references,
|
||||
llvm-include-order,
|
||||
llvm-namespace-comment,
|
||||
misc-throw-by-value-catch-by-reference,
|
||||
modernize*,
|
||||
-modernize-use-trailing-return-type,
|
||||
readability-container-size-empty,
|
||||
'
|
||||
|
||||
WarningsAsErrors: '
|
||||
-*,
|
||||
google-*,
|
||||
-google-runtime-int,
|
||||
-google-runtime-references,
|
||||
llvm-include-order,
|
||||
llvm-namespace-comment,
|
||||
misc-throw-by-value-catch-by-reference,
|
||||
modernize*,
|
||||
readability-container-size-empty,
|
||||
'
|
||||
WarningsAsErrors: '*'
|
||||
|
||||
HeaderFilterRegex: '.*hpp'
|
||||
|
||||
|
2
.github/actions/cmake_config/Dockerfile
vendored
2
.github/actions/cmake_config/Dockerfile
vendored
@ -7,7 +7,7 @@ RUN apt-get update \
|
||||
libidn11=1.33-2.1ubuntu1.2 \
|
||||
ca-certificates=20180409 \
|
||||
make=4.1-9.1ubuntu1 \
|
||||
git=1:2.17.1-1ubuntu0.5 \
|
||||
git=1:2.17.1-1ubuntu0.7 \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
15
.github/workflows/tests.yml
vendored
15
.github/workflows/tests.yml
vendored
@ -13,15 +13,15 @@ jobs:
|
||||
name: Formatting
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/setup-python@v1
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- name: set PY
|
||||
run: echo "::set-env name=PY::$(python --version --version | sha256sum | cut -d' ' -f1)"
|
||||
run: echo "::set-env name=PY::$(python -c 'import hashlib, sys;print(hashlib.sha256(sys.version.encode()+sys.executable.encode()).hexdigest())')"
|
||||
- uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.cache/pre-commit
|
||||
key: pre-commit|${{ env.PY }}|${{ hashFiles('.pre-commit-config.yaml') }}
|
||||
- uses: pre-commit/action@v1.0.0
|
||||
- uses: pre-commit/action@v1.1.0
|
||||
|
||||
cuda-build:
|
||||
name: CUDA build only
|
||||
@ -107,9 +107,14 @@ jobs:
|
||||
with:
|
||||
version: 3.15.6
|
||||
if: success() || failure()
|
||||
- name: CMake 3.16
|
||||
uses: ./.github/actions/cmake_config
|
||||
with:
|
||||
version: 3.16.8
|
||||
if: success() || failure()
|
||||
- name: CMake 3.16 (full)
|
||||
uses: ./.github/actions/cmake_config
|
||||
with:
|
||||
version: 3.16.2
|
||||
version: 3.17.3
|
||||
options: -DCLI11_SANITIZERS=ON -DCLI11_BUILD_EXAMPLES_JSON=ON
|
||||
if: success() || failure()
|
||||
|
30
CHANGELOG.md
30
CHANGELOG.md
@ -1,3 +1,33 @@
|
||||
## Version 2.0: In progress
|
||||
|
||||
* Built-in config format is TOML compliant now [#435]
|
||||
* Config updates [#442]
|
||||
* More powerful containers, `%%` separator [#423]
|
||||
* Add a version flag easily [#452]
|
||||
|
||||
[#435]: https://github.com/CLIUtils/CLI11/pull/435
|
||||
[#443]: https://github.com/CLIUtils/CLI11/pull/443
|
||||
[#423]: https://github.com/CLIUtils/CLI11/pull/423
|
||||
[#452]: https://github.com/CLIUtils/CLI11/pull/452
|
||||
|
||||
|
||||
### Version 1.9.1: Backporting fixes
|
||||
|
||||
This is a patch version that backports fixes from the development of 2.0.
|
||||
|
||||
* Fix an issue with string conversion [#421][]
|
||||
* Cross-compiling improvement for Conan.io [#430][]
|
||||
* Fix option group default propagation [#450][]
|
||||
* Fix for C++20 [#459][]
|
||||
* Support compiling with RTTI off [#461][]
|
||||
|
||||
[#421]: https://github.com/CLIUtils/CLI11/pull/421
|
||||
[#430]: https://github.com/CLIUtils/CLI11/pull/430
|
||||
[#450]: https://github.com/CLIUtils/CLI11/pull/450
|
||||
[#459]: https://github.com/CLIUtils/CLI11/pull/459
|
||||
[#461]: https://github.com/CLIUtils/CLI11/pull/461
|
||||
|
||||
|
||||
## Version 1.9: Config files and cleanup
|
||||
|
||||
Config file handling was revamped to fix common issues, and now supports reading [TOML](https://github.com/toml-lang/toml).
|
||||
|
18
README.md
18
README.md
@ -151,6 +151,21 @@ make
|
||||
GTEST_COLOR=1 CTEST_OUTPUT_ON_FAILURE=1 make test
|
||||
```
|
||||
|
||||
<details><summary>Note: Special instructions for GCC 8</summary><p>
|
||||
|
||||
If you are using GCC 8 and using it in C++17 mode with CLI11. CLI11 makes use of the `<filesystem>` header if available, but specifically for this compiler, the `filesystem` library is separate from the standard library and needs to be linked separately. So it is available but CLI11 doesn't use it by default.
|
||||
|
||||
Specifically `libstdc++fs` needs to be added to the linking list and `CLI11_HAS_FILESYSTEM=1` has to be defined. Then the filesystem variant of the Validators could be used on GCC 8. GCC 9+ does not have this issue so the `<filesystem>` is used by default.
|
||||
|
||||
There may also be other cases where a specific library needs to be linked.
|
||||
|
||||
Defining `CLI11_HAS_FILESYSTEM=0` which will remove the usage and hence any linking issue.
|
||||
|
||||
In some cases certain clang compilations may require linking against `libc++fs`. These situations have not been encountered so the specific situations requiring them are unknown yet.
|
||||
|
||||
</p></details>
|
||||
</br>
|
||||
|
||||
## Usage
|
||||
|
||||
### Adding options
|
||||
@ -910,6 +925,7 @@ This project was created by [Henry Schreiner](https://github.com/henryiii) and m
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/jsoref"><img src="https://avatars0.githubusercontent.com/u/2119212?v=4" width="100px;" alt=""/><br /><sub><b>Josh Soref</b></sub></a><br /><a href="#tool-jsoref" title="Tools">🔧</a></td>
|
||||
<td align="center"><a href="https://github.com/geir-t"><img src="https://avatars3.githubusercontent.com/u/35292136?v=4" width="100px;" alt=""/><br /><sub><b>geir-t</b></sub></a><br /><a href="#platform-geir-t" title="Packaging/porting to new platform">📦</a></td>
|
||||
<td align="center"><a href="https://ondrejcertik.com/"><img src="https://avatars3.githubusercontent.com/u/20568?v=4" width="100px;" alt=""/><br /><sub><b>Ondřej Čertík</b></sub></a><br /><a href="https://github.com/CLIUtils/CLI11/issues?q=author%3Acertik" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@ -929,7 +945,7 @@ CLI11 was developed at the [University of Cincinnati][] to support of the [GooFi
|
||||
[doi-badge]: https://zenodo.org/badge/80064252.svg
|
||||
[doi-link]: https://zenodo.org/badge/latestdoi/80064252
|
||||
[azure-badge]: https://dev.azure.com/CLIUtils/CLI11/_apis/build/status/CLIUtils.CLI11?branchName=master
|
||||
[azure]: https://dev.azure.com/CLIUtils/CLI11/_build/latest?definitionId=1&branchName=master
|
||||
[azure]: https://dev.azure.com/CLIUtils/CLI11
|
||||
[travis-badge]: https://img.shields.io/travis/CLIUtils/CLI11/master.svg?label=Linux/macOS
|
||||
[travis]: https://travis-ci.org/CLIUtils/CLI11
|
||||
[appveyor-badge]: https://img.shields.io/appveyor/ci/HenrySchreiner/cli11/master.svg?label=AppVeyor
|
||||
|
@ -5,6 +5,11 @@
|
||||
|
||||
trigger:
|
||||
- master
|
||||
- 'v*'
|
||||
|
||||
pr:
|
||||
- master
|
||||
- 'v*'
|
||||
|
||||
variables:
|
||||
cli11.single: ON
|
||||
@ -57,6 +62,14 @@ jobs:
|
||||
Windows11:
|
||||
vmImage: 'vs2017-win2016'
|
||||
cli11.std: 11
|
||||
Windowslatest:
|
||||
vmImage: 'windows-2019'
|
||||
cli11.std: 20
|
||||
cli11.options: -DCMAKE_CXX_FLAGS="/std:c++latest /EHsc"
|
||||
Linux17nortti:
|
||||
vmImage: 'ubuntu-latest'
|
||||
cli11.std: 17
|
||||
cli11.options: -DCMAKE_CXX_FLAGS="-fno-rtti"
|
||||
pool:
|
||||
vmImage: $(vmImage)
|
||||
steps:
|
||||
@ -89,6 +102,9 @@ jobs:
|
||||
gcc9:
|
||||
containerImage: gcc:9
|
||||
cli11.std: 17
|
||||
gcc8:
|
||||
containerImage: gcc:8
|
||||
cli11.std: 17
|
||||
gcc4.8:
|
||||
containerImage: gcc:4.8
|
||||
cli11.std: 11
|
||||
@ -100,6 +116,14 @@ jobs:
|
||||
containerImage: silkeh/clang:8
|
||||
cli11.std: 14
|
||||
cli11.options: -DCLI11_FORCE_LIBCXX=ON
|
||||
clang8_17:
|
||||
containerImage: silkeh/clang:8
|
||||
cli11.std: 17
|
||||
cli11.options: -DCLI11_FORCE_LIBCXX=ON
|
||||
clang10_20:
|
||||
containerImage: helics/buildenv:clang10-builder
|
||||
cli11.std: 20
|
||||
cli11.options: -DCLI11_FORCE_LIBCXX=ON -DCMAKE_CXX_FLAGS=-std=c++20
|
||||
container: $[ variables['containerImage'] ]
|
||||
steps:
|
||||
- template: .ci/azure-cmake.yml
|
||||
|
@ -115,7 +115,8 @@ The default configuration file will read TOML files, but will write out files in
|
||||
```cpp
|
||||
app.config_formatter(std::make_shared<CLI::ConfigTOML>());
|
||||
```
|
||||
which makes use of a predefined modification of the ConfigBase class which INI also uses.
|
||||
|
||||
which makes use of a predefined modification of the ConfigBase class which INI also uses. If a custom formatter is used that is not inheriting from the from ConfigBase class `get_config_formatter_base() will return a nullptr if RTTI is on (usually the default), or garbage if RTTI is off, so some care must be exercised in its use with custom configurations.
|
||||
|
||||
## Custom formats
|
||||
|
||||
|
2
extern/googletest
vendored
2
extern/googletest
vendored
@ -1 +1 @@
|
||||
Subproject commit 2fe3bd994b3189899d93f1d5a881e725e046fdc2
|
||||
Subproject commit 859bfe8981d6724c4ea06e73d29accd8588f3230
|
@ -975,7 +975,7 @@ class App {
|
||||
/// creates an option group as part of the given app
|
||||
template <typename T = Option_group>
|
||||
T *add_option_group(std::string group_name, std::string group_description = "") {
|
||||
auto option_group = std::make_shared<T>(std::move(group_description), group_name, nullptr);
|
||||
auto option_group = std::make_shared<T>(std::move(group_description), group_name, this);
|
||||
auto ptr = option_group.get();
|
||||
// move to App_p for overload resolution on older gcc versions
|
||||
App_p app_ptr = std::dynamic_pointer_cast<App>(option_group);
|
||||
@ -1314,15 +1314,15 @@ class App {
|
||||
int exit(const Error &e, std::ostream &out = std::cout, std::ostream &err = std::cerr) const {
|
||||
|
||||
/// Avoid printing anything if this is a CLI::RuntimeError
|
||||
if(dynamic_cast<const CLI::RuntimeError *>(&e) != nullptr)
|
||||
if(e.get_name() == "RuntimeError")
|
||||
return e.get_exit_code();
|
||||
|
||||
if(dynamic_cast<const CLI::CallForHelp *>(&e) != nullptr) {
|
||||
if(e.get_name() == "CallForHelp") {
|
||||
out << help();
|
||||
return e.get_exit_code();
|
||||
}
|
||||
|
||||
if(dynamic_cast<const CLI::CallForAllHelp *>(&e) != nullptr) {
|
||||
if(e.get_name() == "CallForAllHelp") {
|
||||
out << help("", AppFormatMode::All);
|
||||
return e.get_exit_code();
|
||||
}
|
||||
@ -1524,7 +1524,12 @@ class App {
|
||||
|
||||
/// Access the config formatter as a configBase pointer
|
||||
std::shared_ptr<ConfigBase> get_config_formatter_base() const {
|
||||
// This is safer as a dynamic_cast if we have RTTI, as Config -> ConfigBase
|
||||
#if defined(__cpp_rtti) || (defined(__GXX_RTTI) && __GXX_RTTI) || (defined(_HAS_STATIC_RTTI) && (_HAS_STATIC_RTTI == 0))
|
||||
return std::dynamic_pointer_cast<ConfigBase>(config_formatter_);
|
||||
#else
|
||||
return std::static_pointer_cast<ConfigBase>(config_formatter_);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Get the app or subcommand description
|
||||
@ -3055,7 +3060,18 @@ inline std::string help(const App *app, const Error &e) {
|
||||
namespace detail {
|
||||
/// This class is simply to allow tests access to App's protected functions
|
||||
struct AppFriend {
|
||||
#ifdef CLI11_CPP14
|
||||
|
||||
/// Wrap _parse_short, perfectly forward arguments and return
|
||||
template <typename... Args> static decltype(auto) parse_arg(App *app, Args &&... args) {
|
||||
return app->_parse_arg(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/// Wrap _parse_subcommand, perfectly forward arguments and return
|
||||
template <typename... Args> static decltype(auto) parse_subcommand(App *app, Args &&... args) {
|
||||
return app->_parse_subcommand(std::forward<Args>(args)...);
|
||||
}
|
||||
#else
|
||||
/// Wrap _parse_short, perfectly forward arguments and return
|
||||
template <typename... Args>
|
||||
static auto parse_arg(App *app, Args &&... args) ->
|
||||
@ -3069,6 +3085,7 @@ struct AppFriend {
|
||||
typename std::result_of<decltype (&App::_parse_subcommand)(App, Args...)>::type {
|
||||
return app->_parse_subcommand(std::forward<Args>(args)...);
|
||||
}
|
||||
#endif
|
||||
/// Wrap the fallthrough parent function to make sure that is working correctly
|
||||
static App *get_fallthrough_parent(App *app) { return app->_get_fallthrough_parent(); }
|
||||
};
|
||||
|
@ -24,9 +24,9 @@ class App;
|
||||
/// the second argument.
|
||||
|
||||
enum class AppFormatMode {
|
||||
Normal, //< The normal, detailed help
|
||||
All, //< A fully expanded help
|
||||
Sub, //< Used when printed as part of expanded subcommand
|
||||
Normal, ///< The normal, detailed help
|
||||
All, ///< A fully expanded help
|
||||
Sub, ///< Used when printed as part of expanded subcommand
|
||||
};
|
||||
|
||||
/// This is the minimum requirements to run a formatter.
|
||||
|
@ -506,7 +506,7 @@ class Option : public OptionBase<Option> {
|
||||
|
||||
/// Can find a string if needed
|
||||
template <typename T = App> Option *needs(std::string opt_name) {
|
||||
auto opt = dynamic_cast<T *>(parent_)->get_option_no_throw(opt_name);
|
||||
auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
|
||||
if(opt == nullptr) {
|
||||
throw IncorrectConstruction::MissingOption(opt_name);
|
||||
}
|
||||
@ -548,7 +548,7 @@ class Option : public OptionBase<Option> {
|
||||
|
||||
/// Can find a string if needed
|
||||
template <typename T = App> Option *excludes(std::string opt_name) {
|
||||
auto opt = dynamic_cast<T *>(parent_)->get_option_no_throw(opt_name);
|
||||
auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
|
||||
if(opt == nullptr) {
|
||||
throw IncorrectConstruction::MissingOption(opt_name);
|
||||
}
|
||||
@ -585,7 +585,7 @@ class Option : public OptionBase<Option> {
|
||||
template <typename T = App> Option *ignore_case(bool value = true) {
|
||||
if(!ignore_case_ && value) {
|
||||
ignore_case_ = value;
|
||||
auto *parent = dynamic_cast<T *>(parent_);
|
||||
auto *parent = static_cast<T *>(parent_);
|
||||
for(const Option_p &opt : parent->options_) {
|
||||
if(opt.get() == this) {
|
||||
continue;
|
||||
@ -610,7 +610,7 @@ class Option : public OptionBase<Option> {
|
||||
|
||||
if(!ignore_underscore_ && value) {
|
||||
ignore_underscore_ = value;
|
||||
auto *parent = dynamic_cast<T *>(parent_);
|
||||
auto *parent = static_cast<T *>(parent_);
|
||||
for(const Option_p &opt : parent->options_) {
|
||||
if(opt.get() == this) {
|
||||
continue;
|
||||
|
@ -33,7 +33,14 @@
|
||||
#else
|
||||
#include <filesystem>
|
||||
#if defined __cpp_lib_filesystem && __cpp_lib_filesystem >= 201703
|
||||
#if defined _GLIBCXX_RELEASE && _GLIBCXX_RELEASE >= 9
|
||||
#define CLI11_HAS_FILESYSTEM 1
|
||||
#elif defined(__GLIBCXX__)
|
||||
// if we are using gcc and Version <9 default to no filesystem
|
||||
#define CLI11_HAS_FILESYSTEM 0
|
||||
#else
|
||||
#define CLI11_HAS_FILESYSTEM 1
|
||||
#endif
|
||||
#else
|
||||
#define CLI11_HAS_FILESYSTEM 0
|
||||
#endif
|
||||
|
@ -368,6 +368,18 @@ TEST_F(TApp, InvalidOptions) {
|
||||
EXPECT_THROW(ogroup->add_option(opt), CLI::OptionNotFound);
|
||||
}
|
||||
|
||||
TEST_F(TApp, OptionGroupInheritedOptionDefaults) {
|
||||
app.option_defaults()->ignore_case();
|
||||
auto ogroup = app.add_option_group("clusters");
|
||||
int res{0};
|
||||
ogroup->add_option("--test1", res);
|
||||
|
||||
args = {"--Test1", "5"};
|
||||
run();
|
||||
EXPECT_EQ(res, 5);
|
||||
EXPECT_EQ(app.count_all(), 1u);
|
||||
}
|
||||
|
||||
struct ManyGroups : public TApp {
|
||||
|
||||
CLI::Option_group *main{nullptr};
|
||||
|
@ -1,7 +1,13 @@
|
||||
// Copyright (c) 2017-2020, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#include "app_helper.hpp"
|
||||
|
||||
/// This allows a set of strings to be run over by a test
|
||||
struct TApp_TBO : public TApp, public ::testing::WithParamInterface<const char *> {};
|
||||
struct TApp_TBO : public TApp_base, testing::TestWithParam<const char *> {};
|
||||
|
||||
TEST_P(TApp_TBO, TrueBoolOption) {
|
||||
bool value{false}; // Not used, but set just in case
|
||||
@ -13,10 +19,10 @@ TEST_P(TApp_TBO, TrueBoolOption) {
|
||||
}
|
||||
|
||||
// Change to INSTANTIATE_TEST_SUITE_P in GTest master
|
||||
INSTANTIATE_TEST_CASE_P(TrueBoolOptions, TApp_TBO, ::testing::Values("true", "on", "True", "ON"), );
|
||||
INSTANTIATE_TEST_SUITE_P(TrueBoolOptions_test, TApp_TBO, testing::Values("true", "on", "True", "ON"));
|
||||
|
||||
/// This allows a set of strings to be run over by a test
|
||||
struct TApp_FBO : public TApp, public ::testing::WithParamInterface<const char *> {};
|
||||
struct TApp_FBO : public TApp_base, public ::testing::TestWithParam<const char *> {};
|
||||
|
||||
TEST_P(TApp_FBO, FalseBoolOptions) {
|
||||
bool value{true}; // Not used, but set just in case
|
||||
@ -27,4 +33,4 @@ TEST_P(TApp_FBO, FalseBoolOptions) {
|
||||
EXPECT_FALSE(value);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FalseBoolOptions, TApp_FBO, ::testing::Values("false", "off", "False", "OFF"), );
|
||||
INSTANTIATE_TEST_SUITE_P(FalseBoolOptions_test, TApp_FBO, ::testing::Values("false", "off", "False", "OFF"));
|
||||
|
@ -1,3 +1,9 @@
|
||||
// Copyright (c) 2017-2020, University of Cincinnati, developed by Henry Schreiner
|
||||
// under NSF AWARD 1414736 and by the respective contributors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef CLI11_SINGLE_FILE
|
||||
@ -8,13 +14,17 @@
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using input_t = std::vector<std::string>;
|
||||
|
||||
struct TApp : public ::testing::Test {
|
||||
class TApp_base {
|
||||
public:
|
||||
CLI::App app{"My Test Program"};
|
||||
input_t args{};
|
||||
|
||||
virtual ~TApp_base() = default;
|
||||
void run() {
|
||||
// It is okay to re-parse - clear is called automatically before a parse.
|
||||
input_t newargs = args;
|
||||
@ -23,6 +33,8 @@ struct TApp : public ::testing::Test {
|
||||
}
|
||||
};
|
||||
|
||||
class TApp : public TApp_base, public ::testing::Test {};
|
||||
|
||||
class TempFile {
|
||||
std::string _name{};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user