├── test ├── separate │ ├── some1.cpp │ ├── some2.cpp │ └── some3.cpp ├── util │ ├── h1.h │ ├── h2.h │ ├── level1 │ │ ├── bla_h1.h │ │ ├── bla_h2.h │ │ └── level2 │ │ │ ├── deep.h │ │ │ ├── deep2.h │ │ │ ├── deprecated.h │ │ │ ├── deprecated2.h │ │ │ └── level3 │ │ │ ├── inn.h │ │ │ ├── inn2.h │ │ │ ├── deprecated.h │ │ │ └── deprecated2.h │ └── some_folder │ │ ├── source1.cpp │ │ ├── source2.cpp │ │ └── source3.cpp ├── for_c.h ├── pch.h ├── a.cc ├── b.cc ├── c.cc ├── doc_data │ ├── unity.png │ ├── filter_0.png │ └── filter_1.png └── CMakeLists.txt ├── .gitmodules ├── .gitignore ├── appveyor.yml ├── .travis.yml ├── LICENSE.txt ├── README.md └── cmake └── ucm.cmake /test/separate/some1.cpp: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/separate/some2.cpp: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/separate/some3.cpp: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/util/h1.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /test/util/h2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /test/util/level1/bla_h1.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /test/util/level1/bla_h2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /test/for_c.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include -------------------------------------------------------------------------------- /test/pch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include -------------------------------------------------------------------------------- /test/util/level1/level2/deep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /test/util/some_folder/source1.cpp: -------------------------------------------------------------------------------- 1 | int a; 2 | -------------------------------------------------------------------------------- /test/util/some_folder/source2.cpp: -------------------------------------------------------------------------------- 1 | int a; 2 | -------------------------------------------------------------------------------- /test/util/some_folder/source3.cpp: -------------------------------------------------------------------------------- 1 | int a; 2 | -------------------------------------------------------------------------------- /test/a.cc: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 5; 3 | } 4 | -------------------------------------------------------------------------------- /test/util/level1/level2/deep2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /test/util/level1/level2/deprecated.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /test/util/level1/level2/deprecated2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /test/util/level1/level2/level3/inn.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /test/util/level1/level2/level3/inn2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /test/b.cc: -------------------------------------------------------------------------------- 1 | void b() { 2 | std::vector b; 3 | } 4 | -------------------------------------------------------------------------------- /test/util/level1/level2/level3/deprecated.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /test/util/level1/level2/level3/deprecated2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /test/c.cc: -------------------------------------------------------------------------------- 1 | void c() { 2 | std::vector c; 3 | std::list l; 4 | } 5 | -------------------------------------------------------------------------------- /test/doc_data/unity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onqtam/ucm/HEAD/test/doc_data/unity.png -------------------------------------------------------------------------------- /test/doc_data/filter_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onqtam/ucm/HEAD/test/doc_data/filter_0.png -------------------------------------------------------------------------------- /test/doc_data/filter_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onqtam/ucm/HEAD/test/doc_data/filter_1.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "cotire"] 2 | path = cotire 3 | url = https://github.com/sakra/cotire.git 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Compiled Dynamic libraries 8 | *.so 9 | *.dylib 10 | *.dll 11 | 12 | # Compiled Static libraries 13 | *.lai 14 | *.la 15 | *.a 16 | *.lib 17 | 18 | # Executables 19 | *.exe 20 | *.out 21 | *.app 22 | 23 | # Text garbage 24 | *.ii 25 | *.s 26 | 27 | # My garbage :) 28 | test/build/* 29 | *.suo 30 | *.pyc 31 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # http://www.appveyor.com/docs/appveyor-yml 2 | 3 | notifications: 4 | - provider: Email 5 | to: 6 | - vik.kirilov@gmail.com 7 | on_build_status_changed: true 8 | on_build_failure: true 9 | on_build_success: false 10 | 11 | clone_depth: 5 12 | matrix: 13 | fast_finish: true 14 | branches: 15 | except: 16 | - gh-pages 17 | platform: 18 | - x64 19 | configuration: 20 | - Debug 21 | - Release 22 | 23 | install: 24 | - git submodule update --init --recursive 25 | 26 | before_build: 27 | - cmake -G "Visual Studio 14 2015 Win64" test 28 | build: 29 | parallel: true 30 | project: example.sln 31 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: cpp 3 | notifications: 4 | email: 5 | on_success: change 6 | on_failure: always 7 | git: 8 | depth: 5 9 | compiler: 10 | - gcc 11 | - clang 12 | os: 13 | - linux 14 | - osx 15 | before_install: 16 | - git submodule update --init --recursive 17 | install: 18 | - DEPS_DIR="${TRAVIS_BUILD_DIR}/deps" 19 | - mkdir ${DEPS_DIR} && cd ${DEPS_DIR} 20 | 21 | # setup newer cmake 22 | - | 23 | if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then 24 | CMAKE_URL="http://www.cmake.org/files/v3.3/cmake-3.3.2-Linux-x86_64.tar.gz" 25 | mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake 26 | export PATH=${DEPS_DIR}/cmake/bin:${PATH} 27 | else 28 | brew update 29 | brew outdated cmake || brew upgrade cmake 30 | fi 31 | 32 | - cd ${TRAVIS_BUILD_DIR} 33 | script: 34 | - cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON test 35 | - make 36 | after_script: 37 | - cat compile_commands.json 38 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Viktor Kirilov 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 | 23 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.12) 2 | 3 | project(example) 4 | 5 | include(../cmake/ucm.cmake) 6 | 7 | set(UCM_UNITY_BUILD ON) 8 | 9 | # testing setting the runtime back and forth and leaving it static 10 | ucm_set_runtime(STATIC) 11 | ucm_print_flags() 12 | message("") 13 | ucm_set_runtime(DYNAMIC) 14 | ucm_print_flags() 15 | message("") 16 | ucm_set_runtime(STATIC) 17 | ucm_print_flags() 18 | message("") 19 | 20 | if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") 21 | ucm_add_flags(CXX -fvisibility=hidden) 22 | ucm_add_flags(--save-temps CONFIG Debug) 23 | endif() 24 | 25 | if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") 26 | ucm_add_flags(CXX /W3) 27 | ucm_add_flags(/W4 CONFIG Debug) 28 | endif() 29 | 30 | ucm_add_dirs("" TO sources) 31 | ucm_add_files("separate/some1.cpp" "separate/some2.cpp" TO sources) 32 | ucm_add_files("separate/some3.cpp" TO sources FILTER_POP 1) 33 | ucm_add_dirs("util" TO sources RECURSIVE FILTER_POP 1) 34 | 35 | ucm_remove_files("util/some_folder/source2.cpp" "util/some_folder/source3.cpp" FROM sources) 36 | 37 | ucm_remove_directories("util/level1/level2" FROM sources MATCHES "deprecated") 38 | 39 | ucm_include_file_in_sources("c.cc" HEADER "for_c.h") 40 | 41 | # needed because of this: https://github.com/sakra/cotire/issues/89 42 | ucm_include_file_in_sources("c.cc" HEADER "pch.h") 43 | 44 | ucm_add_target(NAME ${PROJECT_NAME} TYPE EXECUTABLE UNITY CPP_PER_UNITY 3 PCH_FILE "pch.h" SOURCES "${sources}" UNITY_EXCLUDED "c.cc" "separate/some2.cpp") 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ucm - useful cmake macros 2 | ------------------------- 3 | 4 | ucm is a collection of cmake macros that help with: 5 | 6 | - managing compiler/linker flags 7 | - collecting source files with grouping in IDEs that mimics the filesystem structure 8 | - easy removing source files from already collected ones 9 | - adding a precompiled header for targets 10 | - [unity builds](#unity-builds) of targets 11 | - others... contribution is welcome! 12 | 13 | Tested with MSVC/GCC/Clang. 14 | 15 | [cotire](https://github.com/sakra/cotire) is an optional submodule for the [ucm_add_target()](#ucm_add_target) macro either do ```git submodule update --init``` after cloning or include cotire in your cmake files before ucm. 16 | 17 | [![Language](https://img.shields.io/badge/language-CMake-blue.svg)](https://en.wikipedia.org/wiki/CMake) 18 | [![License](http://img.shields.io/badge/license-MIT-blue.svg)](http://opensource.org/licenses/MIT) 19 | [![Linux/OSX Status](https://travis-ci.org/onqtam/ucm.svg?branch=master)](https://travis-ci.org/onqtam/ucm) 20 | [![Windows Status](https://ci.appveyor.com/api/projects/status/m80f32y206l9tb52?svg=true)](https://ci.appveyor.com/project/onqtam/ucm) 21 | 22 | Documentation 23 | ------------- 24 | 25 | ##### Macros: 26 | 27 | - [ucm_print_flags](#ucm_print_flags) 28 | - [ucm_add_flags](#ucm_add_flags) 29 | - [ucm_set_flags](#ucm_set_flags) 30 | - [ucm_remove_flags](#ucm_remove_flags) 31 | - [ucm_add_linker_flags](#ucm_add_linker_flags) 32 | - [ucm_set_linker_flags](#ucm_set_linker_flags) 33 | - [ucm_set_runtime](#ucm_set_runtime) 34 | - [ucm_set_xcode_attrib](#ucm_set_xcode_attrib) 35 | - [ucm_add_files](#ucm_add_files) 36 | - [ucm_add_dirs](#ucm_add_dirs) 37 | - [ucm_count_sources](#ucm_count_sources) 38 | - [ucm_include_file_in_sources](#ucm_include_file_in_sources) 39 | - [ucm_dir_list](#ucm_dir_list) 40 | - [ucm_remove_files](#ucm_remove_files) 41 | - [ucm_remove_directories](#ucm_remove_directories) 42 | - [ucm_add_target](#ucm_add_target) 43 | 44 | Macro notation: ```myMacro(NAME [FLAG])``` - ```NAME``` and a name after it are required and FLAG is optional (because in brackets). 45 | 46 | ##### macro ```ucm_print_flags()``` 47 | 48 | Prints all relevant flags - for example with ```-DCMAKE_BUILD_TYPE=Debug``` given to cmake for makefiles: 49 | 50 | ``` 51 | CMAKE_C_FLAGS_DEBUG: -g 52 | CMAKE_CXX_FLAGS_DEBUG: -g 53 | CMAKE_C_FLAGS: --save-temps -std=c++98 -pedantic -m64 -O2 -fvisibility=hidden 54 | CMAKE_CXX_FLAGS: --save-temps -std=c++98 -pedantic -m64 -O2 -fvisibility=hidden 55 | ``` 56 | 57 | or for a multi config generator like Visual Studio: 58 | 59 | ``` 60 | CMAKE_C_FLAGS_DEBUG: /D_DEBUG /MDd /Zi /Ob0 /Od /RTC1 61 | CMAKE_CXX_FLAGS_DEBUG: /D_DEBUG /MDd /Zi /Ob0 /Od /RTC1 62 | CMAKE_C_FLAGS_RELEASE: /MD /O2 /Ob2 /D NDEBUG 63 | CMAKE_CXX_FLAGS_RELEASE: /MD /O2 /Ob2 /D NDEBUG 64 | CMAKE_C_FLAGS: /DWIN32 /D_WINDOWS /W3 /W4 65 | CMAKE_CXX_FLAGS: /DWIN32 /D_WINDOWS /W3 /GR /EHsc /W4 66 | ``` 67 | 68 | ##### macro ```ucm_add_flags([C] [CXX] [CONFIG ] flag1 flag2 flag3...)``` 69 | 70 | Append the flags to a different set depending on it's options - examples: 71 | 72 | ```cmake 73 | ucm_add_flags(-O3 -Wextra) # will add to CMAKE_C_FLAGS and CMAKE_CXX_FLAGS 74 | ucm_add_flags(C -O3) # will add to CMAKE_C_FLAGS 75 | ucm_add_flags(CXX -O3) # will add to CMAKE_CXX_FLAGS 76 | ucm_add_flags(-O3 -Wall CONFIG Debug) # will add to CMAKE_C_FLAGS_DEBUG and CMAKE_CXX_FLAGS_DEBUG 77 | ucm_add_flags(C -Wall CONFIG Debug Release) # will add to CMAKE_C_FLAGS_DEBUG and CMAKE_C_FLAGS_RELEASE 78 | ``` 79 | 80 | ##### macro ```ucm_set_flags([C] [CXX] [CONFIG ] flag1 flag2 flag3...)``` 81 | 82 | Removes the old and sets the new flags to a different set depending on it's options - examples: 83 | 84 | ```cmake 85 | ucm_set_flags(CXX) # will clear CMAKE_CXX_FLAGS 86 | ucm_set_flags() # will clear both CMAKE_C_FLAGS and CMAKE_CXX_FLAGS 87 | ucm_set_flags(CXX -O3) # will set CMAKE_CXX_FLAGS 88 | ucm_set_flags(-O3 -Wall CONFIG Debug) # will set CMAKE_C_FLAGS_DEBUG and CMAKE_CXX_FLAGS_DEBUG 89 | ``` 90 | 91 | ##### macro ```ucm_remove_flags([C] [CXX] [CONFIG ] flag1 flag2 flag3...)``` 92 | 93 | Removes the flags from a different set depending on it's options - examples: 94 | ```cmake 95 | ucm_remove_flags(CXX /EHsc /GR) # will remove from CMAKE_CXX_FLAGS 96 | ucm_remove_flags(/W3) # will remove from both CMAKE_C_FLAGS and CMAKE_CXX_FLAGS 97 | ucm_remove_flags(/RTC1 CONFIG Debug) # will remove from CMAKE_C_FLAGS_DEBUG and CMAKE_CXX_FLAGS_DEBUG 98 | ``` 99 | 100 | ##### macro ```ucm_add_linker_flags([EXE] [MODULE] [SHARED] [STATIC] [CONFIG ] flag1 flag2 flag3...)``` 101 | 102 | Append the flags to a different set depending on it's options - examples: 103 | 104 | ```cmake 105 | ucm_add_linker_flags(/NXCOMPAT) # will add to CMAKE__LINKER_FLAGS (TYPE is all 4 - exe/module/shared/static) 106 | ucm_add_linker_flags(EXE /DYNAMICBASE CONFIG Release) # will add to CMAKE_EXE_LINKER_FLAGS_RELEASE only 107 | ucm_add_flags(EXE /DYNAMICBASE CONFIG Debug Release) # will add to CMAKE_EXE_LINKER_FLAGS_DEBUG and CMAKE_EXE_LINKER_FLAGS_RELEASE 108 | ``` 109 | 110 | ##### macro ```ucm_set_linker_flags([EXE] [MODULE] [SHARED] [STATIC] [CONFIG ] flag1 flag2 flag3...)``` 111 | 112 | Removes the old and sets the new flags to a different set depending on it's options - examples: 113 | 114 | ```cmake 115 | ucm_set_linker_flags(/NXCOMPAT) # will clear all CMAKE__LINKER_FLAGS 116 | ucm_set_linker_flags(EXE /DYNAMICBASE CONFIG Release) # will set CMAKE_EXE_LINKER_FLAGS_RELEASE only 117 | ``` 118 | 119 | ##### macro ```ucm_set_runtime([STATIC] [DYNAMIC])``` 120 | 121 | Sets the runtime to static/dynamic - for example with Visual Studio as a generator: 122 | 123 | ```cmake 124 | ucm_print_flags() 125 | ucm_set_runtime(STATIC) 126 | ucm_print_flags() 127 | ``` 128 | 129 | will result in: 130 | 131 | ``` 132 | CMAKE_C_FLAGS_DEBUG: /D_DEBUG /MDd /Zi /Ob0 /Od /RTC1 133 | CMAKE_CXX_FLAGS_DEBUG: /D_DEBUG /MDd /Zi /Ob0 /Od /RTC1 134 | CMAKE_C_FLAGS_RELEASE: /MD /O2 /Ob2 /D NDEBUG 135 | CMAKE_CXX_FLAGS_RELEASE: /MD /O2 /Ob2 /D NDEBUG 136 | CMAKE_C_FLAGS: /DWIN32 /D_WINDOWS /W3 /W4 137 | CMAKE_CXX_FLAGS: /DWIN32 /D_WINDOWS /W3 /GR /EHsc /W4 138 | 139 | CMAKE_C_FLAGS_DEBUG: /D_DEBUG /MTd /Zi /Ob0 /Od /RTC1 140 | CMAKE_CXX_FLAGS_DEBUG: /D_DEBUG /MTd /Zi /Ob0 /Od /RTC1 141 | CMAKE_C_FLAGS_RELEASE: /MT /O2 /Ob2 /D NDEBUG 142 | CMAKE_CXX_FLAGS_RELEASE: /MT /O2 /Ob2 /D NDEBUG 143 | CMAKE_C_FLAGS: /DWIN32 /D_WINDOWS /W3 /W4 144 | CMAKE_CXX_FLAGS: /DWIN32 /D_WINDOWS /W3 /GR /EHsc /W4 145 | ``` 146 | ##### macro ```ucm_set_xcode_attrib(name value [CLEAR] [CONFIG ])``` 147 | 148 | Sets an Xcode attribute and optionally per-configuration: 149 | 150 | ```cmake 151 | ucm_set_xcode_attrib(DEBUG_INFORMATION_FORMAT "dwarf-with-dsym") 152 | ucm_set_xcode_attrib(DEAD_CODE_STRIPPING "YES" CONFIG Debug Release) 153 | ``` 154 | 155 | will result in: 156 | 157 | ``` 158 | CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT: "dwarf-with-dsym" 159 | CMAKE_XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING[variant=Debug]: "YES" 160 | CMAKE_XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING[variant=Release]: "YES" 161 | ``` 162 | 163 | ##### macro ```ucm_add_files(src1 src2 scr3... TO [FILTER_POP ])``` 164 | 165 | Adds the sources to the sources variable and sets up filters for the solution explorer of Visual Studio (probably for XCode/CodeBlocks too). 166 | 167 | The filters will mimic the filesystem - if we have given ```dir1/test/a.cpp``` we would have by default ```dir1/test``` as nested filters in the solution explorer. This can be controlled with ```FILTER_POP``` - 1 would result in only ```test``` as a filter and 2 would result in no filter for ```a.cpp``` - see [ucm_add_dirs](#ucm_add_dirs) for a visual example. 168 | 169 | ```CMake 170 | ucm_add_files("dir/some1.cpp" "dir/some1.h" TO sources) 171 | ``` 172 | 173 | ##### macro ```ucm_add_dirs(dir1 dir2 dir3... TO [RECURSIVE] [FILTER_POP ] [ADDITIONAL_EXT ext1 ext2 ...])``` 174 | 175 | Adds all sources (sources and headers with all valid c/c++ extensions) from the directories given. 176 | 177 | Can be recursive with the ```RECURSIVE``` flag. 178 | 179 | Like ```ucm_add_files()``` filters for the solution explorer of IDEs can be controlled with ```FILTER_POP``` - example: 180 | 181 | | CMake code | result | 182 | |--------------------------------------------------|----------------------------------| 183 | | ```ucm_add_dirs(util TO sources)``` | ![0](test/doc_data/filter_0.png) | 184 | | ```ucm_add_dirs(util TO sources FILTER_POP 1)``` | ![1](test/doc_data/filter_1.png) | 185 | 186 | Additional extensions for collection can be added with the ```ADDITIONAL_EXT``` list. 187 | 188 | ##### macro ```ucm_count_sources(src1 src2 src3... RESULT )``` 189 | 190 | Given a list of sources - returns the number of source files (no headers - only valid source extensions) in the result. 191 | 192 | ``` 193 | set(sources "a.cpp;b.cpp;h.hpp") 194 | ucm_count_sources(${sources} c.cpp d.cpp RESULT res) # would return 4 in res 195 | ``` 196 | 197 | ##### macro ```ucm_include_file_in_sources(src1 src2 src3... HEADER
)``` 198 | 199 | Includes the header in the source file with a compile flag (without modifying the file) either with ```-include "hdr.h"``` or with ```/FI"hdr.h"``` depending on the compiler. 200 | 201 | ```CMake 202 | ucm_include_file_in_sources(c.cc a.cc b.cc HEADER "common.h") 203 | ``` 204 | 205 | ##### macro ```ucm_dir_list( )``` 206 | 207 | Returns a list of subdirectories for a given directory. 208 | 209 | ```CMake 210 | ucm_dir_list("the/dir" result) 211 | ``` 212 | 213 | ##### macro ```ucm_remove_files(src1 src2 src3... FROM )``` 214 | 215 | Removes the given source files from the sources list - example: 216 | 217 | ```CMake 218 | ucm_add_dirs(utils REC TO sources) 219 | ucm_remove_files(utils/deprecated.h FROM sources) 220 | ``` 221 | 222 | ##### macro ```ucm_remove_directories(dir1 dir2 dir3... FROM [MATCHES pttrn1 pttrn2])``` 223 | 224 | Removes all source files from the given directories from the sources list (recursively) - example: 225 | 226 | ```CMake 227 | ucm_add_dirs(utils REC TO sources) 228 | # and then remove only the ones we don't want 229 | ucm_remove_directories(utils/deprecated utils/experimental FROM sources) 230 | ``` 231 | 232 | Patterns can also be given like this: 233 | 234 | ```CMake 235 | ucm_remove_directories(utils FROM sources MATCHES win32) 236 | ``` 237 | 238 | ##### macro ```ucm_add_target(NAME TYPE SOURCES src1 src2 src3... [PCH_FILE ] [UNITY [CPP_PER_UNITY ] [UNITY_EXCLUDED excl_src1 excl_src2 ...]])``` 239 | 240 | A wrapper of ```add_library()``` and ```add_executable()``` calls. Uses [cotire](https://github.com/sakra/cotire) for platform/compiler independent usage of precompiled headers and/or making a unity build of the target. 241 | 242 | For information about unity builds in general go to the [bottom](#unity-builds). 243 | 244 | ```CMake 245 | ucm_add_target(NAME example TYPE EXECUTABLE SOURCES "${sources}" PCH_FILE precompiled.h) 246 | ``` 247 | 248 | The example above shows how to add a target with a precompiled header. 249 | 250 | ```CMake 251 | ucm_add_target(NAME example TYPE EXECUTABLE SOURCES "${sources}" UNITY CPP_PER_UNITY 20 UNITY_EXCLUDED "separate/some2.cpp") 252 | ``` 253 | 254 | When the ```UCM_UNITY_BUILD``` ucm option is set to ```ON``` (```OFF``` by default) a target registered like in the example above will actually result in 2 targets added - the unity target with ```example``` as a name (included in the build by default) and the original target with ```example_ORIGINAL``` as a name (excluded from the build by default). This allows the user to browse and modify the sources in the original target properly within the IDE. Also ```separate/some2.cpp``` will be built normally and will not be included in the unity sources. 255 | 256 | When new sources are added to the original target the unity target will be updated accordingly by cotire. 257 | 258 | The order in which sources are given to ```SOURCES``` is the order in which they will appear in the unity files so you can combat compilation issues by changing the order of the source files. 259 | 260 | Targets can be excluded from unity builds by adding them in the ```UCM_UNITY_BUILD_EXCLUDE_TARGETS``` list when invoking cmake (handy if a target becomes problematic in a unity build or if you want to iterate fast on a particular target and want to compile it's sources separately). 261 | 262 | Mixed language targets (C/C++) are handled properly - separate unity files are generated for the different languages. 263 | 264 | The macro will self-diagnose the target and if it has more than 1 source file and has not been registered with the UNITY flag a developer warning will be printed that the target may benefit from a unity build. 265 | 266 | CPP_PER_UNITY - to explicitly say how many source files should go into a unity source (default is 100). Another option is to pass not a number but ```-jX``` after ```CPP_PER_UNITY``` and that would mean dividing the sources into X unity sources. 267 | 268 | UNITY_EXCLUDED - list of files from the target that should be excluded from unify-ing (will be used normally by themselves - can be used to fix compilation errors). 269 | 270 | Unity examples - given 100 .cpp files in the target: 271 | 272 | - ```CPP_PER_UNITY 5``` would mean 20 .cxx unity files including 5 of the original .cpp files each 273 | - ```CPP_PER_UNITY 10``` would mean 10 .cxx unity files including 10 of the original .cpp files each 274 | - ```CPP_PER_UNITY -j8``` would mean 8 .cxx unity files dividing the original 100 among them 275 | 276 | How a unity target looks in the IDE: 277 | 278 | ![1](test/doc_data/unity.png) 279 | 280 | Unity builds 281 | ------------ 282 | 283 | For all the pros and cons checkout my [blog post](http://onqtam.github.io/programming/2018-07-07-unity-builds/). 284 | -------------------------------------------------------------------------------- /cmake/ucm.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # ucm.cmake - useful cmake macros 3 | # 4 | # Copyright (c) 2016 Viktor Kirilov 5 | # 6 | # Distributed under the MIT Software License 7 | # See accompanying file LICENSE.txt or copy at 8 | # https://opensource.org/licenses/MIT 9 | # 10 | # The documentation can be found at the library's page: 11 | # https://github.com/onqtam/ucm 12 | 13 | cmake_minimum_required(VERSION 2.8.12) 14 | 15 | include(CMakeParseArguments) 16 | 17 | # optionally include cotire - the git submodule might not be inited (or the user might have already included it) 18 | if(NOT COMMAND cotire) 19 | include(${CMAKE_CURRENT_LIST_DIR}/../cotire/CMake/cotire.cmake OPTIONAL) 20 | endif() 21 | 22 | if(COMMAND cotire AND "1.7.9" VERSION_LESS "${COTIRE_CMAKE_MODULE_VERSION}") 23 | set(ucm_with_cotire 1) 24 | else() 25 | set(ucm_with_cotire 0) 26 | endif() 27 | 28 | option(UCM_UNITY_BUILD "Enable unity build for targets registered with the ucm_add_target() macro" OFF) 29 | option(UCM_NO_COTIRE_FOLDER "Do not use a cotire folder in the solution explorer for all unity and cotire related targets" ON) 30 | 31 | # ucm_add_flags 32 | # Adds compiler flags to CMAKE__FLAGS or to a specific config 33 | macro(ucm_add_flags) 34 | cmake_parse_arguments(ARG "C;CXX;CLEAR_OLD" "" "CONFIG" ${ARGN}) 35 | 36 | if(NOT ARG_CONFIG) 37 | set(ARG_CONFIG " ") 38 | endif() 39 | 40 | foreach(CONFIG ${ARG_CONFIG}) 41 | # determine to which flags to add 42 | if(NOT ${CONFIG} STREQUAL " ") 43 | string(TOUPPER ${CONFIG} CONFIG) 44 | set(CXX_FLAGS CMAKE_CXX_FLAGS_${CONFIG}) 45 | set(C_FLAGS CMAKE_C_FLAGS_${CONFIG}) 46 | else() 47 | set(CXX_FLAGS CMAKE_CXX_FLAGS) 48 | set(C_FLAGS CMAKE_C_FLAGS) 49 | endif() 50 | 51 | # clear the old flags 52 | if(${ARG_CLEAR_OLD}) 53 | if("${ARG_CXX}" OR NOT "${ARG_C}") 54 | set(${CXX_FLAGS} "") 55 | endif() 56 | if("${ARG_C}" OR NOT "${ARG_CXX}") 57 | set(${C_FLAGS} "") 58 | endif() 59 | endif() 60 | 61 | # add all the passed flags 62 | foreach(flag ${ARG_UNPARSED_ARGUMENTS}) 63 | if("${ARG_CXX}" OR NOT "${ARG_C}") 64 | set(${CXX_FLAGS} "${${CXX_FLAGS}} ${flag}") 65 | endif() 66 | if("${ARG_C}" OR NOT "${ARG_CXX}") 67 | set(${C_FLAGS} "${${C_FLAGS}} ${flag}") 68 | endif() 69 | endforeach() 70 | endforeach() 71 | 72 | endmacro() 73 | 74 | # ucm_set_flags 75 | # Sets the CMAKE__FLAGS compiler flags or for a specific config 76 | macro(ucm_set_flags) 77 | ucm_add_flags(CLEAR_OLD ${ARGN}) 78 | endmacro() 79 | 80 | # ucm_remove_flags 81 | # Removes compiler flags from CMAKE__FLAGS or from a specific config 82 | macro(ucm_remove_flags) 83 | cmake_parse_arguments(ARG "C;CXX" "" "CONFIG" ${ARGN}) 84 | 85 | if(NOT ARG_CONFIG) 86 | set(ARG_CONFIG " ") 87 | endif() 88 | 89 | foreach(CONFIG ${ARG_CONFIG}) 90 | # determine from which flags to remove 91 | if(NOT ${CONFIG} STREQUAL " ") 92 | string(TOUPPER ${CONFIG} CONFIG) 93 | set(CXX_FLAGS CMAKE_CXX_FLAGS_${CONFIG}) 94 | set(C_FLAGS CMAKE_C_FLAGS_${CONFIG}) 95 | else() 96 | set(CXX_FLAGS CMAKE_CXX_FLAGS) 97 | set(C_FLAGS CMAKE_C_FLAGS) 98 | endif() 99 | 100 | # remove all the passed flags 101 | foreach(flag ${ARG_UNPARSED_ARGUMENTS}) 102 | if("${ARG_CXX}" OR NOT "${ARG_C}") 103 | string(REGEX REPLACE "${flag}" "" ${CXX_FLAGS} "${${CXX_FLAGS}}") 104 | endif() 105 | if("${ARG_C}" OR NOT "${ARG_CXX}") 106 | string(REGEX REPLACE "${flag}" "" ${C_FLAGS} "${${C_FLAGS}}") 107 | endif() 108 | endforeach() 109 | endforeach() 110 | endmacro() 111 | 112 | # ucm_add_linker_flags 113 | # Adds linker flags to CMAKE__LINKER_FLAGS or to a specific config 114 | macro(ucm_add_linker_flags) 115 | cmake_parse_arguments(ARG "CLEAR_OLD;EXE;MODULE;SHARED;STATIC" "" "CONFIG" ${ARGN}) 116 | 117 | if(NOT ARG_CONFIG) 118 | set(ARG_CONFIG " ") 119 | endif() 120 | 121 | foreach(CONFIG ${ARG_CONFIG}) 122 | string(TOUPPER "${CONFIG}" CONFIG) 123 | 124 | if(NOT ${ARG_EXE} AND NOT ${ARG_MODULE} AND NOT ${ARG_SHARED} AND NOT ${ARG_STATIC}) 125 | set(ARG_EXE 1) 126 | set(ARG_MODULE 1) 127 | set(ARG_SHARED 1) 128 | set(ARG_STATIC 1) 129 | endif() 130 | 131 | set(flags_configs "") 132 | if(${ARG_EXE}) 133 | if(NOT "${CONFIG}" STREQUAL " ") 134 | list(APPEND flags_configs CMAKE_EXE_LINKER_FLAGS_${CONFIG}) 135 | else() 136 | list(APPEND flags_configs CMAKE_EXE_LINKER_FLAGS) 137 | endif() 138 | endif() 139 | if(${ARG_MODULE}) 140 | if(NOT "${CONFIG}" STREQUAL " ") 141 | list(APPEND flags_configs CMAKE_MODULE_LINKER_FLAGS_${CONFIG}) 142 | else() 143 | list(APPEND flags_configs CMAKE_MODULE_LINKER_FLAGS) 144 | endif() 145 | endif() 146 | if(${ARG_SHARED}) 147 | if(NOT "${CONFIG}" STREQUAL " ") 148 | list(APPEND flags_configs CMAKE_SHARED_LINKER_FLAGS_${CONFIG}) 149 | else() 150 | list(APPEND flags_configs CMAKE_SHARED_LINKER_FLAGS) 151 | endif() 152 | endif() 153 | if(${ARG_STATIC}) 154 | if(NOT "${CONFIG}" STREQUAL " ") 155 | list(APPEND flags_configs CMAKE_STATIC_LINKER_FLAGS_${CONFIG}) 156 | else() 157 | list(APPEND flags_configs CMAKE_STATIC_LINKER_FLAGS) 158 | endif() 159 | endif() 160 | 161 | # clear the old flags 162 | if(${ARG_CLEAR_OLD}) 163 | foreach(flags ${flags_configs}) 164 | set(${flags} "") 165 | endforeach() 166 | endif() 167 | 168 | # add all the passed flags 169 | foreach(flag ${ARG_UNPARSED_ARGUMENTS}) 170 | foreach(flags ${flags_configs}) 171 | set(${flags} "${${flags}} ${flag}") 172 | endforeach() 173 | endforeach() 174 | endforeach() 175 | endmacro() 176 | 177 | # ucm_set_linker_flags 178 | # Sets the CMAKE__LINKER_FLAGS linker flags or for a specific config 179 | macro(ucm_set_linker_flags) 180 | ucm_add_linker_flags(CLEAR_OLD ${ARGN}) 181 | endmacro() 182 | 183 | # ucm_gather_flags 184 | # Gathers all lists of flags for printing or manipulation 185 | macro(ucm_gather_flags with_linker result) 186 | set(${result} "") 187 | # add the main flags without a config 188 | list(APPEND ${result} CMAKE_C_FLAGS) 189 | list(APPEND ${result} CMAKE_CXX_FLAGS) 190 | if(${with_linker}) 191 | list(APPEND ${result} CMAKE_EXE_LINKER_FLAGS) 192 | list(APPEND ${result} CMAKE_MODULE_LINKER_FLAGS) 193 | list(APPEND ${result} CMAKE_SHARED_LINKER_FLAGS) 194 | list(APPEND ${result} CMAKE_STATIC_LINKER_FLAGS) 195 | endif() 196 | 197 | if("${CMAKE_CONFIGURATION_TYPES}" STREQUAL "" AND NOT "${CMAKE_BUILD_TYPE}" STREQUAL "") 198 | # handle single config generators - like makefiles/ninja - when CMAKE_BUILD_TYPE is set 199 | string(TOUPPER ${CMAKE_BUILD_TYPE} config) 200 | list(APPEND ${result} CMAKE_C_FLAGS_${config}) 201 | list(APPEND ${result} CMAKE_CXX_FLAGS_${config}) 202 | if(${with_linker}) 203 | list(APPEND ${result} CMAKE_EXE_LINKER_FLAGS_${config}) 204 | list(APPEND ${result} CMAKE_MODULE_LINKER_FLAGS_${config}) 205 | list(APPEND ${result} CMAKE_SHARED_LINKER_FLAGS_${config}) 206 | list(APPEND ${result} CMAKE_STATIC_LINKER_FLAGS_${config}) 207 | endif() 208 | else() 209 | # handle multi config generators (like msvc, xcode) 210 | foreach(config ${CMAKE_CONFIGURATION_TYPES}) 211 | string(TOUPPER ${config} config) 212 | list(APPEND ${result} CMAKE_C_FLAGS_${config}) 213 | list(APPEND ${result} CMAKE_CXX_FLAGS_${config}) 214 | if(${with_linker}) 215 | list(APPEND ${result} CMAKE_EXE_LINKER_FLAGS_${config}) 216 | list(APPEND ${result} CMAKE_MODULE_LINKER_FLAGS_${config}) 217 | list(APPEND ${result} CMAKE_SHARED_LINKER_FLAGS_${config}) 218 | list(APPEND ${result} CMAKE_STATIC_LINKER_FLAGS_${config}) 219 | endif() 220 | endforeach() 221 | endif() 222 | endmacro() 223 | 224 | # ucm_set_runtime 225 | # Sets the runtime (static/dynamic) for msvc/gcc 226 | macro(ucm_set_runtime) 227 | cmake_parse_arguments(ARG "STATIC;DYNAMIC" "" "" ${ARGN}) 228 | 229 | if(ARG_UNPARSED_ARGUMENTS) 230 | message(FATAL_ERROR "unrecognized arguments: ${ARG_UNPARSED_ARGUMENTS}") 231 | endif() 232 | 233 | if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" STREQUAL "") 234 | message(AUTHOR_WARNING "ucm_set_runtime() does not support clang yet!") 235 | endif() 236 | 237 | ucm_gather_flags(0 flags_configs) 238 | 239 | # add/replace the flags 240 | # note that if the user has messed with the flags directly this function might fail 241 | # - for example if with MSVC and the user has removed the flags - here we just switch/replace them 242 | if("${ARG_STATIC}") 243 | foreach(flags ${flags_configs}) 244 | if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") 245 | if(NOT ${flags} MATCHES "-static-libstdc\\+\\+") 246 | set(${flags} "${${flags}} -static-libstdc++") 247 | endif() 248 | if(NOT ${flags} MATCHES "-static-libgcc") 249 | set(${flags} "${${flags}} -static-libgcc") 250 | endif() 251 | elseif(MSVC) 252 | if(${flags} MATCHES "/MD") 253 | string(REGEX REPLACE "/MD" "/MT" ${flags} "${${flags}}") 254 | endif() 255 | endif() 256 | endforeach() 257 | elseif("${ARG_DYNAMIC}") 258 | foreach(flags ${flags_configs}) 259 | if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") 260 | if(${flags} MATCHES "-static-libstdc\\+\\+") 261 | string(REGEX REPLACE "-static-libstdc\\+\\+" "" ${flags} "${${flags}}") 262 | endif() 263 | if(${flags} MATCHES "-static-libgcc") 264 | string(REGEX REPLACE "-static-libgcc" "" ${flags} "${${flags}}") 265 | endif() 266 | elseif(MSVC) 267 | if(${flags} MATCHES "/MT") 268 | string(REGEX REPLACE "/MT" "/MD" ${flags} "${${flags}}") 269 | endif() 270 | endif() 271 | endforeach() 272 | endif() 273 | endmacro() 274 | 275 | # ucm_print_flags 276 | # Prints all compiler flags for all configurations 277 | macro(ucm_print_flags) 278 | ucm_gather_flags(1 flags_configs) 279 | message(STATUS "") 280 | foreach(flags ${flags_configs}) 281 | message(STATUS "${flags}: ${${flags}}") 282 | endforeach() 283 | message(STATUS "") 284 | endmacro() 285 | 286 | # ucm_set_xcode_attrib 287 | # Set xcode attributes - name value CONFIG config1 conifg2.. 288 | macro(ucm_set_xcode_attrib) 289 | cmake_parse_arguments(ARG "" "CLEAR" "CONFIG" ${ARGN}) 290 | 291 | if(NOT ARG_CONFIG) 292 | set(ARG_CONFIG " ") 293 | endif() 294 | 295 | foreach(CONFIG ${ARG_CONFIG}) 296 | # determine to which attributes to add 297 | if(${CONFIG} STREQUAL " ") 298 | if(${ARG_CLEAR}) 299 | # clear the old flags 300 | unset(CMAKE_XCODE_ATTRIBUTE_${ARGV0}) 301 | else() 302 | set(CMAKE_XCODE_ATTRIBUTE_${ARGV0} ${ARGV1}) 303 | endif() 304 | else() 305 | if(${ARG_CLEAR}) 306 | # clear the old flags 307 | unset(CMAKE_XCODE_ATTRIBUTE_${ARGV0}[variant=${CONFIG}]) 308 | else() 309 | set(CMAKE_XCODE_ATTRIBUTE_${ARGV0}[variant=${CONFIG}] ${ARGV1}) 310 | endif() 311 | endif() 312 | endforeach() 313 | endmacro() 314 | 315 | # ucm_count_sources 316 | # Counts the number of source files 317 | macro(ucm_count_sources) 318 | cmake_parse_arguments(ARG "" "RESULT" "" ${ARGN}) 319 | if(${ARG_RESULT} STREQUAL "") 320 | message(FATAL_ERROR "Need to pass RESULT and a variable name to ucm_count_sources()") 321 | endif() 322 | 323 | set(result 0) 324 | foreach(SOURCE_FILE ${ARG_UNPARSED_ARGUMENTS}) 325 | if("${SOURCE_FILE}" MATCHES \\.\(c|C|cc|cp|cpp|CPP|c\\+\\+|cxx|i|ii\)$) 326 | math(EXPR result "${result} + 1") 327 | endif() 328 | endforeach() 329 | set(${ARG_RESULT} ${result}) 330 | endmacro() 331 | 332 | # ucm_include_file_in_sources 333 | # Includes the file to the source with compiler flags 334 | macro(ucm_include_file_in_sources) 335 | cmake_parse_arguments(ARG "" "HEADER" "" ${ARGN}) 336 | if(${ARG_HEADER} STREQUAL "") 337 | message(FATAL_ERROR "Need to pass HEADER and a header file to ucm_include_file_in_sources()") 338 | endif() 339 | 340 | foreach(src ${ARG_UNPARSED_ARGUMENTS}) 341 | if(${src} MATCHES \\.\(c|C|cc|cp|cpp|CPP|c\\+\\+|cxx\)$) 342 | # get old flags 343 | get_source_file_property(old_compile_flags ${src} COMPILE_FLAGS) 344 | if(old_compile_flags STREQUAL "NOTFOUND") 345 | set(old_compile_flags "") 346 | endif() 347 | 348 | # update flags 349 | if(MSVC) 350 | set_source_files_properties(${src} PROPERTIES COMPILE_FLAGS 351 | "${old_compile_flags} /FI\"${CMAKE_CURRENT_SOURCE_DIR}/${ARG_HEADER}\"") 352 | else() 353 | set_source_files_properties(${src} PROPERTIES COMPILE_FLAGS 354 | "${old_compile_flags} -include \"${CMAKE_CURRENT_SOURCE_DIR}/${ARG_HEADER}\"") 355 | endif() 356 | endif() 357 | endforeach() 358 | endmacro() 359 | 360 | # ucm_dir_list 361 | # Returns a list of subdirectories for a given directory 362 | macro(ucm_dir_list thedir result) 363 | file(GLOB sub-dir "${thedir}/*") 364 | set(list_of_dirs "") 365 | foreach(dir ${sub-dir}) 366 | if(IS_DIRECTORY ${dir}) 367 | get_filename_component(DIRNAME ${dir} NAME) 368 | LIST(APPEND list_of_dirs ${DIRNAME}) 369 | endif() 370 | endforeach() 371 | set(${result} ${list_of_dirs}) 372 | endmacro() 373 | 374 | # ucm_trim_front_words 375 | # Trims X times the front word from a string separated with "/" and removes 376 | # the front "/" characters after that (used for filters for visual studio) 377 | macro(ucm_trim_front_words source out num_filter_trims) 378 | set(result "${source}") 379 | set(counter 0) 380 | while(${counter} LESS ${num_filter_trims}) 381 | MATH(EXPR counter "${counter} + 1") 382 | # removes everything at the front up to a "/" character 383 | string(REGEX REPLACE "^([^/]+)" "" result "${result}") 384 | # removes all consecutive "/" characters from the front 385 | string(REGEX REPLACE "^(/+)" "" result "${result}") 386 | endwhile() 387 | set(${out} ${result}) 388 | endmacro() 389 | 390 | # ucm_remove_files 391 | # Removes source files from a list of sources (path is the relative path for it to be found) 392 | macro(ucm_remove_files) 393 | cmake_parse_arguments(ARG "" "FROM" "" ${ARGN}) 394 | 395 | if("${ARG_UNPARSED_ARGUMENTS}" STREQUAL "") 396 | message(FATAL_ERROR "Need to pass some relative files to ucm_remove_files()") 397 | endif() 398 | if(${ARG_FROM} STREQUAL "") 399 | message(FATAL_ERROR "Need to pass FROM and a variable name to ucm_remove_files()") 400 | endif() 401 | 402 | foreach(cur_file ${ARG_UNPARSED_ARGUMENTS}) 403 | list(REMOVE_ITEM ${ARG_FROM} ${cur_file}) 404 | endforeach() 405 | endmacro() 406 | 407 | # ucm_remove_directories 408 | # Removes all source files from the given directories from the sources list 409 | macro(ucm_remove_directories) 410 | cmake_parse_arguments(ARG "" "FROM" "MATCHES" ${ARGN}) 411 | 412 | if("${ARG_UNPARSED_ARGUMENTS}" STREQUAL "") 413 | message(FATAL_ERROR "Need to pass some relative directories to ucm_remove_directories()") 414 | endif() 415 | if(${ARG_FROM} STREQUAL "") 416 | message(FATAL_ERROR "Need to pass FROM and a variable name to ucm_remove_directories()") 417 | endif() 418 | 419 | foreach(cur_dir ${ARG_UNPARSED_ARGUMENTS}) 420 | foreach(cur_file ${${ARG_FROM}}) 421 | string(REGEX MATCH ${cur_dir} res ${cur_file}) 422 | if(NOT "${res}" STREQUAL "") 423 | if("${ARG_MATCHES}" STREQUAL "") 424 | list(REMOVE_ITEM ${ARG_FROM} ${cur_file}) 425 | else() 426 | foreach(curr_ptrn ${ARG_MATCHES}) 427 | string(REGEX MATCH ${curr_ptrn} res ${cur_file}) 428 | if(NOT "${res}" STREQUAL "") 429 | list(REMOVE_ITEM ${ARG_FROM} ${cur_file}) 430 | break() 431 | endif() 432 | endforeach() 433 | endif() 434 | endif() 435 | endforeach() 436 | endforeach() 437 | endmacro() 438 | 439 | # ucm_add_files_impl 440 | macro(ucm_add_files_impl result trim files) 441 | foreach(cur_file ${files}) 442 | SET(${result} ${${result}} ${cur_file}) 443 | get_filename_component(FILEPATH ${cur_file} PATH) 444 | ucm_trim_front_words("${FILEPATH}" FILEPATH "${trim}") 445 | # replacing forward slashes with back slashes so filters can be generated (back slash used in parsing...) 446 | STRING(REPLACE "/" "\\" FILTERS "${FILEPATH}") 447 | SOURCE_GROUP("${FILTERS}" FILES ${cur_file}) 448 | endforeach() 449 | endmacro() 450 | 451 | # ucm_add_files 452 | # Adds files to a list of sources 453 | macro(ucm_add_files) 454 | cmake_parse_arguments(ARG "" "TO;FILTER_POP" "" ${ARGN}) 455 | 456 | if("${ARG_UNPARSED_ARGUMENTS}" STREQUAL "") 457 | message(FATAL_ERROR "Need to pass some relative files to ucm_add_files()") 458 | endif() 459 | if(${ARG_TO} STREQUAL "") 460 | message(FATAL_ERROR "Need to pass TO and a variable name to ucm_add_files()") 461 | endif() 462 | 463 | if("${ARG_FILTER_POP}" STREQUAL "") 464 | set(ARG_FILTER_POP 0) 465 | endif() 466 | 467 | ucm_add_files_impl(${ARG_TO} ${ARG_FILTER_POP} "${ARG_UNPARSED_ARGUMENTS}") 468 | endmacro() 469 | 470 | # ucm_add_dir_impl 471 | macro(ucm_add_dir_impl result rec trim dirs_in additional_ext) 472 | set(dirs "${dirs_in}") 473 | 474 | # handle the "" and "." cases 475 | if("${dirs}" STREQUAL "" OR "${dirs}" STREQUAL ".") 476 | set(dirs "./") 477 | endif() 478 | 479 | foreach(cur_dir ${dirs}) 480 | # to circumvent some linux/cmake/path issues - barely made it work... 481 | if(cur_dir STREQUAL "./") 482 | set(cur_dir "") 483 | else() 484 | set(cur_dir "${cur_dir}/") 485 | endif() 486 | 487 | # since unix is case sensitive - add these valid extensions too 488 | # we don't use "UNIX" but instead "CMAKE_HOST_UNIX" because we might be cross 489 | # compiling (for example emscripten) under windows and UNIX may be set to 1 490 | # Also OSX is case insensitive like windows... 491 | set(additional_file_extensions "") 492 | if(CMAKE_HOST_UNIX AND NOT APPLE) 493 | set(additional_file_extensions 494 | "${cur_dir}*.CPP" 495 | "${cur_dir}*.C" 496 | "${cur_dir}*.H" 497 | "${cur_dir}*.HPP" 498 | ) 499 | endif() 500 | 501 | foreach(ext ${additional_ext}) 502 | list(APPEND additional_file_extensions "${cur_dir}*.${ext}") 503 | endforeach() 504 | 505 | # find all sources and set them as result 506 | FILE(GLOB found_sources RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" 507 | # https://gcc.gnu.org/onlinedocs/gcc-4.4.1/gcc/Overall-Options.html#index-file-name-suffix-71 508 | # sources 509 | "${cur_dir}*.cpp" 510 | "${cur_dir}*.cxx" 511 | "${cur_dir}*.c++" 512 | "${cur_dir}*.cc" 513 | "${cur_dir}*.cp" 514 | "${cur_dir}*.c" 515 | "${cur_dir}*.i" 516 | "${cur_dir}*.ii" 517 | # headers 518 | "${cur_dir}*.h" 519 | "${cur_dir}*.h++" 520 | "${cur_dir}*.hpp" 521 | "${cur_dir}*.hxx" 522 | "${cur_dir}*.hh" 523 | "${cur_dir}*.inl" 524 | "${cur_dir}*.inc" 525 | "${cur_dir}*.ipp" 526 | "${cur_dir}*.ixx" 527 | "${cur_dir}*.txx" 528 | "${cur_dir}*.tpp" 529 | "${cur_dir}*.tcc" 530 | "${cur_dir}*.tpl" 531 | ${additional_file_extensions}) 532 | SET(${result} ${${result}} ${found_sources}) 533 | 534 | # set the proper filters 535 | ucm_trim_front_words("${cur_dir}" cur_dir "${trim}") 536 | # replacing forward slashes with back slashes so filters can be generated (back slash used in parsing...) 537 | STRING(REPLACE "/" "\\" FILTERS "${cur_dir}") 538 | SOURCE_GROUP("${FILTERS}" FILES ${found_sources}) 539 | endforeach() 540 | 541 | if(${rec}) 542 | foreach(cur_dir ${dirs}) 543 | ucm_dir_list("${cur_dir}" subdirs) 544 | foreach(subdir ${subdirs}) 545 | ucm_add_dir_impl(${result} ${rec} ${trim} "${cur_dir}/${subdir}" "${additional_ext}") 546 | endforeach() 547 | endforeach() 548 | endif() 549 | endmacro() 550 | 551 | # ucm_add_dirs 552 | # Adds all files from directories traversing them recursively to a list of sources 553 | # and generates filters according to their location (accepts relative paths only). 554 | # Also this macro trims X times the front word from the filter string for visual studio filters. 555 | macro(ucm_add_dirs) 556 | cmake_parse_arguments(ARG "RECURSIVE" "TO;FILTER_POP" "ADDITIONAL_EXT" ${ARGN}) 557 | 558 | if(${ARG_TO} STREQUAL "") 559 | message(FATAL_ERROR "Need to pass TO and a variable name to ucm_add_dirs()") 560 | endif() 561 | 562 | if("${ARG_FILTER_POP}" STREQUAL "") 563 | set(ARG_FILTER_POP 0) 564 | endif() 565 | 566 | ucm_add_dir_impl(${ARG_TO} ${ARG_RECURSIVE} ${ARG_FILTER_POP} "${ARG_UNPARSED_ARGUMENTS}" "${ARG_ADDITIONAL_EXT}") 567 | endmacro() 568 | 569 | # ucm_add_target 570 | # Adds a target eligible for cotiring - unity build and/or precompiled header 571 | macro(ucm_add_target) 572 | cmake_parse_arguments(ARG "UNITY" "NAME;TYPE;PCH_FILE;CPP_PER_UNITY" "UNITY_EXCLUDED;SOURCES" ${ARGN}) 573 | 574 | if(NOT "${ARG_UNPARSED_ARGUMENTS}" STREQUAL "") 575 | message(FATAL_ERROR "Unrecognized options passed to ucm_add_target()") 576 | endif() 577 | if("${ARG_NAME}" STREQUAL "") 578 | message(FATAL_ERROR "Need to pass NAME and a name for the target to ucm_add_target()") 579 | endif() 580 | set(valid_types EXECUTABLE STATIC SHARED MODULE) 581 | list(FIND valid_types "${ARG_TYPE}" is_type_valid) 582 | if(${is_type_valid} STREQUAL "-1") 583 | message(FATAL_ERROR "Need to pass TYPE and the type for the target [EXECUTABLE/STATIC/SHARED/MODULE] to ucm_add_target()") 584 | endif() 585 | if("${ARG_SOURCES}" STREQUAL "") 586 | message(FATAL_ERROR "Need to pass SOURCES and a list of source files to ucm_add_target()") 587 | endif() 588 | 589 | # init with the global unity flag 590 | set(do_unity ${UCM_UNITY_BUILD}) 591 | 592 | # check the UNITY argument 593 | if(NOT ARG_UNITY) 594 | set(do_unity FALSE) 595 | endif() 596 | 597 | # if target is excluded through the exclusion list 598 | list(FIND UCM_UNITY_BUILD_EXCLUDE_TARGETS ${ARG_NAME} is_target_excluded) 599 | if(NOT ${is_target_excluded} STREQUAL "-1") 600 | set(do_unity FALSE) 601 | endif() 602 | 603 | # unity build only for targets with > 1 source file (otherwise there will be an additional unnecessary target) 604 | if(do_unity) # optimization 605 | ucm_count_sources(${ARG_SOURCES} RESULT num_sources) 606 | if(${num_sources} LESS 2) 607 | set(do_unity FALSE) 608 | endif() 609 | endif() 610 | 611 | set(wanted_cotire ${do_unity}) 612 | 613 | # if cotire cannot be used 614 | if(do_unity AND NOT ucm_with_cotire) 615 | set(do_unity FALSE) 616 | endif() 617 | 618 | # inform the developer that the current target might benefit from a unity build 619 | if(NOT ARG_UNITY AND ${UCM_UNITY_BUILD}) 620 | ucm_count_sources(${ARG_SOURCES} RESULT num_sources) 621 | if(${num_sources} GREATER 1) 622 | message(AUTHOR_WARNING "Target '${ARG_NAME}' may benefit from a unity build.\nIt has ${num_sources} sources - enable with UNITY flag") 623 | endif() 624 | endif() 625 | 626 | # prepare for the unity build 627 | set(orig_target ${ARG_NAME}) 628 | if(do_unity) 629 | # the original target will be added with a different name than the requested 630 | set(orig_target ${ARG_NAME}_ORIGINAL) 631 | 632 | # exclude requested files from unity build of the current target 633 | foreach(excluded_file "${ARG_UNITY_EXCLUDED}") 634 | set_source_files_properties(${excluded_file} PROPERTIES COTIRE_EXCLUDED TRUE) 635 | endforeach() 636 | endif() 637 | 638 | # add the original target 639 | if(${ARG_TYPE} STREQUAL "EXECUTABLE") 640 | add_executable(${orig_target} ${ARG_SOURCES}) 641 | else() 642 | add_library(${orig_target} ${ARG_TYPE} ${ARG_SOURCES}) 643 | endif() 644 | 645 | if(do_unity) 646 | # set the number of unity cpp files to be used for the unity target 647 | if(NOT "${ARG_CPP_PER_UNITY}" STREQUAL "") 648 | set_property(TARGET ${orig_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "${ARG_CPP_PER_UNITY}") 649 | else() 650 | set_property(TARGET ${orig_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "100") 651 | endif() 652 | 653 | if(NOT "${ARG_PCH_FILE}" STREQUAL "") 654 | set_target_properties(${orig_target} PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${ARG_PCH_FILE}") 655 | else() 656 | set_target_properties(${orig_target} PROPERTIES COTIRE_ENABLE_PRECOMPILED_HEADER FALSE) 657 | endif() 658 | # add a unity target for the original one with the name intended for the original 659 | set_target_properties(${orig_target} PROPERTIES COTIRE_UNITY_TARGET_NAME ${ARG_NAME}) 660 | 661 | # this is the library call that does the magic 662 | cotire(${orig_target}) 663 | set_target_properties(clean_cotire PROPERTIES FOLDER "CMakePredefinedTargets") 664 | 665 | # disable the original target and enable the unity one 666 | get_target_property(unity_target_name ${orig_target} COTIRE_UNITY_TARGET_NAME) 667 | set_target_properties(${orig_target} PROPERTIES EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_DEFAULT_BUILD 1) 668 | set_target_properties(${unity_target_name} PROPERTIES EXCLUDE_FROM_ALL 0 EXCLUDE_FROM_DEFAULT_BUILD 0) 669 | 670 | # also set the name of the target output as the original one 671 | set_target_properties(${unity_target_name} PROPERTIES OUTPUT_NAME ${ARG_NAME}) 672 | if(UCM_NO_COTIRE_FOLDER) 673 | # reset the folder property so all unity targets dont end up in a single folder in the solution explorer of VS 674 | set_target_properties(${unity_target_name} PROPERTIES FOLDER "") 675 | endif() 676 | set_target_properties(all_unity PROPERTIES FOLDER "CMakePredefinedTargets") 677 | elseif(NOT "${ARG_PCH_FILE}" STREQUAL "") 678 | set(wanted_cotire TRUE) 679 | if(ucm_with_cotire) 680 | set_target_properties(${orig_target} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE) 681 | set_target_properties(${orig_target} PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${ARG_PCH_FILE}") 682 | cotire(${orig_target}) 683 | set_target_properties(clean_cotire PROPERTIES FOLDER "CMakePredefinedTargets") 684 | endif() 685 | endif() 686 | 687 | # print a message if the target was requested to be cotired but it couldn't 688 | if(wanted_cotire AND NOT ucm_with_cotire) 689 | if(NOT COMMAND cotire) 690 | message(AUTHOR_WARNING "Target \"${ARG_NAME}\" not cotired because cotire isn't loaded") 691 | else() 692 | message(AUTHOR_WARNING "Target \"${ARG_NAME}\" not cotired because cotire is older than the required version") 693 | endif() 694 | endif() 695 | endmacro() 696 | --------------------------------------------------------------------------------