From 88781d22ab51afb9dcf6f1e7156da6800a1d454a Mon Sep 17 00:00:00 2001 From: ClausKlein Date: Wed, 10 Feb 2021 22:33:08 +0100 Subject: [PATCH 1/8] add build time dependency to static lib the header only fmt lib is used to show this --- CMakeLists.txt | 42 +++++++++++++++++++++++++++++---------- all/CMakeLists.txt | 3 +++ include/greeter/greeter.h | 3 +++ source/greeter.cpp | 8 +++++++- test/CMakeLists.txt | 14 ++++++++----- test/source/greeter.cpp | 11 +++++++--- 6 files changed, 62 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d12bd85..0aa365c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.14 FATAL_ERROR) # Note: update this to your new project's name and version project( Greeter - VERSION 1.0 + VERSION 1.1 LANGUAGES CXX ) @@ -18,6 +18,14 @@ if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) ) endif() +# ---- Project settings ---- + +if(NOT DEFINED CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_CXX_EXTENSIONS NO) +endif() + # ---- Add dependencies via CPM ---- # see https://github.com/TheLartians/CPM.cmake for more info @@ -27,7 +35,18 @@ include(cmake/CPM.cmake) CPMAddPackage( NAME PackageProject.cmake GITHUB_REPOSITORY TheLartians/PackageProject.cmake - VERSION 1.4 + VERSION 1.4.1 +) + +# NOTE: If fmt is not imported, this is needed to prevent: CMake Error: install(EXPORT +# "GreeterTargets" ...) includes target "Greeter" which requires target "fmt" that is not in any +# export set. see too https://gitlab.kitware.com/cmake/cmake/-/issues/15415 +set(FMT_VERSION 7.1.3) +CPMAddPackage( + NAME fmt + GIT_TAG ${FMT_VERSION} + GITHUB_REPOSITORY fmtlib/fmt + # XXX OPTION "FMT_INSTALL YES" ) # ---- Add source files ---- @@ -40,17 +59,20 @@ file(GLOB_RECURSE sources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/source/ # ---- Create library ---- # Note: for header-only libraries change all PUBLIC flags to INTERFACE and create an interface -# target: add_library(Greeter INTERFACE) set_target_properties(Greeter PROPERTIES -# INTERFACE_COMPILE_FEATURES cxx_std_17) +# target: +add_library(Greeter) +target_compile_features(Greeter PUBLIC cxx_std_17) -add_library(Greeter ${headers} ${sources}) - -set_target_properties(Greeter PROPERTIES CXX_STANDARD 17) +target_sources(Greeter PRIVATE ${headers} ${sources}) # being a cross-platform target, we enforce standards conformance on MSVC -target_compile_options(Greeter PUBLIC "$<$:/permissive->") +if(MSVC) + target_compile_options(Greeter PUBLIC /permissive) +endif() -# Link dependencies (if required) target_link_libraries(Greeter PUBLIC cxxopts) +# Link dependencies (if required) +target_link_libraries(Greeter PRIVATE $) +# XXX target_link_libraries(Greeter PUBLIC fmt::fmt) target_include_directories( Greeter PUBLIC $ @@ -72,5 +94,5 @@ packageProject( INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include INCLUDE_DESTINATION include/${PROJECT_NAME}-${PROJECT_VERSION} VERSION_HEADER "${VERSION_HEADER_LOCATION}" - DEPENDENCIES "" + # XXX DEPENDENCIES "fmt ${FMT_VERSION}" ) diff --git a/all/CMakeLists.txt b/all/CMakeLists.txt index e131b89..db5f5fb 100644 --- a/all/CMakeLists.txt +++ b/all/CMakeLists.txt @@ -7,6 +7,9 @@ project(BuildAll LANGUAGES CXX) include(../cmake/tools.cmake) +# needed to generate test target +enable_testing() + add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../standalone ${CMAKE_BINARY_DIR}/standalone) add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../test ${CMAKE_BINARY_DIR}/test) add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../documentation ${CMAKE_BINARY_DIR}/documentation) diff --git a/include/greeter/greeter.h b/include/greeter/greeter.h index 77dfe3b..9d367d7 100644 --- a/include/greeter/greeter.h +++ b/include/greeter/greeter.h @@ -26,6 +26,9 @@ namespace greeter { * @return a string containing the greeting */ std::string greet(LanguageCode lang = LanguageCode::EN) const; + + /// @brief Return an iso date string + std::string getIsoDate() const; }; } // namespace greeter diff --git a/source/greeter.cpp b/source/greeter.cpp index b1c54a7..1a5bfb8 100644 --- a/source/greeter.cpp +++ b/source/greeter.cpp @@ -1,8 +1,9 @@ +#include #include using namespace greeter; -Greeter::Greeter(std::string _name) : name(_name) {} +Greeter::Greeter(std::string _name) : name(std::move(_name)) {} std::string Greeter::greet(LanguageCode lang) const { switch (lang) { @@ -17,3 +18,8 @@ std::string Greeter::greet(LanguageCode lang) const { return "Bonjour " + name + "!"; } } + +std::string Greeter::getIsoDate() const { + using namespace std::literals::chrono_literals; + return fmt::format("{:%H:%M:%S}", 3h + 15min + 30s); +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 302d7f2..dfff2c1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,6 +1,10 @@ cmake_minimum_required(VERSION 3.14 FATAL_ERROR) -project(GreeterTests LANGUAGES CXX) +project( + GreeterTests + VERSION 1.1 + LANGUAGES CXX +) # ---- Options ---- @@ -22,7 +26,7 @@ CPMAddPackage( ) if(TEST_INSTALLED_VERSION) - find_package(Greeter REQUIRED) + find_package(Greeter ${PROJECT_VERSION} REQUIRED) else() CPMAddPackage(NAME Greeter SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/..) endif() @@ -46,9 +50,9 @@ set_target_properties(GreeterTests PROPERTIES CXX_STANDARD 17) # enable compiler warnings if(NOT TEST_INSTALLED_VERSION) if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") - target_compile_options(Greeter PUBLIC -Wall -pedantic -Wextra -Werror) + target_compile_options(Greeter PRIVATE -Wall -pedantic -Wextra -Werror) elseif(MSVC) - target_compile_options(Greeter PUBLIC /W4 /WX) + target_compile_options(Greeter PRIVATE /W4 /WX) target_compile_definitions(GreeterTests PUBLIC DOCTEST_CONFIG_USE_STD_HEADERS) endif() endif() @@ -65,7 +69,7 @@ doctest_discover_tests(GreeterTests) # ---- code coverage ---- -if(ENABLE_TEST_COVERAGE) +if(ENABLE_TEST_COVERAGE AND NOT TEST_INSTALLED_VERSION) target_compile_options(Greeter PUBLIC -O0 -g -fprofile-arcs -ftest-coverage) target_link_options(Greeter PUBLIC -fprofile-arcs -ftest-coverage) endif() diff --git a/test/source/greeter.cpp b/test/source/greeter.cpp index 3d507e0..345ecf3 100644 --- a/test/source/greeter.cpp +++ b/test/source/greeter.cpp @@ -16,6 +16,11 @@ TEST_CASE("Greeter") { } TEST_CASE("Greeter version") { - static_assert(std::string_view(GREETER_VERSION) == std::string_view("1.0")); - CHECK(std::string(GREETER_VERSION) == std::string("1.0")); -} \ No newline at end of file + static_assert(std::string_view(GREETER_VERSION) == std::string_view("1.1")); + CHECK(std::string(GREETER_VERSION) == std::string("1.1")); +} + +TEST_CASE("Greeter date") { + const greeter::Greeter greeter("Tests"); + CHECK(greeter.getIsoDate() == std::string("03:15:30")); +} From 5e7f68d260fe8c4d3f829291d56e9bd5fad54543 Mon Sep 17 00:00:00 2001 From: ClausKlein Date: Wed, 10 Feb 2021 22:41:20 +0100 Subject: [PATCH 2/8] use add_test() and add a warning why doctest_discover_tests() is only availabe if doctest is not imported with find_packag() --- test/CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index dfff2c1..dafeaab 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -62,10 +62,11 @@ endif() enable_testing() # Note: doctest and similar testing frameworks can automatically configure CMake tests For other -# testing frameworks add the tests target instead: ADD_TEST(GreeterTests GreeterTests) - -include(${doctest_SOURCE_DIR}/scripts/cmake/doctest.cmake) -doctest_discover_tests(GreeterTests) +# testing frameworks add the tests target instead: +add_test(greeterTests GreeterTests) +# include(${doctest_SOURCE_DIR}/scripts/cmake/doctest.cmake) +# doctest_discover_tests(GreeterTests) +# Waning: if doctest is imported with find_package() this will fail! CK # ---- code coverage ---- From 0f191d72edaf920d3f9f7343ca4d31c5aa9ea715 Mon Sep 17 00:00:00 2001 From: ClausKlein Date: Wed, 10 Feb 2021 22:57:16 +0100 Subject: [PATCH 3/8] cmake-format file --- test/CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index dafeaab..8ba3a94 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -64,9 +64,8 @@ enable_testing() # Note: doctest and similar testing frameworks can automatically configure CMake tests For other # testing frameworks add the tests target instead: add_test(greeterTests GreeterTests) -# include(${doctest_SOURCE_DIR}/scripts/cmake/doctest.cmake) -# doctest_discover_tests(GreeterTests) -# Waning: if doctest is imported with find_package() this will fail! CK +# include(${doctest_SOURCE_DIR}/scripts/cmake/doctest.cmake) doctest_discover_tests(GreeterTests) +# Warning: if doctest is imported with find_package() this will fail! CK # ---- code coverage ---- From 4f309d5b79a756ede0c93049d70eafb8f003c002 Mon Sep 17 00:00:00 2001 From: ClausKlein Date: Wed, 10 Feb 2021 23:06:28 +0100 Subject: [PATCH 4/8] fix missed comment --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0aa365c..b2b1d56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,7 +38,7 @@ CPMAddPackage( VERSION 1.4.1 ) -# NOTE: If fmt is not imported, this is needed to prevent: CMake Error: install(EXPORT +# Note: If fmt is not imported, this is needed to prevent: CMake Error: install(EXPORT # "GreeterTargets" ...) includes target "Greeter" which requires target "fmt" that is not in any # export set. see too https://gitlab.kitware.com/cmake/cmake/-/issues/15415 set(FMT_VERSION 7.1.3) @@ -59,7 +59,7 @@ file(GLOB_RECURSE sources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/source/ # ---- Create library ---- # Note: for header-only libraries change all PUBLIC flags to INTERFACE and create an interface -# target: +# target: add_library(Greeter INTERFACE) add_library(Greeter) target_compile_features(Greeter PUBLIC cxx_std_17) From f158b9ca9c84ba60632ebfede139f5d09326e14a Mon Sep 17 00:00:00 2001 From: ClausKlein Date: Thu, 11 Feb 2021 19:17:06 +0100 Subject: [PATCH 5/8] back to version 1.0 respect most review comments --- CMakeLists.txt | 20 ++++++++++---------- test/CMakeLists.txt | 23 +++++++++++------------ test/source/greeter.cpp | 9 +++++++-- 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b2b1d56..9453ae4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.14 FATAL_ERROR) # Note: update this to your new project's name and version project( Greeter - VERSION 1.1 + VERSION 1.0 LANGUAGES CXX ) @@ -41,12 +41,11 @@ CPMAddPackage( # Note: If fmt is not imported, this is needed to prevent: CMake Error: install(EXPORT # "GreeterTargets" ...) includes target "Greeter" which requires target "fmt" that is not in any # export set. see too https://gitlab.kitware.com/cmake/cmake/-/issues/15415 -set(FMT_VERSION 7.1.3) CPMAddPackage( NAME fmt - GIT_TAG ${FMT_VERSION} - GITHUB_REPOSITORY fmtlib/fmt - # XXX OPTION "FMT_INSTALL YES" + GIT_TAG 7.1.3 + GITHUB_REPOSITORY fmtlib/fmt # to get an installable target + OPTION "FMT_INSTALL YES" ) # ---- Add source files ---- @@ -59,11 +58,11 @@ file(GLOB_RECURSE sources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/source/ # ---- Create library ---- # Note: for header-only libraries change all PUBLIC flags to INTERFACE and create an interface -# target: add_library(Greeter INTERFACE) -add_library(Greeter) -target_compile_features(Greeter PUBLIC cxx_std_17) +# target! EITHER: add_library(Greeter INTERFACE) OR: +add_library(Greeter ${headers} ${sources}) -target_sources(Greeter PRIVATE ${headers} ${sources}) +set_target_properties(Greeter PROPERTIES CXX_STANDARD ${CMAKE_CXX_STANDARD}) +# OR target_compile_features(Greeter PUBLIC cxx_std_17) # being a cross-platform target, we enforce standards conformance on MSVC if(MSVC) @@ -94,5 +93,6 @@ packageProject( INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include INCLUDE_DESTINATION include/${PROJECT_NAME}-${PROJECT_VERSION} VERSION_HEADER "${VERSION_HEADER_LOCATION}" - # XXX DEPENDENCIES "fmt ${FMT_VERSION}" + # TODO COMPATIBILITY SameMajorVersion + DEPENDENCIES "fmt 7.1.3" ) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8ba3a94..ff14a6f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,10 +1,6 @@ cmake_minimum_required(VERSION 3.14 FATAL_ERROR) -project( - GreeterTests - VERSION 1.1 - LANGUAGES CXX -) +project(GreeterTests LANGUAGES CXX) # ---- Options ---- @@ -43,16 +39,16 @@ CPMAddPackage( file(GLOB sources CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp) add_executable(GreeterTests ${sources}) -target_link_libraries(GreeterTests doctest Greeter::Greeter) +target_link_libraries(GreeterTests doctest::doctest Greeter::Greeter) set_target_properties(GreeterTests PROPERTIES CXX_STANDARD 17) # enable compiler warnings if(NOT TEST_INSTALLED_VERSION) if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") - target_compile_options(Greeter PRIVATE -Wall -pedantic -Wextra -Werror) + target_compile_options(Greeter PUBLIC -Wall -Wpedantic -Wextra -Werror) elseif(MSVC) - target_compile_options(Greeter PRIVATE /W4 /WX) + target_compile_options(Greeter PUBLIC /W4 /WX) target_compile_definitions(GreeterTests PUBLIC DOCTEST_CONFIG_USE_STD_HEADERS) endif() endif() @@ -63,13 +59,16 @@ enable_testing() # Note: doctest and similar testing frameworks can automatically configure CMake tests For other # testing frameworks add the tests target instead: -add_test(greeterTests GreeterTests) -# include(${doctest_SOURCE_DIR}/scripts/cmake/doctest.cmake) doctest_discover_tests(GreeterTests) -# Warning: if doctest is imported with find_package() this will fail! CK +if(DEFINED doctest_SOURCE_DIR) + include(${doctest_SOURCE_DIR}/scripts/cmake/doctest.cmake) + doctest_discover_tests(GreeterTests) +else() + add_test(greeterTests GreeterTests) +endif() # ---- code coverage ---- -if(ENABLE_TEST_COVERAGE AND NOT TEST_INSTALLED_VERSION) +if(ENABLE_TEST_COVERAGE) target_compile_options(Greeter PUBLIC -O0 -g -fprofile-arcs -ftest-coverage) target_link_options(Greeter PUBLIC -fprofile-arcs -ftest-coverage) endif() diff --git a/test/source/greeter.cpp b/test/source/greeter.cpp index 345ecf3..cab989b 100644 --- a/test/source/greeter.cpp +++ b/test/source/greeter.cpp @@ -16,8 +16,13 @@ TEST_CASE("Greeter") { } TEST_CASE("Greeter version") { - static_assert(std::string_view(GREETER_VERSION) == std::string_view("1.1")); - CHECK(std::string(GREETER_VERSION) == std::string("1.1")); +#if (__cpp_lib_starts_ends_with) + static_assert(std::string_view(GREETER_VERSION).starts_with("1.0")); // TBD C++20 only + CHECK(std::string(GREETER_VERSION).starts_with("1.0")); // SameMajorVersion +#else + static_assert(std::string_view(GREETER_VERSION) == std::string_view("1.0")); + CHECK(std::string(GREETER_VERSION) == std::string("1.0")); +#endif } TEST_CASE("Greeter date") { From beebf702468b16a4717bbd66ed0f881421d0c38e Mon Sep 17 00:00:00 2001 From: ClausKlein Date: Thu, 11 Feb 2021 20:07:14 +0100 Subject: [PATCH 6/8] fix typo --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9453ae4..2e0e3ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,7 +45,7 @@ CPMAddPackage( NAME fmt GIT_TAG 7.1.3 GITHUB_REPOSITORY fmtlib/fmt # to get an installable target - OPTION "FMT_INSTALL YES" + OPTIONS "FMT_INSTALL YES" ) # ---- Add source files ---- From eedcb6f24ee461cc3db5cd2c7c9bb7a3ff51bbdc Mon Sep 17 00:00:00 2001 From: ClausKlein Date: Thu, 11 Feb 2021 21:34:43 +0100 Subject: [PATCH 7/8] update used CMP package versions --- cmake/CPM.cmake | 6 ++++-- test/CMakeLists.txt | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/cmake/CPM.cmake b/cmake/CPM.cmake index 7e35741..73ee2d0 100644 --- a/cmake/CPM.cmake +++ b/cmake/CPM.cmake @@ -1,6 +1,8 @@ -set(CPM_DOWNLOAD_VERSION 0.28.0) +set(CPM_DOWNLOAD_VERSION 0.28.4) if(CPM_SOURCE_CACHE) + # Expand relative path. This is important if the provided path contains a tilde (~) + get_filename_component(CPM_SOURCE_CACHE ${CPM_SOURCE_CACHE} ABSOLUTE) set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") elseif(DEFINED ENV{CPM_SOURCE_CACHE}) set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") @@ -11,7 +13,7 @@ endif() if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION})) message(STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}") file(DOWNLOAD - https://github.com/TheLartians/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake + https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake ${CPM_DOWNLOAD_LOCATION} ) endif() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ff14a6f..76def2c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -18,7 +18,7 @@ include(../cmake/CPM.cmake) CPMAddPackage( NAME doctest GITHUB_REPOSITORY onqtam/doctest - GIT_TAG 2.3.7 + GIT_TAG 2.4.5 ) if(TEST_INSTALLED_VERSION) From 79060d4af652927b6b246df2bdd3f0260d648aa7 Mon Sep 17 00:00:00 2001 From: ClausKlein Date: Fri, 12 Feb 2021 18:52:34 +0100 Subject: [PATCH 8/8] do it my way, modernize cmake build dynamic lib use makefile wrapper to test all use cases include clang-tidy config file prevent clang-tidy warnings --- .clang-tidy | 26 ++++++++++++++++ CMakeLists.txt | 18 ++++++----- GNUmakefile | 58 ++++++++++++++++++++++++++++++++++++ documentation/CMakeLists.txt | 2 +- include/greeter/greeter.h | 7 ++--- source/greeter.cpp | 15 ++++------ standalone/CMakeLists.txt | 8 +++-- standalone/source/main.cpp | 26 ++++++++++------ test/CMakeLists.txt | 13 ++------ test/source/greeter.cpp | 5 ---- 10 files changed, 128 insertions(+), 50 deletions(-) create mode 100644 .clang-tidy create mode 100755 GNUmakefile diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..56b09c7 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,26 @@ +--- +Checks: "-*,\ +boost-*,\ +cert-*,\ +clang-analyzer-*,\ +cppcoreguidelines-*,\ +-cppcoreguidelines-macro-usage,\ +-cppcoreguidelines-owning-memory,\ +-hicpp-*,\ +misc-*,\ +-misc-non-private-member-variables-in-classes,\ +-modernize-*,\ +-modernize-use-trailing-return-type,\ +performance-*,\ +portability-*,\ +readability-*,\ +-*magic-numbers,\ +-*avoid-c-arrays,\ +" +WarningsAsErrors: '' +HeaderFilterRegex: '.*' +AnalyzeTemporaryDtors: false +FormatStyle: file +User: clausklein +... + diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e0e3ae..cde9bf8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.14 FATAL_ERROR) +cmake_minimum_required(VERSION 3.14...3.19) # ---- Project ---- @@ -21,15 +21,16 @@ endif() # ---- Project settings ---- if(NOT DEFINED CMAKE_CXX_STANDARD) - set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS NO) endif() # ---- Add dependencies via CPM ---- -# see https://github.com/TheLartians/CPM.cmake for more info +# see https://github.com/cpm-cmake/CPM.cmake for more info include(cmake/CPM.cmake) +cpmusepackagelock(package-lock.cmake) # PackageProject.cmake will be used to make our target installable CPMAddPackage( @@ -59,8 +60,9 @@ file(GLOB_RECURSE sources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/source/ # Note: for header-only libraries change all PUBLIC flags to INTERFACE and create an interface # target! EITHER: add_library(Greeter INTERFACE) OR: -add_library(Greeter ${headers} ${sources}) +add_library(Greeter SHARED ${headers} ${sources}) +# EITHER: set_target_properties(Greeter PROPERTIES CXX_STANDARD ${CMAKE_CXX_STANDARD}) # OR target_compile_features(Greeter PUBLIC cxx_std_17) @@ -69,9 +71,9 @@ if(MSVC) target_compile_options(Greeter PUBLIC /permissive) endif() -# Link dependencies (if required) +# Link dependencies EITHER: target_link_libraries(Greeter PRIVATE $) -# XXX target_link_libraries(Greeter PUBLIC fmt::fmt) +# OR: target_link_libraries(Greeter PUBLIC fmt::fmt) target_include_directories( Greeter PUBLIC $ @@ -93,6 +95,6 @@ packageProject( INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include INCLUDE_DESTINATION include/${PROJECT_NAME}-${PROJECT_VERSION} VERSION_HEADER "${VERSION_HEADER_LOCATION}" - # TODO COMPATIBILITY SameMajorVersion - DEPENDENCIES "fmt 7.1.3" + COMPATIBILITY SameMajorVersion + # NOTE: not needed DEPENDENCIES "fmt 7.1.3" ) diff --git a/GNUmakefile b/GNUmakefile new file mode 100755 index 0000000..a177583 --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,58 @@ +# +# CURDIR=$(/bin/pwd) +# +# GENERATOR="Unix Makefiles" +GENERATOR=Ninja + +export CPM_SOURCE_CACHE=${HOME}/.cache/CPM +export CPM_USE_LOCAL_PACKAGES=1 + +.PHONY: update format all test check clean distclean lock + +# the default target does just all +check: all + +all: test + +test: install + + +distclean: + rm -rf build root + +# update CPM.cmake +update: + wget -q -O cmake/CPM.cmake https://github.com/cpm-cmake/CPM.cmake/releases/latest/download/get_cpm.cmake + +lock: install + cmake --build build/install --target cpm-update-package-lock + +# install the library +install: + cmake -S . -B build/install -G "${GENERATOR}" -DCMAKE_PREFIX_PATH=${CURDIR}/root -DCMAKE_INSTALL_PREFIX=${CURDIR}/root -DCMAKE_CXX_STANDARD=20 # --trace-expand + cmake --build build/install --target install + +# test the library +test: + cmake -S test -B build/test -G "${GENERATOR}" -DCMAKE_PREFIX_PATH=${CURDIR}/root -DTEST_INSTALLED_VERSION=1 + cmake --build build/test + cmake --build build/test --target test + +# all together +all: + cmake -S all -B build/all -G "${GENERATOR}" -DCMAKE_PREFIX_PATH=${CURDIR}/root -DTEST_INSTALLED_VERSION=1 -DENABLE_TEST_COVERAGE=1 + cmake --build build/all + cmake --build build/all --target test + cmake --build build/all --target GenerateDocs + cmake --build build/all --target check-format + +format: distclean + find . -name CMakeLists.txt | xargs cmake-format -i + find . -name '*.cpp' | xargs clang-format -i + find . -name '*.h' | xargs clang-format -i + +# check the library +check: + cmake -S standalone -B build/standalone -G "${GENERATOR}" -DCMAKE_PREFIX_PATH=${CURDIR}/root -DCMAKE_EXPORT_COMPILE_COMMANDS=1 + cmake --build build/standalone --target all + run-clang-tidy.py -p build/standalone -checks='-*,modernize-*,misc-*,hicpp-*,cert-*,readability-*,portability-*,performance-*,google-*' standalone diff --git a/documentation/CMakeLists.txt b/documentation/CMakeLists.txt index 8f5cbfe..b3717dc 100644 --- a/documentation/CMakeLists.txt +++ b/documentation/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.14 FATAL_ERROR) +cmake_minimum_required(VERSION 3.14...3.19) project(GreeterDocs) diff --git a/include/greeter/greeter.h b/include/greeter/greeter.h index 9d367d7..19569eb 100644 --- a/include/greeter/greeter.h +++ b/include/greeter/greeter.h @@ -18,17 +18,14 @@ namespace greeter { * @brief Creates a new greeter * @param name the name to greet */ - Greeter(std::string name); + explicit Greeter(std::string name); /** * @brief Creates a localized string containing the greeting * @param lang the language to greet in * @return a string containing the greeting */ - std::string greet(LanguageCode lang = LanguageCode::EN) const; - - /// @brief Return an iso date string - std::string getIsoDate() const; + [[nodiscard]] std::string greet(LanguageCode lang = LanguageCode::EN) const; }; } // namespace greeter diff --git a/source/greeter.cpp b/source/greeter.cpp index 1a5bfb8..11fb416 100644 --- a/source/greeter.cpp +++ b/source/greeter.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace greeter; @@ -9,17 +9,12 @@ std::string Greeter::greet(LanguageCode lang) const { switch (lang) { default: case LanguageCode::EN: - return "Hello, " + name + "!"; + return fmt::format("Hello, {}!", name); case LanguageCode::DE: - return "Hallo " + name + "!"; + return fmt::format("Hallo {}!", name); case LanguageCode::ES: - return "¡Hola " + name + "!"; + return fmt::format("¡Hola {}!", name); case LanguageCode::FR: - return "Bonjour " + name + "!"; + return fmt::format("Bonjour {}!", name); } } - -std::string Greeter::getIsoDate() const { - using namespace std::literals::chrono_literals; - return fmt::format("{:%H:%M:%S}", 3h + 15min + 30s); -} diff --git a/standalone/CMakeLists.txt b/standalone/CMakeLists.txt index 4bb837d..bcf0be6 100644 --- a/standalone/CMakeLists.txt +++ b/standalone/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.14 FATAL_ERROR) +cmake_minimum_required(VERSION 3.14...3.19) project(GreeterStandalone LANGUAGES CXX) @@ -27,4 +27,8 @@ add_executable(GreeterStandalone ${sources}) set_target_properties(GreeterStandalone PROPERTIES CXX_STANDARD 17 OUTPUT_NAME "Greeter") -target_link_libraries(GreeterStandalone Greeter::Greeter cxxopts) +# WORKAROUND for ALIAS target is missing error! CK +if(NOT TARGET cxxopts::cxxopts) + add_library(cxxopts::cxxopts ALIAS cxxopts) +endif() +target_link_libraries(GreeterStandalone Greeter::Greeter cxxopts::cxxopts) diff --git a/standalone/source/main.cpp b/standalone/source/main.cpp index 5464fa5..6874460 100644 --- a/standalone/source/main.cpp +++ b/standalone/source/main.cpp @@ -6,15 +6,20 @@ #include #include -const std::unordered_map languages{ - {"en", greeter::LanguageCode::EN}, - {"de", greeter::LanguageCode::DE}, - {"es", greeter::LanguageCode::ES}, - {"fr", greeter::LanguageCode::FR}, -}; - +// NOLINTNEXTLINE(modernize-use-trailing-return-type) int main(int argc, char** argv) { - cxxopts::Options options(argv[0], "A program to welcome the world!"); + // prevent warning: initialization of 'languages' with static storage duration may throw an + // exception that cannot be caught [cert-err58-cpp] + const std::unordered_map languages{ + {"en", greeter::LanguageCode::EN}, + {"de", greeter::LanguageCode::DE}, + {"es", greeter::LanguageCode::ES}, + {"fr", greeter::LanguageCode::FR}, + }; + + // prevent warning: do not use pointer arithmetic + // [cppcoreguidelines-pro-bounds-pointer-arithmetic] + cxxopts::Options options(*argv, "A program to welcome the world!"); std::string language; std::string name; @@ -33,7 +38,10 @@ int main(int argc, char** argv) { if (result["help"].as()) { std::cout << options.help() << std::endl; return 0; - } else if (result["version"].as()) { + } + + // prevent warning: do not use 'else' after 'return' [readability-else-after-return] + if (result["version"].as()) { std::cout << "Greeter, version " << GREETER_VERSION << std::endl; return 0; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 76def2c..5fa8612 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.14 FATAL_ERROR) +cmake_minimum_required(VERSION 3.14...3.19) project(GreeterTests LANGUAGES CXX) @@ -57,18 +57,11 @@ endif() enable_testing() -# Note: doctest and similar testing frameworks can automatically configure CMake tests For other -# testing frameworks add the tests target instead: -if(DEFINED doctest_SOURCE_DIR) - include(${doctest_SOURCE_DIR}/scripts/cmake/doctest.cmake) - doctest_discover_tests(GreeterTests) -else() - add_test(greeterTests GreeterTests) -endif() +add_test(greeterTests GreeterTests) # ---- code coverage ---- -if(ENABLE_TEST_COVERAGE) +if(ENABLE_TEST_COVERAGE AND NOT Greeter_FOUND) target_compile_options(Greeter PUBLIC -O0 -g -fprofile-arcs -ftest-coverage) target_link_options(Greeter PUBLIC -fprofile-arcs -ftest-coverage) endif() diff --git a/test/source/greeter.cpp b/test/source/greeter.cpp index cab989b..10a1242 100644 --- a/test/source/greeter.cpp +++ b/test/source/greeter.cpp @@ -24,8 +24,3 @@ TEST_CASE("Greeter version") { CHECK(std::string(GREETER_VERSION) == std::string("1.0")); #endif } - -TEST_CASE("Greeter date") { - const greeter::Greeter greeter("Tests"); - CHECK(greeter.getIsoDate() == std::string("03:15:30")); -}