├── .clang-format ├── .github └── workflows │ ├── cmake.yml │ └── codeql.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── CTestConfig.cmake ├── CreateBoilerPlate.sh ├── LICENSE ├── README.md ├── appveyor.yml ├── cmake ├── BoilerPlateConfig.cmake.in ├── CI.CTestScript.cmake ├── CTestCustom.cmake.in ├── CopyDllsForDebug.cmake ├── Coverage.cmake ├── LTO.cmake └── Warnings.cmake ├── external └── CMakeLists.txt ├── include └── foo.h ├── source ├── additional-sourcefile.cpp ├── foo-impl.h ├── foo.cpp ├── main.cpp └── windows-only.cpp └── tests ├── CMakeLists.txt ├── failtest.cpp └── successtest.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | #BasedOnStyle: LLVM 4 | 5 | # Modified 6 | UseTab: Never 7 | ConstructorInitializerIndentWidth: 4 8 | ContinuationIndentWidth: 4 9 | AccessModifierOffset: -4 10 | IndentWidth: 4 11 | AlignConsecutiveAssignments: true 12 | AlignConsecutiveDeclarations: true 13 | AllowShortBlocksOnASingleLine: true 14 | AllowShortCaseLabelsOnASingleLine: true 15 | AllowShortIfStatementsOnASingleLine: true 16 | AlwaysBreakTemplateDeclarations: true 17 | BreakBeforeBraces: Allman 18 | ColumnLimit: 100 19 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 20 | CommentPragmas: '(/<|!<)' 21 | IncludeCategories: 22 | - Regex: '^<(std|cstd)' 23 | Priority: 1 24 | - Regex: '^<' 25 | Priority: 2 26 | - Regex: '.*' 27 | Priority: 3 28 | PointerAlignment: Left 29 | PenaltyExcessCharacter: 200 # for doxygen inline comments (or it would break before the member name) should be enough for the rest 30 | AllowShortFunctionsOnASingleLine: All 31 | 32 | # Unchanged 33 | 34 | AlignAfterOpenBracket: Align 35 | AlignEscapedNewlinesLeft: false 36 | AlignOperands: true 37 | AlignTrailingComments: true 38 | AllowAllParametersOfDeclarationOnNextLine: true 39 | AllowShortLoopsOnASingleLine: false 40 | AlwaysBreakAfterDefinitionReturnType: None 41 | AlwaysBreakAfterReturnType: None 42 | AlwaysBreakBeforeMultilineStrings: false 43 | BinPackArguments: true 44 | BinPackParameters: true 45 | BraceWrapping: 46 | AfterClass: false 47 | AfterControlStatement: false 48 | AfterEnum: false 49 | AfterFunction: false 50 | AfterNamespace: true 51 | AfterObjCDeclaration: false 52 | AfterStruct: false 53 | AfterUnion: false 54 | BeforeCatch: false 55 | BeforeElse: false 56 | IndentBraces: false 57 | BreakBeforeBinaryOperators: None 58 | BreakBeforeTernaryOperators: true 59 | BreakConstructorInitializersBeforeComma: false 60 | BreakAfterJavaFieldAnnotations: false 61 | BreakStringLiterals: true 62 | Cpp11BracedListStyle: true 63 | DerivePointerAlignment: false 64 | DisableFormat: false 65 | ExperimentalAutoDetectBinPacking: false 66 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 67 | IncludeIsMainRegex: '$' 68 | IndentCaseLabels: false 69 | IndentWrappedFunctionNames: false 70 | JavaScriptQuotes: Leave 71 | JavaScriptWrapImports: true 72 | KeepEmptyLinesAtTheStartOfBlocks: true 73 | MacroBlockBegin: '' 74 | MacroBlockEnd: '' 75 | MaxEmptyLinesToKeep: 1 76 | NamespaceIndentation: None 77 | ObjCBlockIndentWidth: 2 78 | ObjCSpaceAfterProperty: false 79 | ObjCSpaceBeforeProtocolList: true 80 | PenaltyBreakBeforeFirstCallParameter: 19 81 | PenaltyBreakComment: 300 82 | PenaltyBreakFirstLessLess: 120 83 | PenaltyBreakString: 1000 84 | PenaltyReturnTypeOnItsOwnLine: 60 85 | ReflowComments: true 86 | SortIncludes: true 87 | SpaceAfterCStyleCast: false 88 | SpaceAfterTemplateKeyword: false 89 | SpaceBeforeAssignmentOperators: true 90 | SpaceBeforeParens: ControlStatements 91 | SpaceInEmptyParentheses: false 92 | SpacesBeforeTrailingComments: 1 93 | SpacesInAngles: false 94 | SpacesInContainerLiterals: true 95 | SpacesInCStyleCastParentheses: false 96 | SpacesInParentheses: false 97 | SpacesInSquareBrackets: false 98 | Standard: Cpp11 99 | 100 | -------------------------------------------------------------------------------- /.github/workflows/cmake.yml: -------------------------------------------------------------------------------- 1 | name: CMake 2 | permissions: 3 | contents: read 4 | 5 | on: 6 | push: 7 | # Always trigger CI on push 8 | pull_request: 9 | branches: [ $default-branch ] 10 | 11 | 12 | jobs: 13 | build: 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | matrix: 17 | os: [ubuntu-latest, windows-latest, macos-latest] 18 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 19 | buildtype: [Debug, Release] 20 | env: 21 | BUILD_TYPE: ${{ matrix.buildtype }} 22 | steps: 23 | - uses: actions/checkout@v4 24 | with: 25 | submodules: 'recursive' 26 | 27 | - name: Configure CMake 28 | # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. 29 | # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type 30 | run: cmake -B ${{runner.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} 31 | 32 | - name: Build 33 | # Build your program with the given configuration 34 | run: cmake --build ${{runner.workspace}}/build --config ${{env.BUILD_TYPE}} 35 | 36 | - name: Test 37 | working-directory: ${{runner.workspace}}/build 38 | # Execute tests defined by the CMake configuration. 39 | # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail 40 | run: ctest -C ${{env.BUILD_TYPE}} 41 | 42 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | schedule: 9 | - cron: '23 5 * * 1' 10 | 11 | jobs: 12 | analyze: 13 | name: Analyze (${{ matrix.language }}) 14 | # Runner size impacts CodeQL analysis time. To learn more, please see: 15 | # - https://gh.io/recommended-hardware-resources-for-running-codeql 16 | # - https://gh.io/supported-runners-and-hardware-resources 17 | # - https://gh.io/using-larger-runners (GitHub.com only) 18 | # Consider using larger runners or machines with greater resources for possible analysis time improvements. 19 | runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} 20 | permissions: 21 | # required for all workflows 22 | security-events: write 23 | 24 | # required to fetch internal or private CodeQL packs 25 | packages: read 26 | 27 | # only required for workflows in private repositories 28 | actions: read 29 | contents: read 30 | 31 | strategy: 32 | fail-fast: false 33 | matrix: 34 | include: 35 | - language: c-cpp 36 | build-mode: autobuild 37 | # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' 38 | # Use `c-cpp` to analyze code written in C, C++ or both 39 | # Use 'java-kotlin' to analyze code written in Java, Kotlin or both 40 | # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both 41 | # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, 42 | # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. 43 | # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how 44 | # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages 45 | steps: 46 | - name: Checkout repository 47 | uses: actions/checkout@v4 48 | with: 49 | submodules: 'recursive' 50 | 51 | 52 | # Initializes the CodeQL tools for scanning. 53 | - name: Initialize CodeQL 54 | uses: github/codeql-action/init@v3 55 | with: 56 | languages: ${{ matrix.language }} 57 | build-mode: ${{ matrix.build-mode }} 58 | # If you wish to specify custom queries, you can do so here or in a config file. 59 | # By default, queries listed here will override any specified in a config file. 60 | # Prefix the list here with "+" to use these queries and those in the config file. 61 | 62 | # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 63 | # queries: security-extended,security-and-quality 64 | 65 | # If the analyze step fails for one of the languages you are analyzing with 66 | # "We were unable to automatically build your code", modify the matrix above 67 | # to set the build mode to "manual" for that language. Then modify this step 68 | # to build your code. 69 | # ℹ️ Command-line programs to run using the OS shell. 70 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 71 | - if: matrix.build-mode == 'manual' 72 | shell: bash 73 | run: | 74 | echo 'If you are using a "manual" build mode for one or more of the' \ 75 | 'languages you are analyzing, replace this with the commands to build' \ 76 | 'your code, for example:' 77 | echo ' make bootstrap' 78 | echo ' make release' 79 | exit 1 80 | 81 | - name: Perform CodeQL Analysis 82 | uses: github/codeql-action/analyze@v3 83 | with: 84 | category: "/language:${{matrix.language}}" 85 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #IDEs 2 | 3 | .vs 4 | .idea 5 | CMakeSettings.json 6 | 7 | # CMake 8 | build*/ 9 | CMakeCache.txt 10 | CMakeFiles 11 | CMakeScripts 12 | Makefile 13 | cmake_install.cmake 14 | install_manifest.txt 15 | CTestTestfile.cmake 16 | Testing/ 17 | 18 | # Object files 19 | *.o 20 | *.ko 21 | *.obj 22 | *.elf 23 | 24 | # Precompiled Headers 25 | *.gch 26 | *.pch 27 | 28 | # Libraries 29 | *.lib 30 | *.a 31 | *.la 32 | *.lo 33 | 34 | # Shared objects (inc. Windows DLLs) 35 | *.dll 36 | *.so 37 | *.so.* 38 | *.dylib 39 | 40 | # Executables 41 | *.exe 42 | *.out 43 | *.app 44 | *.i*86 45 | *.x86_64 46 | *.hex 47 | 48 | # Debug files 49 | *.dSYM/ 50 | *.su 51 | 52 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/fmt"] 2 | path = external/fmt 3 | url = https://github.com/fmtlib/fmt.git 4 | [submodule "external/spdlog"] 5 | path = external/spdlog 6 | url = https://github.com/gabime/spdlog.git 7 | [submodule "external/doctest"] 8 | path = external/doctest 9 | url = https://github.com/onqtam/doctest.git 10 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Main CMakelists for the boilerplate project. 3 | # 4 | # It aims to be a template and a CMake reference, and as such is documented as much as possible. 5 | # While everything might not fit in any project, it should give good defaults and avoid CMake antipatterns. 6 | # If you disagree with some pieces of advice given here, please discuss it with me by opening a Github Issue ! 7 | # 8 | # Project specific options : 9 | # - BP_USE_DOXYGEN 10 | # - BP_BUILD_TESTS (requires BUILD_TESTING set to ON) 11 | # Other options might be available through the cmake scripts including (not exhaustive): 12 | # - ENABLE_WARNINGS_SETTINGS 13 | # - ENABLE_LTO 14 | # 15 | cmake_minimum_required(VERSION 3.16) 16 | 17 | if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) 18 | message(FATAL_ERROR "Do not build in-source. Please remove CMakeCache.txt and the CMakeFiles/ directory. Then build out-of-source.") 19 | endif() 20 | 21 | # Put the project early since modules might need to detect the compiler. 22 | # More information https://cmake.org/cmake/help/latest/command/project.html 23 | project( 24 | "BoilerPlate" # This will exposed as the variable PROJECT_NAME. 25 | VERSION 0.1.0 # Used for installation and defines variables PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR, PROJECT_VERSION_PATCH, and PROJECT_VERSION_TWEAK. 26 | LANGUAGES C CXX # Used to determine the languages to use based on file extensions 27 | ) 28 | 29 | ############################ 30 | ## Modules and scripts ## 31 | ############################ 32 | 33 | # Standard CMake modules 34 | 35 | include(CTest) # Must be called before adding tests but after calling project(). This automatically calls enable_testing() and configures ctest targets when using Make/Ninja 36 | include(CMakeDependentOption) # This is a really useful scripts that creates options that depends on other options. It can even be used with generator expressions ! 37 | include(GNUInstallDirs) # This will define the default values for installation directories (all platforms even if named GNU) 38 | include(InstallRequiredSystemLibraries) # Tell CMake that the `install` target needs to install required system libraries (eg: Windows SDK) 39 | include(CMakePackageConfigHelpers) # Helper to create relocatable packages 40 | 41 | # Custom modules and scripts 42 | 43 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") # Make our cmake scripts available 44 | 45 | include(LTO) 46 | include(Warnings) 47 | include(CopyDllsForDebug) 48 | include(Coverage) 49 | 50 | ############### 51 | ## OPTIONS ## 52 | ############### 53 | 54 | # You should try to give as much control over the project setup to the user. 55 | # When modifying compile flags for example, if they are not mandatory, provide an option. 56 | 57 | option(${PROJECT_NAME}_USE_DOXYGEN "Add a doxygen target to generate the documentation" ON) 58 | option(${PROJECT_NAME}_USE_ADDITIONAL_SOURCEFILE "Use the additional source file" ON) 59 | option(${PROJECT_NAME}_INSTALL "Should ${PROJECT_NAME} be added to the install list? Useful if included using add_subdirectory." ON) 60 | 61 | # Use your own option for tests, in case people use your library through add_subdirectory 62 | cmake_dependent_option(${PROJECT_NAME}_BUILD_TESTS 63 | "Enable ${PROJECT_NAME} project tests targets" ON # By default we want tests if CTest is enabled 64 | "BUILD_TESTING" OFF # Stay coherent with CTest variables 65 | ) 66 | 67 | # External dependencies 68 | add_subdirectory(external EXCLUDE_FROM_ALL) 69 | 70 | # It is always easier to navigate in an IDE when projects are organized in folders. 71 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 72 | 73 | # Whe building a shared library, you do not want to export all symbols by default 74 | # gcc (and hence clang) are wrong about this. 75 | # 76 | # For more information, see https://gcc.gnu.org/wiki/Visibility and https://www.youtube.com/embed/m0DwB4OvDXk 77 | set(CMAKE_CXX_VISIBILITY_PRESET hidden) 78 | set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) 79 | 80 | ############### 81 | ## Project ## 82 | ############### 83 | 84 | 85 | 86 | # Check for LTO support (needs to be after project(...) ) 87 | find_lto(CXX) 88 | 89 | #==========================# 90 | # BoilerPlate executable # 91 | #==========================# 92 | 93 | # Always list the source files explicitly, including headers so that they are listed in the IDE 94 | # If you need to use files based on a variable value, use target_sources 95 | add_executable(BoilerPlate source/main.cpp) 96 | 97 | target_link_libraries(BoilerPlate 98 | #PUBLIC # Useful for libraries, see https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html for more details about transitive usage requirements. 99 | #libraries/targets to link when linking this library 100 | #this will automatically setup the needed flags and dependencies when linking against this target 101 | PRIVATE # The following libraries are only linked for this target, and its flags/dependencies will not be used when linking against this target 102 | general fmt::fmt spdlog::spdlog # It is possible to link some libraries for debug or optimized builds only 103 | #debug DEBUGLIBS 104 | #optimized RELEASELIBS 105 | ) 106 | 107 | # If you need platform specific files to be compiled and do not want to add a new target for this, 108 | # you can use target_sources instead. Note that configuration-dependent sources are not supported yet (see https://gitlab.kitware.com/cmake/cmake/issues/18233) 109 | target_sources(BoilerPlate 110 | PRIVATE 111 | $<$:source/windows-only.cpp> # Use of generator expressions https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html 112 | ) 113 | if(${PROJECT_NAME}_USE_ADDITIONAL_SOURCEFILE) 114 | target_sources(BoilerPlate PRIVATE source/additional-sourcefile.cpp) 115 | # You can add defines if needed. PRIVATE means it will only be defined for this target. (see transitive usage) 116 | target_compile_definitions(BoilerPlate PRIVATE HAS_ADDITIONAL_SOURCEFILE) 117 | endif() 118 | 119 | 120 | # Require c++14, this is better than setting CMAKE_CXX_STANDARD since it won't pollute other targets 121 | # note : cxx_std_* features were added in CMake 3.8.2 122 | target_compile_features(BoilerPlate PRIVATE cxx_std_14) 123 | 124 | # CMake scripts extensions 125 | target_set_warnings(BoilerPlate ENABLE ALL AS_ERROR ALL DISABLE Annoying) # Helper that can set default warning flags for you 126 | target_enable_lto(BoilerPlate optimized) #enable lto if available for non-debug configurations 127 | copy_dlls_for_debug(BoilerPlate "" "") # Copy dependencies next to the executable (DLLs for example) 128 | 129 | # Setup our project as the startup project for Visual so that people don't need to do it manually 130 | set_directory_properties(PROPERTIES VS_STARTUP_PROJECT BoilerPlate) 131 | 132 | #===============# 133 | # Foo library # 134 | #===============# 135 | 136 | # Usually libraries are listed before executables, but in this case we only use it for the tests 137 | # Note that we use both the include and source folders for headers, based on wether they are part of the public API or not. 138 | # For more information about this rationale, see https://github.com/vector-of-bool/pitchfork 139 | add_library(bp_foo 140 | source/foo.cpp 141 | source/foo-impl.h 142 | include/foo.h 143 | ) 144 | 145 | # Since we put the public interface headers in the include directory, we need to tell the compiler so that we can #include . 146 | target_include_directories(bp_foo 147 | PUBLIC # The folder must be used in the include path for any target using this library 148 | $ # Due to the way installation work, we only want this path set when building, not once installed 149 | ) 150 | 151 | # The following properties are useful when you want to have an 'install' target 152 | set_target_properties(${PROJECT_NAME} 153 | PROPERTIES 154 | PUBLIC_HEADER ${CMAKE_CURRENT_LIST_DIR}/include/foo.h # Headers listed here will automatically be copied when installing. Note that directories hierarchy is not preserved. 155 | DEBUG_POSTFIX d # We had a postfix so that we can install debug and release libraries side by side (Windows way) 156 | ) 157 | 158 | # We tell CMake what are the target dependencies 159 | target_link_libraries(bp_foo 160 | PRIVATE # fmt is only needed to build, not to use this library 161 | fmt::fmt # Use the namespaced version to make sure we have the target and not the static lib only (which doesn't have transitive properties) 162 | ) 163 | # Give a 'namespaced' name to libraries targets, as it can't be mistaken with system libraries 164 | # Use the same namespace as the one from the install command. This is only really needed if you want to support usage of your library through add_subdirectory. 165 | add_library(${PROJECT_NAME}::foo ALIAS bp_foo) 166 | 167 | #===========# 168 | # Tests # 169 | #===========# 170 | 171 | if(${PROJECT_NAME}_BUILD_TESTS) 172 | # Let the user add options to the test runner if needed 173 | set(TEST_RUNNER_PARAMS "--force-colors=true" CACHE STRING "Options to add to our test runners commands") 174 | # In a real project you most likely want to exclude test folders 175 | # list(APPEND CUSTOM_COVERAGE_EXCLUDE "/test/") 176 | add_subdirectory(tests) 177 | # You can setup some custom variables and add them to the CTestCustom.cmake.in template to have custom ctest settings 178 | # For example, you can exclude some directories from the coverage reports such as third-parties and tests 179 | configure_file( 180 | ${CMAKE_CURRENT_LIST_DIR}/cmake/CTestCustom.cmake.in 181 | ${CMAKE_CURRENT_BINARY_DIR}/CTestCustom.cmake 182 | @ONLY 183 | ) 184 | endif() 185 | 186 | ############# 187 | ## Doxygen ## 188 | ############# 189 | 190 | if(${PROJECT_NAME}_USE_DOXYGEN AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.9) 191 | find_package(Doxygen 192 | OPTIONAL_COMPONENTS dot mscgen dia 193 | ) 194 | if(DOXYGEN_FOUND) 195 | set(DOXYGEN_USE_MDFILE_AS_MAINPAGE README.md) 196 | doxygen_add_docs( 197 | doc 198 | README.md source 199 | COMMENT "Generate man pages" 200 | ) 201 | endif() 202 | endif() 203 | 204 | 205 | ############### 206 | ## Packaging ## 207 | ############### 208 | 209 | if(${PROJECT_NAME}_INSTALL) 210 | # If we want to use CPack, we need to include it so that it populates variables from our CMakeLists.txt. 211 | # This will also create a `package` target on supported build systems (make, ninja, VS). 212 | # There are various CPACK_* variables you can set before `include(CPack)` to configure it (see https://cmake.org/cmake/help/latest/module/CPack.html#variables-common-to-all-cpack-generators). 213 | set(CPACK_RESOURCE_FILE_README ${CMAKE_CURRENT_LIST_DIR}/README.md) 214 | include(CPack) 215 | 216 | # Let users choose where to install the cmake package descriptions 217 | # For that we make use of the CMake Cache 218 | set(${PROJECT_NAME}_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" CACHE STRING "Path to install ${PROJECT_NAME} Config*.cmake files to.") 219 | set(${PROJECT_NAME}_MODULE_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake" CACHE STRING "Path to install ${PROJECT_NAME}'s .cmake module files to.") 220 | 221 | # Use version checking helper provided by CMake so that users can safely use a version number in their find_package calls 222 | write_basic_package_version_file( 223 | ${PROJECT_NAME}ConfigVersion.cmake # The name of the version file needed by find_package. 224 | VERSION ${PROJECT_VERSION} # The version of the project, already set by the `project` command at the top of this file 225 | COMPATIBILITY SameMajorVersion # We use semantic versioning, backward compatibity is only guaranteed for a same major version 226 | ) 227 | 228 | 229 | # We will need our own file if we have our own dependencies or want some special behavior when the user calls find_package 230 | # otherwise we could simply install the exports as the ${PROJECT_NAME}Config.cmake 231 | configure_package_config_file( 232 | ${PROJECT_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in # This is your template file 233 | ${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake # This is the resulting file 234 | INSTALL_DESTINATION ${${PROJECT_NAME}_INSTALL_CMAKEDIR} # This is where the file will be installed 235 | # List of paths that needs to be relocated once installed 236 | # For example if the variable containing the path is named MY_PATH, all instances of @PACKAGE_MY_PATH@ in the template will be replaced by the relocated version of the path 237 | # This is mostly only needed when you want to install cmake modules or have an unusual layout that cmake is not aware of. 238 | PATH_VARS ${PROJECT_NAME}_MODULE_INSTALL_DIR # This will be exposed as @PACKAGE_BoilerPlate_MODULE_INSTALL_DIR@ in the template file 239 | # Imported targets do not require the following macros 240 | NO_SET_AND_CHECK_MACRO 241 | NO_CHECK_REQUIRED_COMPONENTS_MACRO 242 | ) 243 | 244 | 245 | # The following will export the targets under the name ${PROJECT_NAME}_Targets, not install them yet 246 | # It will then need a call to `install(EXPORT)` 247 | install( 248 | TARGETS 249 | BoilerPlate # We can install executables 250 | bp_foo # ... and libraries 251 | fmt # If we compiled other libraries using add_subdirectory instead of find_package (target is not exported), we'll need to export them too (they are needed for linking) your library. 252 | EXPORT ${PROJECT_NAME}_Targets 253 | # Following is only needed pre-cmake3.14 254 | # RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 255 | # LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 256 | # ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 257 | # Note PUBLIC_HEADER DESTINATION is necessary only if you provide RUNTIME/LIBRARY/ARCHIVE otherwise CMake will map it to the INCLUDES destination (CMake will warn you with "INSTALL TARGETS - target BoilerPlate has PUBLIC_HEADER files but no PUBLIC_HEADER DESTINATION." ) 258 | # PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 259 | # If you want to split between runtime and dev for examples, take a look at COMPONENT, NAMELINK_COMPONENT etc 260 | # More info in Craig Scott's talk "Deep CMake for library authors" https://www.youtube.com/watch?v=m0DwB4OvDXk 261 | INCLUDES 262 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 263 | ) 264 | 265 | # This time, install all the exported targets under the ${PROJECT_NAME}_Targets name. 266 | install( 267 | EXPORT ${PROJECT_NAME}_Targets 268 | NAMESPACE ${PROJECT_NAME}:: # Always specify a namespace so that users can make sure they link targets with transitive properties and not only the library 269 | FILE ${PROJECT_NAME}Targets.cmake # This is the file that needs to be included from your *Config.cmake. Otherwise, you could just make this your actual *Config.cmake file. 270 | DESTINATION ${${PROJECT_NAME}_INSTALL_CMAKEDIR} 271 | ) 272 | 273 | 274 | # So far we only installed the exported targets, now install the package config files. 275 | # If you do not list headers in the PUBLIC_HEADER property, you will need to copy them using `install(FILES)` or `install(DIRECTORY)` too. 276 | # In that case, you can use CMAKE_INSTALL_INCLUDEDIR as the base destination path. 277 | install(FILES 278 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake 279 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake 280 | DESTINATION 281 | ${${PROJECT_NAME}_INSTALL_CMAKEDIR} 282 | ) 283 | 284 | endif() 285 | 286 | -------------------------------------------------------------------------------- /CTestConfig.cmake: -------------------------------------------------------------------------------- 1 | set(CTEST_PROJECT_NAME "cpp-boilerplate") 2 | set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC") 3 | 4 | set(CTEST_DROP_METHOD "http") 5 | set(CTEST_DROP_SITE "my.cdash.org") 6 | set(CTEST_DROP_LOCATION "/submit.php?project=cpp-boilerplate") 7 | set(CTEST_DROP_SITE_CDASH TRUE) 8 | 9 | # In case where you don't want to submit your reports to CDash, 10 | # You can : 11 | # - use CTest in script mode and not call the Submit step 12 | # - Call the various steps directly from make/ninja (targets are {Mode}{Step}) 13 | # where Mode is Nightly, Continuous, or Experimental 14 | # and Step is one of Start Update Configure Build Test Coverage MemCheck 15 | # Check the CTest documentation for more details 16 | # - Same but using the 'ctest' command line 17 | # - set(CTestSubmitRetryCount 0) and wait for timeout but this will return an error ? -------------------------------------------------------------------------------- /CreateBoilerPlate.sh: -------------------------------------------------------------------------------- 1 | git init 2 | touch README.md 3 | git add README.md 4 | git add .gitignore 5 | git commit -m"initial commit" 6 | cd external 7 | rm -rf fmt 8 | git submodule add --depth 1 -- https://github.com/fmtlib/fmt.git 9 | rm -rf spdlog 10 | git submodule add --depth 1 -- https://github.com/gabime/spdlog.git 11 | rm -rf doctest 12 | git submodule add --depth 1 -- https://github.com/onqtam/doctest.git 13 | cd .. 14 | 15 | echo "Repository is now prepared with basic dependencies" 16 | echo "You now can remove those or commit them." 17 | echo "You will need to update the CMakeLists.txt and CI configuration files." -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Lectem 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C++/CMake modern boilerplate 2 | 3 | [![CMake](https://github.com/Lectem/cpp-boilerplate/actions/workflows/cmake.yml/badge.svg)](https://github.com/Lectem/cpp-boilerplate/actions/workflows/cmake.yml) 4 | [![Appveyor build status](https://ci.appveyor.com/api/projects/status/63mnrl1am9plfc4f/branch/master?svg=true)](https://ci.appveyor.com/project/Lectem/boilerplate/branch/master) 5 | [![Coverage](https://codecov.io/gh/Lectem/cpp-boilerplate/branch/master/graph/badge.svg)](https://codecov.io/gh/Lectem/cpp-boilerplate) 6 | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/dfaaaa975fd349b4a565500d97c8d5e1)](https://app.codacy.com/gh/Lectem/cpp-boilerplate/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) 7 | [![CodeQL](https://github.com/Lectem/cpp-boilerplate/actions/workflows/codeql.yml/badge.svg)](https://github.com/Lectem/cpp-boilerplate/actions/workflows/codeql.yml) 8 | [![CDash dashboard](https://img.shields.io/badge/CDash-Access-blue.svg)](http://my.cdash.org/index.php?project=cpp-boilerplate) 9 | 10 | [![Pull requests](https://img.shields.io/github/issues-pr-raw/Lectem/cpp-boilerplate.svg)](https://github.com/Lectem/cpp-boilerplate/pulls) 11 | [![Opened issues](https://img.shields.io/github/issues-raw/Lectem/cpp-boilerplate.svg)](https://github.com/Lectem/cpp-boilerplate/issues) 12 | [![Documentation](https://img.shields.io/badge/Documentation-latest-blue.svg)](https://lectem.github.io/cpp-boilerplate) 13 | 14 | This is a template for new projects, gives a good CMake base and a few dependencies you most likely want in your project. It also set ups some basic CI builds. 15 | 16 | It uses "modern" CMake, ie 3.x paradigms, and should be a good starting point for both people willing to learn it and those that want to update/upgrade their CMakeLists.txt! 17 | 18 | Everything will not necessarily be useful for new projects, but serves as a learning document where most of the CMake features you will need should be showcased. 19 | 20 | If you disagree with some pieces of advice given here, please discuss it with me by opening a Github Issue! Enhancements are always welcome. 21 | 22 | ## Usage 23 | 24 | If you want to bootstrap a new project you only need to : 25 | 26 | - If you don't already have your git repository setup 27 | - Simply copy/paste the folder (without the .git folder) and run the createBoilerPlate.sh file. This will create an initial git commit and add the _required_ submodules. 28 | - Hack CMakeLists.txt and CTestConfig.cmake to change the project name, remove unnecessary parts/comments. 29 | - Ready to go ! 30 | 31 | The CI providers used and that might need some setup : 32 | - Github actions (no setup required) 33 | - AppVeyor, for MSVC on Windows 34 | - Codecov.io, for the codecoverage reports 35 | - CDash, for test and coverage reports using CTest. Can also be used to build nightlies. 36 | 37 | ## Requirements : 38 | 39 | - CMake 3.16 (Not needed for all scripts) 40 | - Git (for the submodules) 41 | - Any of the CI providers listed above if needed. 42 | 43 | ## Some features/notes : 44 | 45 | - Scripts lying in the cmake/ folder can be copy/pasted for use in any CMake project 46 | - Uses c++14 47 | - CopyDllsForDebug.cmake script : A small wrapper around fixup_bundle to copy DLLs to the output directory on windows 48 | - LTO.cmake script : Easier link time optimization configuration (should work on all CMake 3.x versions) as it used to be painful to setup. 49 | - Warnings.cmake script : A wrapper around common warning settings 50 | - Basic unit-testing using [doctest](https://github.com/onqtam/doctest) 51 | - Coverage.cmake : Test coverage script to add a 'Coverage' build type to CMake 52 | - CodeQL already knows about cmake and can build most of the projects without any special configuration. A sample configuration is in this project, mostly due to using submodules. 53 | 54 | ## FAQ 55 | 56 | **Q**: I'm new to this CMake stuff, where do I start ? 57 | 58 | **A**: I would suggest reading my [blog posts](https://siliceum.com/en/blog/post/cmake_01_cmake-basics), [CGold](https://cgold.readthedocs.io) or [An introduction to Modern CMake](https://cliutils.gitlab.io/modern-cmake/README.html) or simply the latest and official [tutorial](https://cmake.org/cmake/help/latest/guide/tutorial/index.html)! 59 | 60 | ___ 61 | 62 | **Q**: Why can't I link some new libraries I put inside the external folder ? 63 | 64 | **A**: By default targets are not at the GLOBAL scope, which means your CMakelists.txt might not see it. 65 | In this case you can either add an alias/imported library or use find_package/library as you would if the library was not in your buildtree. 66 | 67 | ___ 68 | 69 | **Q**: Should I always put my dependencies in the folder external 70 | 71 | **A**: Absolutely not ! It is a great place for small libraries, but you probably don't want to have to rebuild big libs every time. 72 | For those, you can use a package manager such as [VCPKG](https://github.com/microsoft/vcpkg/), [CPM](https://github.com/cpm-cmake/CPM.cmake) or simply rely on `find_package`. 73 | 74 | ___ 75 | 76 | **Q**: I don't understand why you made the choice of XXXXXX here ? 77 | 78 | **A**: Open a new issue ! 79 | 80 | ## External dependencies (using submodules) 81 | 82 | Those dependencies can be easily removed by changing the external/CMakelists.txt and cleaning main.cpp. 83 | 84 | - [libfmt](https://github.com/fmtlib/fmt) In my opinion the best formating library 85 | - [spdlog](https://github.com/gabime/spdlog) A logging library based on libfmt 86 | - [doctest](https://github.com/onqtam/doctest) A test library not as heavy as the others 87 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | #---------------------------------# 2 | # environment configuration # 3 | #---------------------------------# 4 | 5 | # Build worker image (VM template) 6 | image: Visual Studio 2015 7 | 8 | clone_depth: 3 9 | 10 | platform: 11 | - Win32 12 | - x64 13 | 14 | configuration: 15 | - Debug 16 | - Release 17 | 18 | environment: 19 | matrix: 20 | - TOOLSET: v140 21 | # - TOOLSET: v140_clang_c2 22 | 23 | matrix: 24 | fast_finish: true 25 | allow_failures: 26 | - TOOLSET: v140_clang_c2 27 | 28 | # scripts that are called at very beginning, before repo cloning 29 | init: 30 | - cmd: cmake --version 31 | - cmd: msbuild /version 32 | 33 | install: 34 | - git submodule update --init --recursive 35 | 36 | before_build: 37 | - mkdir build 38 | - cd build 39 | - if "%platform%"=="Win32" set CMAKE_GENERATOR_NAME=Visual Studio 14 2015 40 | - if "%platform%"=="x64" set CMAKE_GENERATOR_NAME=Visual Studio 14 2015 Win64 41 | - cmake -G "%CMAKE_GENERATOR_NAME%" -T %TOOLSET% -DCMAKE_BUILD_TYPE=%configuration% -DBP_BUILD_TESTS=ON .. 42 | - cd .. 43 | 44 | build: 45 | project: build/BoilerPlate.sln 46 | parallel: true 47 | verbosity: minimal 48 | 49 | test_script: 50 | - cd build 51 | - ctest -C %configuration% . 52 | - cd .. 53 | 54 | -------------------------------------------------------------------------------- /cmake/BoilerPlateConfig.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | # Required so that on windows Release and RelWithDebInfo can be used instead of default fallback which is Debug 4 | # See https://gitlab.kitware.com/cmake/cmake/issues/20319 5 | 6 | set(CMAKE_MAP_IMPORTED_CONFIG_MINSIZEREL MinSizeRel RelWithDebInfo Release Debug "") 7 | set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO RelWithDebInfo Release MinSizeRel Debug "") 8 | set(CMAKE_MAP_IMPORTED_CONFIG_RELEASE Release RelWithDebInfo MinSizeRel Debug "") 9 | 10 | # Since we install some cmake modules, add them to the modules path 11 | list(APPEND CMAKE_MODULE_PATH "@PACKAGE_BoilerPlate_MODULE_INSTALL_DIR@") 12 | 13 | # If your package depends an another one, you MUST specify it here 14 | include(CMakeFindDependencyMacro) 15 | #find_dependency(NAME_OF_THE_REQUIRED_PACKAGE REQUIRED) 16 | 17 | include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") 18 | -------------------------------------------------------------------------------- /cmake/CI.CTestScript.cmake: -------------------------------------------------------------------------------- 1 | # It might be better than calling 'make Continuous' for CI such as travis since it will skip the update step while still doing the later steps 2 | # It is also makes it easier to customize the test runs and show the output since we can use command-line arguments 3 | set(CTEST_SOURCE_DIRECTORY "./") 4 | set(CTEST_BINARY_DIRECTORY "./buildCI") 5 | 6 | set(CTEST_CMAKE_GENERATOR "Unix Makefiles") 7 | #set(CTEST_USE_LAUNCHERS 1) 8 | set(CTEST_PROJECT_NAME "BoilerPlate") 9 | set(CTEST_BUILD_CONFIGURATION "Coverage") # Only works for multi-config generators 10 | 11 | if(NOT "$ENV{GCOV}" STREQUAL "") 12 | set(GCOV_NAME "$ENV{GCOV}") 13 | else() 14 | set(GCOV_NAME "gcov") 15 | endif() 16 | 17 | find_program(CTEST_COVERAGE_COMMAND NAMES "${GCOV_NAME}") 18 | 19 | #set(CTEST_MEMORYCHECK_COMMAND "valgrind") 20 | #set(CTEST_MEMORYCHECK_TYPE "ThreadSanitizer") 21 | 22 | ctest_start("Continuous") 23 | ctest_configure(OPTIONS -DCMAKE_BUILD_TYPE=${CTEST_BUILD_CONFIGURATION}) 24 | # Done by default when not using a script... Do it here since the CTestCustom.cmake file is generated by our CMakeLists. 25 | ctest_read_custom_files( ${CTEST_BINARY_DIRECTORY} ) 26 | ctest_build() 27 | ctest_test(RETURN_VALUE RET_VAL_TEST) 28 | if(RET_VAL_TEST) 29 | # We need to send an error if we want to detect fails in CI 30 | message(FATAL_ERROR "Some tests failed !") 31 | endif() 32 | if(CTEST_COVERAGE_COMMAND) 33 | ctest_coverage() 34 | else() 35 | message(WARNING "GCov not found, not running coverage") 36 | endif() 37 | #ctest_memcheck() 38 | ctest_submit() # Comment this if you want to use the script but not use CDash -------------------------------------------------------------------------------- /cmake/CTestCustom.cmake.in: -------------------------------------------------------------------------------- 1 | list(APPEND CTEST_CUSTOM_COVERAGE_EXCLUDE 2 | # Exclude list set by cmake 3 | @CUSTOM_COVERAGE_EXCLUDE@ 4 | 5 | # Exclude try_compile sources from coverage results: 6 | "/CMakeFiles/CMakeTmp/" 7 | 8 | # Exclude Qt source files from coverage results: 9 | "[A-Za-z]./[Qq]t/qt-.+-opensource-src" 10 | ) -------------------------------------------------------------------------------- /cmake/CopyDllsForDebug.cmake: -------------------------------------------------------------------------------- 1 | # This is a helper script to run BundleUtilities fixup_bundle as postbuild 2 | # for a target. The primary use case is to copy .DLLs to the build directory for 3 | # the Windows platform. It allows generator expressions to be used to determine 4 | # the binary location 5 | # 6 | # Usage : copy_dlls_for_debug TARGET LIBS DIRS 7 | # - TARGET : A cmake target 8 | # - See fixup_bundle for LIBS and DIRS arguments 9 | 10 | if(RUN_IT) 11 | # Script ran by the add_custom_command 12 | include(BundleUtilities) 13 | fixup_bundle("${TO_FIXUP_FILE}" "${TO_FIXUP_LIBS}" "${TO_FIXUP_DIRS}") 14 | # End of script ran by the add_custom_command 15 | else() 16 | set(THIS_FILE ${CMAKE_CURRENT_LIST_FILE} PARENT_SCOPE) 17 | function(copy_dlls_for_debug _target _libs _dirs) 18 | if(WIN32) 19 | 20 | if(CMAKE_VERSION GREATER_EQUAL 3.21) 21 | add_custom_command(TARGET ${_target} POST_BUILD 22 | COMMAND ${CMAKE_COMMAND} -E copy -t $ $ 23 | COMMAND_EXPAND_LISTS 24 | ) 25 | else() 26 | add_custom_command( 27 | TARGET ${_target} POST_BUILD 28 | COMMAND ${CMAKE_COMMAND} -DRUN_IT:BOOL=ON -DTO_FIXUP_FILE=$ -DTO_FIXUP_LIBS=${_libs} -DTO_FIXUP_DIRS=${_dirs} -P ${THIS_FILE} 29 | COMMENT "Fixing up dependencies for ${_target}" 30 | VERBATIM 31 | ) 32 | endif() 33 | endif(WIN32) 34 | endfunction() 35 | endif() -------------------------------------------------------------------------------- /cmake/Coverage.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # CMake module that detects if the compilers support coverage 3 | # 4 | # If this is the case, the build type Coverage is set up for coverage, and COVERAGE_SUPPORTED is set to true. 5 | # By default the Coverage build type is added to CMAKE_CONFIGURATION_TYPES on multi-config generators. 6 | # This can be controlled through the COVERAGE_IN_CONFIGURATION_TYPES option. 7 | # 8 | 9 | # License: 10 | # 11 | # Copyright (C) 2017 Lectem 12 | # 13 | # Permission is hereby granted, free of charge, to any person 14 | # obtaining a copy of this software and associated documentation files 15 | # (the 'Software') deal in the Software without restriction, 16 | # including without limitation the rights to use, copy, modify, merge, 17 | # publish, distribute, sublicense, and/or sell copies of the Software, 18 | # and to permit persons to whom the Software is furnished to do so, 19 | # subject to the following conditions: 20 | # 21 | # The above copyright notice and this permission notice shall be 22 | # included in all copies or substantial portions of the Software. 23 | # 24 | # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 25 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 | # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 | # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | # SOFTWARE. 32 | 33 | include(CMakeDependentOption) 34 | 35 | set(COVERAGE_COMPILER_FLAGS "-g -O0 --coverage" CACHE INTERNAL "") 36 | set(COVERAGE_LINKER_FLAGS "--coverage" CACHE INTERNAL "") 37 | 38 | get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) 39 | 40 | foreach(_LANG IN LISTS ENABLED_LANGUAGES) 41 | include(Check${_LANG}CompilerFlag OPTIONAL) 42 | set(CMAKE_REQUIRED_LIBRARIES ${COVERAGE_LINKER_FLAGS}) # This is ugly, but better than rewriting/fixing check__compiler_flag 43 | 44 | if(_LANG STREQUAL "C") 45 | check_c_compiler_flag("--coverage" ${_LANG}_COVERAGE_SUPPORTED) 46 | elseif(_LANG STREQUAL "CXX") 47 | check_cxx_compiler_flag("--coverage" ${_LANG}_COVERAGE_SUPPORTED) 48 | else() 49 | if(DEFINED ${_LANG}_COVERAGE_SUPPORTED) 50 | message(STATUS "Skipping ${_LANG}, not supported by Coverage.cmake script") 51 | endif() 52 | set(${_LANG}_COVERAGE_SUPPORTED FALSE) 53 | continue() 54 | endif() 55 | if(${_LANG}_COVERAGE_SUPPORTED) 56 | set(CMAKE_${_LANG}_FLAGS_COVERAGE 57 | ${COVERAGE_COMPILER_FLAGS} 58 | CACHE STRING "Flags used by the ${_LANG} compiler during coverage builds." 59 | ) 60 | mark_as_advanced(CMAKE_${_LANG}_FLAGS_COVERAGE) 61 | set(COVERAGE_SUPPORTED TRUE CACHE INTERNAL "Whether or not coverage is supported by at least one compiler.") 62 | endif() 63 | endforeach() 64 | 65 | if(COVERAGE_SUPPORTED) 66 | set(CMAKE_EXE_LINKER_FLAGS_COVERAGE 67 | "${COVERAGE_LINKER_FLAGS}" 68 | CACHE STRING "Flags used for linking binaries during coverage builds." 69 | ) 70 | set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE 71 | "${COVERAGE_LINKER_FLAGS}" 72 | CACHE STRING "Flags used by the shared libraries linker during coverage builds." 73 | ) 74 | mark_as_advanced( 75 | CMAKE_EXE_LINKER_FLAGS_COVERAGE 76 | CMAKE_SHARED_LINKER_FLAGS_COVERAGE 77 | ) 78 | endif() 79 | 80 | 81 | cmake_dependent_option(COVERAGE_IN_CONFIGURATION_TYPES 82 | "Should the Coverage target be in the CMAKE_CONFIGURATION_TYPES list if supported ?" ON 83 | "CMAKE_CONFIGURATION_TYPES;COVERAGE_SUPPORTED" OFF # No need for this option if we are not using a multi-config generator 84 | ) 85 | 86 | if(COVERAGE_IN_CONFIGURATION_TYPES) 87 | # Modify this only if using a multi-config generator, some modules rely on this variable to detect those generators. 88 | if(CMAKE_CONFIGURATION_TYPES AND COVERAGE_SUPPORTED) 89 | list(APPEND CMAKE_CONFIGURATION_TYPES Coverage) 90 | list(REMOVE_DUPLICATES CMAKE_CONFIGURATION_TYPES) 91 | set(CMAKE_CONFIGURATION_TYPES 92 | "${CMAKE_CONFIGURATION_TYPES}" 93 | CACHE STRING 94 | "Semicolon separated list of supported configuration types, only supports ${CMAKE_CONFIGURATION_TYPES} anything else will be ignored." 95 | FORCE 96 | ) 97 | endif() 98 | else() 99 | if(Coverage IN_LIST CMAKE_CONFIGURATION_TYPES) 100 | message(STATUS "Removing Coverage configuration type (COVERAGE_IN_CONFIGURATION_TYPES is OFF)") 101 | list(REMOVE_ITEM CMAKE_CONFIGURATION_TYPES Coverage) 102 | list(REMOVE_DUPLICATES CMAKE_CONFIGURATION_TYPES) 103 | set(CMAKE_CONFIGURATION_TYPES 104 | "${CMAKE_CONFIGURATION_TYPES}" 105 | CACHE STRING 106 | "Semicolon separated list of supported configuration types, only supports ${CMAKE_CONFIGURATION_TYPES} anything else will be ignored." 107 | FORCE 108 | ) 109 | endif() 110 | endif() -------------------------------------------------------------------------------- /cmake/LTO.cmake: -------------------------------------------------------------------------------- 1 | # Usage : 2 | # 3 | # Variable : ENABLE_LTO | Enable or disable LTO support for this build 4 | # 5 | # find_lto(lang) 6 | # - lang is C or CXX (the language to test LTO for) 7 | # - call it after project() so that the compiler is already detected 8 | # 9 | # This will check for LTO support and create a target_enable_lto(target [debug,optimized,general]) macro. 10 | # The 2nd parameter has the same meaning as in target_link_libraries, and is used to enable LTO only for those build configurations 11 | # 'debug' is by default the Debug configuration, and 'optimized' all the other configurations 12 | # 13 | # if ENABLE_LTO is set to false, an empty macro will be generated 14 | # 15 | # Then to enable LTO for your target use 16 | # 17 | # target_enable_lto(mytarget general) 18 | # 19 | # It is however recommended to use it only for non debug builds the following way : 20 | # 21 | # target_enable_lto(mytarget optimized) 22 | # 23 | # Note : For CMake versions < 3.9, target_link_library is used in it's non plain version. 24 | # You will need to specify PUBLIC/PRIVATE/INTERFACE to all your other target_link_library calls for the target 25 | # 26 | # WARNING for cmake versions older than 3.9 : 27 | # This module will override CMAKE_AR CMAKE_RANLIB and CMAKE_NM by the gcc versions if found when building with gcc 28 | 29 | 30 | # License: 31 | # 32 | # Copyright (C) 2016 Lectem 33 | # 34 | # Permission is hereby granted, free of charge, to any person 35 | # obtaining a copy of this software and associated documentation files 36 | # (the 'Software') deal in the Software without restriction, 37 | # including without limitation the rights to use, copy, modify, merge, 38 | # publish, distribute, sublicense, and/or sell copies of the Software, 39 | # and to permit persons to whom the Software is furnished to do so, 40 | # subject to the following conditions: 41 | # 42 | # The above copyright notice and this permission notice shall be 43 | # included in all copies or substantial portions of the Software. 44 | # 45 | # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 46 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 47 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 48 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 49 | # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 50 | # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 51 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 52 | # SOFTWARE. 53 | 54 | 55 | cmake_minimum_required(VERSION 3.1) 56 | 57 | option(ENABLE_LTO "enable link time optimization" ON) 58 | 59 | macro(find_lto lang) 60 | if(ENABLE_LTO AND NOT LTO_${lang}_CHECKED) 61 | 62 | #LTO support was added for clang/gcc in 3.9 63 | if(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} VERSION_LESS 3.9) 64 | cmake_policy(SET CMP0054 NEW) 65 | message(STATUS "Checking for LTO Compatibility") 66 | # Since GCC 4.9 we need to use gcc-ar / gcc-ranlib / gcc-nm 67 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 68 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_GCC_AR OR NOT CMAKE_GCC_RANLIB OR NOT CMAKE_GCC_NM) 69 | find_program(CMAKE_GCC_AR NAMES 70 | "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ar" 71 | "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ar-${_version}" 72 | DOC "gcc provided wrapper for ar which adds the --plugin option" 73 | ) 74 | find_program(CMAKE_GCC_RANLIB NAMES 75 | "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ranlib" 76 | "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ranlib-${_version}" 77 | DOC "gcc provided wrapper for ranlib which adds the --plugin option" 78 | ) 79 | # Not needed, but at least stay coherent 80 | find_program(CMAKE_GCC_NM NAMES 81 | "${_CMAKE_TOOLCHAIN_PREFIX}gcc-nm" 82 | "${_CMAKE_TOOLCHAIN_PREFIX}gcc-nm-${_version}" 83 | DOC "gcc provided wrapper for nm which adds the --plugin option" 84 | ) 85 | mark_as_advanced(CMAKE_GCC_AR CMAKE_GCC_RANLIB CMAKE_GCC_NM) 86 | set(CMAKE_LTO_AR ${CMAKE_GCC_AR}) 87 | set(CMAKE_LTO_RANLIB ${CMAKE_GCC_RANLIB}) 88 | set(CMAKE_LTO_NM ${CMAKE_GCC_NM}) 89 | endif() 90 | if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") 91 | set(CMAKE_LTO_AR ${CMAKE_AR}) 92 | set(CMAKE_LTO_RANLIB ${CMAKE_RANLIB}) 93 | set(CMAKE_LTO_NM ${CMAKE_NM}) 94 | endif() 95 | 96 | if(CMAKE_LTO_AR AND CMAKE_LTO_RANLIB) 97 | set(__lto_flags -flto) 98 | 99 | if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 4.7) 100 | list(APPEND __lto_flags -fno-fat-lto-objects) 101 | endif() 102 | 103 | if(NOT DEFINED CMAKE_${lang}_PASSED_LTO_TEST) 104 | set(__output_dir "${CMAKE_PLATFORM_INFO_DIR}/LtoTest1${lang}") 105 | file(MAKE_DIRECTORY "${__output_dir}") 106 | set(__output_base "${__output_dir}/lto-test-${lang}") 107 | 108 | execute_process( 109 | COMMAND ${CMAKE_COMMAND} -E echo "void foo() {}" 110 | COMMAND ${CMAKE_${lang}_COMPILER} ${__lto_flags} -c -xc - 111 | -o "${__output_base}.o" 112 | RESULT_VARIABLE __result 113 | ERROR_QUIET 114 | OUTPUT_QUIET 115 | ) 116 | 117 | if("${__result}" STREQUAL "0") 118 | execute_process( 119 | COMMAND ${CMAKE_LTO_AR} cr "${__output_base}.a" "${__output_base}.o" 120 | RESULT_VARIABLE __result 121 | ERROR_QUIET 122 | OUTPUT_QUIET 123 | ) 124 | endif() 125 | 126 | if("${__result}" STREQUAL "0") 127 | execute_process( 128 | COMMAND ${CMAKE_LTO_RANLIB} "${__output_base}.a" 129 | RESULT_VARIABLE __result 130 | ERROR_QUIET 131 | OUTPUT_QUIET 132 | ) 133 | endif() 134 | 135 | if("${__result}" STREQUAL "0") 136 | execute_process( 137 | COMMAND ${CMAKE_COMMAND} -E echo "void foo(); int main() {foo();}" 138 | COMMAND ${CMAKE_${lang}_COMPILER} ${__lto_flags} -xc - 139 | -x none "${__output_base}.a" -o "${__output_base}" 140 | RESULT_VARIABLE __result 141 | ERROR_QUIET 142 | OUTPUT_QUIET 143 | ) 144 | endif() 145 | 146 | if("${__result}" STREQUAL "0") 147 | set(__lto_found TRUE) 148 | endif() 149 | 150 | set(CMAKE_${lang}_PASSED_LTO_TEST 151 | ${__lto_found} CACHE INTERNAL 152 | "If the compiler passed a simple LTO test compile") 153 | endif() 154 | if(CMAKE_${lang}_PASSED_LTO_TEST) 155 | message(STATUS "Checking for LTO Compatibility - works") 156 | set(LTO_${lang}_SUPPORT TRUE CACHE BOOL "Do we have LTO support ?") 157 | set(LTO_COMPILE_FLAGS -flto CACHE STRING "Link Time Optimization compile flags") 158 | set(LTO_LINK_FLAGS -flto CACHE STRING "Link Time Optimization link flags") 159 | else() 160 | message(STATUS "Checking for LTO Compatibility - not working") 161 | endif() 162 | 163 | endif() 164 | elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") 165 | message(STATUS "Checking for LTO Compatibility - works (assumed for clang)") 166 | set(LTO_${lang}_SUPPORT TRUE CACHE BOOL "Do we have LTO support ?") 167 | set(LTO_COMPILE_FLAGS -flto CACHE STRING "Link Time Optimization compile flags") 168 | set(LTO_LINK_FLAGS -flto CACHE STRING "Link Time Optimization link flags") 169 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 170 | message(STATUS "Checking for LTO Compatibility - works") 171 | set(LTO_${lang}_SUPPORT TRUE CACHE BOOL "Do we have LTO support ?") 172 | set(LTO_COMPILE_FLAGS /GL CACHE STRING "Link Time Optimization compile flags") 173 | set(LTO_LINK_FLAGS -LTCG:INCREMENTAL CACHE STRING "Link Time Optimization link flags") 174 | else() 175 | message(STATUS "Checking for LTO Compatibility - compiler not handled by module") 176 | endif() 177 | mark_as_advanced(LTO_${lang}_SUPPORT LTO_COMPILE_FLAGS LTO_LINK_FLAGS) 178 | 179 | 180 | set(LTO_${lang}_CHECKED TRUE CACHE INTERNAL "" ) 181 | 182 | if(CMAKE_GCC_AR AND CMAKE_GCC_RANLIB AND CMAKE_GCC_NM) 183 | # THIS IS HACKY BUT THERE IS NO OTHER SOLUTION ATM 184 | set(CMAKE_AR ${CMAKE_GCC_AR} CACHE FILEPATH "Forcing gcc-ar instead of ar" FORCE) 185 | set(CMAKE_NM ${CMAKE_GCC_NM} CACHE FILEPATH "Forcing gcc-nm instead of nm" FORCE) 186 | set(CMAKE_RANLIB ${CMAKE_GCC_RANLIB} CACHE FILEPATH "Forcing gcc-ranlib instead of ranlib" FORCE) 187 | endif() 188 | endif(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} VERSION_LESS 3.9) 189 | endif(ENABLE_LTO AND NOT LTO_${lang}_CHECKED) 190 | 191 | 192 | if(ENABLE_LTO) 193 | #Special case for cmake older than 3.9, using a library for gcc/clang, but could setup the flags directly. 194 | #Taking advantage of the [debug,optimized] parameter of target_link_libraries 195 | if(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} VERSION_LESS 3.9) 196 | if(LTO_${lang}_SUPPORT) 197 | if(NOT TARGET __enable_lto_tgt) 198 | add_library(__enable_lto_tgt INTERFACE) 199 | endif() 200 | target_compile_options(__enable_lto_tgt INTERFACE ${LTO_COMPILE_FLAGS}) 201 | #this might not work for all platforms... in which case we'll have to set the link flags on the target directly 202 | target_link_libraries(__enable_lto_tgt INTERFACE ${LTO_LINK_FLAGS} ) 203 | macro(target_enable_lto _target _build_configuration) 204 | if(${_build_configuration} STREQUAL "optimized" OR ${_build_configuration} STREQUAL "debug" ) 205 | target_link_libraries(${_target} PRIVATE ${_build_configuration} __enable_lto_tgt) 206 | else() 207 | target_link_libraries(${_target} PRIVATE __enable_lto_tgt) 208 | endif() 209 | endmacro() 210 | else() 211 | #In old cmake versions, we can set INTERPROCEDURAL_OPTIMIZATION even if not supported by the compiler 212 | #So if we didn't detect it, let cmake give it a try 213 | set(__IPO_SUPPORTED TRUE) 214 | endif() 215 | else() 216 | cmake_policy(SET CMP0069 NEW) 217 | include(CheckIPOSupported) 218 | # Optional IPO. Do not use IPO if it's not supported by compiler. 219 | check_ipo_supported(RESULT __IPO_SUPPORTED OUTPUT output) 220 | if(NOT __IPO_SUPPORTED) 221 | message(STATUS "IPO is not supported or broken.") 222 | else() 223 | message(STATUS "IPO is supported !") 224 | endif() 225 | endif() 226 | if(__IPO_SUPPORTED) 227 | macro(target_enable_lto _target _build_configuration) 228 | if(NOT ${_build_configuration} STREQUAL "debug" ) 229 | #enable for all configurations 230 | set_target_properties(${_target} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE) 231 | endif() 232 | if(${_build_configuration} STREQUAL "optimized" ) 233 | #blacklist debug configurations 234 | set(__enable_debug_lto FALSE) 235 | else() 236 | #enable only for debug configurations 237 | set(__enable_debug_lto TRUE) 238 | endif() 239 | get_property(DEBUG_CONFIGURATIONS GLOBAL PROPERTY DEBUG_CONFIGURATIONS) 240 | if(NOT DEBUG_CONFIGURATIONS) 241 | set(DEBUG_CONFIGURATIONS DEBUG) # This is what is done by CMAKE internally... since DEBUG_CONFIGURATIONS is empty by default 242 | endif() 243 | foreach(config IN LISTS DEBUG_CONFIGURATIONS) 244 | set_target_properties(${_target} PROPERTIES INTERPROCEDURAL_OPTIMIZATION_${config} ${__enable_debug_lto}) 245 | endforeach() 246 | endmacro() 247 | endif() 248 | endif() 249 | if(NOT COMMAND target_enable_lto) 250 | macro(target_enable_lto _target _build_configuration) 251 | endmacro() 252 | endif() 253 | endmacro() 254 | -------------------------------------------------------------------------------- /cmake/Warnings.cmake: -------------------------------------------------------------------------------- 1 | # Helper script to set warnings 2 | # Usage : 3 | # target_set_warnings(target 4 | # [ENABLE [ALL] [list of warning names]] 5 | # [DISABLE [ALL/Annoying] [list of warning names]] 6 | # [AS_ERROR ALL] 7 | # ) 8 | # 9 | # ENABLE 10 | # * ALL: means all the warnings possible to enable through a one parameter switch. 11 | # Note that for some compilers, this does not mean every single warning will be enabled (GCC for instance). 12 | # * Any other name: enable the warning with the given name 13 | # 14 | # DISABLE 15 | # * ALL: will override any other settings and this target INTERFACE includes will be considered as system includes by targets linking it. 16 | # * Annoying: Warnings that the author thinks should only be used as static analysis tools not in production. On MSVC, also sets _CRT_SECURE_NO_WARNINGS. 17 | # * Any other name: disable the warning with the given name 18 | # 19 | # AS_ERROR 20 | # * ALL: is the only option available as not all compilers let us set specific warnings as error from command line (MSVC). 21 | # 22 | # 23 | # License: 24 | # 25 | # Copyright (C) 2019 Lectem 26 | # 27 | # Permission is hereby granted, free of charge, to any person 28 | # obtaining a copy of this software and associated documentation files 29 | # (the 'Software') deal in the Software without restriction, 30 | # including without limitation the rights to use, copy, modify, merge, 31 | # publish, distribute, sublicense, and/or sell copies of the Software, 32 | # and to permit persons to whom the Software is furnished to do so, 33 | # subject to the following conditions: 34 | # 35 | # The above copyright notice and this permission notice shall be 36 | # included in all copies or substantial portions of the Software. 37 | # 38 | # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 39 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 40 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 41 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 42 | # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 43 | # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 44 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 45 | # SOFTWARE. 46 | 47 | 48 | cmake_minimum_required(VERSION 3.1) 49 | 50 | option(ENABLE_WARNINGS_SETTINGS "Allow target_set_warnings to add flags and defines. Set this to OFF if you want to provide your own warning parameters." ON) 51 | 52 | function(target_set_warnings) 53 | if(NOT ENABLE_WARNINGS_SETTINGS) 54 | return() 55 | endif() 56 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") 57 | set(WMSVC TRUE) 58 | set(WARNING_ENABLE_PREFIX "/w1") # Means the warning will be available at all levels that do emit warnings 59 | set(WARNING_DISABLE_PREFIX "/wd") 60 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 61 | set(WGCC TRUE) 62 | set(WARNING_ENABLE_PREFIX "-W") 63 | set(WARNING_DISABLE_PREFIX "-Wno-") 64 | elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") 65 | set(WCLANG TRUE) 66 | set(WARNING_ENABLE_PREFIX "-W") 67 | set(WARNING_DISABLE_PREFIX "-Wno-") 68 | endif() 69 | set(multiValueArgs ENABLE DISABLE AS_ERROR) 70 | cmake_parse_arguments(this "" "" "${multiValueArgs}" ${ARGN}) 71 | list(FIND this_ENABLE "ALL" enable_all) 72 | list(FIND this_DISABLE "ALL" disable_all) 73 | list(FIND this_AS_ERROR "ALL" as_error_all) 74 | if(NOT ${enable_all} EQUAL -1) 75 | if(WMSVC) 76 | # Not all the warnings, but WAll is unusable when using libraries 77 | # Unless you'd like to support MSVC in the code with pragmas, this is probably the best option 78 | list(APPEND WarningFlags "/W4") 79 | elseif(WGCC) 80 | list(APPEND WarningFlags "-Wall" "-Wextra" "-Wpedantic") 81 | elseif(WCLANG) 82 | list(APPEND WarningFlags "-Wall" "-Weverything" "-Wpedantic") 83 | endif() 84 | elseif(NOT ${disable_all} EQUAL -1) 85 | set(SystemIncludes TRUE) # Treat includes as if coming from system 86 | if(WMSVC) 87 | list(APPEND WarningFlags "/w" "/W0") 88 | elseif(WGCC OR WCLANG) 89 | list(APPEND WarningFlags "-w") 90 | endif() 91 | endif() 92 | 93 | list(FIND this_DISABLE "Annoying" disable_annoying) 94 | if(NOT ${disable_annoying} EQUAL -1) 95 | if(WMSVC) 96 | # bounds-checked functions require to set __STDC_WANT_LIB_EXT1__ which we usually don't need/want 97 | list(APPEND WarningDefinitions -D_CRT_SECURE_NO_WARNINGS) 98 | # disable C4514 C4710 C4711... Those are useless to add most of the time 99 | #list(APPEND WarningFlags "/wd4514" "/wd4710" "/wd4711") 100 | #list(APPEND WarningFlags "/wd4365") #signed/unsigned mismatch 101 | #list(APPEND WarningFlags "/wd4668") # is not defined as a preprocessor macro, replacing with '0' for 102 | elseif(WGCC OR WCLANG) 103 | list(APPEND WarningFlags -Wno-switch-enum) 104 | if(WCLANG) 105 | list(APPEND WarningFlags -Wno-unknown-warning-option -Wno-padded -Wno-undef -Wno-reserved-id-macro -Wno-inconsistent-missing-destructor-override -fcomment-block-commands=test,retval) 106 | if(NOT CMAKE_CXX_STANDARD EQUAL 98) 107 | list(APPEND WarningFlags -Wno-c++98-compat -Wno-c++98-compat-pedantic) 108 | endif() 109 | if ("${CMAKE_CXX_SIMULATE_ID}" STREQUAL "MSVC") # clang-cl has some VCC flags by default that it will not recognize... 110 | list(APPEND WarningFlags -Wno-unused-command-line-argument) 111 | endif() 112 | endif(WCLANG) 113 | endif() 114 | endif() 115 | 116 | if(NOT ${as_error_all} EQUAL -1) 117 | if(WMSVC) 118 | list(APPEND WarningFlags "/WX") 119 | elseif(WGCC OR WCLANG) 120 | list(APPEND WarningFlags "-Werror") 121 | endif() 122 | endif() 123 | 124 | if(this_ENABLE) 125 | list(REMOVE_ITEM this_ENABLE ALL) 126 | foreach(warning-name IN LISTS this_ENABLE) 127 | list(APPEND WarningFlags "${WARNING_ENABLE_PREFIX}${warning-name}") 128 | endforeach() 129 | endif() 130 | 131 | 132 | if(this_DISABLE) 133 | list(REMOVE_ITEM this_DISABLE ALL Annoying) 134 | foreach(warning-name IN LISTS this_DISABLE) 135 | list(APPEND WarningFlags "${WARNING_DISABLE_PREFIX}${warning-name}") 136 | endforeach() 137 | endif() 138 | 139 | foreach(target IN LISTS this_UNPARSED_ARGUMENTS) 140 | if(WarningFlags) 141 | target_compile_options(${target} PRIVATE ${WarningFlags}) 142 | endif() 143 | if(WarningDefinitions) 144 | target_compile_definitions(${target} PRIVATE ${WarningDefinitions}) 145 | endif() 146 | if(SystemIncludes) 147 | set_target_properties(${target} PROPERTIES 148 | INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $) 149 | endif() 150 | endforeach() 151 | endfunction(target_set_warnings) 152 | -------------------------------------------------------------------------------- /external/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(external C CXX) 2 | 3 | set(CMAKE_FOLDER external) # This will regroup all the external targets in a subfolder in IDEs such as Visual Studio 4 | 5 | set(BUILD_TESTING_BCKP ${BUILD_TESTING}) 6 | set(BUILD_TESTING OFF CACHE BOOL "Force disable of tests for external dependencies" FORCE) 7 | 8 | set(CUSTOM_COVERAGE_EXCLUDE ${CUSTOM_COVERAGE_EXCLUDE} "external" PARENT_SCOPE) # Replaced in CTestCustom.cmake.in 9 | 10 | 11 | #Use fmtlib for formatting 12 | add_subdirectory(fmt EXCLUDE_FROM_ALL) 13 | target_set_warnings(fmt DISABLE ALL) # Treat fmtlib as a system include as to ignore the warnings 14 | 15 | #Use spdlog for logging, and tell it to use our version of fmtlib 16 | add_subdirectory(spdlog EXCLUDE_FROM_ALL) 17 | target_compile_definitions(spdlog INTERFACE SPDLOG_FMT_EXTERNAL) 18 | target_set_warnings(spdlog DISABLE ALL) # Treat spdlog as a system include as to ignore the warnings 19 | 20 | #Doctest for unit tests 21 | add_library(doctest INTERFACE) 22 | target_include_directories( 23 | doctest 24 | INTERFACE 25 | doctest/doctest # note : will expose the parts/ folder... 26 | ) 27 | add_library(doctest::doctest ALIAS doctest) 28 | target_compile_features(doctest INTERFACE cxx_std_11) 29 | 30 | set(BUILD_TESTING ${BUILD_TESTING_BCKP} CACHE BOOL "Build tests (default variable for CTest)" FORCE) #Set it back to its past value 31 | -------------------------------------------------------------------------------- /include/foo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | int foo(bool branch = false); 4 | -------------------------------------------------------------------------------- /source/additional-sourcefile.cpp: -------------------------------------------------------------------------------- 1 | 2 | // This file is only compiled if the cmake option BP_USE_ADDITIONAL_SOURCEFILE is set to ON 3 | 4 | #ifndef HAS_ADDITIONAL_SOURCEFILE 5 | #error If this file is compiled, the target must have HAS_ADDITIONAL_SOURCEFILE defined 6 | #endif 7 | -------------------------------------------------------------------------------- /source/foo-impl.h: -------------------------------------------------------------------------------- 1 | 2 | // This is where you would put implementation details of your library 3 | // It is recommended to only put public header files in the include/ folder, that is files that are required 4 | // to use your library. I suggest using the pitchfork layout which can be found here: 5 | // https://api.csswg.org/bikeshed/?force=1&url=https://raw.githubusercontent.com/vector-of-bool/pitchfork/develop/data/spec.bs 6 | -------------------------------------------------------------------------------- /source/foo.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "foo.h" 3 | #include 4 | 5 | 6 | int foo(bool branch) 7 | { 8 | if(branch) 9 | { 10 | fmt::print("This line will be untested, so that coverage is not 100%\n"); 11 | } 12 | else 13 | { 14 | fmt::print("This is the default behaviour and will be tested\n"); 15 | } 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /source/main.cpp: -------------------------------------------------------------------------------- 1 | /** @file main.cpp 2 | * Just a simple hello world using libfmt 3 | */ 4 | // The previous block is needed in every file for which you want to generate documentation 5 | 6 | #include 7 | 8 | // This should be in the headers 9 | 10 | /** 11 | * @brief A function that does nothing but generate documentation 12 | * @return The answer to life, the universe and everything 13 | */ 14 | int foo(); 15 | 16 | int main(int argc, char* argv[]) 17 | { 18 | if (argc) 19 | { 20 | fmt::print("hello world from {}!", argv[0]); 21 | } 22 | return 0; 23 | } 24 | 25 | // Implementation 26 | int foo() { return 42; } 27 | -------------------------------------------------------------------------------- /source/windows-only.cpp: -------------------------------------------------------------------------------- 1 | #ifndef WIN32_LEAN_AND_MEAN 2 | #define WIN32_LEAN_AND_MEAN 3 | #endif 4 | #include 5 | 6 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | # Note : must be included by master CMakeLists.txt 3 | # Tests in static libraries might not get registered, see https://github.com/onqtam/doctest/blob/master/doc/markdown/faq.md#why-are-my-tests-in-a-static-library-not-getting-registered 4 | # For this reason, and because it is interesting to have individual 5 | # test executables for each library, it is suggested not to put tests directly in the libraries (even though doctest advocates this usage) 6 | # Creating multiple executables is of course not mandatory, and one could use the same executable with various command lines to filter what tests to run. 7 | 8 | add_executable(failtest failtest.cpp) 9 | target_link_libraries(failtest doctest::doctest) 10 | 11 | add_test( 12 | # Use some per-module/project prefix so that it is easier to run only tests for this module 13 | NAME BP.failtest 14 | COMMAND failtest ${TEST_RUNNER_PARAMS} 15 | ) 16 | set_tests_properties( 17 | BP.failtest 18 | PROPERTIES 19 | WILL_FAIL TRUE # We expect this test to fail 20 | ) 21 | 22 | add_executable(successtest successtest.cpp) 23 | target_link_libraries(successtest doctest::doctest ${PROJECT_NAME}::foo) 24 | 25 | add_test( 26 | NAME BP.successtest 27 | COMMAND successtest ${TEST_RUNNER_PARAMS} 28 | ) 29 | -------------------------------------------------------------------------------- /tests/failtest.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | #include "doctest.h" 3 | 4 | static int factorial(int number) { return number <= 1 ? number : factorial(number - 1) * number; } 5 | 6 | TEST_CASE("testing the factorial function") { 7 | CHECK(factorial(0) == 1); 8 | CHECK(factorial(1) == 1); 9 | CHECK(factorial(2) == 2); 10 | CHECK(factorial(3) == 6); 11 | CHECK(factorial(10) == 3628800); 12 | } 13 | #if __GNUC__ // Doesn't crash for gcc/clang, but will with msvc 14 | TEST_CASE("Trigger ASan") 15 | { 16 | int *array = new int[100]; 17 | delete [] array; 18 | array[0] = 0; //boom 19 | REQUIRE(false); 20 | } 21 | #endif -------------------------------------------------------------------------------- /tests/successtest.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | #include "doctest.h" 3 | #include 4 | 5 | static int the_answer_to_life(){return (1<<1) + (1<<3) + (1<<5);} 6 | 7 | TEST_CASE("Main test") { 8 | CHECK(the_answer_to_life() == 42); 9 | } 10 | 11 | int untested_function(){ return 666; } // This should show as not tested in coverage 12 | 13 | TEST_CASE("Foo test") { 14 | CHECK(foo() == 0); 15 | // We are not testing this correctly on purpose to test coverage 16 | // Should check foo(true) too for full coverage 17 | } 18 | --------------------------------------------------------------------------------