diff --git a/.appveyor.yml b/.appveyor.yml index 29451187..5a8df0c2 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -13,7 +13,7 @@ install: build_script: - mkdir build - cd build - - ps: cmake .. -DCLI11_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_GENERATOR="Visual Studio 14 2015" + - ps: cmake .. -DCLI11_WARNINGS_AS_ERRORS=ON -DCLI11_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_GENERATOR="Visual Studio 14 2015" - ps: cmake --build . - cd .. - conan create . CLIUtils/CLI11 diff --git a/.ci/azure-build.yml b/.ci/azure-build.yml index b7cb5bb5..234e442d 100644 --- a/.ci/azure-build.yml +++ b/.ci/azure-build.yml @@ -2,7 +2,7 @@ steps: - task: CMake@1 inputs: - cmakeArgs: .. -DCLI11_SINGLE_FILE=$(cli11.single) -DCLI11_CXX_STD=$(cli11.std) -DCLI11_SINGLE_FILE_TESTS=$(cli11.single) -DCMAKE_BUILD_TYPE=$(cli11.build_type) $(cli11.options) + cmakeArgs: .. -DCLI11_WARNINGS_AS_ERRORS=ON -DCLI11_SINGLE_FILE=$(cli11.single) -DCLI11_CXX_STD=$(cli11.std) -DCLI11_SINGLE_FILE_TESTS=$(cli11.single) -DCMAKE_BUILD_TYPE=$(cli11.build_type) $(cli11.options) displayName: 'Configure' - script: cmake --build . diff --git a/.ci/make_and_test.sh b/.ci/make_and_test.sh index 6aec305e..e326aa4d 100755 --- a/.ci/make_and_test.sh +++ b/.ci/make_and_test.sh @@ -8,7 +8,7 @@ set -evx mkdir -p build cd build -cmake .. -DCLI11_SINGLE_FILE=ON -DCLI11_CXX_STD=$STD -DCLI11_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER_LAUNCHER=ccache $@ +cmake .. -DCLI11_WARNINGS_AS_ERRORS=ON -DCLI11_SINGLE_FILE=ON -DCLI11_CXX_STD=$STD -DCLI11_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER_LAUNCHER=ccache $@ cmake --build . -- -j2 set +evx diff --git a/CMakeLists.txt b/CMakeLists.txt index 020d7cf3..7073a0ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,9 +11,6 @@ else() cmake_policy(VERSION 3.14) endif() -# TESTING: remove this later -set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_COMMAND} -E time") - set(VERSION_REGEX "#define CLI11_VERSION[ \t]+\"(.+)\"") # Read in the line containing the version @@ -26,6 +23,9 @@ string(REGEX REPLACE ${VERSION_REGEX} "\\1" VERSION_STRING "${VERSION_STRING}") # Add the project project(CLI11 LANGUAGES CXX VERSION ${VERSION_STRING}) +# Special target that adds warnings. Is not exported. +add_library(CLI11_warnings INTERFACE) + # Only if built as the main project if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) # User settable @@ -45,11 +45,19 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_STANDARD_REQUIRED ON) + option(CLI11_WARNINGS_AS_ERRORS "Turn all warnings into errors (for CI)") + # Be moderately paranoid with flags if(MSVC) - add_definitions("/W4") + target_compile_options(CLI11_warnings INTERFACE "/W4") + if(CLI11_WARNINGS_AS_ERRORS) + target_compile_options(CLI11_warnings INTERFACE "/WX") + endif() else() - add_definitions(-Wall -Wextra -pedantic -Wshadow) + target_compile_options(CLI11_warnings INTERFACE -Wall -Wextra -pedantic -Wshadow) + if(CLI11_WARNINGS_AS_ERRORS) + target_compile_options(CLI11_warnings INTERFACE -Werror) + endif() endif() if(CMAKE_VERSION VERSION_GREATER 3.6) diff --git a/cmake/AddGoogletest.cmake b/cmake/AddGoogletest.cmake index 12eb621d..f99e8844 100644 --- a/cmake/AddGoogletest.cmake +++ b/cmake/AddGoogletest.cmake @@ -1,4 +1,4 @@ -# +# # # Downloads GTest and provides a helper macro to add tests. Add make check, as well, which # gives output on failed tests without having to set an environment variable. @@ -25,7 +25,7 @@ endif() # Target must already exist macro(add_gtest TESTNAME) target_link_libraries(${TESTNAME} PUBLIC gtest gmock gtest_main) - + if(GOOGLE_TEST_INDIVIDUAL) if(CMAKE_VERSION VERSION_LESS 3.10) gtest_add_tests(TARGET ${TESTNAME} @@ -36,7 +36,7 @@ macro(add_gtest TESTNAME) gtest_discover_tests(${TESTNAME} TEST_PREFIX "${TESTNAME}." PROPERTIES FOLDER "Tests") - + endif() else() add_test(${TESTNAME} ${TESTNAME}) @@ -59,6 +59,13 @@ BUILD_GTEST set_target_properties(gtest gtest_main gmock gmock_main PROPERTIES FOLDER "Extern") +foreach(TGT IN ITEMS gtest gtest_main gmock gmock_main) + get_property(DIR_LIST TARGET ${TGT} PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + foreach(ITEM IN LISTS DIR_LIST) + set_property(TARGET ${TGT} APPEND PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${ITEM}") + endforeach() +endforeach() + if(MSVC) if (MSVC_VERSION GREATER_EQUAL 1900) target_compile_definitions(gtest PUBLIC _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 16cea0c7..07ed55a4 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -19,8 +19,8 @@ if(CLI11_EXAMPLE_JSON) if(NOT EXISTS "${CLI11_SOURCE_DIR}/extern/json/single_include/nlohmann/json.hpp") message(ERROR "You are missing the json package for CLI11_EXAMPLE_JSON. Please update your submodules (git submodule update --init)") endif() - if(CMAKE_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) - message(WARNING "The json example requires GCC 4.9+ (requirement on json library)") + if(CMAKE_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8) + message(WARNING "The json example requires GCC 4.8+ (requirement on json library)") endif() add_cli_exe(json json.cpp) target_include_directories(json PUBLIC SYSTEM "${CLI11_SOURCE_DIR}/extern/json/single_include") @@ -69,7 +69,7 @@ set_property(TEST subcom_partitioned_none PROPERTY PASS_REGULAR_EXPRESSION "This is a timer:" "--file is required" "Run with --help for more information.") - + add_test(NAME subcom_partitioned_all COMMAND subcom_partitioned --file this --count --count -d 1.2) set_property(TEST subcom_partitioned_all PROPERTY PASS_REGULAR_EXPRESSION "This is a timer:" @@ -93,7 +93,7 @@ set_property(TEST option_groups_extra PROPERTY PASS_REGULAR_EXPRESSION add_test(NAME option_groups_extra2 COMMAND option_groups --csv --address "192.168.1.1" -o "test.out") set_property(TEST option_groups_extra2 PROPERTY PASS_REGULAR_EXPRESSION "at most 1") - + add_cli_exe(positional_arity positional_arity.cpp) add_test(NAME positional_arity1 COMMAND positional_arity one ) set_property(TEST positional_arity1 PROPERTY PASS_REGULAR_EXPRESSION @@ -132,7 +132,7 @@ set_property(TEST shapes_all PROPERTY PASS_REGULAR_EXPRESSION "circle4" "rectangle2 with edges [2.1,2.1]" "triangel1 with sides [4.5]") - + add_cli_exe(ranges ranges.cpp) add_test(NAME ranges_range COMMAND ranges --range 1 2 3) set_property(TEST ranges_range PROPERTY PASS_REGULAR_EXPRESSION diff --git a/extern/json b/extern/json index db53bdac..1126c9ca 160000 --- a/extern/json +++ b/extern/json @@ -1 +1 @@ -Subproject commit db53bdac1926d1baebcb459b685dcd2e4608c355 +Subproject commit 1126c9ca74fdea22d2ce3a065ac0fcb5792cbdaf diff --git a/extern/sanitizers b/extern/sanitizers index 6947cff3..99e159ec 160000 --- a/extern/sanitizers +++ b/extern/sanitizers @@ -1 +1 @@ -Subproject commit 6947cff3a9c9305eb9c16135dd81da3feb4bf87f +Subproject commit 99e159ec9bc8dd362b08d18436bd40ff0648417b diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index f86c170f..0994c541 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -1105,8 +1105,11 @@ class App { } /// Get a pointer to subcommand by index App *get_subcommand(int index = 0) const { - if((index >= 0) && (index < static_cast(subcommands_.size()))) - return subcommands_[index].get(); + if(index >= 0) { + auto uindex = static_cast(index); + if(uindex < subcommands_.size()) + return subcommands_[uindex].get(); + } throw OptionNotFound(std::to_string(index)); } @@ -1130,8 +1133,11 @@ class App { /// Get an owning pointer to subcommand by index CLI::App_p get_subcommand_ptr(int index = 0) const { - if((index >= 0) && (index < static_cast(subcommands_.size()))) - return subcommands_[index]; + if(index >= 0) { + auto uindex = static_cast(index); + if(uindex < subcommands_.size()) + return subcommands_[uindex]; + } throw OptionNotFound(std::to_string(index)); } @@ -1274,13 +1280,13 @@ class App { /// This must be called after the options are in but before the rest of the program. void parse(int argc, const char *const *argv) { // If the name is not set, read from command line - if((name_.empty()) || (has_automatic_name_)) { + if(name_.empty() || has_automatic_name_) { has_automatic_name_ = true; name_ = argv[0]; } std::vector args; - args.reserve(argc - 1); + args.reserve(static_cast(argc - 1)); for(int i = argc - 1; i > 0; i--) args.emplace_back(argv[i]); parse(std::move(args)); diff --git a/include/CLI/Option.hpp b/include/CLI/Option.hpp index 4eab08e7..3d90ab87 100644 --- a/include/CLI/Option.hpp +++ b/include/CLI/Option.hpp @@ -722,7 +722,7 @@ class Option : public OptionBase