From 0da8fa94112b648bc2e3351b45a565069e1d3084 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 5 Jun 2017 10:21:55 -0400 Subject: [PATCH 1/4] Msvc warn fix (#20) * Remove windows warning, use secure getenv * Fix typo in last commit * Fix typo in windows version * Fix another typo in windows version * Fixing error, dropping warn suppression --- CMakeLists.txt | 1 - include/CLI/App.hpp | 22 +++++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a5666a7e..38955915 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,6 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) # Be moderately paranoid with flags if(MSVC) add_definitions("/W4") - add_definitions(-D_CRT_SECURE_NO_WARNINGS) else() add_definitions("-Wall -Wextra -pedantic") endif() diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index 85035f7e..594b607d 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -815,9 +815,25 @@ class App { // Get envname options if not yet passed for(const Option_p &opt : options_) { if(opt->count() == 0 && opt->envname_ != "") { - char *ename = std::getenv(opt->envname_.c_str()); - if(ename != nullptr) { - opt->add_result(std::string(ename)); + char *buffer = nullptr; + std::string ename_string; + + #ifdef _MSC_VER + // Windows version + size_t sz = 0; + if(_dupenv_s(&buffer, &sz, opt->envname_.c_str()) == 0 && buffer != nullptr) { + ename_string = std::string(buffer); + free(buffer); + } + #else + // This also works on Windows, but gives a warning + buffer = std::getenv(opt->envname_.c_str()); + if(buffer != nullptr) + ename_string = std::string(buffer); + #endif + + if(!ename_string.empty()) { + opt->add_result(ename_string); } } } From 657b599b5202796b8cbbd6ecb174d14a2e669c59 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 5 Jun 2017 11:22:09 -0400 Subject: [PATCH 2/4] Cmake cleanup (#21) * Fixes for #8, vars hidden and findPython used * Adding compat with default python, better defaults --- CMakeLists.txt | 11 +++++++++-- cmake/AddGoogletest.cmake | 2 ++ scripts/MakeSingleHeader.py | 16 ++++++++-------- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 38955915..f8b8e0b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,11 +53,18 @@ add_library(CLI11 INTERFACE) target_include_directories(CLI11 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") # Single file test -option(CLI_SINGLE_FILE "Generate a single header file (and test)" ${CUR_PROJ}) +find_package(PythonInterp) +if(CUR_PROJ AND PYTHONINTERP_FOUND) + set(CLI_SINGLE_FILE_DEFAULT ON) +else() + set(CLI_SINGLE_FILE_DEFAULT OFF) +endif() +option(CLI_SINGLE_FILE "Generate a single header file (and test)" ${CLI_SINGLE_FILE_DEFAULT}) if(CLI_SINGLE_FILE) + find_package(PythonInterp REQUIRED) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include") add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp" - COMMAND python "${CMAKE_CURRENT_SOURCE_DIR}/scripts/MakeSingleHeader.py" "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp" + COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/scripts/MakeSingleHeader.py" "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/CLI/CLI.hpp" ${CLI_headers} ) add_custom_target(generate_cli_single_file ALL diff --git a/cmake/AddGoogletest.cmake b/cmake/AddGoogletest.cmake index e18ce48a..5e026cca 100644 --- a/cmake/AddGoogletest.cmake +++ b/cmake/AddGoogletest.cmake @@ -46,6 +46,8 @@ gtest_build_tests gtest_disable_pthreads gtest_force_shared_crt gtest_hide_internal_symbols +BUILD_GMOCK +BUILD_GTEST ) set_target_properties(gtest gtest_main gmock gmock_main diff --git a/scripts/MakeSingleHeader.py b/scripts/MakeSingleHeader.py index 15760929..23c2de3f 100755 --- a/scripts/MakeSingleHeader.py +++ b/scripts/MakeSingleHeader.py @@ -4,24 +4,24 @@ from __future__ import print_function, unicode_literals +import os import re import argparse -from pathlib import Path from subprocess import check_output includes_local = re.compile(r"""^#include "(.*)"$""", re.MULTILINE) includes_system = re.compile(r"""^#include \<(.*)\>$""", re.MULTILINE) -DIR = Path(__file__).resolve().parent -BDIR = DIR.parent / 'include' +DIR = os.path.dirname(os.path.abspath(__file__)) # Path(__file__).resolve().parent +BDIR = os.path.join(os.path.dirname(DIR), 'include') # DIR.parent / 'include' print("Git directory:", DIR) TAG = check_output(['git', 'describe', '--tags', '--always'], cwd=str(DIR)).decode("utf-8") def MakeHeader(out): - main_header = BDIR / 'CLI/CLI.hpp' - with main_header.open() as f: + main_header = os.path.join(BDIR, 'CLI', 'CLI.hpp') + with open(main_header) as f: header = f.read() include_files = includes_local.findall(header) @@ -29,7 +29,7 @@ def MakeHeader(out): headers = set() output = '' for inc in include_files: - with (BDIR / inc).open() as f: + with open(os.path.join(BDIR, inc)) as f: inner = f.read() headers |= set(includes_system.findall(inner)) output += '\n// From {inc}\n\n'.format(inc=inc) @@ -50,7 +50,7 @@ def MakeHeader(out): {header_list} {output}'''.format(header_list=header_list, output=output, tag=TAG) - with Path(out).open('w') as f: + with open(out, 'w') as f: f.write(output) print("Created {out}".format(out=out)) @@ -58,6 +58,6 @@ def MakeHeader(out): if __name__ == '__main__': parser = argparse.ArgumentParser() - parser.add_argument("output", nargs='?', default=BDIR / 'CLI11.hpp') + parser.add_argument("output", nargs='?', default=os.path.join(BDIR, 'CLI11.hpp')) args = parser.parse_args() MakeHeader(args.output) From bc054e516e02d0e09383289eda88343352e1383d Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 5 Jun 2017 16:25:29 -0400 Subject: [PATCH 3/4] Added recent PRs and Issues --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4814a7f7..ea9cc7be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ ## Version 1.1 (in progress) -* Added `app.parse_order()` with original parse order -* Added `prefix_command()`, which is like `allow_extras` but instantly stops and returns. +* Added `app.parse_order()` with original parse order ([#13](https://github.com/CLIUtils/CLI11/issues/13), [#16](https://github.com/CLIUtils/CLI11/pull/16)) +* Added `prefix_command()`, which is like `allow_extras` but instantly stops and returns. ([#8](https://github.com/CLIUtils/CLI11/issues/8), [#17](https://github.com/CLIUtils/CLI11/pull/17)) +* Removed Windows error ([#10](https://github.com/CLIUtils/CLI11/issues/10), [#20](https://github.com/CLIUtils/CLI11/pull/20)) +* Some improvements to CMake, detect Python and no dependencies on Python 2 (like Python 3) ([#18](https://github.com/CLIUtils/CLI11/issues/18), [#21](https://github.com/CLIUtils/CLI11/pull/21)) + ## Version 1.0 * Cleanup using `clang-tidy` and `clang-format` From c435239b7288af1ffb7134a1b290c3c8aaf389d9 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 5 Jun 2017 16:30:56 -0400 Subject: [PATCH 4/4] Minor updates to README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 42a32f5d..8ce93cac 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ CLI11 provides all the features you expect in a powerful command line parser, with a beautiful, minimal syntax and no dependencies beyond C++11. It is header only, and comes in a single file form for easy inclusion in projects. It is easy to use for small projects, but powerful enough for complex command line projects, and can be customized for frameworks. It is tested on [Travis] and [AppVeyor], and is being included in the [GooFit GPU fitting framework][GooFit]. It was inspired by [`plumbum.cli`][Plumbum] for Python. CLI11 has a user friendly introduction in this README, a more indepth tutorial [GitBook], as well as [API documentation][api-docs] generated by Travis. -See the [changelog](./CHANGELOG.md) or [GitHub Releases] for details for current and past releases. The 1.0 announcement post can be found [here](http://iscinumpy.blogspot.com/2017/06/announcing-cli11-version-10.html). +See the [changelog](./CHANGELOG.md) or [GitHub Releases] for details for current and past releases. The version 1.0 announcement post can be found [here](http://iscinumpy.blogspot.com/2017/06/announcing-cli11-version-10.html). ### Why write another CLI parser? @@ -126,7 +126,7 @@ app.add_set_ignore_case(... // String only App* subcom = app.add_subcommand(name, discription); ``` -An option name must start with a alphabetic character or underscore. For long options, anything but an equals sign or a comma is valid after that. Names are given as a comma separated string, with the dash or dashes. An option or flag can have as many names as you want, and afterward, using `count`, you can use any of the names, with dashes as needed, to count the options. One of the names is allowed to be given without proceeding dash(es); if present the option is a positional option, and that name will be used on help line for its positional form. If you want the default value to print in the help description, pass in `true` for the final parameter for `add_option` or `add_set`. +An option name must start with a alphabetic character or underscore. For long options, anything but an equals sign or a comma is valid after that. Names are given as a comma separated string, with the dash or dashes. An option or flag can have as many names as you want, and afterward, using `count`, you can use any of the names, with dashes as needed, to count the options. One of the names is allowed to be given without proceeding dash(es); if present the option is a positional option, and that name will be used on help line for its positional form. If you want the default value to print in the help description, pass in `true` for the final parameter for `add_option` or `add_set`. The set options allow your users to pick from a set of predefined options. ### Example