From 7a687663923242bbf10b3d0b749c76848d51399b Mon Sep 17 00:00:00 2001 From: Jannik Beyerstedt Date: Tue, 14 Jul 2020 09:02:35 +0200 Subject: [PATCH] C/Cpp: Add CMake example --- README.md | 8 ++-- cpp/CMakeLists.txt | 99 ++++++++++++++++++++++++++++++++++++++++ cpp/template-file.cpp | 9 ++-- cpp/template-file.h | 13 +++--- cpp/test/CMakeLists.txt | 62 +++++++++++++++++++++++++ cpp/test/main.cpp | 16 +++++++ cpp/vscode-settings.json | 8 ++++ 7 files changed, 201 insertions(+), 14 deletions(-) create mode 100644 cpp/CMakeLists.txt create mode 100644 cpp/test/CMakeLists.txt create mode 100644 cpp/test/main.cpp create mode 100644 cpp/vscode-settings.json diff --git a/README.md b/README.md index 259dab4..38e5881 100644 --- a/README.md +++ b/README.md @@ -12,12 +12,12 @@ Just copy the files, that are needed for your project's toolchain, to your repos ## Usage For all projects use: -- .editorconfig +- .editorconfig (VS Code Extension: `editorconfig.editorconfig`) For C/C++ use: -- .clang-format +- .clang-format (VS Code Extensions: `ms-vscode.cpptools`, optionally `ms-vscode.cmake-tools`, `twxs.cmake`) For Python use: -- .pep8 -- pylintrc +- .pep8 (VS Code Extensions: `ms-python.python`. PIP Package: `autopep8`) +- pylintrc (VS Code Extensions: `ms-python.python`. PIP Package: `pylint`) diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt new file mode 100644 index 0000000..2068961 --- /dev/null +++ b/cpp/CMakeLists.txt @@ -0,0 +1,99 @@ +cmake_minimum_required(VERSION 3.13) +project(ctestapp VERSION 0.1.0) # TODO: replace the name `cpptestapp` at every occurrence in this file! + +# # Only do these if this is the main project, and not if it is included through add_subdirectory +# if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) +# include(CTest) +# endif() + +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED True) +# set(CMAKE_VERBOSE_MAKEFILE ON) + +# configure clang-tidy +set(CLANG_TIDY_HEADER_FILTER "src/") +set(CLANG_TIDY_CHECKS "-*,bugprone-*,cert-*,modernize-*,-modernize-use-trailing-return-type,readability-*,performance-*,llvm-*,-llvm-header-guard,google-*,-google-readability-todo,cppcoreguidelines-*,-cppcoreguidelines-owning-memory,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-macro-usage,-cppcoreguidelines-non-private-member-variables-in-classes") +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# run clang-tidy on Release builds, disable with `set_target_properties(lib_foobar PROPERTIES CXX_CLANG_TIDY "")` +if (CMAKE_BUILD_TYPE STREQUAL "Release") + set(CMAKE_CXX_CLANG_TIDY + clang-tidy; + -header-filter=${CLANG_TIDY_HEADER_FILTER}; + -checks=${CLANG_TIDY_CHECKS}; + ) +endif() + + +## CONFIGURE LIBRARIES + +# # example for a header only library: https://github.com/nlohmann/json +# add_library(lib_json INTERFACE) +# target_include_directories(lib_json INTERFACE ${PROJECT_SOURCE_DIR}/thirdparty/nlohmann_json) + +# # example for a compiled only library: https://github.com/emilk/loguru +# find_package(Threads) +# add_library(lib_loguru STATIC +# ${PROJECT_SOURCE_DIR}/thirdparty/loguru/loguru.cpp +# ${PROJECT_SOURCE_DIR}/thirdparty/loguru/loguru.hpp +# ) +# target_include_directories(lib_loguru PUBLIC ${PROJECT_SOURCE_DIR}/thirdparty/loguru) +# target_link_libraries(lib_loguru PRIVATE ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS}) # add libraries required by loguru +# set_target_properties(lib_loguru PROPERTIES CXX_CLANG_TIDY "") # do not run clang-tidy here + + +## CONFIGURE MAIN EXECUTABLE + +# add our own files +set(SOURCES + ${PROJECT_SOURCE_DIR}/src/main.cpp + # add additional sources here +) + +add_executable(ctestapp ${SOURCES}) + +# add libraries +# target_link_libraries(AftermarketV2X-UseCaseApp PRIVATE lib_json) +# target_link_libraries(AftermarketV2X-UseCaseApp PRIVATE lib_loguru) + +# define which compile target should be installed with `make install` +install(TARGETS ctestapp + RUNTIME DESTINATION bin) + + +## CONFIGURE TESTS + +# # Testing only available if this is the main app +# if((CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) AND BUILD_TESTING) +# if (CMAKE_BUILD_TYPE STREQUAL "Release") +# set(CMAKE_CXX_CLANG_TIDY "") # do not run clang-tidy for the tests +# endif() +# add_subdirectory(test) +# endif() + + +## CONFIGURE ADDITIONAL DEVELOPMENT TARGETS + +# add a manual clang-tidy make target (run with `make tidy`) +# Caveat: This only works well, when all sources are added to the SOURCES variable. +# If your project is separated into multiple (internal) libraries, use the integrated +# clang-tidy runner of CMake, which is already enabled on Release builds. +find_program(CLANG_TIDY "clang-tidy") +if(CLANG_TIDY) + # get include directories and convert them to compiler flags (prepend "-I") + get_property(TIDY_INCLUDE_DIRS TARGET ctestapp PROPERTY INCLUDE_DIRECTORIES) + foreach(X IN ITEMS ${TIDY_INCLUDE_DIRS}) + list(APPEND TIDY_INCLUDE_DIRS_ARG "-I${X}") + endforeach() + + # add a Make target named "tidy" (to run clang-tidy manually) + add_custom_target(tidy + COMMAND ${CLANG_TIDY} + -header-filter=${CLANG_TIDY_HEADER_FILTER} + -checks=${CLANG_TIDY_CHECKS} + -p=${PROJECT_BINARY_DIR} + ${SOURCES} + -- + ${TIDY_INCLUDE_DIRS_ARG} + ) +endif() diff --git a/cpp/template-file.cpp b/cpp/template-file.cpp index e478364..313f43e 100644 --- a/cpp/template-file.cpp +++ b/cpp/template-file.cpp @@ -12,12 +12,15 @@ // include system headers here -// then include more specific library headers +// include third party libraries here -// include local headers last +// include locally used headers/ other module's headers here + +// include the module's header last +#include "template-file.h" /** - * The implementation specific explanation might also be added to the source file. + * An implementation specific explanation might also be added to the source file. */ int add(int a, int b) { return a + b; diff --git a/cpp/template-file.h b/cpp/template-file.h index 88f6a7a..9bed9ab 100644 --- a/cpp/template-file.h +++ b/cpp/template-file.h @@ -13,11 +13,10 @@ #ifndef _TEMPLATE_FILE_H #define _TEMPLATE_FILE_H -// include system headers here +// only include what is needed by this header file here! +// starting with the most generic (standard library) -// then include more specific library headers - -// include local headers last +// followed by more specific headers (third party libraries, local modules) /** * @brief Use brief, otherwise the index won't have a brief explanation. @@ -34,9 +33,9 @@ typedef enum BoxEnum_enum { * @brief This method adds two integers. * * Detailed explanation. - * @param a First integer to add. - * @param b Second integer to add. - * @return The sum of both parameters. + * @param a First integer to add. + * @param b Second integer to add. + * @return The sum of both parameters. */ int add(int a, int b); diff --git a/cpp/test/CMakeLists.txt b/cpp/test/CMakeLists.txt new file mode 100644 index 0000000..e6a354a --- /dev/null +++ b/cpp/test/CMakeLists.txt @@ -0,0 +1,62 @@ +include(GoogleTest) + +## CONFIGURE TESTING LIBRARY + +# download and add googletest testing library +set(INSTALL_GTEST OFF CACHE BOOL "Install GTest") +FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG release-1.10.0 +) +FetchContent_GetProperties(googletest) +if(NOT googletest_POPULATED) + FetchContent_Populate(googletest) + add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR}) +endif() + +# convinience macro. Attention, the 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} + TEST_PREFIX "${TESTNAME}." + TEST_LIST TmpTestList) + set_tests_properties(${TmpTestList} PROPERTIES FOLDER "Tests") # for IDEs + else() + gtest_discover_tests(${TESTNAME} + TEST_PREFIX "${TESTNAME}." + PROPERTIES FOLDER "Tests") + endif() + else() + add_test(${TESTNAME} ${TESTNAME}) + set_target_properties(${TESTNAME} PROPERTIES FOLDER "Tests") # for IDEs + endif() +endmacro() + +# add a make target with better test output, than the standard `make test` +if(CMAKE_CONFIGURATION_TYPES) + add_custom_target(check COMMAND env GTEST_COLOR=1 ${CMAKE_CTEST_COMMAND} + --force-new-ctest-process --output-on-failure + --build-config "$") +else() + add_custom_target(check COMMAND env GTEST_COLOR=1 ${CMAKE_CTEST_COMMAND} + --force-new-ctest-process --output-on-failure) +endif() +set_target_properties(check PROPERTIES FOLDER "Scripts") + + +## CONFIGURE TESTS + +# # add tests for convinience interfaces +# add_executable(interfacetests +# main.cpp +# template-test.cpp +# ) +# add_gtest(interfacetests) + +# target_include_directories(interfacetests INTERFACE ${gtest_SOURCE_DIR}/include) +# target_link_libraries(interfacetests PRIVATE main_util_v2x) +# target_link_libraries(interfacetests PRIVATE main_util_hmi) diff --git a/cpp/test/main.cpp b/cpp/test/main.cpp new file mode 100644 index 0000000..2955f27 --- /dev/null +++ b/cpp/test/main.cpp @@ -0,0 +1,16 @@ +/** + * @file test/main.cpp + * @brief Main function for all unit tests. + * + * @author Name + * @copyright (c) Company Name/ Author, YEAR + * @copyright Licensed under the Apache License, Version 2.0 + * @copyright Licensed under the GNU GPLv3 License + */ + +#include "gtest/gtest.h" + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/cpp/vscode-settings.json b/cpp/vscode-settings.json new file mode 100644 index 0000000..4c9eeef --- /dev/null +++ b/cpp/vscode-settings.json @@ -0,0 +1,8 @@ +{ + "C_Cpp.default.configurationProvider": "vector-of-bool.cmake-tools", + "C_Cpp.clang_format_style": "file", + "C_Cpp.clang_format_sortIncludes": true, + "editor.formatOnSave": true, + "cmake.configureOnOpen": true, + "cmake.generator": "Unix Makefiles" +} \ No newline at end of file