├── LICENSE └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018, Adi Shavit 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CMake Snippets `${✂️}` 2 | *Short copy-pasteable "Modern" CMake snippets.* 3 | 4 | These snippets are not comprehensive and are not a replacement for documentation. 5 | Use them to avoid needing to memorize them. 6 | 7 | ## New Project 8 | Name your project and set the minimum CMake version 9 | 10 | ```cmake 11 | cmake_minimum_required(VERSION 3.4) 12 | project(MyProj) 13 | ``` 14 | > [`cmake_minimum_required()`](https://cmake.org/cmake/help/latest/command/cmake_minimum_required.html), [`project()`](https://cmake.org/cmake/help/latest/command/project.html) 15 | 16 | 17 | ## Default Build Type 18 | Set default build type, e.g. Release. Turn on Debug with `-DCMAKE_BUILD_TYPE=Debug` 19 | ```cmake 20 | if(NOT CMAKE_BUILD_TYPE) 21 | set(CMAKE_BUILD_TYPE Release) 22 | endif() 23 | ``` 24 | > [`CMAKE_BUILD_TYPE`](https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html) 25 | 26 | ## Adding `#include` Paths 27 | Prefer per-target includes to scope-based commands: 28 | ```cmake 29 | target_include_directories(my_app PUBLIC mylib/include) 30 | ``` 31 | This command adds `mylib/include` to the `my_app` include search paths. 32 | 33 | When another dependent target uses `target_link_libraries()` to *link* with a lib with `INTERFACE` or `PUBLIC` `target_include_directories()`, the linking target will automatically have the library include directories added. 34 | 35 | Thus you should prefer `target_include_directories()` to the older command: 36 | ```cmake 37 | include_directories(my_app mylib/include) 38 | ``` 39 | `include_directories()` works at directory scope. All targets in this `CMakeList.txt`, as well as those in all subdirectories added after the point of its call, will have the path `mylib/include` added to their include path. 40 | 41 | 42 | 43 | > [`target_include_directories()`](https://cmake.org/cmake/help/latest/command/target_include_directories.html), [`include_directories()`](https://cmake.org/cmake/help/latest/command/include_directories.html) [SO-1](https://stackoverflow.com/a/31969632/135862), [SO-2](https://stackoverflow.com/a/40244458/135862) 44 | 45 | ## Create Header Only Library 46 | ```cmake 47 | add_library(my_header_only_lib INTERFACE) # No sources provided 48 | target_sources(my_header_only_lib INTERFACE my_header.hpp) # Adds header files to target, will appear in IDEs 49 | target_include_directories(my_header_only_lib INTERFACE my_header.hpp) # Allow lib dependent target to auto add includes too 50 | ``` 51 | When another target uses `target_link_libraries()` to link with `my_header_only_lib`, the linking target will automatically have the library include directories added. 52 | 53 | > [`add_library()`](https://cmake.org/cmake/help/latest/command/add_library.html), [`target_sources()`](https://cmake.org/cmake/help/latest/command/target_sources.html), [`target_include_directories()`](https://cmake.org/cmake/help/latest/command/target_include_directories.html), [SO-2](https://stackoverflow.com/a/40244458/135862) 54 | 55 | ## Setting C++ Standard 56 | Set the *default* C++ standard for *all* targets: 57 | ```cmake 58 | set(CMAKE_CXX_STANDARD 17) # C++17 59 | ``` 60 | Set the C++ standard for a specific target `my_app`: 61 | ```cmake 62 | set_property(TARGET my_app PROPERTY CXX_STANDARD 17) # C++17 63 | ``` 64 | This is preferable to setting the compiler-specific commands such as `-std=c++17`. 65 | > [`CMAKE_CXX_STANDARD`](https://cmake.org/cmake/help/latest/variable/CMAKE_CXX_STANDARD.html), [`CXX_STANDARD`](https://cmake.org/cmake/help/latest/prop_tgt/CXX_STANDARD.html) 66 | 67 | ## Put Targets in IDE/Solution Folders 68 | Turn on project folder support property and set each target to its named folder 69 | ```cmake 70 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) # Turn on this feature 71 | ... 72 | set_property(TARGET my_lib PROPERTY FOLDER "libs") 73 | set_property(TARGET another_lib PROPERTY FOLDER "libs/3rdParty") 74 | set_property(TARGET my_app PROPERTY FOLDER "utils") 75 | ``` 76 | > [`USE_FOLDERS`](https://cmake.org/cmake/help/latest/prop_gbl/USE_FOLDERS.html), [`FOLDER`](https://cmake.org/cmake/help/latest/prop_tgt/FOLDER.html#prop_tgt:FOLDER) 77 | 78 | ## Add Build Option 79 | Adds a CMake togglable variable that will also appear in cmake-gui, for conditional build settings. 80 | If the variable is set via the command line or the GUI the default initial value will be ignored: 81 | 82 | ```cmake 83 | option(ENABLE_PYTHON_BINDINGS "Build Python bindings" OFF) # Adds option, sets default to OFF 84 | 85 | if(ENABLE_PYTHON_BINDINGS) 86 | add_subdirectory(external_libs/pybind11) 87 | endif() 88 | ``` 89 | This will create a toggleable check box in `cmake-gui`. 90 | To toggle from the command line use `cmake ... -DENABLE_PYTHON_BINDINGS=ON`. 91 | 92 | > [option()](https://cmake.org/cmake/help/latest/command/option.html) 93 | 94 | ## (Unit) Testing 95 | 96 | ### Activate testing 97 | 98 | Activate testing support for [ctest](https://cmake.org/cmake/help/latest/manual/ctest.1.html) via [enable_testing](https://cmake.org/cmake/help/latest/command/enable_testing.html) 99 | 100 | ### Adding a test 101 | 102 | Test programs are normal executable created via [add_executable](https://cmake.org/cmake/help/latest/command/add_executable.html). 103 | 104 | For that cmake knows an executable is a test it has to be registered as such. This is done via the [add_test](https://cmake.org/cmake/help/latest/command/add_test.html) command. 105 | 106 | ### Setting test properties 107 | 108 | It is possible to add properties to a test, these are set via the [set_tests_properties](https://cmake.org/cmake/help/v3.0/command/set_tests_properties.html) command. 109 | 110 | * `WILL_FAIL` true tells cmake that a test is expected to fail 111 | * `TIMEOUT` limits the test runtime to the number of seconds specified. 112 | 113 | ### Example 114 | 115 | ```cmake 116 | enable_testing() 117 | add_executable(mytest testcode1.cpp testcode2.cpp) 118 | add_test(NAME myapp_mytest COMMAND mytest) 119 | set_tests_properties(myapp_mytest TIMEOUT 1) 120 | ``` 121 | 122 | ### Running tests 123 | 124 | If testing is enabled and at least one test has ben registered there is now a `test` target available, which can be invoked via `make test` in the build directory. 125 | 126 | Alternative, running directly `ctest` in the build directory is also a possibility. 127 | 128 | If there are multiple test binaries in a project it is possible to execute them in parallel. 129 | This works by the `-j` (jobs) command line switch. 130 | `ctest -j8` in case of running ctest, `make test ARGS=-j8` to pass the switch via make test to ctest. 131 | 132 | ### Providing Test Data Paths at Build Time 133 | Sometimes we cannot generate the data for the tests at run time and need to load it from some folder. 134 | We can do this by creating a private build preprocessor variable for our unit test app. 135 | 136 | In our `CMakeLists.txt` we add the path location in the repo (or any such similar info): 137 | ```cmake 138 | target_compile_definitions(unit_tests PRIVATE TEST_DATA_DIR=${PROJECT_SOURCE_DIR}/test_data) 139 | ``` 140 | 141 | and in our unit test source code we can use this flag as follows: 142 | 143 | ```cpp 144 | #ifndef TEST_DATA_DIR 145 | #error "Must specify test data directory path in TEST_DATA_DIR." 146 | #else 147 | #define STRINGIFY(x) #x 148 | #define TOSTRING(x) STRINGIFY(x) 149 | constexpr const char* testDataFolder = TOSTRING(TEST_DATA_DIR); 150 | #undef TOSTRING 151 | #undef STRINGIFY 152 | #endif 153 | ``` 154 | 155 | The constexpr (global) variable `testDataFolder` will hold the path to use at build time. 156 | 157 | 158 | ## Profiling 159 | If you are using MSVC you can use a generator expression to add `/PROFILE` to the link options for your target if `RelWithDebInfo` is the target. 160 | ```cmake 161 | if (MSVC) 162 | target_link_options(my_target PRIVATE $<$:/PROFILE>) 163 | endif() 164 | ``` 165 | Note: `target_link_options` is from 3.13, you can use `target_link_libraries` if you're on an old version. 166 | HT: [@TartanLlama](https://stackoverflow.com/a/54347917/135862) 167 | --------------------------------------------------------------------------------