OSDN Git Service

[General] Merge upstream 2018-05-24. Still not test to build, will test.
[csp-qt/common_source_project-fm7.git] / source / build-cmake / cmake / cotire.cmake
1 # - cotire (compile time reducer)
2 #
3 # See the cotire manual for usage hints.
4 #
5 #=============================================================================
6 # Copyright 2012-2018 Sascha Kratky
7 #
8 # Permission is hereby granted, free of charge, to any person
9 # obtaining a copy of this software and associated documentation
10 # files (the "Software"), to deal in the Software without
11 # restriction, including without limitation the rights to use,
12 # copy, modify, merge, publish, distribute, sublicense, and/or sell
13 # copies of the Software, and to permit persons to whom the
14 # Software is furnished to do so, subject to the following
15 # conditions:
16 #
17 # The above copyright notice and this permission notice shall be
18 # included in all copies or substantial portions of the Software.
19 #
20 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 # OTHER DEALINGS IN THE SOFTWARE.
28 #=============================================================================
29
30 if(__COTIRE_INCLUDED)
31         return()
32 endif()
33 set(__COTIRE_INCLUDED TRUE)
34
35 # call cmake_minimum_required, but prevent modification of the CMake policy stack in include mode
36 # cmake_minimum_required also sets the policy version as a side effect, which we have to avoid
37 if (NOT CMAKE_SCRIPT_MODE_FILE)
38         cmake_policy(PUSH)
39 endif()
40 cmake_minimum_required(VERSION 2.8.12)
41 if (NOT CMAKE_SCRIPT_MODE_FILE)
42         cmake_policy(POP)
43 endif()
44
45 set (COTIRE_CMAKE_MODULE_FILE "${CMAKE_CURRENT_LIST_FILE}")
46 set (COTIRE_CMAKE_MODULE_VERSION "1.8.0")
47
48 # activate select policies
49 if (POLICY CMP0025)
50         # Compiler id for Apple Clang is now AppleClang
51         cmake_policy(SET CMP0025 NEW)
52 endif()
53
54 if (POLICY CMP0026)
55         # disallow use of the LOCATION target property
56         cmake_policy(SET CMP0026 NEW)
57 endif()
58
59 if (POLICY CMP0038)
60         # targets may not link directly to themselves
61         cmake_policy(SET CMP0038 NEW)
62 endif()
63
64 if (POLICY CMP0039)
65         # utility targets may not have link dependencies
66         cmake_policy(SET CMP0039 NEW)
67 endif()
68
69 if (POLICY CMP0040)
70         # target in the TARGET signature of add_custom_command() must exist
71         cmake_policy(SET CMP0040 NEW)
72 endif()
73
74 if (POLICY CMP0045)
75         # error on non-existent target in get_target_property
76         cmake_policy(SET CMP0045 NEW)
77 endif()
78
79 if (POLICY CMP0046)
80         # error on non-existent dependency in add_dependencies
81         cmake_policy(SET CMP0046 NEW)
82 endif()
83
84 if (POLICY CMP0049)
85         # do not expand variables in target source entries
86         cmake_policy(SET CMP0049 NEW)
87 endif()
88
89 if (POLICY CMP0050)
90         # disallow add_custom_command SOURCE signatures
91         cmake_policy(SET CMP0050 NEW)
92 endif()
93
94 if (POLICY CMP0051)
95         # include TARGET_OBJECTS expressions in a target's SOURCES property
96         cmake_policy(SET CMP0051 NEW)
97 endif()
98
99 if (POLICY CMP0053)
100         # simplify variable reference and escape sequence evaluation
101         cmake_policy(SET CMP0053 NEW)
102 endif()
103
104 if (POLICY CMP0054)
105         # only interpret if() arguments as variables or keywords when unquoted
106         cmake_policy(SET CMP0054 NEW)
107 endif()
108
109 if (POLICY CMP0055)
110         # strict checking for break() command
111         cmake_policy(SET CMP0055 NEW)
112 endif()
113
114 include(CMakeParseArguments)
115 include(ProcessorCount)
116
117 function (cotire_get_configuration_types _configsVar)
118         set (_configs "")
119         if (CMAKE_CONFIGURATION_TYPES)
120                 list (APPEND _configs ${CMAKE_CONFIGURATION_TYPES})
121         endif()
122         if (CMAKE_BUILD_TYPE)
123                 list (APPEND _configs "${CMAKE_BUILD_TYPE}")
124         endif()
125         if (_configs)
126                 list (REMOVE_DUPLICATES _configs)
127                 set (${_configsVar} ${_configs} PARENT_SCOPE)
128         else()
129                 set (${_configsVar} "None" PARENT_SCOPE)
130         endif()
131 endfunction()
132
133 function (cotire_get_source_file_extension _sourceFile _extVar)
134         # get_filename_component returns extension from first occurrence of . in file name
135         # this function computes the extension from last occurrence of . in file name
136         string (FIND "${_sourceFile}" "." _index REVERSE)
137         if (_index GREATER -1)
138                 math (EXPR _index "${_index} + 1")
139                 string (SUBSTRING "${_sourceFile}" ${_index} -1 _sourceExt)
140         else()
141                 set (_sourceExt "")
142         endif()
143         set (${_extVar} "${_sourceExt}" PARENT_SCOPE)
144 endfunction()
145
146 macro (cotire_check_is_path_relative_to _path _isRelativeVar)
147         set (${_isRelativeVar} FALSE)
148         if (IS_ABSOLUTE "${_path}")
149                 foreach (_dir ${ARGN})
150                         file (RELATIVE_PATH _relPath "${_dir}" "${_path}")
151                         if (NOT _relPath OR (NOT IS_ABSOLUTE "${_relPath}" AND NOT "${_relPath}" MATCHES "^\\.\\."))
152                                 set (${_isRelativeVar} TRUE)
153                                 break()
154                         endif()
155                 endforeach()
156         endif()
157 endmacro()
158
159 function (cotire_filter_language_source_files _language _target _sourceFilesVar _excludedSourceFilesVar _cotiredSourceFilesVar)
160         if (CMAKE_${_language}_SOURCE_FILE_EXTENSIONS)
161                 set (_languageExtensions "${CMAKE_${_language}_SOURCE_FILE_EXTENSIONS}")
162         else()
163                 set (_languageExtensions "")
164         endif()
165         if (CMAKE_${_language}_IGNORE_EXTENSIONS)
166                 set (_ignoreExtensions "${CMAKE_${_language}_IGNORE_EXTENSIONS}")
167         else()
168                 set (_ignoreExtensions "")
169         endif()
170         if (COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS)
171                 set (_excludeExtensions "${COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS}")
172         else()
173                 set (_excludeExtensions "")
174         endif()
175         if (COTIRE_DEBUG AND _languageExtensions)
176                 message (STATUS "${_language} source file extensions: ${_languageExtensions}")
177         endif()
178         if (COTIRE_DEBUG AND _ignoreExtensions)
179                 message (STATUS "${_language} ignore extensions: ${_ignoreExtensions}")
180         endif()
181         if (COTIRE_DEBUG AND _excludeExtensions)
182                 message (STATUS "${_language} exclude extensions: ${_excludeExtensions}")
183         endif()
184         if (CMAKE_VERSION VERSION_LESS "3.1.0")
185                 set (_allSourceFiles ${ARGN})
186         else()
187                 # as of CMake 3.1 target sources may contain generator expressions
188                 # since we cannot obtain required property information about source files added
189                 # through generator expressions at configure time, we filter them out
190                 string (GENEX_STRIP "${ARGN}" _allSourceFiles)
191         endif()
192         set (_filteredSourceFiles "")
193         set (_excludedSourceFiles "")
194         foreach (_sourceFile ${_allSourceFiles})
195                 get_source_file_property(_sourceIsHeaderOnly "${_sourceFile}" HEADER_FILE_ONLY)
196                 get_source_file_property(_sourceIsExternal "${_sourceFile}" EXTERNAL_OBJECT)
197                 get_source_file_property(_sourceIsSymbolic "${_sourceFile}" SYMBOLIC)
198                 if (NOT _sourceIsHeaderOnly AND NOT _sourceIsExternal AND NOT _sourceIsSymbolic)
199                         cotire_get_source_file_extension("${_sourceFile}" _sourceExt)
200                         if (_sourceExt)
201                                 list (FIND _ignoreExtensions "${_sourceExt}" _ignoreIndex)
202                                 if (_ignoreIndex LESS 0)
203                                         list (FIND _excludeExtensions "${_sourceExt}" _excludeIndex)
204                                         if (_excludeIndex GREATER -1)
205                                                 list (APPEND _excludedSourceFiles "${_sourceFile}")
206                                         else()
207                                                 list (FIND _languageExtensions "${_sourceExt}" _sourceIndex)
208                                                 if (_sourceIndex GREATER -1)
209                                                         # consider source file unless it is excluded explicitly
210                                                         get_source_file_property(_sourceIsExcluded "${_sourceFile}" COTIRE_EXCLUDED)
211                                                         if (_sourceIsExcluded)
212                                                                 list (APPEND _excludedSourceFiles "${_sourceFile}")
213                                                         else()
214                                                                 list (APPEND _filteredSourceFiles "${_sourceFile}")
215                                                         endif()
216                                                 else()
217                                                         get_source_file_property(_sourceLanguage "${_sourceFile}" LANGUAGE)
218                                                         if ("${_sourceLanguage}" STREQUAL "${_language}")
219                                                                 # add to excluded sources, if file is not ignored and has correct language without having the correct extension
220                                                                 list (APPEND _excludedSourceFiles "${_sourceFile}")
221                                                         endif()
222                                                 endif()
223                                         endif()
224                                 endif()
225                         endif()
226                 endif()
227         endforeach()
228         # separate filtered source files from already cotired ones
229         # the COTIRE_TARGET property of a source file may be set while a target is being processed by cotire
230         set (_sourceFiles "")
231         set (_cotiredSourceFiles "")
232         foreach (_sourceFile ${_filteredSourceFiles})
233                 get_source_file_property(_sourceIsCotired "${_sourceFile}" COTIRE_TARGET)
234                 if (_sourceIsCotired)
235                         list (APPEND _cotiredSourceFiles "${_sourceFile}")
236                 else()
237                         get_source_file_property(_sourceCompileFlags "${_sourceFile}" COMPILE_FLAGS)
238                         if (_sourceCompileFlags)
239                                 # add to excluded sources, if file has custom compile flags
240                                 list (APPEND _excludedSourceFiles "${_sourceFile}")
241                         else()
242                                 get_source_file_property(_sourceCompileOptions "${_sourceFile}" COMPILE_OPTIONS)
243                                 if (_sourceCompileOptions)
244                                         # add to excluded sources, if file has list of custom compile options
245                                         list (APPEND _excludedSourceFiles "${_sourceFile}")
246                                 else()
247                                         list (APPEND _sourceFiles "${_sourceFile}")
248                                 endif()
249                         endif()
250                 endif()
251         endforeach()
252         if (COTIRE_DEBUG)
253                 if (_sourceFiles)
254                         message (STATUS "Filtered ${_target} ${_language} sources: ${_sourceFiles}")
255                 endif()
256                 if (_excludedSourceFiles)
257                         message (STATUS "Excluded ${_target} ${_language} sources: ${_excludedSourceFiles}")
258                 endif()
259                 if (_cotiredSourceFiles)
260                         message (STATUS "Cotired ${_target} ${_language} sources: ${_cotiredSourceFiles}")
261                 endif()
262         endif()
263         set (${_sourceFilesVar} ${_sourceFiles} PARENT_SCOPE)
264         set (${_excludedSourceFilesVar} ${_excludedSourceFiles} PARENT_SCOPE)
265         set (${_cotiredSourceFilesVar} ${_cotiredSourceFiles} PARENT_SCOPE)
266 endfunction()
267
268 function (cotire_get_objects_with_property_on _filteredObjectsVar _property _type)
269         set (_filteredObjects "")
270         foreach (_object ${ARGN})
271                 get_property(_isSet ${_type} "${_object}" PROPERTY ${_property} SET)
272                 if (_isSet)
273                         get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property})
274                         if (_propertyValue)
275                                 list (APPEND _filteredObjects "${_object}")
276                         endif()
277                 endif()
278         endforeach()
279         set (${_filteredObjectsVar} ${_filteredObjects} PARENT_SCOPE)
280 endfunction()
281
282 function (cotire_get_objects_with_property_off _filteredObjectsVar _property _type)
283         set (_filteredObjects "")
284         foreach (_object ${ARGN})
285                 get_property(_isSet ${_type} "${_object}" PROPERTY ${_property} SET)
286                 if (_isSet)
287                         get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property})
288                         if (NOT _propertyValue)
289                                 list (APPEND _filteredObjects "${_object}")
290                         endif()
291                 endif()
292         endforeach()
293         set (${_filteredObjectsVar} ${_filteredObjects} PARENT_SCOPE)
294 endfunction()
295
296 function (cotire_get_source_file_property_values _valuesVar _property)
297         set (_values "")
298         foreach (_sourceFile ${ARGN})
299                 get_source_file_property(_propertyValue "${_sourceFile}" ${_property})
300                 if (_propertyValue)
301                         list (APPEND _values "${_propertyValue}")
302                 endif()
303         endforeach()
304         set (${_valuesVar} ${_values} PARENT_SCOPE)
305 endfunction()
306
307 function (cotire_resolve_config_properties _configurations _propertiesVar)
308         set (_properties "")
309         foreach (_property ${ARGN})
310                 if ("${_property}" MATCHES "<CONFIG>")
311                         foreach (_config ${_configurations})
312                                 string (TOUPPER "${_config}" _upperConfig)
313                                 string (REPLACE "<CONFIG>" "${_upperConfig}" _configProperty "${_property}")
314                                 list (APPEND _properties ${_configProperty})
315                         endforeach()
316                 else()
317                         list (APPEND _properties ${_property})
318                 endif()
319         endforeach()
320         set (${_propertiesVar} ${_properties} PARENT_SCOPE)
321 endfunction()
322
323 function (cotire_copy_set_properties _configurations _type _source _target)
324         cotire_resolve_config_properties("${_configurations}" _properties ${ARGN})
325         foreach (_property ${_properties})
326                 get_property(_isSet ${_type} ${_source} PROPERTY ${_property} SET)
327                 if (_isSet)
328                         get_property(_propertyValue ${_type} ${_source} PROPERTY ${_property})
329                         set_property(${_type} ${_target} PROPERTY ${_property} "${_propertyValue}")
330                 endif()
331         endforeach()
332 endfunction()
333
334 function (cotire_get_target_usage_requirements _target _config _targetRequirementsVar)
335         set (_targetRequirements "")
336         get_target_property(_librariesToProcess ${_target} LINK_LIBRARIES)
337         while (_librariesToProcess)
338                 # remove from head
339                 list (GET _librariesToProcess 0 _library)
340                 list (REMOVE_AT _librariesToProcess 0)
341                 if (_library MATCHES "^\\$<\\$<CONFIG:${_config}>:([A-Za-z0-9_:-]+)>$")
342                         set (_library "${CMAKE_MATCH_1}")
343                 elseif (_config STREQUAL "None" AND _library MATCHES "^\\$<\\$<CONFIG:>:([A-Za-z0-9_:-]+)>$")
344                         set (_library "${CMAKE_MATCH_1}")
345                 endif()
346                 if (TARGET ${_library})
347                         list (FIND _targetRequirements ${_library} _index)
348                         if (_index LESS 0)
349                                 list (APPEND _targetRequirements ${_library})
350                                 # BFS traversal of transitive libraries
351                                 get_target_property(_libraries ${_library} INTERFACE_LINK_LIBRARIES)
352                                 if (_libraries)
353                                         list (APPEND _librariesToProcess ${_libraries})
354                                         list (REMOVE_DUPLICATES _librariesToProcess)
355                                 endif()
356                         endif()
357                 endif()
358         endwhile()
359         set (${_targetRequirementsVar} ${_targetRequirements} PARENT_SCOPE)
360 endfunction()
361
362 function (cotire_filter_compile_flags _language _flagFilter _matchedOptionsVar _unmatchedOptionsVar)
363         if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
364                 set (_flagPrefix "[/-]")
365         else()
366                 set (_flagPrefix "--?")
367         endif()
368         set (_optionFlag "")
369         set (_matchedOptions "")
370         set (_unmatchedOptions "")
371         foreach (_compileFlag ${ARGN})
372                 if (_compileFlag)
373                         if (_optionFlag AND NOT "${_compileFlag}" MATCHES "^${_flagPrefix}")
374                                 # option with separate argument
375                                 list (APPEND _matchedOptions "${_compileFlag}")
376                                 set (_optionFlag "")
377                         elseif ("${_compileFlag}" MATCHES "^(${_flagPrefix})(${_flagFilter})$")
378                                 # remember option
379                                 set (_optionFlag "${CMAKE_MATCH_2}")
380                         elseif ("${_compileFlag}" MATCHES "^(${_flagPrefix})(${_flagFilter})(.+)$")
381                                 # option with joined argument
382                                 list (APPEND _matchedOptions "${CMAKE_MATCH_3}")
383                                 set (_optionFlag "")
384                         else()
385                                 # flush remembered option
386                                 if (_optionFlag)
387                                         list (APPEND _matchedOptions "${_optionFlag}")
388                                         set (_optionFlag "")
389                                 endif()
390                                 # add to unfiltered options
391                                 list (APPEND _unmatchedOptions "${_compileFlag}")
392                         endif()
393                 endif()
394         endforeach()
395         if (_optionFlag)
396                 list (APPEND _matchedOptions "${_optionFlag}")
397         endif()
398         if (COTIRE_DEBUG AND _matchedOptions)
399                 message (STATUS "Filter ${_flagFilter} matched: ${_matchedOptions}")
400         endif()
401         if (COTIRE_DEBUG AND _unmatchedOptions)
402                 message (STATUS "Filter ${_flagFilter} unmatched: ${_unmatchedOptions}")
403         endif()
404         set (${_matchedOptionsVar} ${_matchedOptions} PARENT_SCOPE)
405         set (${_unmatchedOptionsVar} ${_unmatchedOptions} PARENT_SCOPE)
406 endfunction()
407
408 function (cotire_is_target_supported _target _isSupportedVar)
409         if (NOT TARGET "${_target}")
410                 set (${_isSupportedVar} FALSE PARENT_SCOPE)
411                 return()
412         endif()
413         get_target_property(_imported ${_target} IMPORTED)
414         if (_imported)
415                 set (${_isSupportedVar} FALSE PARENT_SCOPE)
416                 return()
417         endif()
418         get_target_property(_targetType ${_target} TYPE)
419         if (NOT _targetType MATCHES "EXECUTABLE|(STATIC|SHARED|MODULE|OBJECT)_LIBRARY")
420                 set (${_isSupportedVar} FALSE PARENT_SCOPE)
421                 return()
422         endif()
423         set (${_isSupportedVar} TRUE PARENT_SCOPE)
424 endfunction()
425
426 function (cotire_get_target_compile_flags _config _language _target _flagsVar)
427         string (TOUPPER "${_config}" _upperConfig)
428         # collect options from CMake language variables
429         set (_compileFlags "")
430         if (CMAKE_${_language}_FLAGS)
431                 set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_FLAGS}")
432         endif()
433         if (CMAKE_${_language}_FLAGS_${_upperConfig})
434                 set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_FLAGS_${_upperConfig}}")
435         endif()
436         if (_target)
437                 # add target compile flags
438                 get_target_property(_targetflags ${_target} COMPILE_FLAGS)
439                 if (_targetflags)
440                         set (_compileFlags "${_compileFlags} ${_targetflags}")
441                 endif()
442         endif()
443         if (UNIX)
444                 separate_arguments(_compileFlags UNIX_COMMAND "${_compileFlags}")
445         elseif(WIN32)
446                 separate_arguments(_compileFlags WINDOWS_COMMAND "${_compileFlags}")
447         else()
448                 separate_arguments(_compileFlags)
449         endif()
450         # target compile options
451         if (_target)
452                 get_target_property(_targetOptions ${_target} COMPILE_OPTIONS)
453                 if (_targetOptions)
454                         list (APPEND _compileFlags ${_targetOptions})
455                 endif()
456         endif()
457         # interface compile options from linked library targets
458         if (_target)
459                 set (_linkedTargets "")
460                 cotire_get_target_usage_requirements(${_target} ${_config} _linkedTargets)
461                 foreach (_linkedTarget ${_linkedTargets})
462                         get_target_property(_targetOptions ${_linkedTarget} INTERFACE_COMPILE_OPTIONS)
463                         if (_targetOptions)
464                                 list (APPEND _compileFlags ${_targetOptions})
465                         endif()
466                 endforeach()
467         endif()
468         # handle language standard properties
469         if (CMAKE_${_language}_STANDARD_DEFAULT)
470                 # used compiler supports language standard levels
471                 if (_target)
472                         get_target_property(_targetLanguageStandard ${_target} ${_language}_STANDARD)
473                         if (_targetLanguageStandard)
474                                 set (_type "EXTENSION")
475                                 get_property(_isSet TARGET ${_target} PROPERTY ${_language}_EXTENSIONS SET)
476                                 if (_isSet)
477                                         get_target_property(_targetUseLanguageExtensions ${_target} ${_language}_EXTENSIONS)
478                                         if (NOT _targetUseLanguageExtensions)
479                                                 set (_type "STANDARD")
480                                         endif()
481                                 endif()
482                                 if (CMAKE_${_language}${_targetLanguageStandard}_${_type}_COMPILE_OPTION)
483                                         list (APPEND _compileFlags "${CMAKE_${_language}${_targetLanguageStandard}_${_type}_COMPILE_OPTION}")
484                                 endif()
485                         endif()
486                 endif()
487         endif()
488         # handle the POSITION_INDEPENDENT_CODE target property
489         if (_target)
490                 get_target_property(_targetPIC ${_target} POSITION_INDEPENDENT_CODE)
491                 if (_targetPIC)
492                         get_target_property(_targetType ${_target} TYPE)
493                         if (_targetType STREQUAL "EXECUTABLE" AND CMAKE_${_language}_COMPILE_OPTIONS_PIE)
494                                 list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_PIE}")
495                         elseif (CMAKE_${_language}_COMPILE_OPTIONS_PIC)
496                                 list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_PIC}")
497                         endif()
498                 endif()
499         endif()
500         # handle visibility target properties
501         if (_target)
502                 get_target_property(_targetVisibility ${_target} ${_language}_VISIBILITY_PRESET)
503                 if (_targetVisibility AND CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY)
504                         list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY}${_targetVisibility}")
505                 endif()
506                 get_target_property(_targetVisibilityInlines ${_target} VISIBILITY_INLINES_HIDDEN)
507                 if (_targetVisibilityInlines AND CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN)
508                         list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN}")
509                 endif()
510         endif()
511         # platform specific flags
512         if (APPLE)
513                 get_target_property(_architectures ${_target} OSX_ARCHITECTURES_${_upperConfig})
514                 if (NOT _architectures)
515                         get_target_property(_architectures ${_target} OSX_ARCHITECTURES)
516                 endif()
517                 if (_architectures)
518                         foreach (_arch ${_architectures})
519                                 list (APPEND _compileFlags "-arch" "${_arch}")
520                         endforeach()
521                 endif()
522                 if (CMAKE_OSX_SYSROOT)
523                         if (CMAKE_${_language}_SYSROOT_FLAG)
524                                 list (APPEND _compileFlags "${CMAKE_${_language}_SYSROOT_FLAG}" "${CMAKE_OSX_SYSROOT}")
525                         else()
526                                 list (APPEND _compileFlags "-isysroot" "${CMAKE_OSX_SYSROOT}")
527                         endif()
528                 endif()
529                 if (CMAKE_OSX_DEPLOYMENT_TARGET)
530                         if (CMAKE_${_language}_OSX_DEPLOYMENT_TARGET_FLAG)
531                                 list (APPEND _compileFlags "${CMAKE_${_language}_OSX_DEPLOYMENT_TARGET_FLAG}${CMAKE_OSX_DEPLOYMENT_TARGET}")
532                         else()
533                                 list (APPEND _compileFlags "-mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}")
534                         endif()
535                 endif()
536         endif()
537         if (COTIRE_DEBUG AND _compileFlags)
538                 message (STATUS "Target ${_target} compile flags: ${_compileFlags}")
539         endif()
540         set (${_flagsVar} ${_compileFlags} PARENT_SCOPE)
541 endfunction()
542
543 function (cotire_get_target_include_directories _config _language _target _includeDirsVar _systemIncludeDirsVar)
544         set (_includeDirs "")
545         set (_systemIncludeDirs "")
546         # default include dirs
547         if (CMAKE_INCLUDE_CURRENT_DIR)
548                 list (APPEND _includeDirs "${CMAKE_CURRENT_BINARY_DIR}")
549                 list (APPEND _includeDirs "${CMAKE_CURRENT_SOURCE_DIR}")
550         endif()
551         set (_targetFlags "")
552         cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags)
553         # parse additional include directories from target compile flags
554         if (CMAKE_INCLUDE_FLAG_${_language})
555                 string (STRIP "${CMAKE_INCLUDE_FLAG_${_language}}" _includeFlag)
556                 string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}")
557                 if (_includeFlag)
558                         set (_dirs "")
559                         cotire_filter_compile_flags("${_language}" "${_includeFlag}" _dirs _ignore ${_targetFlags})
560                         if (_dirs)
561                                 list (APPEND _includeDirs ${_dirs})
562                         endif()
563                 endif()
564         endif()
565         # parse additional system include directories from target compile flags
566         if (CMAKE_INCLUDE_SYSTEM_FLAG_${_language})
567                 string (STRIP "${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}" _includeFlag)
568                 string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}")
569                 if (_includeFlag)
570                         set (_dirs "")
571                         cotire_filter_compile_flags("${_language}" "${_includeFlag}" _dirs _ignore ${_targetFlags})
572                         if (_dirs)
573                                 list (APPEND _systemIncludeDirs ${_dirs})
574                         endif()
575                 endif()
576         endif()
577         # target include directories
578         get_directory_property(_dirs DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" INCLUDE_DIRECTORIES)
579         if (_target)
580                 get_target_property(_targetDirs ${_target} INCLUDE_DIRECTORIES)
581                 if (_targetDirs)
582                         list (APPEND _dirs ${_targetDirs})
583                 endif()
584                 get_target_property(_targetDirs ${_target} INTERFACE_SYSTEM_INCLUDE_DIRECTORIES)
585                 if (_targetDirs)
586                         list (APPEND _systemIncludeDirs ${_targetDirs})
587                 endif()
588         endif()
589         # interface include directories from linked library targets
590         if (_target)
591                 set (_linkedTargets "")
592                 cotire_get_target_usage_requirements(${_target} ${_config} _linkedTargets)
593                 foreach (_linkedTarget ${_linkedTargets})
594                         get_target_property(_linkedTargetType ${_linkedTarget} TYPE)
595                         if (CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE AND NOT CMAKE_VERSION VERSION_LESS "3.4.0" AND
596                                 _linkedTargetType MATCHES "(STATIC|SHARED|MODULE|OBJECT)_LIBRARY")
597                                 # CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE refers to CMAKE_CURRENT_BINARY_DIR and CMAKE_CURRENT_SOURCE_DIR
598                                 # at the time, when the target was created. These correspond to the target properties BINARY_DIR and SOURCE_DIR
599                                 # which are only available with CMake 3.4 or later.
600                                 get_target_property(_targetDirs ${_linkedTarget} BINARY_DIR)
601                                 if (_targetDirs)
602                                         list (APPEND _dirs ${_targetDirs})
603                                 endif()
604                                 get_target_property(_targetDirs ${_linkedTarget} SOURCE_DIR)
605                                 if (_targetDirs)
606                                         list (APPEND _dirs ${_targetDirs})
607                                 endif()
608                         endif()
609                         get_target_property(_targetDirs ${_linkedTarget} INTERFACE_INCLUDE_DIRECTORIES)
610                         if (_targetDirs)
611                                 list (APPEND _dirs ${_targetDirs})
612                         endif()
613                         get_target_property(_targetDirs ${_linkedTarget} INTERFACE_SYSTEM_INCLUDE_DIRECTORIES)
614                         if (_targetDirs)
615                                 list (APPEND _systemIncludeDirs ${_targetDirs})
616                         endif()
617                 endforeach()
618         endif()
619         if (dirs)
620                 list (REMOVE_DUPLICATES _dirs)
621         endif()
622         list (LENGTH _includeDirs _projectInsertIndex)
623         foreach (_dir ${_dirs})
624                 if (CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE)
625                         cotire_check_is_path_relative_to("${_dir}" _isRelative "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}")
626                         if (_isRelative)
627                                 list (LENGTH _includeDirs _len)
628                                 if (_len EQUAL _projectInsertIndex)
629                                         list (APPEND _includeDirs "${_dir}")
630                                 else()
631                                         list (INSERT _includeDirs _projectInsertIndex "${_dir}")
632                                 endif()
633                                 math (EXPR _projectInsertIndex "${_projectInsertIndex} + 1")
634                         else()
635                                 list (APPEND _includeDirs "${_dir}")
636                         endif()
637                 else()
638                         list (APPEND _includeDirs "${_dir}")
639                 endif()
640         endforeach()
641         list (REMOVE_DUPLICATES _includeDirs)
642         list (REMOVE_DUPLICATES _systemIncludeDirs)
643         if (CMAKE_${_language}_IMPLICIT_INCLUDE_DIRECTORIES)
644                 list (REMOVE_ITEM _includeDirs ${CMAKE_${_language}_IMPLICIT_INCLUDE_DIRECTORIES})
645         endif()
646         if (WIN32 AND NOT MINGW)
647                 # convert Windows paths in include directories to CMake paths
648                 if (_includeDirs)
649                         set (_paths "")
650                         foreach (_dir ${_includeDirs})
651                                 file (TO_CMAKE_PATH "${_dir}" _path)
652                                 list (APPEND _paths "${_path}")
653                         endforeach()
654                         set (_includeDirs ${_paths})
655                 endif()
656                 if (_systemIncludeDirs)
657                         set (_paths "")
658                         foreach (_dir ${_systemIncludeDirs})
659                                 file (TO_CMAKE_PATH "${_dir}" _path)
660                                 list (APPEND _paths "${_path}")
661                         endforeach()
662                         set (_systemIncludeDirs ${_paths})
663                 endif()
664         endif()
665         if (COTIRE_DEBUG AND _includeDirs)
666                 message (STATUS "Target ${_target} include dirs: ${_includeDirs}")
667         endif()
668         set (${_includeDirsVar} ${_includeDirs} PARENT_SCOPE)
669         if (COTIRE_DEBUG AND _systemIncludeDirs)
670                 message (STATUS "Target ${_target} system include dirs: ${_systemIncludeDirs}")
671         endif()
672         set (${_systemIncludeDirsVar} ${_systemIncludeDirs} PARENT_SCOPE)
673 endfunction()
674
675 function (cotire_get_target_export_symbol _target _exportSymbolVar)
676         set (_exportSymbol "")
677         get_target_property(_targetType ${_target} TYPE)
678         get_target_property(_enableExports ${_target} ENABLE_EXPORTS)
679         if (_targetType MATCHES "(SHARED|MODULE)_LIBRARY" OR
680                 (_targetType STREQUAL "EXECUTABLE" AND _enableExports))
681                 get_target_property(_exportSymbol ${_target} DEFINE_SYMBOL)
682                 if (NOT _exportSymbol)
683                         set (_exportSymbol "${_target}_EXPORTS")
684                 endif()
685                 string (MAKE_C_IDENTIFIER "${_exportSymbol}" _exportSymbol)
686         endif()
687         set (${_exportSymbolVar} ${_exportSymbol} PARENT_SCOPE)
688 endfunction()
689
690 function (cotire_get_target_compile_definitions _config _language _target _definitionsVar)
691         string (TOUPPER "${_config}" _upperConfig)
692         set (_configDefinitions "")
693         # CMAKE_INTDIR for multi-configuration build systems
694         if (NOT "${CMAKE_CFG_INTDIR}" STREQUAL ".")
695                 list (APPEND _configDefinitions "CMAKE_INTDIR=\"${_config}\"")
696         endif()
697         # target export define symbol
698         cotire_get_target_export_symbol("${_target}" _defineSymbol)
699         if (_defineSymbol)
700                 list (APPEND _configDefinitions "${_defineSymbol}")
701         endif()
702         # directory compile definitions
703         get_directory_property(_definitions DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMPILE_DEFINITIONS)
704         if (_definitions)
705                 list (APPEND _configDefinitions ${_definitions})
706         endif()
707         get_directory_property(_definitions DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMPILE_DEFINITIONS_${_upperConfig})
708         if (_definitions)
709                 list (APPEND _configDefinitions ${_definitions})
710         endif()
711         # target compile definitions
712         get_target_property(_definitions ${_target} COMPILE_DEFINITIONS)
713         if (_definitions)
714                 list (APPEND _configDefinitions ${_definitions})
715         endif()
716         get_target_property(_definitions ${_target} COMPILE_DEFINITIONS_${_upperConfig})
717         if (_definitions)
718                 list (APPEND _configDefinitions ${_definitions})
719         endif()
720         # interface compile definitions from linked library targets
721         set (_linkedTargets "")
722         cotire_get_target_usage_requirements(${_target} ${_config} _linkedTargets)
723         foreach (_linkedTarget ${_linkedTargets})
724                 get_target_property(_definitions ${_linkedTarget} INTERFACE_COMPILE_DEFINITIONS)
725                 if (_definitions)
726                         list (APPEND _configDefinitions ${_definitions})
727                 endif()
728         endforeach()
729         # parse additional compile definitions from target compile flags
730         # and do not look at directory compile definitions, which we already handled
731         set (_targetFlags "")
732         cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags)
733         cotire_filter_compile_flags("${_language}" "D" _definitions _ignore ${_targetFlags})
734         if (_definitions)
735                 list (APPEND _configDefinitions ${_definitions})
736         endif()
737         list (REMOVE_DUPLICATES _configDefinitions)
738         if (COTIRE_DEBUG AND _configDefinitions)
739                 message (STATUS "Target ${_target} compile definitions: ${_configDefinitions}")
740         endif()
741         set (${_definitionsVar} ${_configDefinitions} PARENT_SCOPE)
742 endfunction()
743
744 function (cotire_get_target_compiler_flags _config _language _target _compilerFlagsVar)
745         # parse target compile flags omitting compile definitions and include directives
746         set (_targetFlags "")
747         cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags)
748         set (_flagFilter "D")
749         if (CMAKE_INCLUDE_FLAG_${_language})
750                 string (STRIP "${CMAKE_INCLUDE_FLAG_${_language}}" _includeFlag)
751                 string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}")
752                 if (_includeFlag)
753                         set (_flagFilter "${_flagFilter}|${_includeFlag}")
754                 endif()
755         endif()
756         if (CMAKE_INCLUDE_SYSTEM_FLAG_${_language})
757                 string (STRIP "${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}" _includeFlag)
758                 string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}")
759                 if (_includeFlag)
760                         set (_flagFilter "${_flagFilter}|${_includeFlag}")
761                 endif()
762         endif()
763         set (_compilerFlags "")
764         cotire_filter_compile_flags("${_language}" "${_flagFilter}" _ignore _compilerFlags ${_targetFlags})
765         if (COTIRE_DEBUG AND _compilerFlags)
766                 message (STATUS "Target ${_target} compiler flags: ${_compilerFlags}")
767         endif()
768         set (${_compilerFlagsVar} ${_compilerFlags} PARENT_SCOPE)
769 endfunction()
770
771 function (cotire_add_sys_root_paths _pathsVar)
772         if (APPLE)
773                 if (CMAKE_OSX_SYSROOT AND CMAKE_${_language}_HAS_ISYSROOT)
774                         foreach (_path IN LISTS ${_pathsVar})
775                                 if (IS_ABSOLUTE "${_path}")
776                                         get_filename_component(_path "${CMAKE_OSX_SYSROOT}/${_path}" ABSOLUTE)
777                                         if (EXISTS "${_path}")
778                                                 list (APPEND ${_pathsVar} "${_path}")
779                                         endif()
780                                 endif()
781                         endforeach()
782                 endif()
783         endif()
784         set (${_pathsVar} ${${_pathsVar}} PARENT_SCOPE)
785 endfunction()
786
787 function (cotire_get_source_extra_properties _sourceFile _pattern _resultVar)
788         set (_extraProperties ${ARGN})
789         set (_result "")
790         if (_extraProperties)
791                 list (FIND _extraProperties "${_sourceFile}" _index)
792                 if (_index GREATER -1)
793                         math (EXPR _index "${_index} + 1")
794                         list (LENGTH _extraProperties _len)
795                         math (EXPR _len "${_len} - 1")
796                         foreach (_index RANGE ${_index} ${_len})
797                                 list (GET _extraProperties ${_index} _value)
798                                 if (_value MATCHES "${_pattern}")
799                                         list (APPEND _result "${_value}")
800                                 else()
801                                         break()
802                                 endif()
803                         endforeach()
804                 endif()
805         endif()
806         set (${_resultVar} ${_result} PARENT_SCOPE)
807 endfunction()
808
809 function (cotire_get_source_compile_definitions _config _language _sourceFile _definitionsVar)
810         set (_compileDefinitions "")
811         if (NOT CMAKE_SCRIPT_MODE_FILE)
812                 string (TOUPPER "${_config}" _upperConfig)
813                 get_source_file_property(_definitions "${_sourceFile}" COMPILE_DEFINITIONS)
814                 if (_definitions)
815                         list (APPEND _compileDefinitions ${_definitions})
816                 endif()
817                 get_source_file_property(_definitions "${_sourceFile}" COMPILE_DEFINITIONS_${_upperConfig})
818                 if (_definitions)
819                         list (APPEND _compileDefinitions ${_definitions})
820                 endif()
821         endif()
822         cotire_get_source_extra_properties("${_sourceFile}" "^[a-zA-Z0-9_]+(=.*)?$" _definitions ${ARGN})
823         if (_definitions)
824                 list (APPEND _compileDefinitions ${_definitions})
825         endif()
826         if (COTIRE_DEBUG AND _compileDefinitions)
827                 message (STATUS "Source ${_sourceFile} compile definitions: ${_compileDefinitions}")
828         endif()
829         set (${_definitionsVar} ${_compileDefinitions} PARENT_SCOPE)
830 endfunction()
831
832 function (cotire_get_source_files_compile_definitions _config _language _definitionsVar)
833         set (_configDefinitions "")
834         foreach (_sourceFile ${ARGN})
835                 cotire_get_source_compile_definitions("${_config}" "${_language}" "${_sourceFile}" _sourceDefinitions)
836                 if (_sourceDefinitions)
837                         list (APPEND _configDefinitions "${_sourceFile}" ${_sourceDefinitions} "-")
838                 endif()
839         endforeach()
840         set (${_definitionsVar} ${_configDefinitions} PARENT_SCOPE)
841 endfunction()
842
843 function (cotire_get_source_undefs _sourceFile _property _sourceUndefsVar)
844         set (_sourceUndefs "")
845         if (NOT CMAKE_SCRIPT_MODE_FILE)
846                 get_source_file_property(_undefs "${_sourceFile}" ${_property})
847                 if (_undefs)
848                         list (APPEND _sourceUndefs ${_undefs})
849                 endif()
850         endif()
851         cotire_get_source_extra_properties("${_sourceFile}" "^[a-zA-Z0-9_]+$" _undefs ${ARGN})
852         if (_undefs)
853                 list (APPEND _sourceUndefs ${_undefs})
854         endif()
855         if (COTIRE_DEBUG AND _sourceUndefs)
856                 message (STATUS "Source ${_sourceFile} ${_property} undefs: ${_sourceUndefs}")
857         endif()
858         set (${_sourceUndefsVar} ${_sourceUndefs} PARENT_SCOPE)
859 endfunction()
860
861 function (cotire_get_source_files_undefs _property _sourceUndefsVar)
862         set (_sourceUndefs "")
863         foreach (_sourceFile ${ARGN})
864                 cotire_get_source_undefs("${_sourceFile}" ${_property} _undefs)
865                 if (_undefs)
866                         list (APPEND _sourceUndefs "${_sourceFile}" ${_undefs} "-")
867                 endif()
868         endforeach()
869         set (${_sourceUndefsVar} ${_sourceUndefs} PARENT_SCOPE)
870 endfunction()
871
872 macro (cotire_set_cmd_to_prologue _cmdVar)
873         set (${_cmdVar} "${CMAKE_COMMAND}")
874         if (COTIRE_DEBUG)
875                 list (APPEND ${_cmdVar} "--warn-uninitialized")
876         endif()
877         list (APPEND ${_cmdVar} "-DCOTIRE_BUILD_TYPE:STRING=$<CONFIGURATION>")
878         if (XCODE)
879                 list (APPEND ${_cmdVar} "-DXCODE:BOOL=TRUE")
880         endif()
881         if (COTIRE_VERBOSE)
882                 list (APPEND ${_cmdVar} "-DCOTIRE_VERBOSE:BOOL=ON")
883         elseif("${CMAKE_GENERATOR}" MATCHES "Makefiles")
884                 list (APPEND ${_cmdVar} "-DCOTIRE_VERBOSE:BOOL=$(VERBOSE)")
885         endif()
886 endmacro()
887
888 function (cotire_init_compile_cmd _cmdVar _language _compilerLauncher _compilerExe _compilerArg1)
889         if (NOT _compilerLauncher)
890                 set (_compilerLauncher ${CMAKE_${_language}_COMPILER_LAUNCHER})
891         endif()
892         if (NOT _compilerExe)
893                 set (_compilerExe "${CMAKE_${_language}_COMPILER}")
894         endif()
895         if (NOT _compilerArg1)
896                 set (_compilerArg1 ${CMAKE_${_language}_COMPILER_ARG1})
897         endif()
898         if (WIN32)
899                 file (TO_NATIVE_PATH "${_compilerExe}" _compilerExe)
900         endif()
901         string (STRIP "${_compilerArg1}" _compilerArg1)
902         if ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
903                 # compiler launcher is only supported for Makefile and Ninja
904                 set (${_cmdVar} ${_compilerLauncher} "${_compilerExe}" ${_compilerArg1} PARENT_SCOPE)
905         else()
906                 set (${_cmdVar} "${_compilerExe}" ${_compilerArg1} PARENT_SCOPE)
907         endif()
908 endfunction()
909
910 macro (cotire_add_definitions_to_cmd _cmdVar _language)
911         foreach (_definition ${ARGN})
912                 if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
913                         list (APPEND ${_cmdVar} "/D${_definition}")
914                 else()
915                         list (APPEND ${_cmdVar} "-D${_definition}")
916                 endif()
917         endforeach()
918 endmacro()
919
920 function (cotire_add_includes_to_cmd _cmdVar _language _includesVar _systemIncludesVar)
921         set (_includeDirs ${${_includesVar}} ${${_systemIncludesVar}})
922         if (_includeDirs)
923                 list (REMOVE_DUPLICATES _includeDirs)
924                 foreach (_include ${_includeDirs})
925                         if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
926                                 file (TO_NATIVE_PATH "${_include}" _include)
927                                 list (APPEND ${_cmdVar} "${CMAKE_INCLUDE_FLAG_${_language}}${CMAKE_INCLUDE_FLAG_SEP_${_language}}${_include}")
928                         else()
929                                 set (_index -1)
930                                 if ("${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}" MATCHES ".+")
931                                         list (FIND ${_systemIncludesVar} "${_include}" _index)
932                                 endif()
933                                 if (_index GREATER -1)
934                                         list (APPEND ${_cmdVar} "${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}${CMAKE_INCLUDE_FLAG_SEP_${_language}}${_include}")
935                                 else()
936                                         list (APPEND ${_cmdVar} "${CMAKE_INCLUDE_FLAG_${_language}}${CMAKE_INCLUDE_FLAG_SEP_${_language}}${_include}")
937                                 endif()
938                         endif()
939                 endforeach()
940         endif()
941         set (${_cmdVar} ${${_cmdVar}} PARENT_SCOPE)
942 endfunction()
943
944 function (cotire_add_frameworks_to_cmd _cmdVar _language _includesVar _systemIncludesVar)
945         if (APPLE)
946                 set (_frameworkDirs "")
947                 foreach (_include ${${_includesVar}})
948                         if (IS_ABSOLUTE "${_include}" AND _include MATCHES "\\.framework$")
949                                 get_filename_component(_frameworkDir "${_include}" DIRECTORY)
950                                 list (APPEND _frameworkDirs "${_frameworkDir}")
951                         endif()
952                 endforeach()
953                 set (_systemFrameworkDirs "")
954                 foreach (_include ${${_systemIncludesVar}})
955                         if (IS_ABSOLUTE "${_include}" AND _include MATCHES "\\.framework$")
956                                 get_filename_component(_frameworkDir "${_include}" DIRECTORY)
957                                 list (APPEND _systemFrameworkDirs "${_frameworkDir}")
958                         endif()
959                 endforeach()
960                 if (_systemFrameworkDirs)
961                         list (APPEND _frameworkDirs ${_systemFrameworkDirs})
962                 endif()
963                 if (_frameworkDirs)
964                         list (REMOVE_DUPLICATES _frameworkDirs)
965                         foreach (_frameworkDir ${_frameworkDirs})
966                                 set (_index -1)
967                                 if ("${CMAKE_${_language}_SYSTEM_FRAMEWORK_SEARCH_FLAG}" MATCHES ".+")
968                                         list (FIND _systemFrameworkDirs "${_frameworkDir}" _index)
969                                 endif()
970                                 if (_index GREATER -1)
971                                         list (APPEND ${_cmdVar} "${CMAKE_${_language}_SYSTEM_FRAMEWORK_SEARCH_FLAG}${_frameworkDir}")
972                                 else()
973                                         list (APPEND ${_cmdVar} "${CMAKE_${_language}_FRAMEWORK_SEARCH_FLAG}${_frameworkDir}")
974                                 endif()
975                         endforeach()
976                 endif()
977         endif()
978         set (${_cmdVar} ${${_cmdVar}} PARENT_SCOPE)
979 endfunction()
980
981 macro (cotire_add_compile_flags_to_cmd _cmdVar)
982         foreach (_flag ${ARGN})
983                 list (APPEND ${_cmdVar} "${_flag}")
984         endforeach()
985 endmacro()
986
987 function (cotire_check_file_up_to_date _fileIsUpToDateVar _file)
988         if (EXISTS "${_file}")
989                 set (_triggerFile "")
990                 foreach (_dependencyFile ${ARGN})
991                         if (EXISTS "${_dependencyFile}")
992                                 # IS_NEWER_THAN returns TRUE if both files have the same timestamp
993                                 # thus we do the comparison in both directions to exclude ties
994                                 if ("${_dependencyFile}" IS_NEWER_THAN "${_file}" AND
995                                         NOT "${_file}" IS_NEWER_THAN "${_dependencyFile}")
996                                         set (_triggerFile "${_dependencyFile}")
997                                         break()
998                                 endif()
999                         endif()
1000                 endforeach()
1001                 if (_triggerFile)
1002                         if (COTIRE_VERBOSE)
1003                                 get_filename_component(_fileName "${_file}" NAME)
1004                                 message (STATUS "${_fileName} update triggered by ${_triggerFile} change.")
1005                         endif()
1006                         set (${_fileIsUpToDateVar} FALSE PARENT_SCOPE)
1007                 else()
1008                         if (COTIRE_VERBOSE)
1009                                 get_filename_component(_fileName "${_file}" NAME)
1010                                 message (STATUS "${_fileName} is up-to-date.")
1011                         endif()
1012                         set (${_fileIsUpToDateVar} TRUE PARENT_SCOPE)
1013                 endif()
1014         else()
1015                 if (COTIRE_VERBOSE)
1016                         get_filename_component(_fileName "${_file}" NAME)
1017                         message (STATUS "${_fileName} does not exist yet.")
1018                 endif()
1019                 set (${_fileIsUpToDateVar} FALSE PARENT_SCOPE)
1020         endif()
1021 endfunction()
1022
1023 macro (cotire_find_closest_relative_path _headerFile _includeDirs _relPathVar)
1024         set (${_relPathVar} "")
1025         foreach (_includeDir ${_includeDirs})
1026                 if (IS_DIRECTORY "${_includeDir}")
1027                         file (RELATIVE_PATH _relPath "${_includeDir}" "${_headerFile}")
1028                         if (NOT IS_ABSOLUTE "${_relPath}" AND NOT "${_relPath}" MATCHES "^\\.\\.")
1029                                 string (LENGTH "${${_relPathVar}}" _closestLen)
1030                                 string (LENGTH "${_relPath}" _relLen)
1031                                 if (_closestLen EQUAL 0 OR _relLen LESS _closestLen)
1032                                         set (${_relPathVar} "${_relPath}")
1033                                 endif()
1034                         endif()
1035                 elseif ("${_includeDir}" STREQUAL "${_headerFile}")
1036                         # if path matches exactly, return short non-empty string
1037                         set (${_relPathVar} "1")
1038                         break()
1039                 endif()
1040         endforeach()
1041 endmacro()
1042
1043 macro (cotire_check_header_file_location _headerFile _insideIncludeDirs _outsideIncludeDirs _headerIsInside)
1044         # check header path against ignored and honored include directories
1045         cotire_find_closest_relative_path("${_headerFile}" "${_insideIncludeDirs}" _insideRelPath)
1046         if (_insideRelPath)
1047                 # header is inside, but could be become outside if there is a shorter outside match
1048                 cotire_find_closest_relative_path("${_headerFile}" "${_outsideIncludeDirs}" _outsideRelPath)
1049                 if (_outsideRelPath)
1050                         string (LENGTH "${_insideRelPath}" _insideRelPathLen)
1051                         string (LENGTH "${_outsideRelPath}" _outsideRelPathLen)
1052                         if (_outsideRelPathLen LESS _insideRelPathLen)
1053                                 set (${_headerIsInside} FALSE)
1054                         else()
1055                                 set (${_headerIsInside} TRUE)
1056                         endif()
1057                 else()
1058                         set (${_headerIsInside} TRUE)
1059                 endif()
1060         else()
1061                 # header is outside
1062                 set (${_headerIsInside} FALSE)
1063         endif()
1064 endmacro()
1065
1066 macro (cotire_check_ignore_header_file_path _headerFile _headerIsIgnoredVar)
1067         if (NOT EXISTS "${_headerFile}")
1068                 set (${_headerIsIgnoredVar} TRUE)
1069         elseif (IS_DIRECTORY "${_headerFile}")
1070                 set (${_headerIsIgnoredVar} TRUE)
1071         elseif ("${_headerFile}" MATCHES "\\.\\.|[_-]fixed" AND "${_headerFile}" MATCHES "\\.h$")
1072                 # heuristic: ignore C headers with embedded parent directory references or "-fixed" or "_fixed" in path
1073                 # these often stem from using GCC #include_next tricks, which may break the precompiled header compilation
1074                 # with the error message "error: no include path in which to search for header.h"
1075                 set (${_headerIsIgnoredVar} TRUE)
1076         else()
1077                 set (${_headerIsIgnoredVar} FALSE)
1078         endif()
1079 endmacro()
1080
1081 macro (cotire_check_ignore_header_file_ext _headerFile _ignoreExtensionsVar _headerIsIgnoredVar)
1082         # check header file extension
1083         cotire_get_source_file_extension("${_headerFile}" _headerFileExt)
1084         set (${_headerIsIgnoredVar} FALSE)
1085         if (_headerFileExt)
1086                 list (FIND ${_ignoreExtensionsVar} "${_headerFileExt}" _index)
1087                 if (_index GREATER -1)
1088                         set (${_headerIsIgnoredVar} TRUE)
1089                 endif()
1090         endif()
1091 endmacro()
1092
1093 macro (cotire_parse_line _line _headerFileVar _headerDepthVar)
1094         if (MSVC)
1095                 # cl.exe /showIncludes produces different output, depending on the language pack used, e.g.:
1096                 # English: "Note: including file:   C:\directory\file"
1097                 # German: "Hinweis: Einlesen der Datei:   C:\directory\file"
1098                 # We use a very general regular expression, relying on the presence of the : characters
1099                 if (_line MATCHES "( +)([a-zA-Z]:[^:]+)$")
1100                         string (LENGTH "${CMAKE_MATCH_1}" ${_headerDepthVar})
1101                         get_filename_component(${_headerFileVar} "${CMAKE_MATCH_2}" ABSOLUTE)
1102                 else()
1103                         set (${_headerFileVar} "")
1104                         set (${_headerDepthVar} 0)
1105                 endif()
1106         else()
1107                 if (_line MATCHES "^(\\.+) (.*)$")
1108                         # GCC like output
1109                         string (LENGTH "${CMAKE_MATCH_1}" ${_headerDepthVar})
1110                         if (IS_ABSOLUTE "${CMAKE_MATCH_2}")
1111                                 set (${_headerFileVar} "${CMAKE_MATCH_2}")
1112                         else()
1113                                 get_filename_component(${_headerFileVar} "${CMAKE_MATCH_2}" REALPATH)
1114                         endif()
1115                 else()
1116                         set (${_headerFileVar} "")
1117                         set (${_headerDepthVar} 0)
1118                 endif()
1119         endif()
1120 endmacro()
1121
1122 function (cotire_parse_includes _language _scanOutput _ignoredIncludeDirs _honoredIncludeDirs _ignoredExtensions _selectedIncludesVar _unparsedLinesVar)
1123         if (WIN32)
1124                 # prevent CMake macro invocation errors due to backslash characters in Windows paths
1125                 string (REPLACE "\\" "/" _scanOutput "${_scanOutput}")
1126         endif()
1127         # canonize slashes
1128         string (REPLACE "//" "/" _scanOutput "${_scanOutput}")
1129         # prevent semicolon from being interpreted as a line separator
1130         string (REPLACE ";" "\\;" _scanOutput "${_scanOutput}")
1131         # then separate lines
1132         string (REGEX REPLACE "\n" ";" _scanOutput "${_scanOutput}")
1133         list (LENGTH _scanOutput _len)
1134         # remove duplicate lines to speed up parsing
1135         list (REMOVE_DUPLICATES _scanOutput)
1136         list (LENGTH _scanOutput _uniqueLen)
1137         if (COTIRE_VERBOSE OR COTIRE_DEBUG)
1138                 message (STATUS "Scanning ${_uniqueLen} unique lines of ${_len} for includes")
1139                 if (_ignoredExtensions)
1140                         message (STATUS "Ignored extensions: ${_ignoredExtensions}")
1141                 endif()
1142                 if (_ignoredIncludeDirs)
1143                         message (STATUS "Ignored paths: ${_ignoredIncludeDirs}")
1144                 endif()
1145                 if (_honoredIncludeDirs)
1146                         message (STATUS "Included paths: ${_honoredIncludeDirs}")
1147                 endif()
1148         endif()
1149         set (_sourceFiles ${ARGN})
1150         set (_selectedIncludes "")
1151         set (_unparsedLines "")
1152         # stack keeps track of inside/outside project status of processed header files
1153         set (_headerIsInsideStack "")
1154         foreach (_line IN LISTS _scanOutput)
1155                 if (_line)
1156                         cotire_parse_line("${_line}" _headerFile _headerDepth)
1157                         if (_headerFile)
1158                                 cotire_check_header_file_location("${_headerFile}" "${_ignoredIncludeDirs}" "${_honoredIncludeDirs}" _headerIsInside)
1159                                 if (COTIRE_DEBUG)
1160                                         message (STATUS "${_headerDepth}: ${_headerFile} ${_headerIsInside}")
1161                                 endif()
1162                                 # update stack
1163                                 list (LENGTH _headerIsInsideStack _stackLen)
1164                                 if (_headerDepth GREATER _stackLen)
1165                                         math (EXPR _stackLen "${_stackLen} + 1")
1166                                         foreach (_index RANGE ${_stackLen} ${_headerDepth})
1167                                                 list (APPEND _headerIsInsideStack ${_headerIsInside})
1168                                         endforeach()
1169                                 else()
1170                                         foreach (_index RANGE ${_headerDepth} ${_stackLen})
1171                                                 list (REMOVE_AT _headerIsInsideStack -1)
1172                                         endforeach()
1173                                         list (APPEND _headerIsInsideStack ${_headerIsInside})
1174                                 endif()
1175                                 if (COTIRE_DEBUG)
1176                                         message (STATUS "${_headerIsInsideStack}")
1177                                 endif()
1178                                 # header is a candidate if it is outside project
1179                                 if (NOT _headerIsInside)
1180                                         # get parent header file's inside/outside status
1181                                         if (_headerDepth GREATER 1)
1182                                                 math (EXPR _index "${_headerDepth} - 2")
1183                                                 list (GET _headerIsInsideStack ${_index} _parentHeaderIsInside)
1184                                         else()
1185                                                 set (_parentHeaderIsInside TRUE)
1186                                         endif()
1187                                         # select header file if parent header file is inside project
1188                                         # (e.g., a project header file that includes a standard header file)
1189                                         if (_parentHeaderIsInside)
1190                                                 cotire_check_ignore_header_file_path("${_headerFile}" _headerIsIgnored)
1191                                                 if (NOT _headerIsIgnored)
1192                                                         cotire_check_ignore_header_file_ext("${_headerFile}" _ignoredExtensions _headerIsIgnored)
1193                                                         if (NOT _headerIsIgnored)
1194                                                                 list (APPEND _selectedIncludes "${_headerFile}")
1195                                                         else()
1196                                                                 # fix header's inside status on stack, it is ignored by extension now
1197                                                                 list (REMOVE_AT _headerIsInsideStack -1)
1198                                                                 list (APPEND _headerIsInsideStack TRUE)
1199                                                         endif()
1200                                                 endif()
1201                                                 if (COTIRE_DEBUG)
1202                                                         message (STATUS "${_headerFile} ${_ignoredExtensions} ${_headerIsIgnored}")
1203                                                 endif()
1204                                         endif()
1205                                 endif()
1206                         else()
1207                                 if (MSVC)
1208                                         # for cl.exe do not keep unparsed lines which solely consist of a source file name
1209                                         string (FIND "${_sourceFiles}" "${_line}" _index)
1210                                         if (_index LESS 0)
1211                                                 list (APPEND _unparsedLines "${_line}")
1212                                         endif()
1213                                 else()
1214                                         list (APPEND _unparsedLines "${_line}")
1215                                 endif()
1216                         endif()
1217                 endif()
1218         endforeach()
1219         list (REMOVE_DUPLICATES _selectedIncludes)
1220         set (${_selectedIncludesVar} ${_selectedIncludes} PARENT_SCOPE)
1221         set (${_unparsedLinesVar} ${_unparsedLines} PARENT_SCOPE)
1222 endfunction()
1223
1224 function (cotire_scan_includes _includesVar)
1225         set(_options "")
1226         set(_oneValueArgs COMPILER_ID COMPILER_EXECUTABLE COMPILER_ARG1 COMPILER_VERSION LANGUAGE UNPARSED_LINES SCAN_RESULT)
1227         set(_multiValueArgs COMPILE_DEFINITIONS COMPILE_FLAGS INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES
1228                 IGNORE_PATH INCLUDE_PATH IGNORE_EXTENSIONS INCLUDE_PRIORITY_PATH COMPILER_LAUNCHER)
1229         cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
1230         set (_sourceFiles ${_option_UNPARSED_ARGUMENTS})
1231         if (NOT _option_LANGUAGE)
1232                 set (_option_LANGUAGE "CXX")
1233         endif()
1234         if (NOT _option_COMPILER_ID)
1235                 set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}")
1236         endif()
1237         if (NOT _option_COMPILER_VERSION)
1238                 set (_option_COMPILER_VERSION "${CMAKE_${_option_LANGUAGE}_COMPILER_VERSION}")
1239         endif()
1240         cotire_init_compile_cmd(_cmd "${_option_LANGUAGE}" "${_option_COMPILER_LAUNCHER}" "${_option_COMPILER_EXECUTABLE}" "${_option_COMPILER_ARG1}")
1241         cotire_add_definitions_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_COMPILE_DEFINITIONS})
1242         cotire_add_compile_flags_to_cmd(_cmd ${_option_COMPILE_FLAGS})
1243         cotire_add_includes_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES)
1244         cotire_add_frameworks_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES)
1245         cotire_add_makedep_flags("${_option_LANGUAGE}" "${_option_COMPILER_ID}" "${_option_COMPILER_VERSION}" _cmd)
1246         # only consider existing source files for scanning
1247         set (_existingSourceFiles "")
1248         foreach (_sourceFile ${_sourceFiles})
1249                 if (EXISTS "${_sourceFile}")
1250                         list (APPEND _existingSourceFiles "${_sourceFile}")
1251                 endif()
1252         endforeach()
1253         if (NOT _existingSourceFiles)
1254                 set (${_includesVar} "" PARENT_SCOPE)
1255                 return()
1256         endif()
1257         # add source files to be scanned
1258         if (WIN32)
1259                 foreach (_sourceFile ${_existingSourceFiles})
1260                         file (TO_NATIVE_PATH "${_sourceFile}" _sourceFileNative)
1261                         list (APPEND _cmd "${_sourceFileNative}")
1262                 endforeach()
1263         else()
1264                 list (APPEND _cmd ${_existingSourceFiles})
1265         endif()
1266         if (COTIRE_VERBOSE)
1267                 message (STATUS "execute_process: ${_cmd}")
1268         endif()
1269         if (MSVC_IDE OR _option_COMPILER_ID MATCHES "MSVC")
1270                 # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared
1271                 unset (ENV{VS_UNICODE_OUTPUT})
1272         endif()
1273         execute_process(
1274                 COMMAND ${_cmd}
1275                 WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
1276                 RESULT_VARIABLE _result
1277                 OUTPUT_QUIET
1278                 ERROR_VARIABLE _output)
1279         if (_result)
1280                 message (STATUS "Result ${_result} scanning includes of ${_existingSourceFiles}.")
1281         endif()
1282         cotire_parse_includes(
1283                 "${_option_LANGUAGE}" "${_output}"
1284                 "${_option_IGNORE_PATH}" "${_option_INCLUDE_PATH}"
1285                 "${_option_IGNORE_EXTENSIONS}"
1286                 _includes _unparsedLines
1287                 ${_sourceFiles})
1288         if (_option_INCLUDE_PRIORITY_PATH)
1289                 set (_sortedIncludes "")
1290                 foreach (_priorityPath ${_option_INCLUDE_PRIORITY_PATH})
1291                         foreach (_include ${_includes})
1292                                 string (FIND ${_include} ${_priorityPath} _position)
1293                                 if (_position GREATER -1)
1294                                         list (APPEND _sortedIncludes ${_include})
1295                                 endif()
1296                         endforeach()
1297                 endforeach()
1298                 if (_sortedIncludes)
1299                         list (INSERT _includes 0 ${_sortedIncludes})
1300                         list (REMOVE_DUPLICATES _includes)
1301                 endif()
1302         endif()
1303         set (${_includesVar} ${_includes} PARENT_SCOPE)
1304         if (_option_UNPARSED_LINES)
1305                 set (${_option_UNPARSED_LINES} ${_unparsedLines} PARENT_SCOPE)
1306         endif()
1307         if (_option_SCAN_RESULT)
1308                 set (${_option_SCAN_RESULT} ${_result} PARENT_SCOPE)
1309         endif()
1310 endfunction()
1311
1312 macro (cotire_append_undefs _contentsVar)
1313         set (_undefs ${ARGN})
1314         if (_undefs)
1315                 list (REMOVE_DUPLICATES _undefs)
1316                 foreach (_definition ${_undefs})
1317                         list (APPEND ${_contentsVar} "#undef ${_definition}")
1318                 endforeach()
1319         endif()
1320 endmacro()
1321
1322 macro (cotire_comment_str _language _commentText _commentVar)
1323         if ("${_language}" STREQUAL "CMAKE")
1324                 set (${_commentVar} "# ${_commentText}")
1325         else()
1326                 set (${_commentVar} "/* ${_commentText} */")
1327         endif()
1328 endmacro()
1329
1330 function (cotire_write_file _language _file _contents _force)
1331         get_filename_component(_moduleName "${COTIRE_CMAKE_MODULE_FILE}" NAME)
1332         cotire_comment_str("${_language}" "${_moduleName} ${COTIRE_CMAKE_MODULE_VERSION} generated file" _header1)
1333         cotire_comment_str("${_language}" "${_file}" _header2)
1334         set (_contents "${_header1}\n${_header2}\n${_contents}")
1335         if (COTIRE_DEBUG)
1336                 message (STATUS "${_contents}")
1337         endif()
1338         if (_force OR NOT EXISTS "${_file}")
1339                 file (WRITE "${_file}" "${_contents}")
1340         else()
1341                 file (READ "${_file}" _oldContents)
1342                 if (NOT "${_oldContents}" STREQUAL "${_contents}")
1343                         file (WRITE "${_file}" "${_contents}")
1344                 else()
1345                         if (COTIRE_DEBUG)
1346                                 message (STATUS "${_file} unchanged")
1347                         endif()
1348                 endif()
1349         endif()
1350 endfunction()
1351
1352 function (cotire_generate_unity_source _unityFile)
1353         set(_options "")
1354         set(_oneValueArgs LANGUAGE)
1355         set(_multiValueArgs
1356                 DEPENDS SOURCES_COMPILE_DEFINITIONS
1357                 PRE_UNDEFS SOURCES_PRE_UNDEFS POST_UNDEFS SOURCES_POST_UNDEFS PROLOGUE EPILOGUE)
1358         cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
1359         if (_option_DEPENDS)
1360                 cotire_check_file_up_to_date(_unityFileIsUpToDate "${_unityFile}" ${_option_DEPENDS})
1361                 if (_unityFileIsUpToDate)
1362                         return()
1363                 endif()
1364         endif()
1365         set (_sourceFiles ${_option_UNPARSED_ARGUMENTS})
1366         if (NOT _option_PRE_UNDEFS)
1367                 set (_option_PRE_UNDEFS "")
1368         endif()
1369         if (NOT _option_SOURCES_PRE_UNDEFS)
1370                 set (_option_SOURCES_PRE_UNDEFS "")
1371         endif()
1372         if (NOT _option_POST_UNDEFS)
1373                 set (_option_POST_UNDEFS "")
1374         endif()
1375         if (NOT _option_SOURCES_POST_UNDEFS)
1376                 set (_option_SOURCES_POST_UNDEFS "")
1377         endif()
1378         set (_contents "")
1379         if (_option_PROLOGUE)
1380                 list (APPEND _contents ${_option_PROLOGUE})
1381         endif()
1382         if (_option_LANGUAGE AND _sourceFiles)
1383                 if ("${_option_LANGUAGE}" STREQUAL "CXX")
1384                         list (APPEND _contents "#ifdef __cplusplus")
1385                 elseif ("${_option_LANGUAGE}" STREQUAL "C")
1386                         list (APPEND _contents "#ifndef __cplusplus")
1387                 endif()
1388         endif()
1389         set (_compileUndefinitions "")
1390         foreach (_sourceFile ${_sourceFiles})
1391                 cotire_get_source_compile_definitions(
1392                         "${_option_CONFIGURATION}" "${_option_LANGUAGE}" "${_sourceFile}" _compileDefinitions
1393                         ${_option_SOURCES_COMPILE_DEFINITIONS})
1394                 cotire_get_source_undefs("${_sourceFile}" COTIRE_UNITY_SOURCE_PRE_UNDEFS _sourcePreUndefs ${_option_SOURCES_PRE_UNDEFS})
1395                 cotire_get_source_undefs("${_sourceFile}" COTIRE_UNITY_SOURCE_POST_UNDEFS _sourcePostUndefs ${_option_SOURCES_POST_UNDEFS})
1396                 if (_option_PRE_UNDEFS)
1397                         list (APPEND _compileUndefinitions ${_option_PRE_UNDEFS})
1398                 endif()
1399                 if (_sourcePreUndefs)
1400                         list (APPEND _compileUndefinitions ${_sourcePreUndefs})
1401                 endif()
1402                 if (_compileUndefinitions)
1403                         cotire_append_undefs(_contents ${_compileUndefinitions})
1404                         set (_compileUndefinitions "")
1405                 endif()
1406                 if (_sourcePostUndefs)
1407                         list (APPEND _compileUndefinitions ${_sourcePostUndefs})
1408                 endif()
1409                 if (_option_POST_UNDEFS)
1410                         list (APPEND _compileUndefinitions ${_option_POST_UNDEFS})
1411                 endif()
1412                 foreach (_definition ${_compileDefinitions})
1413                         if (_definition MATCHES "^([a-zA-Z0-9_]+)=(.+)$")
1414                                 list (APPEND _contents "#define ${CMAKE_MATCH_1} ${CMAKE_MATCH_2}")
1415                                 list (INSERT _compileUndefinitions 0 "${CMAKE_MATCH_1}")
1416                         else()
1417                                 list (APPEND _contents "#define ${_definition}")
1418                                 list (INSERT _compileUndefinitions 0 "${_definition}")
1419                         endif()
1420                 endforeach()
1421                 # use absolute path as source file location
1422                 get_filename_component(_sourceFileLocation "${_sourceFile}" ABSOLUTE)
1423                 if (WIN32)
1424                         file (TO_NATIVE_PATH "${_sourceFileLocation}" _sourceFileLocation)
1425                 endif()
1426                 list (APPEND _contents "#include \"${_sourceFileLocation}\"")
1427         endforeach()
1428         if (_compileUndefinitions)
1429                 cotire_append_undefs(_contents ${_compileUndefinitions})
1430                 set (_compileUndefinitions "")
1431         endif()
1432         if (_option_LANGUAGE AND _sourceFiles)
1433                 list (APPEND _contents "#endif")
1434         endif()
1435         if (_option_EPILOGUE)
1436                 list (APPEND _contents ${_option_EPILOGUE})
1437         endif()
1438         list (APPEND _contents "")
1439         string (REPLACE ";" "\n" _contents "${_contents}")
1440         if (COTIRE_VERBOSE)
1441                 message ("${_contents}")
1442         endif()
1443         cotire_write_file("${_option_LANGUAGE}" "${_unityFile}" "${_contents}" TRUE)
1444 endfunction()
1445
1446 function (cotire_generate_prefix_header _prefixFile)
1447         set(_options "")
1448         set(_oneValueArgs LANGUAGE COMPILER_EXECUTABLE COMPILER_ARG1 COMPILER_ID COMPILER_VERSION)
1449         set(_multiValueArgs DEPENDS COMPILE_DEFINITIONS COMPILE_FLAGS
1450                 INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES IGNORE_PATH INCLUDE_PATH
1451                 IGNORE_EXTENSIONS INCLUDE_PRIORITY_PATH COMPILER_LAUNCHER)
1452         cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
1453         if (NOT _option_COMPILER_ID)
1454                 set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}")
1455         endif()
1456         if (NOT _option_COMPILER_VERSION)
1457                 set (_option_COMPILER_VERSION "${CMAKE_${_option_LANGUAGE}_COMPILER_VERSION}")
1458         endif()
1459         if (_option_DEPENDS)
1460                 cotire_check_file_up_to_date(_prefixFileIsUpToDate "${_prefixFile}" ${_option_DEPENDS})
1461                 if (_prefixFileIsUpToDate)
1462                         # create empty log file
1463                         set (_unparsedLinesFile "${_prefixFile}.log")
1464                         file (WRITE "${_unparsedLinesFile}" "")
1465                         return()
1466                 endif()
1467         endif()
1468         set (_prologue "")
1469         set (_epilogue "")
1470         if (_option_COMPILER_ID MATCHES "Clang")
1471                 set (_prologue "#pragma clang system_header")
1472         elseif (_option_COMPILER_ID MATCHES "GNU")
1473                 set (_prologue "#pragma GCC system_header")
1474         elseif (_option_COMPILER_ID MATCHES "MSVC")
1475                 set (_prologue "#pragma warning(push, 0)")
1476                 set (_epilogue "#pragma warning(pop)")
1477         elseif (_option_COMPILER_ID MATCHES "Intel")
1478                 # Intel compiler requires hdrstop pragma to stop generating PCH file
1479                 set (_epilogue "#pragma hdrstop")
1480         endif()
1481         set (_sourceFiles ${_option_UNPARSED_ARGUMENTS})
1482         cotire_scan_includes(_selectedHeaders ${_sourceFiles}
1483                 LANGUAGE "${_option_LANGUAGE}"
1484                 COMPILER_LAUNCHER "${_option_COMPILER_LAUNCHER}"
1485                 COMPILER_EXECUTABLE "${_option_COMPILER_EXECUTABLE}"
1486                 COMPILER_ARG1 "${_option_COMPILER_ARG1}"
1487                 COMPILER_ID "${_option_COMPILER_ID}"
1488                 COMPILER_VERSION "${_option_COMPILER_VERSION}"
1489                 COMPILE_DEFINITIONS ${_option_COMPILE_DEFINITIONS}
1490                 COMPILE_FLAGS ${_option_COMPILE_FLAGS}
1491                 INCLUDE_DIRECTORIES ${_option_INCLUDE_DIRECTORIES}
1492                 SYSTEM_INCLUDE_DIRECTORIES ${_option_SYSTEM_INCLUDE_DIRECTORIES}
1493                 IGNORE_PATH ${_option_IGNORE_PATH}
1494                 INCLUDE_PATH ${_option_INCLUDE_PATH}
1495                 IGNORE_EXTENSIONS ${_option_IGNORE_EXTENSIONS}
1496                 INCLUDE_PRIORITY_PATH ${_option_INCLUDE_PRIORITY_PATH}
1497                 UNPARSED_LINES _unparsedLines
1498                 SCAN_RESULT _scanResult)
1499         cotire_generate_unity_source("${_prefixFile}"
1500                 PROLOGUE ${_prologue} EPILOGUE ${_epilogue} LANGUAGE "${_option_LANGUAGE}" ${_selectedHeaders})
1501         set (_unparsedLinesFile "${_prefixFile}.log")
1502         if (_unparsedLines)
1503                 if (COTIRE_VERBOSE OR _scanResult OR NOT _selectedHeaders)
1504                         list (LENGTH _unparsedLines _skippedLineCount)
1505                         if (WIN32)
1506                                 file (TO_NATIVE_PATH "${_unparsedLinesFile}" _unparsedLinesLogPath)
1507                         else()
1508                                 set (_unparsedLinesLogPath "${_unparsedLinesFile}")
1509                         endif()
1510                         message (STATUS "${_skippedLineCount} line(s) skipped, see ${_unparsedLinesLogPath}")
1511                 endif()
1512                 string (REPLACE ";" "\n" _unparsedLines "${_unparsedLines}")
1513         endif()
1514         file (WRITE "${_unparsedLinesFile}" "${_unparsedLines}\n")
1515 endfunction()
1516
1517 function (cotire_add_makedep_flags _language _compilerID _compilerVersion _flagsVar)
1518         set (_flags ${${_flagsVar}})
1519         if (_compilerID MATCHES "MSVC")
1520                 # cl.exe options used
1521                 # /nologo suppresses display of sign-on banner
1522                 # /TC treat all files named on the command line as C source files
1523                 # /TP treat all files named on the command line as C++ source files
1524                 # /EP preprocess to stdout without #line directives
1525                 # /showIncludes list include files
1526                 set (_sourceFileTypeC "/TC")
1527                 set (_sourceFileTypeCXX "/TP")
1528                 if (_flags)
1529                         # append to list
1530                         list (APPEND _flags /nologo "${_sourceFileType${_language}}" /EP /showIncludes)
1531                 else()
1532                         # return as a flag string
1533                         set (_flags "${_sourceFileType${_language}} /EP /showIncludes")
1534                 endif()
1535         elseif (_compilerID MATCHES "GNU")
1536                 # GCC options used
1537                 # -H print the name of each header file used
1538                 # -E invoke preprocessor
1539                 # -fdirectives-only do not expand macros, requires GCC >= 4.3
1540                 if (_flags)
1541                         # append to list
1542                         list (APPEND _flags -H -E)
1543                         if (NOT "${_compilerVersion}" VERSION_LESS "4.3.0")
1544                                 list (APPEND _flags -fdirectives-only)
1545                         endif()
1546                 else()
1547                         # return as a flag string
1548                         set (_flags "-H -E")
1549                         if (NOT "${_compilerVersion}" VERSION_LESS "4.3.0")
1550                                 set (_flags "${_flags} -fdirectives-only")
1551                         endif()
1552                 endif()
1553         elseif (_compilerID MATCHES "Clang")
1554                 if (UNIX)
1555                         # Clang options used
1556                         # -H print the name of each header file used
1557                         # -E invoke preprocessor
1558                         # -fno-color-diagnostics do not print diagnostics in color
1559                         # -Eonly just run preprocessor, no output
1560                         if (_flags)
1561                                 # append to list
1562                                 list (APPEND _flags -H -E -fno-color-diagnostics -Xclang -Eonly)
1563                         else()
1564                                 # return as a flag string
1565                                 set (_flags "-H -E -fno-color-diagnostics -Xclang -Eonly")
1566                         endif()
1567                 elseif (WIN32)
1568                         # Clang-cl.exe options used
1569                         # /TC treat all files named on the command line as C source files
1570                         # /TP treat all files named on the command line as C++ source files
1571                         # /EP preprocess to stdout without #line directives
1572                         # -H print the name of each header file used
1573                         # -fno-color-diagnostics do not print diagnostics in color
1574                         # -Eonly just run preprocessor, no output
1575                         set (_sourceFileTypeC "/TC")
1576                         set (_sourceFileTypeCXX "/TP")
1577                         if (_flags)
1578                                 # append to list
1579                                 list (APPEND _flags "${_sourceFileType${_language}}" /EP -fno-color-diagnostics -Xclang -H -Xclang -Eonly)
1580                         else()
1581                                 # return as a flag string
1582                                 set (_flags "${_sourceFileType${_language}} /EP -fno-color-diagnostics -Xclang -H -Xclang -Eonly")
1583                         endif()
1584                 endif()
1585         elseif (_compilerID MATCHES "Intel")
1586                 if (WIN32)
1587                         # Windows Intel options used
1588                         # /nologo do not display compiler version information
1589                         # /QH display the include file order
1590                         # /EP preprocess to stdout, omitting #line directives
1591                         # /TC process all source or unrecognized file types as C source files
1592                         # /TP process all source or unrecognized file types as C++ source files
1593                         set (_sourceFileTypeC "/TC")
1594                         set (_sourceFileTypeCXX "/TP")
1595                         if (_flags)
1596                                 # append to list
1597                                 list (APPEND _flags /nologo "${_sourceFileType${_language}}" /EP /QH)
1598                         else()
1599                                 # return as a flag string
1600                                 set (_flags "${_sourceFileType${_language}} /EP /QH")
1601                         endif()
1602                 else()
1603                         # Linux / Mac OS X Intel options used
1604                         # -H print the name of each header file used
1605                         # -EP preprocess to stdout, omitting #line directives
1606                         # -Kc++ process all source or unrecognized file types as C++ source files
1607                         if (_flags)
1608                                 # append to list
1609                                 if ("${_language}" STREQUAL "CXX")
1610                                         list (APPEND _flags -Kc++)
1611                                 endif()
1612                                 list (APPEND _flags -H -EP)
1613                         else()
1614                                 # return as a flag string
1615                                 if ("${_language}" STREQUAL "CXX")
1616                                         set (_flags "-Kc++ ")
1617                                 endif()
1618                                 set (_flags "${_flags}-H -EP")
1619                         endif()
1620                 endif()
1621         else()
1622                 message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.")
1623         endif()
1624         set (${_flagsVar} ${_flags} PARENT_SCOPE)
1625 endfunction()
1626
1627 function (cotire_add_pch_compilation_flags _language _compilerID _compilerVersion _prefixFile _pchFile _hostFile _flagsVar)
1628         set (_flags ${${_flagsVar}})
1629         if (_compilerID MATCHES "MSVC")
1630                 file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative)
1631                 file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative)
1632                 file (TO_NATIVE_PATH "${_hostFile}" _hostFileNative)
1633                 # cl.exe options used
1634                 # /Yc creates a precompiled header file
1635                 # /Fp specifies precompiled header binary file name
1636                 # /FI forces inclusion of file
1637                 # /TC treat all files named on the command line as C source files
1638                 # /TP treat all files named on the command line as C++ source files
1639                 # /Zs syntax check only
1640                 # /Zm precompiled header memory allocation scaling factor
1641                 set (_sourceFileTypeC "/TC")
1642                 set (_sourceFileTypeCXX "/TP")
1643                 if (_flags)
1644                         # append to list
1645                         list (APPEND _flags /nologo "${_sourceFileType${_language}}"
1646                                 "/Yc${_prefixFileNative}" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}" /Zs "${_hostFileNative}")
1647                         if (COTIRE_PCH_MEMORY_SCALING_FACTOR)
1648                                 list (APPEND _flags "/Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}")
1649                         endif()
1650                 else()
1651                         # return as a flag string
1652                         set (_flags "/Yc\"${_prefixFileNative}\" /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"")
1653                         if (COTIRE_PCH_MEMORY_SCALING_FACTOR)
1654                                 set (_flags "${_flags} /Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}")
1655                         endif()
1656                 endif()
1657         elseif (_compilerID MATCHES "GNU")
1658                 # GCC options used
1659                 # -x specify the source language
1660                 # -c compile but do not link
1661                 # -o place output in file
1662                 # note that we cannot use -w to suppress all warnings upon pre-compiling, because turning off a warning may
1663                 # alter compile flags as a side effect (e.g., -Wwrite-string implies -fconst-strings)
1664                 set (_xLanguage_C "c-header")
1665                 set (_xLanguage_CXX "c++-header")
1666                 if (_flags)
1667                         # append to list
1668                         list (APPEND _flags -x "${_xLanguage_${_language}}" -c "${_prefixFile}" -o "${_pchFile}")
1669                 else()
1670                         # return as a flag string
1671                         set (_flags "-x ${_xLanguage_${_language}} -c \"${_prefixFile}\" -o \"${_pchFile}\"")
1672                 endif()
1673         elseif (_compilerID MATCHES "Clang")
1674                 if (UNIX)
1675                         # Clang options used
1676                         # -x specify the source language
1677                         # -c compile but do not link
1678                         # -o place output in file
1679                         # -fno-pch-timestamp disable inclusion of timestamp in precompiled headers (clang 4.0.0+)
1680                         set (_xLanguage_C "c-header")
1681                         set (_xLanguage_CXX "c++-header")
1682                         if (_flags)
1683                                 # append to list
1684                                 list (APPEND _flags -x "${_xLanguage_${_language}}" -c "${_prefixFile}" -o "${_pchFile}")
1685                                 if (NOT "${_compilerVersion}" VERSION_LESS "4.0.0")
1686                                         list (APPEND _flags -Xclang -fno-pch-timestamp)
1687                                 endif()
1688                         else()
1689                                 # return as a flag string
1690                                 set (_flags "-x ${_xLanguage_${_language}} -c \"${_prefixFile}\" -o \"${_pchFile}\"")
1691                                 if (NOT "${_compilerVersion}" VERSION_LESS "4.0.0")
1692                                         set (_flags "${_flags} -Xclang -fno-pch-timestamp")
1693                                 endif()
1694                         endif()
1695                 elseif (WIN32)
1696                         # Clang-cl.exe options used
1697                         # /Yc creates a precompiled header file
1698                         # /Fp specifies precompiled header binary file name
1699                         # /FI forces inclusion of file
1700                         # /Zs syntax check only
1701                         # /TC treat all files named on the command line as C source files
1702                         # /TP treat all files named on the command line as C++ source files
1703                         set (_sourceFileTypeC "/TC")
1704                         set (_sourceFileTypeCXX "/TP")
1705                         if (_flags)
1706                                 # append to list
1707                                 list (APPEND _flags "${_sourceFileType${_language}}"
1708                                                 "/Yc${_prefixFile}" "/Fp${_pchFile}" "/FI${_prefixFile}" /Zs "${_hostFile}")
1709                         else()
1710                                 # return as a flag string
1711                                 set (_flags "/Yc\"${_prefixFile}\" /Fp\"${_pchFile}\" /FI\"${_prefixFile}\"")
1712                         endif()
1713                 endif()
1714         elseif (_compilerID MATCHES "Intel")
1715                 if (WIN32)
1716                         file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative)
1717                         file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative)
1718                         file (TO_NATIVE_PATH "${_hostFile}" _hostFileNative)
1719                         # Windows Intel options used
1720                         # /nologo do not display compiler version information
1721                         # /Yc create a precompiled header (PCH) file
1722                         # /Fp specify a path or file name for precompiled header files
1723                         # /FI tells the preprocessor to include a specified file name as the header file
1724                         # /TC process all source or unrecognized file types as C source files
1725                         # /TP process all source or unrecognized file types as C++ source files
1726                         # /Zs syntax check only
1727                         # /Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2)
1728                         set (_sourceFileTypeC "/TC")
1729                         set (_sourceFileTypeCXX "/TP")
1730                         if (_flags)
1731                                 # append to list
1732                                 list (APPEND _flags /nologo "${_sourceFileType${_language}}"
1733                                         "/Yc" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}" /Zs "${_hostFileNative}")
1734                                 if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
1735                                         list (APPEND _flags "/Wpch-messages")
1736                                 endif()
1737                         else()
1738                                 # return as a flag string
1739                                 set (_flags "/Yc /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"")
1740                                 if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
1741                                         set (_flags "${_flags} /Wpch-messages")
1742                                 endif()
1743                         endif()
1744                 else()
1745                         # Linux / Mac OS X Intel options used
1746                         # -pch-dir location for precompiled header files
1747                         # -pch-create name of the precompiled header (PCH) to create
1748                         # -Kc++ process all source or unrecognized file types as C++ source files
1749                         # -fsyntax-only check only for correct syntax
1750                         # -Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2)
1751                         get_filename_component(_pchDir "${_pchFile}" DIRECTORY)
1752                         get_filename_component(_pchName "${_pchFile}" NAME)
1753                         set (_xLanguage_C "c-header")
1754                         set (_xLanguage_CXX "c++-header")
1755                         set (_pchSuppressMessages FALSE)
1756                         if ("${CMAKE_${_language}_FLAGS}" MATCHES ".*-Wno-pch-messages.*")
1757                                 set(_pchSuppressMessages TRUE)
1758                         endif()
1759                         if (_flags)
1760                                 # append to list
1761                                 if ("${_language}" STREQUAL "CXX")
1762                                         list (APPEND _flags -Kc++)
1763                                 endif()
1764                                 list (APPEND _flags -include "${_prefixFile}" -pch-dir "${_pchDir}" -pch-create "${_pchName}" -fsyntax-only "${_hostFile}")
1765                                 if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
1766                                         if (NOT _pchSuppressMessages)
1767                                                 list (APPEND _flags -Wpch-messages)
1768                                         endif()
1769                                 endif()
1770                         else()
1771                                 # return as a flag string
1772                                 set (_flags "-include \"${_prefixFile}\" -pch-dir \"${_pchDir}\" -pch-create \"${_pchName}\"")
1773                                 if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
1774                                         if (NOT _pchSuppressMessages)
1775                                                 set (_flags "${_flags} -Wpch-messages")
1776                                         endif()
1777                                 endif()
1778                         endif()
1779                 endif()
1780         else()
1781                 message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.")
1782         endif()
1783         set (${_flagsVar} ${_flags} PARENT_SCOPE)
1784 endfunction()
1785
1786 function (cotire_add_prefix_pch_inclusion_flags _language _compilerID _compilerVersion _prefixFile _pchFile _flagsVar)
1787         set (_flags ${${_flagsVar}})
1788         if (_compilerID MATCHES "MSVC")
1789                 file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative)
1790                 # cl.exe options used
1791                 # /Yu uses a precompiled header file during build
1792                 # /Fp specifies precompiled header binary file name
1793                 # /FI forces inclusion of file
1794                 # /Zm precompiled header memory allocation scaling factor
1795                 if (_pchFile)
1796                         file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative)
1797                         if (_flags)
1798                                 # append to list
1799                                 list (APPEND _flags "/Yu${_prefixFileNative}" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}")
1800                                 if (COTIRE_PCH_MEMORY_SCALING_FACTOR)
1801                                         list (APPEND _flags "/Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}")
1802                                 endif()
1803                         else()
1804                                 # return as a flag string
1805                                 set (_flags "/Yu\"${_prefixFileNative}\" /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"")
1806                                 if (COTIRE_PCH_MEMORY_SCALING_FACTOR)
1807                                         set (_flags "${_flags} /Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}")
1808                                 endif()
1809                         endif()
1810                 else()
1811                         # no precompiled header, force inclusion of prefix header
1812                         if (_flags)
1813                                 # append to list
1814                                 list (APPEND _flags "/FI${_prefixFileNative}")
1815                         else()
1816                                 # return as a flag string
1817                                 set (_flags "/FI\"${_prefixFileNative}\"")
1818                         endif()
1819                 endif()
1820         elseif (_compilerID MATCHES "GNU")
1821                 # GCC options used
1822                 # -include process include file as the first line of the primary source file
1823                 # -Winvalid-pch warns if precompiled header is found but cannot be used
1824                 # note: ccache requires the -include flag to be used in order to process precompiled header correctly
1825                 if (_flags)
1826                         # append to list
1827                         list (APPEND _flags -Winvalid-pch -include "${_prefixFile}")
1828                 else()
1829                         # return as a flag string
1830                         set (_flags "-Winvalid-pch -include \"${_prefixFile}\"")
1831                 endif()
1832         elseif (_compilerID MATCHES "Clang")
1833                 if (UNIX)
1834                         # Clang options used
1835                         # -include process include file as the first line of the primary source file
1836                         # note: ccache requires the -include flag to be used in order to process precompiled header correctly
1837                         if (_flags)
1838                                 # append to list
1839                                 list (APPEND _flags -include "${_prefixFile}")
1840                         else()
1841                                 # return as a flag string
1842                                 set (_flags "-include \"${_prefixFile}\"")
1843                         endif()
1844                 elseif (WIN32)
1845                         # Clang-cl.exe options used
1846                         # /Yu uses a precompiled header file during build
1847                         # /Fp specifies precompiled header binary file name
1848                         # /FI forces inclusion of file
1849                         if (_pchFile)
1850                                 if (_flags)
1851                                         # append to list
1852                                         list (APPEND _flags "/Yu${_prefixFile}" "/Fp${_pchFile}" "/FI${_prefixFile}")
1853                                 else()
1854                                         # return as a flag string
1855                                         set (_flags "/Yu\"${_prefixFile}\" /Fp\"${_pchFile}\" /FI\"${_prefixFile}\"")
1856                                 endif()
1857                         else()
1858                                 # no precompiled header, force inclusion of prefix header
1859                                 if (_flags)
1860                                         # append to list
1861                                         list (APPEND _flags "/FI${_prefixFile}")
1862                                 else()
1863                                         # return as a flag string
1864                                         set (_flags "/FI\"${_prefixFile}\"")
1865                                 endif()
1866                         endif()
1867                 endif()
1868         elseif (_compilerID MATCHES "Intel")
1869                 if (WIN32)
1870                         file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative)
1871                         # Windows Intel options used
1872                         # /Yu use a precompiled header (PCH) file
1873                         # /Fp specify a path or file name for precompiled header files
1874                         # /FI tells the preprocessor to include a specified file name as the header file
1875                         # /Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2)
1876                         if (_pchFile)
1877                                 file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative)
1878                                 if (_flags)
1879                                         # append to list
1880                                         list (APPEND _flags "/Yu" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}")
1881                                         if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
1882                                                 list (APPEND _flags "/Wpch-messages")
1883                                         endif()
1884                                 else()
1885                                         # return as a flag string
1886                                         set (_flags "/Yu /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"")
1887                                         if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
1888                                                 set (_flags "${_flags} /Wpch-messages")
1889                                         endif()
1890                                 endif()
1891                         else()
1892                                 # no precompiled header, force inclusion of prefix header
1893                                 if (_flags)
1894                                         # append to list
1895                                         list (APPEND _flags "/FI${_prefixFileNative}")
1896                                 else()
1897                                         # return as a flag string
1898                                         set (_flags "/FI\"${_prefixFileNative}\"")
1899                                 endif()
1900                         endif()
1901                 else()
1902                         # Linux / Mac OS X Intel options used
1903                         # -pch-dir location for precompiled header files
1904                         # -pch-use name of the precompiled header (PCH) to use
1905                         # -include process include file as the first line of the primary source file
1906                         # -Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2)
1907                         if (_pchFile)
1908                                 get_filename_component(_pchDir "${_pchFile}" DIRECTORY)
1909                                 get_filename_component(_pchName "${_pchFile}" NAME)
1910                                 set (_pchSuppressMessages FALSE)
1911                                 if ("${CMAKE_${_language}_FLAGS}" MATCHES ".*-Wno-pch-messages.*")
1912                                         set(_pchSuppressMessages TRUE)
1913                                 endif()
1914                                 if (_flags)
1915                                         # append to list
1916                                         list (APPEND _flags -include "${_prefixFile}" -pch-dir "${_pchDir}" -pch-use "${_pchName}")
1917                                         if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
1918                                                 if (NOT _pchSuppressMessages)
1919                                                         list (APPEND _flags -Wpch-messages)
1920                                                 endif()
1921                                         endif()
1922                                 else()
1923                                         # return as a flag string
1924                                         set (_flags "-include \"${_prefixFile}\" -pch-dir \"${_pchDir}\" -pch-use \"${_pchName}\"")
1925                                         if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
1926                                                 if (NOT _pchSuppressMessages)
1927                                                         set (_flags "${_flags} -Wpch-messages")
1928                                                 endif()
1929                                         endif()
1930                                 endif()
1931                         else()
1932                                 # no precompiled header, force inclusion of prefix header
1933                                 if (_flags)
1934                                         # append to list
1935                                         list (APPEND _flags -include "${_prefixFile}")
1936                                 else()
1937                                         # return as a flag string
1938                                         set (_flags "-include \"${_prefixFile}\"")
1939                                 endif()
1940                         endif()
1941                 endif()
1942         else()
1943                 message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.")
1944         endif()
1945         set (${_flagsVar} ${_flags} PARENT_SCOPE)
1946 endfunction()
1947
1948 function (cotire_precompile_prefix_header _prefixFile _pchFile _hostFile)
1949         set(_options "")
1950         set(_oneValueArgs COMPILER_EXECUTABLE COMPILER_ARG1 COMPILER_ID COMPILER_VERSION LANGUAGE)
1951         set(_multiValueArgs COMPILE_DEFINITIONS COMPILE_FLAGS INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES SYS COMPILER_LAUNCHER)
1952         cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
1953         if (NOT _option_LANGUAGE)
1954                 set (_option_LANGUAGE "CXX")
1955         endif()
1956         if (NOT _option_COMPILER_ID)
1957                 set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}")
1958         endif()
1959         if (NOT _option_COMPILER_VERSION)
1960                 set (_option_COMPILER_VERSION "${CMAKE_${_option_LANGUAGE}_COMPILER_VERSION}")
1961         endif()
1962         cotire_init_compile_cmd(_cmd "${_option_LANGUAGE}" "${_option_COMPILER_LAUNCHER}" "${_option_COMPILER_EXECUTABLE}" "${_option_COMPILER_ARG1}")
1963         cotire_add_definitions_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_COMPILE_DEFINITIONS})
1964         cotire_add_compile_flags_to_cmd(_cmd ${_option_COMPILE_FLAGS})
1965         cotire_add_includes_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES)
1966         cotire_add_frameworks_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES)
1967         cotire_add_pch_compilation_flags(
1968                 "${_option_LANGUAGE}" "${_option_COMPILER_ID}" "${_option_COMPILER_VERSION}"
1969                 "${_prefixFile}" "${_pchFile}" "${_hostFile}" _cmd)
1970         if (COTIRE_VERBOSE)
1971                 message (STATUS "execute_process: ${_cmd}")
1972         endif()
1973         if (MSVC_IDE OR _option_COMPILER_ID MATCHES "MSVC")
1974                 # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared
1975                 unset (ENV{VS_UNICODE_OUTPUT})
1976         elseif (_option_COMPILER_ID MATCHES "Clang" AND _option_COMPILER_VERSION VERSION_LESS "4.0.0")
1977                 if (_option_COMPILER_LAUNCHER MATCHES "ccache" OR
1978                         _option_COMPILER_EXECUTABLE MATCHES "ccache")
1979                         # Newer versions of Clang embed a compilation timestamp into the precompiled header binary,
1980                         # which results in "file has been modified since the precompiled header was built" errors if ccache is used.
1981                         # We work around the problem by disabling ccache upon pre-compiling the prefix header.
1982                         set (ENV{CCACHE_DISABLE} "true")
1983                 endif()
1984         endif()
1985         execute_process(
1986                 COMMAND ${_cmd}
1987                 WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
1988                 RESULT_VARIABLE _result)
1989         if (_result)
1990                 message (FATAL_ERROR "cotire: error ${_result} precompiling ${_prefixFile}.")
1991         endif()
1992 endfunction()
1993
1994 function (cotire_check_precompiled_header_support _language _target _msgVar)
1995         set (_unsupportedCompiler
1996                 "Precompiled headers not supported for ${_language} compiler ${CMAKE_${_language}_COMPILER_ID}")
1997         if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC")
1998                 # PCH supported since Visual Studio C++ 6.0
1999                 # and CMake does not support an earlier version
2000                 set (${_msgVar} "" PARENT_SCOPE)
2001         elseif (CMAKE_${_language}_COMPILER_ID MATCHES "GNU")
2002                 # GCC PCH support requires version >= 3.4
2003                 if ("${CMAKE_${_language}_COMPILER_VERSION}" VERSION_LESS "3.4.0")
2004                         set (${_msgVar} "${_unsupportedCompiler} version ${CMAKE_${_language}_COMPILER_VERSION}." PARENT_SCOPE)
2005                 else()
2006                         set (${_msgVar} "" PARENT_SCOPE)
2007                 endif()
2008         elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Clang")
2009                 if (UNIX)
2010                         # all Unix Clang versions have PCH support
2011                         set (${_msgVar} "" PARENT_SCOPE)
2012                 elseif (WIN32)
2013                         # only clang-cl is supported under Windows
2014                         get_filename_component(_compilerName "${CMAKE_${_language}_COMPILER}" NAME_WE)
2015                         if (NOT _compilerName MATCHES "cl$")
2016                                 set (${_msgVar} "${_unsupportedCompiler} version ${CMAKE_${_language}_COMPILER_VERSION}. Use clang-cl instead." PARENT_SCOPE)
2017                         endif()
2018                 endif()
2019         elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Intel")
2020                 # Intel PCH support requires version >= 8.0.0
2021                 if ("${CMAKE_${_language}_COMPILER_VERSION}" VERSION_LESS "8.0.0")
2022                         set (${_msgVar} "${_unsupportedCompiler} version ${CMAKE_${_language}_COMPILER_VERSION}." PARENT_SCOPE)
2023                 else()
2024                         set (${_msgVar} "" PARENT_SCOPE)
2025                 endif()
2026         else()
2027                 set (${_msgVar} "${_unsupportedCompiler}." PARENT_SCOPE)
2028         endif()
2029         # check if ccache is used as a compiler launcher
2030         get_target_property(_launcher ${_target} ${_language}_COMPILER_LAUNCHER)
2031         get_filename_component(_realCompilerExe "${CMAKE_${_language}_COMPILER}" REALPATH)
2032         if (_realCompilerExe MATCHES "ccache" OR _launcher MATCHES "ccache")
2033                 # verify that ccache configuration is compatible with precompiled headers
2034                 # always check environment variable CCACHE_SLOPPINESS, because earlier versions of ccache
2035                 # do not report the "sloppiness" setting correctly upon printing ccache configuration
2036                 if (DEFINED ENV{CCACHE_SLOPPINESS})
2037                         if (NOT "$ENV{CCACHE_SLOPPINESS}" MATCHES "pch_defines" OR
2038                                 NOT "$ENV{CCACHE_SLOPPINESS}" MATCHES "time_macros")
2039                                 set (${_msgVar}
2040                                         "ccache requires the environment variable CCACHE_SLOPPINESS to be set to \"pch_defines,time_macros\"."
2041                                         PARENT_SCOPE)
2042                         endif()
2043                 else()
2044                         if (_realCompilerExe MATCHES "ccache")
2045                                 set (_ccacheExe "${_realCompilerExe}")
2046                         else()
2047                                 set (_ccacheExe "${_launcher}")
2048                         endif()
2049                         execute_process(
2050                                 COMMAND "${_ccacheExe}" "--print-config"
2051                                 WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
2052                                 RESULT_VARIABLE _result
2053                                 OUTPUT_VARIABLE _ccacheConfig OUTPUT_STRIP_TRAILING_WHITESPACE
2054                                 ERROR_QUIET)
2055                         if (_result)
2056                                 set (${_msgVar} "ccache configuration cannot be determined." PARENT_SCOPE)
2057                         elseif (NOT _ccacheConfig MATCHES "sloppiness.*=.*time_macros" OR
2058                                 NOT _ccacheConfig MATCHES "sloppiness.*=.*pch_defines")
2059                                 set (${_msgVar}
2060                                         "ccache requires configuration setting \"sloppiness\" to be set to \"pch_defines,time_macros\"."
2061                                         PARENT_SCOPE)
2062                         endif()
2063                 endif()
2064         endif()
2065         if (APPLE)
2066                 # PCH compilation not supported by GCC / Clang for multi-architecture builds (e.g., i386, x86_64)
2067                 cotire_get_configuration_types(_configs)
2068                 foreach (_config ${_configs})
2069                         set (_targetFlags "")
2070                         cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags)
2071                         cotire_filter_compile_flags("${_language}" "arch" _architectures _ignore ${_targetFlags})
2072                         list (LENGTH _architectures _numberOfArchitectures)
2073                         if (_numberOfArchitectures GREATER 1)
2074                                 string (REPLACE ";" ", " _architectureStr "${_architectures}")
2075                                 set (${_msgVar}
2076                                         "Precompiled headers not supported on Darwin for multi-architecture builds (${_architectureStr})."
2077                                         PARENT_SCOPE)
2078                                 break()
2079                         endif()
2080                 endforeach()
2081         endif()
2082 endfunction()
2083
2084 macro (cotire_get_intermediate_dir _cotireDir)
2085         # ${CMAKE_CFG_INTDIR} may reference a build-time variable when using a generator which supports configuration types
2086         get_filename_component(${_cotireDir} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${COTIRE_INTDIR}" ABSOLUTE)
2087 endmacro()
2088
2089 macro (cotire_setup_file_extension_variables)
2090         set (_unityFileExt_C ".c")
2091         set (_unityFileExt_CXX ".cxx")
2092         set (_prefixFileExt_C ".h")
2093         set (_prefixFileExt_CXX ".hxx")
2094         set (_prefixSourceFileExt_C ".c")
2095         set (_prefixSourceFileExt_CXX ".cxx")
2096 endmacro()
2097
2098 function (cotire_make_single_unity_source_file_path _language _target _unityFileVar)
2099         cotire_setup_file_extension_variables()
2100         if (NOT DEFINED _unityFileExt_${_language})
2101                 set (${_unityFileVar} "" PARENT_SCOPE)
2102                 return()
2103         endif()
2104         set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}")
2105         set (_unityFileName "${_unityFileBaseName}${_unityFileExt_${_language}}")
2106         cotire_get_intermediate_dir(_baseDir)
2107         set (_unityFile "${_baseDir}/${_unityFileName}")
2108         set (${_unityFileVar} "${_unityFile}" PARENT_SCOPE)
2109 endfunction()
2110
2111 function (cotire_make_unity_source_file_paths _language _target _maxIncludes _unityFilesVar)
2112         cotire_setup_file_extension_variables()
2113         if (NOT DEFINED _unityFileExt_${_language})
2114                 set (${_unityFileVar} "" PARENT_SCOPE)
2115                 return()
2116         endif()
2117         set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}")
2118         cotire_get_intermediate_dir(_baseDir)
2119         set (_startIndex 0)
2120         set (_index 0)
2121         set (_unityFiles "")
2122         set (_sourceFiles ${ARGN})
2123         foreach (_sourceFile ${_sourceFiles})
2124                 get_source_file_property(_startNew "${_sourceFile}" COTIRE_START_NEW_UNITY_SOURCE)
2125                 math (EXPR _unityFileCount "${_index} - ${_startIndex}")
2126                 if (_startNew OR (_maxIncludes GREATER 0 AND NOT _unityFileCount LESS _maxIncludes))
2127                         if (_index GREATER 0)
2128                                 # start new unity file segment
2129                                 math (EXPR _endIndex "${_index} - 1")
2130                                 set (_unityFileName "${_unityFileBaseName}_${_startIndex}_${_endIndex}${_unityFileExt_${_language}}")
2131                                 list (APPEND _unityFiles "${_baseDir}/${_unityFileName}")
2132                         endif()
2133                         set (_startIndex ${_index})
2134                 endif()
2135                 math (EXPR _index "${_index} + 1")
2136         endforeach()
2137         list (LENGTH _sourceFiles _numberOfSources)
2138         if (_startIndex EQUAL 0)
2139                 # there is only a single unity file
2140                 cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFiles)
2141         elseif (_startIndex LESS _numberOfSources)
2142                 # end with final unity file segment
2143                 math (EXPR _endIndex "${_index} - 1")
2144                 set (_unityFileName "${_unityFileBaseName}_${_startIndex}_${_endIndex}${_unityFileExt_${_language}}")
2145                 list (APPEND _unityFiles "${_baseDir}/${_unityFileName}")
2146         endif()
2147         set (${_unityFilesVar} ${_unityFiles} PARENT_SCOPE)
2148         if (COTIRE_DEBUG AND _unityFiles)
2149                 message (STATUS "unity files: ${_unityFiles}")
2150         endif()
2151 endfunction()
2152
2153 function (cotire_unity_to_prefix_file_path _language _target _unityFile _prefixFileVar)
2154         cotire_setup_file_extension_variables()
2155         if (NOT DEFINED _unityFileExt_${_language})
2156                 set (${_prefixFileVar} "" PARENT_SCOPE)
2157                 return()
2158         endif()
2159         set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}")
2160         set (_prefixFileBaseName "${_target}_${_language}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}")
2161         string (REPLACE "${_unityFileBaseName}" "${_prefixFileBaseName}" _prefixFile "${_unityFile}")
2162         string (REGEX REPLACE "${_unityFileExt_${_language}}$" "${_prefixFileExt_${_language}}" _prefixFile "${_prefixFile}")
2163         set (${_prefixFileVar} "${_prefixFile}" PARENT_SCOPE)
2164 endfunction()
2165
2166 function (cotire_prefix_header_to_source_file_path _language _prefixHeaderFile _prefixSourceFileVar)
2167         cotire_setup_file_extension_variables()
2168         if (NOT DEFINED _prefixSourceFileExt_${_language})
2169                 set (${_prefixSourceFileVar} "" PARENT_SCOPE)
2170                 return()
2171         endif()
2172         string (REGEX REPLACE "${_prefixFileExt_${_language}}$" "${_prefixSourceFileExt_${_language}}" _prefixSourceFile "${_prefixHeaderFile}")
2173         set (${_prefixSourceFileVar} "${_prefixSourceFile}" PARENT_SCOPE)
2174 endfunction()
2175
2176 function (cotire_make_prefix_file_name _language _target _prefixFileBaseNameVar _prefixFileNameVar)
2177         cotire_setup_file_extension_variables()
2178         if (NOT _language)
2179                 set (_prefixFileBaseName "${_target}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}")
2180                 set (_prefixFileName "${_prefixFileBaseName}${_prefixFileExt_C}")
2181         elseif (DEFINED _prefixFileExt_${_language})
2182                 set (_prefixFileBaseName "${_target}_${_language}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}")
2183                 set (_prefixFileName "${_prefixFileBaseName}${_prefixFileExt_${_language}}")
2184         else()
2185                 set (_prefixFileBaseName "")
2186                 set (_prefixFileName "")
2187         endif()
2188         set (${_prefixFileBaseNameVar} "${_prefixFileBaseName}" PARENT_SCOPE)
2189         set (${_prefixFileNameVar} "${_prefixFileName}" PARENT_SCOPE)
2190 endfunction()
2191
2192 function (cotire_make_prefix_file_path _language _target _prefixFileVar)
2193         cotire_make_prefix_file_name("${_language}" "${_target}" _prefixFileBaseName _prefixFileName)
2194         set (${_prefixFileVar} "" PARENT_SCOPE)
2195         if (_prefixFileName)
2196                 if (NOT _language)
2197                         set (_language "C")
2198                 endif()
2199                 if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang|Intel|MSVC")
2200                         cotire_get_intermediate_dir(_baseDir)
2201                         set (${_prefixFileVar} "${_baseDir}/${_prefixFileName}" PARENT_SCOPE)
2202                 endif()
2203         endif()
2204 endfunction()
2205
2206 function (cotire_make_pch_file_path _language _target _pchFileVar)
2207         cotire_make_prefix_file_name("${_language}" "${_target}" _prefixFileBaseName _prefixFileName)
2208         set (${_pchFileVar} "" PARENT_SCOPE)
2209         if (_prefixFileBaseName AND _prefixFileName)
2210                 cotire_check_precompiled_header_support("${_language}" "${_target}" _msg)
2211                 if (NOT _msg)
2212                         if (XCODE)
2213                                 # For Xcode, we completely hand off the compilation of the prefix header to the IDE
2214                                 return()
2215                         endif()
2216                         cotire_get_intermediate_dir(_baseDir)
2217                         if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC")
2218                                 # MSVC uses the extension .pch added to the prefix header base name
2219                                 set (${_pchFileVar} "${_baseDir}/${_prefixFileBaseName}.pch" PARENT_SCOPE)
2220                         elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Clang")
2221                                 # Clang looks for a precompiled header corresponding to the prefix header with the extension .pch appended
2222                                 set (${_pchFileVar} "${_baseDir}/${_prefixFileName}.pch" PARENT_SCOPE)
2223                         elseif (CMAKE_${_language}_COMPILER_ID MATCHES "GNU")
2224                                 # GCC looks for a precompiled header corresponding to the prefix header with the extension .gch appended
2225                                 set (${_pchFileVar} "${_baseDir}/${_prefixFileName}.gch" PARENT_SCOPE)
2226                         elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Intel")
2227                                 # Intel uses the extension .pchi added to the prefix header base name
2228                                 set (${_pchFileVar} "${_baseDir}/${_prefixFileBaseName}.pchi" PARENT_SCOPE)
2229                         endif()
2230                 endif()
2231         endif()
2232 endfunction()
2233
2234 function (cotire_select_unity_source_files _unityFile _sourcesVar)
2235         set (_sourceFiles ${ARGN})
2236         if (_sourceFiles AND "${_unityFile}" MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}_([0-9]+)_([0-9]+)")
2237                 set (_startIndex ${CMAKE_MATCH_1})
2238                 set (_endIndex ${CMAKE_MATCH_2})
2239                 list (LENGTH _sourceFiles _numberOfSources)
2240                 if (NOT _startIndex LESS _numberOfSources)
2241                         math (EXPR _startIndex "${_numberOfSources} - 1")
2242                 endif()
2243                 if (NOT _endIndex LESS _numberOfSources)
2244                         math (EXPR _endIndex "${_numberOfSources} - 1")
2245                 endif()
2246                 set (_files "")
2247                 foreach (_index RANGE ${_startIndex} ${_endIndex})
2248                         list (GET _sourceFiles ${_index} _file)
2249                         list (APPEND _files "${_file}")
2250                 endforeach()
2251         else()
2252                 set (_files ${_sourceFiles})
2253         endif()
2254         set (${_sourcesVar} ${_files} PARENT_SCOPE)
2255 endfunction()
2256
2257 function (cotire_get_unity_source_dependencies _language _target _dependencySourcesVar)
2258         set (_dependencySources "")
2259         # depend on target's generated source files
2260         get_target_property(_targetSourceFiles ${_target} SOURCES)
2261         cotire_get_objects_with_property_on(_generatedSources GENERATED SOURCE ${_targetSourceFiles})
2262         if (_generatedSources)
2263                 # but omit all generated source files that have the COTIRE_EXCLUDED property set to true
2264                 cotire_get_objects_with_property_on(_excludedGeneratedSources COTIRE_EXCLUDED SOURCE ${_generatedSources})
2265                 if (_excludedGeneratedSources)
2266                         list (REMOVE_ITEM _generatedSources ${_excludedGeneratedSources})
2267                 endif()
2268                 # and omit all generated source files that have the COTIRE_DEPENDENCY property set to false explicitly
2269                 cotire_get_objects_with_property_off(_excludedNonDependencySources COTIRE_DEPENDENCY SOURCE ${_generatedSources})
2270                 if (_excludedNonDependencySources)
2271                         list (REMOVE_ITEM _generatedSources ${_excludedNonDependencySources})
2272                 endif()
2273                 if (_generatedSources)
2274                         list (APPEND _dependencySources ${_generatedSources})
2275                 endif()
2276         endif()
2277         if (COTIRE_DEBUG AND _dependencySources)
2278                 message (STATUS "${_language} ${_target} unity source dependencies: ${_dependencySources}")
2279         endif()
2280         set (${_dependencySourcesVar} ${_dependencySources} PARENT_SCOPE)
2281 endfunction()
2282
2283 function (cotire_get_prefix_header_dependencies _language _target _dependencySourcesVar)
2284         set (_dependencySources "")
2285         # depend on target source files marked with custom COTIRE_DEPENDENCY property
2286         get_target_property(_targetSourceFiles ${_target} SOURCES)
2287         cotire_get_objects_with_property_on(_dependencySources COTIRE_DEPENDENCY SOURCE ${_targetSourceFiles})
2288         if (COTIRE_DEBUG AND _dependencySources)
2289                 message (STATUS "${_language} ${_target} prefix header dependencies: ${_dependencySources}")
2290         endif()
2291         set (${_dependencySourcesVar} ${_dependencySources} PARENT_SCOPE)
2292 endfunction()
2293
2294 function (cotire_generate_target_script _language _configurations _target _targetScriptVar _targetConfigScriptVar)
2295         set (_targetSources ${ARGN})
2296         cotire_get_prefix_header_dependencies(${_language} ${_target} COTIRE_TARGET_PREFIX_DEPENDS ${_targetSources})
2297         cotire_get_unity_source_dependencies(${_language} ${_target} COTIRE_TARGET_UNITY_DEPENDS ${_targetSources})
2298         # set up variables to be configured
2299         set (COTIRE_TARGET_LANGUAGE "${_language}")
2300         get_target_property(COTIRE_TARGET_IGNORE_PATH ${_target} COTIRE_PREFIX_HEADER_IGNORE_PATH)
2301         cotire_add_sys_root_paths(COTIRE_TARGET_IGNORE_PATH)
2302         get_target_property(COTIRE_TARGET_INCLUDE_PATH ${_target} COTIRE_PREFIX_HEADER_INCLUDE_PATH)
2303         cotire_add_sys_root_paths(COTIRE_TARGET_INCLUDE_PATH)
2304         get_target_property(COTIRE_TARGET_PRE_UNDEFS ${_target} COTIRE_UNITY_SOURCE_PRE_UNDEFS)
2305         get_target_property(COTIRE_TARGET_POST_UNDEFS ${_target} COTIRE_UNITY_SOURCE_POST_UNDEFS)
2306         get_target_property(COTIRE_TARGET_MAXIMUM_NUMBER_OF_INCLUDES ${_target} COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES)
2307         get_target_property(COTIRE_TARGET_INCLUDE_PRIORITY_PATH ${_target} COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH)
2308         cotire_get_source_files_undefs(COTIRE_UNITY_SOURCE_PRE_UNDEFS COTIRE_TARGET_SOURCES_PRE_UNDEFS ${_targetSources})
2309         cotire_get_source_files_undefs(COTIRE_UNITY_SOURCE_POST_UNDEFS COTIRE_TARGET_SOURCES_POST_UNDEFS ${_targetSources})
2310         set (COTIRE_TARGET_CONFIGURATION_TYPES "${_configurations}")
2311         foreach (_config ${_configurations})
2312                 string (TOUPPER "${_config}" _upperConfig)
2313                 cotire_get_target_include_directories(
2314                         "${_config}" "${_language}" "${_target}" COTIRE_TARGET_INCLUDE_DIRECTORIES_${_upperConfig} COTIRE_TARGET_SYSTEM_INCLUDE_DIRECTORIES_${_upperConfig})
2315                 cotire_get_target_compile_definitions(
2316                         "${_config}" "${_language}" "${_target}" COTIRE_TARGET_COMPILE_DEFINITIONS_${_upperConfig})
2317                 cotire_get_target_compiler_flags(
2318                         "${_config}" "${_language}" "${_target}" COTIRE_TARGET_COMPILE_FLAGS_${_upperConfig})
2319                 cotire_get_source_files_compile_definitions(
2320                         "${_config}" "${_language}" COTIRE_TARGET_SOURCES_COMPILE_DEFINITIONS_${_upperConfig} ${_targetSources})
2321         endforeach()
2322         get_target_property(COTIRE_TARGET_${_language}_COMPILER_LAUNCHER ${_target} ${_language}_COMPILER_LAUNCHER)
2323         # set up COTIRE_TARGET_SOURCES
2324         set (COTIRE_TARGET_SOURCES "")
2325         foreach (_sourceFile ${_targetSources})
2326                 get_source_file_property(_generated "${_sourceFile}" GENERATED)
2327                 if (_generated)
2328                         # use absolute paths for generated files only, retrieving the LOCATION property is an expensive operation
2329                         get_source_file_property(_sourceLocation "${_sourceFile}" LOCATION)
2330                         list (APPEND COTIRE_TARGET_SOURCES "${_sourceLocation}")
2331                 else()
2332                         list (APPEND COTIRE_TARGET_SOURCES "${_sourceFile}")
2333                 endif()
2334         endforeach()
2335         # copy variable definitions to cotire target script
2336         get_cmake_property(_vars VARIABLES)
2337         string (REGEX MATCHALL "COTIRE_[A-Za-z0-9_]+" _matchVars "${_vars}")
2338         # omit COTIRE_*_INIT variables
2339         string (REGEX MATCHALL "COTIRE_[A-Za-z0-9_]+_INIT" _initVars "${_matchVars}")
2340         if (_initVars)
2341                 list (REMOVE_ITEM _matchVars ${_initVars})
2342         endif()
2343         # omit COTIRE_VERBOSE which is passed as a CMake define on command line
2344         list (REMOVE_ITEM _matchVars COTIRE_VERBOSE)
2345         set (_contents "")
2346         set (_contentsHasGeneratorExpressions FALSE)
2347         foreach (_var IN LISTS _matchVars ITEMS
2348                 XCODE MSVC CMAKE_GENERATOR CMAKE_BUILD_TYPE CMAKE_CONFIGURATION_TYPES
2349                 CMAKE_${_language}_COMPILER_ID CMAKE_${_language}_COMPILER_VERSION
2350                 CMAKE_${_language}_COMPILER_LAUNCHER CMAKE_${_language}_COMPILER CMAKE_${_language}_COMPILER_ARG1
2351                 CMAKE_INCLUDE_FLAG_${_language} CMAKE_INCLUDE_FLAG_SEP_${_language}
2352                 CMAKE_INCLUDE_SYSTEM_FLAG_${_language}
2353                 CMAKE_${_language}_FRAMEWORK_SEARCH_FLAG
2354                 CMAKE_${_language}_SYSTEM_FRAMEWORK_SEARCH_FLAG
2355                 CMAKE_${_language}_SOURCE_FILE_EXTENSIONS)
2356                 if (DEFINED ${_var})
2357                         string (REPLACE "\"" "\\\"" _value "${${_var}}")
2358                         set (_contents "${_contents}set (${_var} \"${_value}\")\n")
2359                         if (NOT _contentsHasGeneratorExpressions)
2360                                 if ("${_value}" MATCHES "\\$<.*>")
2361                                         set (_contentsHasGeneratorExpressions TRUE)
2362                                 endif()
2363                         endif()
2364                 endif()
2365         endforeach()
2366         # generate target script file
2367         get_filename_component(_moduleName "${COTIRE_CMAKE_MODULE_FILE}" NAME)
2368         set (_targetCotireScript "${CMAKE_CURRENT_BINARY_DIR}/${_target}_${_language}_${_moduleName}")
2369         cotire_write_file("CMAKE" "${_targetCotireScript}" "${_contents}" FALSE)
2370         if (_contentsHasGeneratorExpressions)
2371                 # use file(GENERATE ...) to expand generator expressions in the target script at CMake generate-time
2372                 set (_configNameOrNoneGeneratorExpression "$<$<CONFIG:>:None>$<$<NOT:$<CONFIG:>>:$<CONFIGURATION>>")
2373                 set (_targetCotireConfigScript "${CMAKE_CURRENT_BINARY_DIR}/${_target}_${_language}_${_configNameOrNoneGeneratorExpression}_${_moduleName}")
2374                 file (GENERATE OUTPUT "${_targetCotireConfigScript}" INPUT "${_targetCotireScript}")
2375         else()
2376                 set (_targetCotireConfigScript "${_targetCotireScript}")
2377         endif()
2378         set (${_targetScriptVar} "${_targetCotireScript}" PARENT_SCOPE)
2379         set (${_targetConfigScriptVar} "${_targetCotireConfigScript}" PARENT_SCOPE)
2380 endfunction()
2381
2382 function (cotire_setup_pch_file_compilation _language _target _targetScript _prefixFile _pchFile _hostFile)
2383         set (_sourceFiles ${ARGN})
2384         if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel" OR
2385                 (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "Clang"))
2386                 # for MSVC, Intel and Clang-cl, we attach the precompiled header compilation to the host file
2387                 # the remaining files include the precompiled header, see cotire_setup_pch_file_inclusion
2388                 if (_sourceFiles)
2389                         set (_flags "")
2390                         cotire_add_pch_compilation_flags(
2391                                 "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}"
2392                                 "${_prefixFile}" "${_pchFile}" "${_hostFile}" _flags)
2393                         set_property (SOURCE ${_hostFile} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ")
2394                         set_property (SOURCE ${_hostFile} APPEND PROPERTY OBJECT_OUTPUTS "${_pchFile}")
2395                         # make object file generated from host file depend on prefix header
2396                         set_property (SOURCE ${_hostFile} APPEND PROPERTY OBJECT_DEPENDS "${_prefixFile}")
2397                         # mark host file as cotired to prevent it from being used in another cotired target
2398                         set_property (SOURCE ${_hostFile} PROPERTY COTIRE_TARGET "${_target}")
2399                 endif()
2400         elseif ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
2401                 # for makefile based generator, we add a custom command to precompile the prefix header
2402                 if (_targetScript)
2403                         cotire_set_cmd_to_prologue(_cmds)
2404                         list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "precompile" "${_targetScript}" "${_prefixFile}" "${_pchFile}" "${_hostFile}")
2405                         if (MSVC_IDE)
2406                                 file (TO_NATIVE_PATH "${_pchFile}" _pchFileLogPath)
2407                         else()
2408                                 file (RELATIVE_PATH _pchFileLogPath "${CMAKE_BINARY_DIR}" "${_pchFile}")
2409                         endif()
2410                         # make precompiled header compilation depend on the actual compiler executable used to force
2411                         # re-compilation when the compiler executable is updated. This prevents "created by a different GCC executable"
2412                         # warnings when the precompiled header is included.
2413                         get_filename_component(_realCompilerExe "${CMAKE_${_language}_COMPILER}" ABSOLUTE)
2414                         if (COTIRE_DEBUG)
2415                                 message (STATUS "add_custom_command: OUTPUT ${_pchFile} ${_cmds} DEPENDS ${_prefixFile} ${_realCompilerExe} IMPLICIT_DEPENDS ${_language} ${_prefixFile}")
2416                         endif()
2417                         set_property (SOURCE "${_pchFile}" PROPERTY GENERATED TRUE)
2418                         add_custom_command(
2419                                 OUTPUT "${_pchFile}"
2420                                 COMMAND ${_cmds}
2421                                 DEPENDS "${_prefixFile}" "${_realCompilerExe}"
2422                                 IMPLICIT_DEPENDS ${_language} "${_prefixFile}"
2423                                 WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
2424                                 COMMENT "Building ${_language} precompiled header ${_pchFileLogPath}"
2425                                 VERBATIM)
2426                 endif()
2427         endif()
2428 endfunction()
2429
2430 function (cotire_setup_pch_file_inclusion _language _target _wholeTarget _prefixFile _pchFile _hostFile)
2431         if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel" OR
2432                 (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "Clang"))
2433                 # for MSVC, Intel and clang-cl, we include the precompiled header in all but the host file
2434                 # the host file does the precompiled header compilation, see cotire_setup_pch_file_compilation
2435                 set (_sourceFiles ${ARGN})
2436                 list (LENGTH _sourceFiles _numberOfSourceFiles)
2437                 if (_numberOfSourceFiles GREATER 0)
2438                         # mark sources as cotired to prevent them from being used in another cotired target
2439                         set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}")
2440                         set (_flags "")
2441                         cotire_add_prefix_pch_inclusion_flags(
2442                                 "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}"
2443                                 "${_prefixFile}" "${_pchFile}" _flags)
2444                         set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ")
2445                         # make object files generated from source files depend on precompiled header
2446                         set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_pchFile}")
2447                 endif()
2448         elseif ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
2449                 set (_sourceFiles ${_hostFile} ${ARGN})
2450                 if (NOT _wholeTarget)
2451                         # for makefile based generator, we force the inclusion of the prefix header for a subset
2452                         # of the source files, if this is a multi-language target or has excluded files
2453                         set (_flags "")
2454                         cotire_add_prefix_pch_inclusion_flags(
2455                                 "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}"
2456                                 "${_prefixFile}" "${_pchFile}" _flags)
2457                         set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ")
2458                         # mark sources as cotired to prevent them from being used in another cotired target
2459                         set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}")
2460                 endif()
2461                 # make object files generated from source files depend on precompiled header
2462                 set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_pchFile}")
2463         endif()
2464 endfunction()
2465
2466 function (cotire_setup_prefix_file_inclusion _language _target _prefixFile)
2467         set (_sourceFiles ${ARGN})
2468         # force the inclusion of the prefix header for the given source files
2469         set (_flags "")
2470         set (_pchFile "")
2471         cotire_add_prefix_pch_inclusion_flags(
2472                 "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}"
2473                 "${_prefixFile}" "${_pchFile}" _flags)
2474         set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ")
2475         # mark sources as cotired to prevent them from being used in another cotired target
2476         set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}")
2477         # make object files generated from source files depend on prefix header
2478         set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_prefixFile}")
2479 endfunction()
2480
2481 function (cotire_get_first_set_property_value _propertyValueVar _type _object)
2482         set (_properties ${ARGN})
2483         foreach (_property ${_properties})
2484                 get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property})
2485                 if (_propertyValue)
2486                         set (${_propertyValueVar} ${_propertyValue} PARENT_SCOPE)
2487                         return()
2488                 endif()
2489         endforeach()
2490         set (${_propertyValueVar} "" PARENT_SCOPE)
2491 endfunction()
2492
2493 function (cotire_setup_combine_command _language _targetScript _joinedFile _cmdsVar)
2494         set (_files ${ARGN})
2495         set (_filesPaths "")
2496         foreach (_file ${_files})
2497                 get_filename_component(_filePath "${_file}" ABSOLUTE)
2498                 list (APPEND _filesPaths "${_filePath}")
2499         endforeach()
2500         cotire_set_cmd_to_prologue(_prefixCmd)
2501         list (APPEND _prefixCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "combine")
2502         if (_targetScript)
2503                 list (APPEND _prefixCmd "${_targetScript}")
2504         endif()
2505         list (APPEND _prefixCmd "${_joinedFile}" ${_filesPaths})
2506         if (COTIRE_DEBUG)
2507                 message (STATUS "add_custom_command: OUTPUT ${_joinedFile} COMMAND ${_prefixCmd} DEPENDS ${_files}")
2508         endif()
2509         set_property (SOURCE "${_joinedFile}" PROPERTY GENERATED TRUE)
2510         if (MSVC_IDE)
2511                 file (TO_NATIVE_PATH "${_joinedFile}" _joinedFileLogPath)
2512         else()
2513                 file (RELATIVE_PATH _joinedFileLogPath "${CMAKE_BINARY_DIR}" "${_joinedFile}")
2514         endif()
2515         get_filename_component(_joinedFileBaseName "${_joinedFile}" NAME_WE)
2516         get_filename_component(_joinedFileExt "${_joinedFile}" EXT)
2517         if (_language AND _joinedFileBaseName MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}$")
2518                 set (_comment "Generating ${_language} unity source ${_joinedFileLogPath}")
2519         elseif (_language AND _joinedFileBaseName MATCHES "${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}$")
2520                 if (_joinedFileExt MATCHES "^\\.c")
2521                         set (_comment "Generating ${_language} prefix source ${_joinedFileLogPath}")
2522                 else()
2523                         set (_comment "Generating ${_language} prefix header ${_joinedFileLogPath}")
2524                 endif()
2525         else()
2526                 set (_comment "Generating ${_joinedFileLogPath}")
2527         endif()
2528         add_custom_command(
2529                 OUTPUT "${_joinedFile}"
2530                 COMMAND ${_prefixCmd}
2531                 DEPENDS ${_files}
2532                 COMMENT "${_comment}"
2533                 WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
2534                 VERBATIM)
2535         list (APPEND ${_cmdsVar} COMMAND ${_prefixCmd})
2536         set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE)
2537 endfunction()
2538
2539 function (cotire_setup_target_pch_usage _languages _target _wholeTarget)
2540         if (XCODE)
2541                 # for Xcode, we attach a pre-build action to generate the unity sources and prefix headers
2542                 set (_prefixFiles "")
2543                 foreach (_language ${_languages})
2544                         get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER)
2545                         if (_prefixFile)
2546                                 list (APPEND _prefixFiles "${_prefixFile}")
2547                         endif()
2548                 endforeach()
2549                 set (_cmds ${ARGN})
2550                 list (LENGTH _prefixFiles _numberOfPrefixFiles)
2551                 if (_numberOfPrefixFiles GREATER 1)
2552                         # we also generate a generic, single prefix header which includes all language specific prefix headers
2553                         set (_language "")
2554                         set (_targetScript "")
2555                         cotire_make_prefix_file_path("${_language}" ${_target} _prefixHeader)
2556                         cotire_setup_combine_command("${_language}" "${_targetScript}" "${_prefixHeader}" _cmds ${_prefixFiles})
2557                 else()
2558                         set (_prefixHeader "${_prefixFiles}")
2559                 endif()
2560                 if (COTIRE_DEBUG)
2561                         message (STATUS "add_custom_command: TARGET ${_target} PRE_BUILD ${_cmds}")
2562                 endif()
2563                 # because CMake PRE_BUILD command does not support dependencies,
2564                 # we check dependencies explicity in cotire script mode when the pre-build action is run
2565                 add_custom_command(
2566                         TARGET "${_target}"
2567                         PRE_BUILD ${_cmds}
2568                         WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
2569                         COMMENT "Updating target ${_target} prefix headers"
2570                         VERBATIM)
2571                 # make Xcode precompile the generated prefix header with ProcessPCH and ProcessPCH++
2572                 set_target_properties(${_target} PROPERTIES XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER "YES")
2573                 set_target_properties(${_target} PROPERTIES XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${_prefixHeader}")
2574         elseif ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
2575                 # for makefile based generator, we force inclusion of the prefix header for all target source files
2576                 # if this is a single-language target without any excluded files
2577                 if (_wholeTarget)
2578                         set (_language "${_languages}")
2579                         # for MSVC, Intel and clang-cl, precompiled header inclusion is always done on the source file level
2580                         # see cotire_setup_pch_file_inclusion
2581                         if (NOT CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel" AND NOT
2582                                 (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "Clang"))
2583                                 get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER)
2584                                 if (_prefixFile)
2585                                         get_property(_pchFile TARGET ${_target} PROPERTY COTIRE_${_language}_PRECOMPILED_HEADER)
2586                                         set (_options COMPILE_OPTIONS)
2587                                         cotire_add_prefix_pch_inclusion_flags(
2588                                                 "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}"
2589                                                 "${_prefixFile}" "${_pchFile}" _options)
2590                                         set_property(TARGET ${_target} APPEND PROPERTY ${_options})
2591                                 endif()
2592                         endif()
2593                 endif()
2594         endif()
2595 endfunction()
2596
2597 function (cotire_setup_unity_generation_commands _language _target _targetScript _targetConfigScript _unityFiles _cmdsVar)
2598         set (_dependencySources "")
2599         cotire_get_unity_source_dependencies(${_language} ${_target} _dependencySources ${ARGN})
2600         foreach (_unityFile ${_unityFiles})
2601                 set_property (SOURCE "${_unityFile}" PROPERTY GENERATED TRUE)
2602                 # set up compiled unity source dependencies via OBJECT_DEPENDS
2603                 # this ensures that missing source files are generated before the unity file is compiled
2604                 if (COTIRE_DEBUG AND _dependencySources)
2605                         message (STATUS "${_unityFile} OBJECT_DEPENDS ${_dependencySources}")
2606                 endif()
2607                 if (_dependencySources)
2608                         # the OBJECT_DEPENDS property requires a list of full paths
2609                         set (_objectDependsPaths "")
2610                         foreach (_sourceFile ${_dependencySources})
2611                                 get_source_file_property(_sourceLocation "${_sourceFile}" LOCATION)
2612                                 list (APPEND _objectDependsPaths "${_sourceLocation}")
2613                         endforeach()
2614                         set_property (SOURCE "${_unityFile}" PROPERTY OBJECT_DEPENDS ${_objectDependsPaths})
2615                 endif()
2616                 if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
2617                         # unity file compilation results in potentially huge object file,
2618                         # thus use /bigobj by default unter cl.exe and Windows Intel
2619                         set_property (SOURCE "${_unityFile}" APPEND_STRING PROPERTY COMPILE_FLAGS "/bigobj")
2620                 endif()
2621                 cotire_set_cmd_to_prologue(_unityCmd)
2622                 list (APPEND _unityCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "unity" "${_targetConfigScript}" "${_unityFile}")
2623                 if (CMAKE_VERSION VERSION_LESS "3.1.0")
2624                         set (_unityCmdDepends "${_targetScript}")
2625                 else()
2626                         # CMake 3.1.0 supports generator expressions in arguments to DEPENDS
2627                         set (_unityCmdDepends "${_targetConfigScript}")
2628                 endif()
2629                 if (MSVC_IDE)
2630                         file (TO_NATIVE_PATH "${_unityFile}" _unityFileLogPath)
2631                 else()
2632                         file (RELATIVE_PATH _unityFileLogPath "${CMAKE_BINARY_DIR}" "${_unityFile}")
2633                 endif()
2634                 if (COTIRE_DEBUG)
2635                         message (STATUS "add_custom_command: OUTPUT ${_unityFile} COMMAND ${_unityCmd} DEPENDS ${_unityCmdDepends}")
2636                 endif()
2637                 add_custom_command(
2638                         OUTPUT "${_unityFile}"
2639                         COMMAND ${_unityCmd}
2640                         DEPENDS ${_unityCmdDepends}
2641                         COMMENT "Generating ${_language} unity source ${_unityFileLogPath}"
2642                         WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
2643                         VERBATIM)
2644                 list (APPEND ${_cmdsVar} COMMAND ${_unityCmd})
2645         endforeach()
2646         set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE)
2647 endfunction()
2648
2649 function (cotire_setup_prefix_generation_command _language _target _targetScript _prefixFile _unityFiles _cmdsVar)
2650         set (_sourceFiles ${ARGN})
2651         set (_dependencySources "")
2652         cotire_get_prefix_header_dependencies(${_language} ${_target} _dependencySources ${_sourceFiles})
2653         cotire_set_cmd_to_prologue(_prefixCmd)
2654         list (APPEND _prefixCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "prefix" "${_targetScript}" "${_prefixFile}" ${_unityFiles})
2655         set_property (SOURCE "${_prefixFile}" PROPERTY GENERATED TRUE)
2656         # make prefix header generation depend on the actual compiler executable used to force
2657         # re-generation when the compiler executable is updated. This prevents "file not found"
2658         # errors for compiler version specific system header files.
2659         get_filename_component(_realCompilerExe "${CMAKE_${_language}_COMPILER}" ABSOLUTE)
2660         if (COTIRE_DEBUG)
2661                 message (STATUS "add_custom_command: OUTPUT ${_prefixFile} COMMAND ${_prefixCmd} DEPENDS ${_unityFile} ${_dependencySources} ${_realCompilerExe}")
2662         endif()
2663         if (MSVC_IDE)
2664                 file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileLogPath)
2665         else()
2666                 file (RELATIVE_PATH _prefixFileLogPath "${CMAKE_BINARY_DIR}" "${_prefixFile}")
2667         endif()
2668         get_filename_component(_prefixFileExt "${_prefixFile}" EXT)
2669         if (_prefixFileExt MATCHES "^\\.c")
2670                 set (_comment "Generating ${_language} prefix source ${_prefixFileLogPath}")
2671         else()
2672                 set (_comment "Generating ${_language} prefix header ${_prefixFileLogPath}")
2673         endif()
2674         # prevent pre-processing errors upon generating the prefix header when a target's generated include file does not yet exist
2675         # we do not add a file-level dependency for the target's generated files though, because we only want to depend on their existence
2676         # thus we make the prefix header generation depend on a custom helper target which triggers the generation of the files
2677         set (_preTargetName "${_target}${COTIRE_PCH_TARGET_SUFFIX}_pre")
2678         if (TARGET ${_preTargetName})
2679                 # custom helper target has already been generated while processing a different language
2680                 list (APPEND _dependencySources ${_preTargetName})
2681         else()
2682                 get_target_property(_targetSourceFiles ${_target} SOURCES)
2683                 cotire_get_objects_with_property_on(_generatedSources GENERATED SOURCE ${_targetSourceFiles})
2684                 if (_generatedSources)
2685                         add_custom_target("${_preTargetName}" DEPENDS ${_generatedSources})
2686                         cotire_init_target("${_preTargetName}")
2687                         list (APPEND _dependencySources ${_preTargetName})
2688                 endif()
2689         endif()
2690         add_custom_command(
2691                 OUTPUT "${_prefixFile}" "${_prefixFile}.log"
2692                 COMMAND ${_prefixCmd}
2693                 DEPENDS ${_unityFiles} ${_dependencySources} "${_realCompilerExe}"
2694                 COMMENT "${_comment}"
2695                 WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
2696                 VERBATIM)
2697         list (APPEND ${_cmdsVar} COMMAND ${_prefixCmd})
2698         set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE)
2699 endfunction()
2700
2701 function (cotire_setup_prefix_generation_from_unity_command _language _target _targetScript _prefixFile _unityFiles _cmdsVar)
2702         set (_sourceFiles ${ARGN})
2703         if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang")
2704                 # GNU and Clang require indirect compilation of the prefix header to make them honor the system_header pragma
2705                 cotire_prefix_header_to_source_file_path(${_language} "${_prefixFile}" _prefixSourceFile)
2706         else()
2707                 set (_prefixSourceFile "${_prefixFile}")
2708         endif()
2709         cotire_setup_prefix_generation_command(
2710                 ${_language} ${_target} "${_targetScript}"
2711                 "${_prefixSourceFile}" "${_unityFiles}" ${_cmdsVar} ${_sourceFiles})
2712         if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang")
2713                 # set up generation of a prefix source file which includes the prefix header
2714                 cotire_setup_combine_command(${_language} "${_targetScript}" "${_prefixFile}" _cmds ${_prefixSourceFile})
2715         endif()
2716         set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE)
2717 endfunction()
2718
2719 function (cotire_setup_prefix_generation_from_provided_command _language _target _targetScript _prefixFile _cmdsVar)
2720         set (_prefixHeaderFiles ${ARGN})
2721         if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang")
2722                 # GNU and Clang require indirect compilation of the prefix header to make them honor the system_header pragma
2723                 cotire_prefix_header_to_source_file_path(${_language} "${_prefixFile}" _prefixSourceFile)
2724         else()
2725                 set (_prefixSourceFile "${_prefixFile}")
2726         endif()
2727         cotire_setup_combine_command(${_language} "${_targetScript}" "${_prefixSourceFile}" _cmds ${_prefixHeaderFiles})
2728         if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang")
2729                 # set up generation of a prefix source file which includes the prefix header
2730                 cotire_setup_combine_command(${_language} "${_targetScript}" "${_prefixFile}" _cmds ${_prefixSourceFile})
2731         endif()
2732         set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE)
2733 endfunction()
2734
2735 function (cotire_init_cotire_target_properties _target)
2736         get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER SET)
2737         if (NOT _isSet)
2738                 set_property(TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER TRUE)
2739         endif()
2740         get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD SET)
2741         if (NOT _isSet)
2742                 set_property(TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD TRUE)
2743         endif()
2744         get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ADD_CLEAN SET)
2745         if (NOT _isSet)
2746                 set_property(TARGET ${_target} PROPERTY COTIRE_ADD_CLEAN FALSE)
2747         endif()
2748         get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH SET)
2749         if (NOT _isSet)
2750                 set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH "${CMAKE_SOURCE_DIR}")
2751                 cotire_check_is_path_relative_to("${CMAKE_BINARY_DIR}" _isRelative "${CMAKE_SOURCE_DIR}")
2752                 if (NOT _isRelative)
2753                         set_property(TARGET ${_target} APPEND PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH "${CMAKE_BINARY_DIR}")
2754                 endif()
2755         endif()
2756         get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PATH SET)
2757         if (NOT _isSet)
2758                 set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PATH "")
2759         endif()
2760         get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH SET)
2761         if (NOT _isSet)
2762                 set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH "")
2763         endif()
2764         get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_PRE_UNDEFS SET)
2765         if (NOT _isSet)
2766                 set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_PRE_UNDEFS "")
2767         endif()
2768         get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_POST_UNDEFS SET)
2769         if (NOT _isSet)
2770                 set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_POST_UNDEFS "")
2771         endif()
2772         get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_LINK_LIBRARIES_INIT SET)
2773         if (NOT _isSet)
2774                 set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_LINK_LIBRARIES_INIT "COPY_UNITY")
2775         endif()
2776         get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES SET)
2777         if (NOT _isSet)
2778                 if (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES)
2779                         set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES}")
2780                 else()
2781                         set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "")
2782                 endif()
2783         endif()
2784 endfunction()
2785
2786 function (cotire_make_target_message _target _languages _disableMsg _targetMsgVar)
2787         get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER)
2788         get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD)
2789         string (REPLACE ";" " " _languagesStr "${_languages}")
2790         math (EXPR _numberOfExcludedFiles "${ARGC} - 4")
2791         if (_numberOfExcludedFiles EQUAL 0)
2792                 set (_excludedStr "")
2793         elseif (COTIRE_VERBOSE OR _numberOfExcludedFiles LESS 4)
2794                 string (REPLACE ";" ", " _excludedStr "excluding ${ARGN}")
2795         else()
2796                 set (_excludedStr "excluding ${_numberOfExcludedFiles} files")
2797         endif()
2798         set (_targetMsg "")
2799         if (NOT _languages)
2800                 set (_targetMsg "Target ${_target} cannot be cotired.")
2801                 if (_disableMsg)
2802                         set (_targetMsg "${_targetMsg} ${_disableMsg}")
2803                 endif()
2804         elseif (NOT _targetUsePCH AND NOT _targetAddSCU)
2805                 set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build and precompiled header.")
2806                 if (_disableMsg)
2807                         set (_targetMsg "${_targetMsg} ${_disableMsg}")
2808                 endif()
2809         elseif (NOT _targetUsePCH)
2810                 if (_excludedStr)
2811                         set (_targetMsg "${_languagesStr} target ${_target} cotired without precompiled header ${_excludedStr}.")
2812                 else()
2813                         set (_targetMsg "${_languagesStr} target ${_target} cotired without precompiled header.")
2814                 endif()
2815                 if (_disableMsg)
2816                         set (_targetMsg "${_targetMsg} ${_disableMsg}")
2817                 endif()
2818         elseif (NOT _targetAddSCU)
2819                 if (_excludedStr)
2820                         set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build ${_excludedStr}.")
2821                 else()
2822                         set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build.")
2823                 endif()
2824                 if (_disableMsg)
2825                         set (_targetMsg "${_targetMsg} ${_disableMsg}")
2826                 endif()
2827         else()
2828                 if (_excludedStr)
2829                         set (_targetMsg "${_languagesStr} target ${_target} cotired ${_excludedStr}.")
2830                 else()
2831                         set (_targetMsg "${_languagesStr} target ${_target} cotired.")
2832                 endif()
2833         endif()
2834         set (${_targetMsgVar} "${_targetMsg}" PARENT_SCOPE)
2835 endfunction()
2836
2837 function (cotire_choose_target_languages _target _targetLanguagesVar _wholeTargetVar)
2838         set (_languages ${ARGN})
2839         set (_allSourceFiles "")
2840         set (_allExcludedSourceFiles "")
2841         set (_allCotiredSourceFiles "")
2842         set (_targetLanguages "")
2843         set (_pchEligibleTargetLanguages "")
2844         get_target_property(_targetType ${_target} TYPE)
2845         get_target_property(_targetSourceFiles ${_target} SOURCES)
2846         get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER)
2847         get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD)
2848         set (_disableMsg "")
2849         foreach (_language ${_languages})
2850                 get_target_property(_prefixHeader ${_target} COTIRE_${_language}_PREFIX_HEADER)
2851                 get_target_property(_unityBuildFile ${_target} COTIRE_${_language}_UNITY_SOURCE)
2852                 if (_prefixHeader OR _unityBuildFile)
2853                         message (STATUS "cotire: target ${_target} has already been cotired.")
2854                         set (${_targetLanguagesVar} "" PARENT_SCOPE)
2855                         return()
2856                 endif()
2857                 if (_targetUsePCH AND "${_language}" MATCHES "^C|CXX$" AND DEFINED CMAKE_${_language}_COMPILER_ID)
2858                         if (CMAKE_${_language}_COMPILER_ID)
2859                                 cotire_check_precompiled_header_support("${_language}" "${_target}" _disableMsg)
2860                                 if (_disableMsg)
2861                                         set (_targetUsePCH FALSE)
2862                                 endif()
2863                         endif()
2864                 endif()
2865                 set (_sourceFiles "")
2866                 set (_excludedSources "")
2867                 set (_cotiredSources "")
2868                 cotire_filter_language_source_files(${_language} ${_target} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles})
2869                 if (_sourceFiles OR _excludedSources OR _cotiredSources)
2870                         list (APPEND _targetLanguages ${_language})
2871                 endif()
2872                 if (_sourceFiles)
2873                         list (APPEND _allSourceFiles ${_sourceFiles})
2874                 endif()
2875                 list (LENGTH _sourceFiles _numberOfSources)
2876                 if (NOT _numberOfSources LESS ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES})
2877                         list (APPEND _pchEligibleTargetLanguages ${_language})
2878                 endif()
2879                 if (_excludedSources)
2880                         list (APPEND _allExcludedSourceFiles ${_excludedSources})
2881                 endif()
2882                 if (_cotiredSources)
2883                         list (APPEND _allCotiredSourceFiles ${_cotiredSources})
2884                 endif()
2885         endforeach()
2886         set (_targetMsgLevel STATUS)
2887         if (NOT _targetLanguages)
2888                 string (REPLACE ";" " or " _languagesStr "${_languages}")
2889                 set (_disableMsg "No ${_languagesStr} source files.")
2890                 set (_targetUsePCH FALSE)
2891                 set (_targetAddSCU FALSE)
2892         endif()
2893         if (_targetUsePCH)
2894                 if (_allCotiredSourceFiles)
2895                         cotire_get_source_file_property_values(_cotireTargets COTIRE_TARGET ${_allCotiredSourceFiles})
2896                         list (REMOVE_DUPLICATES _cotireTargets)
2897                         string (REPLACE ";" ", " _cotireTargetsStr "${_cotireTargets}")
2898                         set (_disableMsg "Target sources already include a precompiled header for target(s) ${_cotireTargets}.")
2899                         set (_disableMsg "${_disableMsg} Set target property COTIRE_ENABLE_PRECOMPILED_HEADER to FALSE for targets ${_target},")
2900                         set (_disableMsg "${_disableMsg} ${_cotireTargetsStr} to get a workable build system.")
2901                         set (_targetMsgLevel SEND_ERROR)
2902                         set (_targetUsePCH FALSE)
2903                 elseif (NOT _pchEligibleTargetLanguages)
2904                         set (_disableMsg "Too few applicable sources.")
2905                         set (_targetUsePCH FALSE)
2906                 elseif (XCODE AND _allExcludedSourceFiles)
2907                         # for Xcode, we cannot apply the precompiled header to individual sources, only to the whole target
2908                         set (_disableMsg "Exclusion of source files not supported for generator Xcode.")
2909                         set (_targetUsePCH FALSE)
2910                 elseif (XCODE AND "${_targetType}" STREQUAL "OBJECT_LIBRARY")
2911                         # for Xcode, we cannot apply the required PRE_BUILD action to generate the prefix header to an OBJECT_LIBRARY target
2912                         set (_disableMsg "Required PRE_BUILD action not supported for OBJECT_LIBRARY targets for generator Xcode.")
2913                         set (_targetUsePCH FALSE)
2914                 endif()
2915         endif()
2916         if (_targetAddSCU)
2917                 # disable unity builds if automatic Qt processing is used
2918                 get_target_property(_targetAutoMoc ${_target} AUTOMOC)
2919                 get_target_property(_targetAutoUic ${_target} AUTOUIC)
2920                 get_target_property(_targetAutoRcc ${_target} AUTORCC)
2921                 if (_targetAutoMoc OR _targetAutoUic OR _targetAutoRcc)
2922                         if (_disableMsg)
2923                                 set (_disableMsg "${_disableMsg} Target uses automatic CMake Qt processing.")
2924                         else()
2925                                 set (_disableMsg "Target uses automatic CMake Qt processing.")
2926                         endif()
2927                         set (_targetAddSCU FALSE)
2928                 endif()
2929         endif()
2930         set_property(TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER ${_targetUsePCH})
2931         set_property(TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD ${_targetAddSCU})
2932         cotire_make_target_message(${_target} "${_targetLanguages}" "${_disableMsg}" _targetMsg ${_allExcludedSourceFiles})
2933         if (_targetMsg)
2934                 if (NOT DEFINED COTIREMSG_${_target})
2935                         set (COTIREMSG_${_target} "")
2936                 endif()
2937                 if (COTIRE_VERBOSE OR NOT "${_targetMsgLevel}" STREQUAL "STATUS" OR
2938                         NOT "${COTIREMSG_${_target}}" STREQUAL "${_targetMsg}")
2939                         # cache message to avoid redundant messages on re-configure
2940                         set (COTIREMSG_${_target} "${_targetMsg}" CACHE INTERNAL "${_target} cotire message.")
2941                         message (${_targetMsgLevel} "${_targetMsg}")
2942                 endif()
2943         endif()
2944         list (LENGTH _targetLanguages _numberOfLanguages)
2945         if (_numberOfLanguages GREATER 1 OR _allExcludedSourceFiles)
2946                 set (${_wholeTargetVar} FALSE PARENT_SCOPE)
2947         else()
2948                 set (${_wholeTargetVar} TRUE PARENT_SCOPE)
2949         endif()
2950         set (${_targetLanguagesVar} ${_targetLanguages} PARENT_SCOPE)
2951 endfunction()
2952
2953 function (cotire_compute_unity_max_number_of_includes _target _maxIncludesVar)
2954         set (_sourceFiles ${ARGN})
2955         get_target_property(_maxIncludes ${_target} COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES)
2956         if (_maxIncludes MATCHES "(-j|--parallel|--jobs) ?([0-9]*)")
2957                 if (DEFINED CMAKE_MATCH_2)
2958                         set (_numberOfThreads "${CMAKE_MATCH_2}")
2959                 else()
2960                         set (_numberOfThreads "")
2961                 endif()
2962                 if (NOT _numberOfThreads)
2963                         # use all available cores
2964                         ProcessorCount(_numberOfThreads)
2965                 endif()
2966                 list (LENGTH _sourceFiles _numberOfSources)
2967                 math (EXPR _maxIncludes "(${_numberOfSources} + ${_numberOfThreads} - 1) / ${_numberOfThreads}")
2968         elseif (NOT _maxIncludes MATCHES "[0-9]+")
2969                 set (_maxIncludes 0)
2970         endif()
2971         if (COTIRE_DEBUG)
2972                 message (STATUS "${_target} unity source max includes: ${_maxIncludes}")
2973         endif()
2974         set (${_maxIncludesVar} ${_maxIncludes} PARENT_SCOPE)
2975 endfunction()
2976
2977 function (cotire_process_target_language _language _configurations _target _wholeTarget _cmdsVar)
2978         set (${_cmdsVar} "" PARENT_SCOPE)
2979         get_target_property(_targetSourceFiles ${_target} SOURCES)
2980         set (_sourceFiles "")
2981         set (_excludedSources "")
2982         set (_cotiredSources "")
2983         cotire_filter_language_source_files(${_language} ${_target} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles})
2984         if (NOT _sourceFiles AND NOT _cotiredSources)
2985                 return()
2986         endif()
2987         set (_cmds "")
2988         # check for user provided unity source file list
2989         get_property(_unitySourceFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE_INIT)
2990         if (NOT _unitySourceFiles)
2991                 set (_unitySourceFiles ${_sourceFiles} ${_cotiredSources})
2992         endif()
2993         cotire_generate_target_script(
2994                 ${_language} "${_configurations}" ${_target} _targetScript _targetConfigScript ${_unitySourceFiles})
2995         # set up unity files for parallel compilation
2996         cotire_compute_unity_max_number_of_includes(${_target} _maxIncludes ${_unitySourceFiles})
2997         cotire_make_unity_source_file_paths(${_language} ${_target} ${_maxIncludes} _unityFiles ${_unitySourceFiles})
2998         list (LENGTH _unityFiles _numberOfUnityFiles)
2999         if (_numberOfUnityFiles EQUAL 0)
3000                 return()
3001         elseif (_numberOfUnityFiles GREATER 1)
3002                 cotire_setup_unity_generation_commands(
3003                         ${_language} ${_target} "${_targetScript}" "${_targetConfigScript}" "${_unityFiles}" _cmds ${_unitySourceFiles})
3004         endif()
3005         # set up single unity file for prefix header generation
3006         cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFile)
3007         cotire_setup_unity_generation_commands(
3008                 ${_language} ${_target} "${_targetScript}" "${_targetConfigScript}" "${_unityFile}" _cmds ${_unitySourceFiles})
3009         cotire_make_prefix_file_path(${_language} ${_target} _prefixFile)
3010         # set up prefix header
3011         if (_prefixFile)
3012                 # check for user provided prefix header files
3013                 get_property(_prefixHeaderFiles TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER_INIT)
3014                 if (_prefixHeaderFiles)
3015                         cotire_setup_prefix_generation_from_provided_command(
3016                                 ${_language} ${_target} "${_targetConfigScript}" "${_prefixFile}" _cmds ${_prefixHeaderFiles})
3017                 else()
3018                         cotire_setup_prefix_generation_from_unity_command(
3019                                 ${_language} ${_target} "${_targetConfigScript}" "${_prefixFile}" "${_unityFile}" _cmds ${_unitySourceFiles})
3020                 endif()
3021                 # check if selected language has enough sources at all
3022                 list (LENGTH _sourceFiles _numberOfSources)
3023                 if (_numberOfSources LESS ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES})
3024                         set (_targetUsePCH FALSE)
3025                 else()
3026                         get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER)
3027                 endif()
3028                 if (_targetUsePCH)
3029                         cotire_make_pch_file_path(${_language} ${_target} _pchFile)
3030                         if (_pchFile)
3031                                 # first file in _sourceFiles is passed as the host file
3032                                 cotire_setup_pch_file_compilation(
3033                                         ${_language} ${_target} "${_targetConfigScript}" "${_prefixFile}" "${_pchFile}" ${_sourceFiles})
3034                                 cotire_setup_pch_file_inclusion(
3035                                         ${_language} ${_target} ${_wholeTarget} "${_prefixFile}" "${_pchFile}" ${_sourceFiles})
3036                         endif()
3037                 elseif (_prefixHeaderFiles)
3038                         # user provided prefix header must be included unconditionally
3039                         cotire_setup_prefix_file_inclusion(${_language} ${_target} "${_prefixFile}" ${_sourceFiles})
3040                 endif()
3041         endif()
3042         # mark target as cotired for language
3043         set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE "${_unityFiles}")
3044         if (_prefixFile)
3045                 set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER "${_prefixFile}")
3046                 if (_targetUsePCH AND _pchFile)
3047                         set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_PRECOMPILED_HEADER "${_pchFile}")
3048                 endif()
3049         endif()
3050         set (${_cmdsVar} ${_cmds} PARENT_SCOPE)
3051 endfunction()
3052
3053 function (cotire_setup_clean_target _target)
3054         set (_cleanTargetName "${_target}${COTIRE_CLEAN_TARGET_SUFFIX}")
3055         if (NOT TARGET "${_cleanTargetName}")
3056                 cotire_set_cmd_to_prologue(_cmds)
3057                 get_filename_component(_outputDir "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" ABSOLUTE)
3058                 list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "cleanup" "${_outputDir}" "${COTIRE_INTDIR}" "${_target}")
3059                 add_custom_target(${_cleanTargetName}
3060                         COMMAND ${_cmds}
3061                         WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
3062                         COMMENT "Cleaning up target ${_target} cotire generated files"
3063                         VERBATIM)
3064                 cotire_init_target("${_cleanTargetName}")
3065         endif()
3066 endfunction()
3067
3068 function (cotire_setup_pch_target _languages _configurations _target)
3069         if ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
3070                 # for makefile based generators, we add a custom target to trigger the generation of the cotire related files
3071                 set (_dependsFiles "")
3072                 foreach (_language ${_languages})
3073                         set (_props COTIRE_${_language}_PREFIX_HEADER COTIRE_${_language}_UNITY_SOURCE)
3074                         if (NOT CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel" AND NOT
3075                                 (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "Clang"))
3076                                 # MSVC, Intel and clang-cl only create precompiled header as a side effect
3077                                 list (INSERT _props 0 COTIRE_${_language}_PRECOMPILED_HEADER)
3078                         endif()
3079                         cotire_get_first_set_property_value(_dependsFile TARGET ${_target} ${_props})
3080                         if (_dependsFile)
3081                                 list (APPEND _dependsFiles "${_dependsFile}")
3082                         endif()
3083                 endforeach()
3084                 if (_dependsFiles)
3085                         set (_pchTargetName "${_target}${COTIRE_PCH_TARGET_SUFFIX}")
3086                         add_custom_target("${_pchTargetName}" DEPENDS ${_dependsFiles})
3087                         cotire_init_target("${_pchTargetName}")
3088                         cotire_add_to_pch_all_target(${_pchTargetName})
3089                 endif()
3090         else()
3091                 # for other generators, we add the "clean all" target to clean up the precompiled header
3092                 cotire_setup_clean_all_target()
3093         endif()
3094 endfunction()
3095
3096 function (cotire_filter_object_libraries _target _objectLibrariesVar)
3097         set (_objectLibraries "")
3098         foreach (_source ${ARGN})
3099                 if (_source MATCHES "^\\$<TARGET_OBJECTS:.+>$")
3100                         list (APPEND _objectLibraries "${_source}")
3101                 endif()
3102         endforeach()
3103         set (${_objectLibrariesVar} ${_objectLibraries} PARENT_SCOPE)
3104 endfunction()
3105
3106 function (cotire_collect_unity_target_sources _target _languages _unityTargetSourcesVar)
3107         get_target_property(_targetSourceFiles ${_target} SOURCES)
3108         set (_unityTargetSources ${_targetSourceFiles})
3109         foreach (_language ${_languages})
3110                 get_property(_unityFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE)
3111                 if (_unityFiles)
3112                         # remove source files that are included in the unity source
3113                         set (_sourceFiles "")
3114                         set (_excludedSources "")
3115                         set (_cotiredSources "")
3116                         cotire_filter_language_source_files(${_language} ${_target} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles})
3117                         if (_sourceFiles OR _cotiredSources)
3118                                 list (REMOVE_ITEM _unityTargetSources ${_sourceFiles} ${_cotiredSources})
3119                         endif()
3120                         # add unity source files instead
3121                         list (APPEND _unityTargetSources ${_unityFiles})
3122                 endif()
3123         endforeach()
3124         # handle object libraries which are part of the target's sources
3125         get_target_property(_linkLibrariesStrategy ${_target} COTIRE_UNITY_LINK_LIBRARIES_INIT)
3126         if ("${_linkLibrariesStrategy}" MATCHES "^COPY_UNITY$")
3127                 cotire_filter_object_libraries(${_target} _objectLibraries ${_targetSourceFiles})
3128                 if (_objectLibraries)
3129                         cotire_map_libraries("${_linkLibrariesStrategy}" _unityObjectLibraries ${_objectLibraries})
3130                         list (REMOVE_ITEM _unityTargetSources ${_objectLibraries})
3131                         list (APPEND _unityTargetSources ${_unityObjectLibraries})
3132                 endif()
3133         endif()
3134         set (${_unityTargetSourcesVar} ${_unityTargetSources} PARENT_SCOPE)
3135 endfunction()
3136
3137 function (cotire_setup_unity_target_pch_usage _languages _target)
3138         foreach (_language ${_languages})
3139                 get_property(_unityFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE)
3140                 if (_unityFiles)
3141                         get_property(_userPrefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER_INIT)
3142                         get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER)
3143                         if (_userPrefixFile AND _prefixFile)
3144                                 # user provided prefix header must be included unconditionally by unity sources
3145                                 cotire_setup_prefix_file_inclusion(${_language} ${_target} "${_prefixFile}" ${_unityFiles})
3146                         endif()
3147                 endif()
3148         endforeach()
3149 endfunction()
3150
3151 function (cotire_setup_unity_build_target _languages _configurations _target)
3152         get_target_property(_unityTargetName ${_target} COTIRE_UNITY_TARGET_NAME)
3153         if (NOT _unityTargetName)
3154                 set (_unityTargetName "${_target}${COTIRE_UNITY_BUILD_TARGET_SUFFIX}")
3155         endif()
3156         # determine unity target sub type
3157         get_target_property(_targetType ${_target} TYPE)
3158         if ("${_targetType}" STREQUAL "EXECUTABLE")
3159                 set (_unityTargetSubType "")
3160         elseif (_targetType MATCHES "(STATIC|SHARED|MODULE|OBJECT)_LIBRARY")
3161                 set (_unityTargetSubType "${CMAKE_MATCH_1}")
3162         else()
3163                 message (WARNING "cotire: target ${_target} has unknown target type ${_targetType}.")
3164                 return()
3165         endif()
3166         # determine unity target sources
3167         set (_unityTargetSources "")
3168         cotire_collect_unity_target_sources(${_target} "${_languages}" _unityTargetSources)
3169         # prevent AUTOMOC, AUTOUIC and AUTORCC properties from being set when the unity target is created
3170         set (CMAKE_AUTOMOC OFF)
3171         set (CMAKE_AUTOUIC OFF)
3172         set (CMAKE_AUTORCC OFF)
3173         if (COTIRE_DEBUG)
3174                 message (STATUS "add target ${_targetType} ${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}")
3175         endif()
3176         # generate unity target
3177         if ("${_targetType}" STREQUAL "EXECUTABLE")
3178                 add_executable(${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources})
3179         else()
3180                 add_library(${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources})
3181         endif()
3182         # copy output location properties
3183         set (_outputDirProperties
3184                 ARCHIVE_OUTPUT_DIRECTORY ARCHIVE_OUTPUT_DIRECTORY_<CONFIG>
3185                 LIBRARY_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY_<CONFIG>
3186                 RUNTIME_OUTPUT_DIRECTORY RUNTIME_OUTPUT_DIRECTORY_<CONFIG>)
3187         if (COTIRE_UNITY_OUTPUT_DIRECTORY)
3188                 set (_setDefaultOutputDir TRUE)
3189                 if (IS_ABSOLUTE "${COTIRE_UNITY_OUTPUT_DIRECTORY}")
3190                         set (_outputDir "${COTIRE_UNITY_OUTPUT_DIRECTORY}")
3191                 else()
3192                         # append relative COTIRE_UNITY_OUTPUT_DIRECTORY to target's actual output directory
3193                         cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName} ${_outputDirProperties})
3194                         cotire_resolve_config_properties("${_configurations}" _properties ${_outputDirProperties})
3195                         foreach (_property ${_properties})
3196                                 get_property(_outputDir TARGET ${_target} PROPERTY ${_property})
3197                                 if (_outputDir)
3198                                         get_filename_component(_outputDir "${_outputDir}/${COTIRE_UNITY_OUTPUT_DIRECTORY}" ABSOLUTE)
3199                                         set_property(TARGET ${_unityTargetName} PROPERTY ${_property} "${_outputDir}")
3200                                         set (_setDefaultOutputDir FALSE)
3201                                 endif()
3202                         endforeach()
3203                         if (_setDefaultOutputDir)
3204                                 get_filename_component(_outputDir "${CMAKE_CURRENT_BINARY_DIR}/${COTIRE_UNITY_OUTPUT_DIRECTORY}" ABSOLUTE)
3205                         endif()
3206                 endif()
3207                 if (_setDefaultOutputDir)
3208                         set_target_properties(${_unityTargetName} PROPERTIES
3209                                 ARCHIVE_OUTPUT_DIRECTORY "${_outputDir}"
3210                                 LIBRARY_OUTPUT_DIRECTORY "${_outputDir}"
3211                                 RUNTIME_OUTPUT_DIRECTORY "${_outputDir}")
3212                 endif()
3213         else()
3214                 cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName}
3215                         ${_outputDirProperties})
3216         endif()
3217         # copy output name
3218         cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName}
3219                 ARCHIVE_OUTPUT_NAME ARCHIVE_OUTPUT_NAME_<CONFIG>
3220                 LIBRARY_OUTPUT_NAME LIBRARY_OUTPUT_NAME_<CONFIG>
3221                 OUTPUT_NAME OUTPUT_NAME_<CONFIG>
3222                 RUNTIME_OUTPUT_NAME RUNTIME_OUTPUT_NAME_<CONFIG>
3223                 PREFIX <CONFIG>_POSTFIX SUFFIX
3224                 IMPORT_PREFIX IMPORT_SUFFIX)
3225         # copy compile stuff
3226         cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName}
3227                 COMPILE_DEFINITIONS COMPILE_DEFINITIONS_<CONFIG>
3228                 COMPILE_FLAGS COMPILE_OPTIONS
3229                 Fortran_FORMAT Fortran_MODULE_DIRECTORY
3230                 INCLUDE_DIRECTORIES
3231                 INTERPROCEDURAL_OPTIMIZATION INTERPROCEDURAL_OPTIMIZATION_<CONFIG>
3232                 POSITION_INDEPENDENT_CODE
3233                 C_COMPILER_LAUNCHER CXX_COMPILER_LAUNCHER
3234                 C_INCLUDE_WHAT_YOU_USE CXX_INCLUDE_WHAT_YOU_USE
3235                 C_VISIBILITY_PRESET CXX_VISIBILITY_PRESET VISIBILITY_INLINES_HIDDEN
3236                 C_CLANG_TIDY CXX_CLANG_TIDY)
3237         # copy compile features
3238         cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName}
3239                 C_EXTENSIONS C_STANDARD C_STANDARD_REQUIRED
3240                 CXX_EXTENSIONS CXX_STANDARD CXX_STANDARD_REQUIRED
3241                 COMPILE_FEATURES)
3242         # copy interface stuff
3243         cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName}
3244                 COMPATIBLE_INTERFACE_BOOL COMPATIBLE_INTERFACE_NUMBER_MAX COMPATIBLE_INTERFACE_NUMBER_MIN
3245                 COMPATIBLE_INTERFACE_STRING
3246                 INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_FEATURES INTERFACE_COMPILE_OPTIONS
3247                 INTERFACE_INCLUDE_DIRECTORIES INTERFACE_SOURCES
3248                 INTERFACE_POSITION_INDEPENDENT_CODE INTERFACE_SYSTEM_INCLUDE_DIRECTORIES
3249                 INTERFACE_AUTOUIC_OPTIONS NO_SYSTEM_FROM_IMPORTED)
3250         # copy link stuff
3251         cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName}
3252                 BUILD_WITH_INSTALL_RPATH BUILD_WITH_INSTALL_NAME_DIR
3253                 INSTALL_RPATH INSTALL_RPATH_USE_LINK_PATH SKIP_BUILD_RPATH
3254                 LINKER_LANGUAGE LINK_DEPENDS LINK_DEPENDS_NO_SHARED
3255                 LINK_FLAGS LINK_FLAGS_<CONFIG>
3256                 LINK_INTERFACE_LIBRARIES LINK_INTERFACE_LIBRARIES_<CONFIG>
3257                 LINK_INTERFACE_MULTIPLICITY LINK_INTERFACE_MULTIPLICITY_<CONFIG>
3258                 LINK_SEARCH_START_STATIC LINK_SEARCH_END_STATIC
3259                 STATIC_LIBRARY_FLAGS STATIC_LIBRARY_FLAGS_<CONFIG>
3260                 NO_SONAME SOVERSION VERSION
3261                 LINK_WHAT_YOU_USE BUILD_RPATH)
3262         # copy cmake stuff
3263         cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName}
3264                 IMPLICIT_DEPENDS_INCLUDE_TRANSFORM RULE_LAUNCH_COMPILE RULE_LAUNCH_CUSTOM RULE_LAUNCH_LINK)
3265         # copy Apple platform specific stuff
3266         cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName}
3267                 BUNDLE BUNDLE_EXTENSION FRAMEWORK FRAMEWORK_VERSION INSTALL_NAME_DIR
3268                 MACOSX_BUNDLE MACOSX_BUNDLE_INFO_PLIST MACOSX_FRAMEWORK_INFO_PLIST MACOSX_RPATH
3269                 OSX_ARCHITECTURES OSX_ARCHITECTURES_<CONFIG> PRIVATE_HEADER PUBLIC_HEADER RESOURCE XCTEST
3270                 IOS_INSTALL_COMBINED XCODE_EXPLICIT_FILE_TYPE XCODE_PRODUCT_TYPE)
3271         # copy Windows platform specific stuff
3272         cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName}
3273                 GNUtoMS
3274                 COMPILE_PDB_NAME COMPILE_PDB_NAME_<CONFIG>
3275                 COMPILE_PDB_OUTPUT_DIRECTORY COMPILE_PDB_OUTPUT_DIRECTORY_<CONFIG>
3276                 PDB_NAME PDB_NAME_<CONFIG> PDB_OUTPUT_DIRECTORY PDB_OUTPUT_DIRECTORY_<CONFIG>
3277                 VS_DESKTOP_EXTENSIONS_VERSION VS_DOTNET_REFERENCES VS_DOTNET_TARGET_FRAMEWORK_VERSION
3278                 VS_GLOBAL_KEYWORD VS_GLOBAL_PROJECT_TYPES VS_GLOBAL_ROOTNAMESPACE
3279                 VS_IOT_EXTENSIONS_VERSION VS_IOT_STARTUP_TASK
3280                 VS_KEYWORD VS_MOBILE_EXTENSIONS_VERSION
3281                 VS_SCC_AUXPATH VS_SCC_LOCALPATH VS_SCC_PROJECTNAME VS_SCC_PROVIDER
3282                 VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION
3283                 VS_WINRT_COMPONENT VS_WINRT_EXTENSIONS VS_WINRT_REFERENCES
3284                 WIN32_EXECUTABLE WINDOWS_EXPORT_ALL_SYMBOLS
3285                 DEPLOYMENT_REMOTE_DIRECTORY VS_CONFIGURATION_TYPE
3286                 VS_SDK_REFERENCES VS_USER_PROPS VS_DEBUGGER_WORKING_DIRECTORY)
3287         # copy Android platform specific stuff
3288         cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName}
3289                 ANDROID_API ANDROID_API_MIN ANDROID_GUI
3290                 ANDROID_ANT_ADDITIONAL_OPTIONS ANDROID_ARCH ANDROID_ASSETS_DIRECTORIES
3291                 ANDROID_JAR_DEPENDENCIES ANDROID_JAR_DIRECTORIES ANDROID_JAVA_SOURCE_DIR
3292                 ANDROID_NATIVE_LIB_DEPENDENCIES ANDROID_NATIVE_LIB_DIRECTORIES
3293                 ANDROID_PROCESS_MAX ANDROID_PROGUARD ANDROID_PROGUARD_CONFIG_PATH
3294                 ANDROID_SECURE_PROPS_PATH ANDROID_SKIP_ANT_STEP ANDROID_STL_TYPE)
3295         # copy CUDA platform specific stuff
3296         cotire_copy_set_properties("${_configurations}" TARGET ${_target} ${_unityTargetName}
3297                 CUDA_PTX_COMPILATION CUDA_SEPARABLE_COMPILATION CUDA_RESOLVE_DEVICE_SYMBOLS
3298                 CUDA_EXTENSIONS CUDA_STANDARD CUDA_STANDARD_REQUIRED)
3299         # use output name from original target
3300         get_target_property(_targetOutputName ${_unityTargetName} OUTPUT_NAME)
3301         if (NOT _targetOutputName)
3302                 set_property(TARGET ${_unityTargetName} PROPERTY OUTPUT_NAME "${_target}")
3303         endif()
3304         # use export symbol from original target
3305         cotire_get_target_export_symbol("${_target}" _defineSymbol)
3306         if (_defineSymbol)
3307                 set_property(TARGET ${_unityTargetName} PROPERTY DEFINE_SYMBOL "${_defineSymbol}")
3308                 if ("${_targetType}" STREQUAL "EXECUTABLE")
3309                         set_property(TARGET ${_unityTargetName} PROPERTY ENABLE_EXPORTS TRUE)
3310                 endif()
3311         endif()
3312         # enable parallel compilation for MSVC
3313         if (MSVC AND "${CMAKE_GENERATOR}" MATCHES "Visual Studio")
3314                 list (LENGTH _unityTargetSources _numberOfUnityTargetSources)
3315                 if (_numberOfUnityTargetSources GREATER 1)
3316                         set_property(TARGET ${_unityTargetName} APPEND PROPERTY COMPILE_OPTIONS "/MP")
3317                 endif()
3318         endif()
3319         cotire_init_target(${_unityTargetName})
3320         cotire_add_to_unity_all_target(${_unityTargetName})
3321         set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_TARGET_NAME "${_unityTargetName}")
3322 endfunction(cotire_setup_unity_build_target)
3323
3324 function (cotire_target _target)
3325         set(_options "")
3326         set(_oneValueArgs "")
3327         set(_multiValueArgs LANGUAGES CONFIGURATIONS)
3328         cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
3329         if (NOT _option_LANGUAGES)
3330                 get_property (_option_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
3331         endif()
3332         if (NOT _option_CONFIGURATIONS)
3333                 cotire_get_configuration_types(_option_CONFIGURATIONS)
3334         endif()
3335         # check if cotire can be applied to target at all
3336         cotire_is_target_supported(${_target} _isSupported)
3337         if (NOT _isSupported)
3338                 get_target_property(_imported ${_target} IMPORTED)
3339                 get_target_property(_targetType ${_target} TYPE)
3340                 if (_imported)
3341                         message (WARNING "cotire: imported ${_targetType} target ${_target} cannot be cotired.")
3342                 else()
3343                         message (STATUS "cotire: ${_targetType} target ${_target} cannot be cotired.")
3344                 endif()
3345                 return()
3346         endif()
3347         # resolve alias
3348         get_target_property(_aliasName ${_target} ALIASED_TARGET)
3349         if (_aliasName)
3350                 if (COTIRE_DEBUG)
3351                         message (STATUS "${_target} is an alias. Applying cotire to aliased target ${_aliasName} instead.")
3352                 endif()
3353                 set (_target ${_aliasName})
3354         endif()
3355         # check if target needs to be cotired for build type
3356         # when using configuration types, the test is performed at build time
3357         cotire_init_cotire_target_properties(${_target})
3358         if (NOT CMAKE_CONFIGURATION_TYPES)
3359                 if (CMAKE_BUILD_TYPE)
3360                         list (FIND _option_CONFIGURATIONS "${CMAKE_BUILD_TYPE}" _index)
3361                 else()
3362                         list (FIND _option_CONFIGURATIONS "None" _index)
3363                 endif()
3364                 if (_index EQUAL -1)
3365                         if (COTIRE_DEBUG)
3366                                 message (STATUS "CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} not cotired (${_option_CONFIGURATIONS})")
3367                         endif()
3368                         return()
3369                 endif()
3370         endif()
3371         # when not using configuration types, immediately create cotire intermediate dir
3372         if (NOT CMAKE_CONFIGURATION_TYPES)
3373                 cotire_get_intermediate_dir(_baseDir)
3374                 file (MAKE_DIRECTORY "${_baseDir}")
3375         endif()
3376         # choose languages that apply to the target
3377         cotire_choose_target_languages("${_target}" _targetLanguages _wholeTarget ${_option_LANGUAGES})
3378         if (NOT _targetLanguages)
3379                 return()
3380         endif()
3381         set (_cmds "")
3382         foreach (_language ${_targetLanguages})
3383                 cotire_process_target_language("${_language}" "${_option_CONFIGURATIONS}" ${_target} ${_wholeTarget} _cmd)
3384                 if (_cmd)
3385                         list (APPEND _cmds ${_cmd})
3386                 endif()
3387         endforeach()
3388         get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD)
3389         if (_targetAddSCU)
3390                 cotire_setup_unity_build_target("${_targetLanguages}" "${_option_CONFIGURATIONS}" ${_target})
3391         endif()
3392         get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER)
3393         if (_targetUsePCH)
3394                 cotire_setup_target_pch_usage("${_targetLanguages}" ${_target} ${_wholeTarget} ${_cmds})
3395                 cotire_setup_pch_target("${_targetLanguages}" "${_option_CONFIGURATIONS}" ${_target})
3396                 if (_targetAddSCU)
3397                         cotire_setup_unity_target_pch_usage("${_targetLanguages}" ${_target})
3398                 endif()
3399         endif()
3400         get_target_property(_targetAddCleanTarget ${_target} COTIRE_ADD_CLEAN)
3401         if (_targetAddCleanTarget)
3402                 cotire_setup_clean_target(${_target})
3403         endif()
3404 endfunction(cotire_target)
3405
3406 function (cotire_map_libraries _strategy _mappedLibrariesVar)
3407         set (_mappedLibraries "")
3408         foreach (_library ${ARGN})
3409                 if (_library MATCHES "^\\$<LINK_ONLY:(.+)>$")
3410                         set (_libraryName "${CMAKE_MATCH_1}")
3411                         set (_linkOnly TRUE)
3412                         set (_objectLibrary FALSE)
3413                 elseif (_library MATCHES "^\\$<TARGET_OBJECTS:(.+)>$")
3414                         set (_libraryName "${CMAKE_MATCH_1}")
3415                         set (_linkOnly FALSE)
3416                         set (_objectLibrary TRUE)
3417                 else()
3418                         set (_libraryName "${_library}")
3419                         set (_linkOnly FALSE)
3420                         set (_objectLibrary FALSE)
3421                 endif()
3422                 if ("${_strategy}" MATCHES "COPY_UNITY")
3423                         cotire_is_target_supported(${_libraryName} _isSupported)
3424                         if (_isSupported)
3425                                 # use target's corresponding unity target, if available
3426                                 get_target_property(_libraryUnityTargetName ${_libraryName} COTIRE_UNITY_TARGET_NAME)
3427                                 if (TARGET "${_libraryUnityTargetName}")
3428                                         if (_linkOnly)
3429                                                 list (APPEND _mappedLibraries "$<LINK_ONLY:${_libraryUnityTargetName}>")
3430                                         elseif (_objectLibrary)
3431                                                 list (APPEND _mappedLibraries "$<TARGET_OBJECTS:${_libraryUnityTargetName}>")
3432                                         else()
3433                                                 list (APPEND _mappedLibraries "${_libraryUnityTargetName}")
3434                                         endif()
3435                                 else()
3436                                         list (APPEND _mappedLibraries "${_library}")
3437                                 endif()
3438                         else()
3439                                 list (APPEND _mappedLibraries "${_library}")
3440                         endif()
3441                 else()
3442                         list (APPEND _mappedLibraries "${_library}")
3443                 endif()
3444         endforeach()
3445         list (REMOVE_DUPLICATES _mappedLibraries)
3446         set (${_mappedLibrariesVar} ${_mappedLibraries} PARENT_SCOPE)
3447 endfunction()
3448
3449 function (cotire_target_link_libraries _target)
3450         cotire_is_target_supported(${_target} _isSupported)
3451         if (NOT _isSupported)
3452                 return()
3453         endif()
3454         get_target_property(_unityTargetName ${_target} COTIRE_UNITY_TARGET_NAME)
3455         if (TARGET "${_unityTargetName}")
3456                 get_target_property(_linkLibrariesStrategy ${_target} COTIRE_UNITY_LINK_LIBRARIES_INIT)
3457                 if (COTIRE_DEBUG)
3458                         message (STATUS "unity target ${_unityTargetName} link strategy: ${_linkLibrariesStrategy}")
3459                 endif()
3460                 if ("${_linkLibrariesStrategy}" MATCHES "^(COPY|COPY_UNITY)$")
3461                         get_target_property(_linkLibraries ${_target} LINK_LIBRARIES)
3462                         if (_linkLibraries)
3463                                 cotire_map_libraries("${_linkLibrariesStrategy}" _unityLinkLibraries ${_linkLibraries})
3464                                 set_target_properties(${_unityTargetName} PROPERTIES LINK_LIBRARIES "${_unityLinkLibraries}")
3465                                 if (COTIRE_DEBUG)
3466                                         message (STATUS "unity target ${_unityTargetName} link libraries: ${_unityLinkLibraries}")
3467                                 endif()
3468                         endif()
3469                         get_target_property(_interfaceLinkLibraries ${_target} INTERFACE_LINK_LIBRARIES)
3470                         if (_interfaceLinkLibraries)
3471                                 cotire_map_libraries("${_linkLibrariesStrategy}" _unityLinkInterfaceLibraries ${_interfaceLinkLibraries})
3472                                 set_target_properties(${_unityTargetName} PROPERTIES INTERFACE_LINK_LIBRARIES "${_unityLinkInterfaceLibraries}")
3473                                 if (COTIRE_DEBUG)
3474                                         message (STATUS "unity target ${_unityTargetName} interface link libraries: ${_unityLinkInterfaceLibraries}")
3475                                 endif()
3476                         endif()
3477                         get_target_property(_manualDependencies ${_target} MANUALLY_ADDED_DEPENDENCIES)
3478                         if (_manualDependencies)
3479                                 cotire_map_libraries("${_linkLibrariesStrategy}" _unityManualDependencies ${_manualDependencies})
3480                                 if (_unityManualDependencies)
3481                                         add_dependencies("${_unityTargetName}" ${_unityManualDependencies})
3482                                 endif()
3483                         endif()
3484                 endif()
3485         endif()
3486 endfunction(cotire_target_link_libraries)
3487
3488 function (cotire_cleanup _binaryDir _cotireIntermediateDirName _targetName)
3489         if (_targetName)
3490                 file (GLOB_RECURSE _cotireFiles "${_binaryDir}/${_targetName}*.*")
3491         else()
3492                 file (GLOB_RECURSE _cotireFiles "${_binaryDir}/*.*")
3493         endif()
3494         # filter files in intermediate directory
3495         set (_filesToRemove "")
3496         foreach (_file ${_cotireFiles})
3497                 get_filename_component(_dir "${_file}" DIRECTORY)
3498                 get_filename_component(_dirName "${_dir}" NAME)
3499                 if ("${_dirName}" STREQUAL "${_cotireIntermediateDirName}")
3500                         list (APPEND _filesToRemove "${_file}")
3501                 endif()
3502         endforeach()
3503         if (_filesToRemove)
3504                 if (COTIRE_VERBOSE)
3505                         message (STATUS "cleaning up ${_filesToRemove}")
3506                 endif()
3507                 file (REMOVE ${_filesToRemove})
3508         endif()
3509 endfunction()
3510
3511 function (cotire_init_target _targetName)
3512         if (COTIRE_TARGETS_FOLDER)
3513                 set_target_properties(${_targetName} PROPERTIES FOLDER "${COTIRE_TARGETS_FOLDER}")
3514         endif()
3515         set_target_properties(${_targetName} PROPERTIES EXCLUDE_FROM_ALL TRUE)
3516         if (MSVC_IDE)
3517                 set_target_properties(${_targetName} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD TRUE)
3518         endif()
3519 endfunction()
3520
3521 function (cotire_add_to_pch_all_target _pchTargetName)
3522         set (_targetName "${COTIRE_PCH_ALL_TARGET_NAME}")
3523         if (NOT TARGET "${_targetName}")
3524                 add_custom_target("${_targetName}"
3525                         WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
3526                         VERBATIM)
3527                 cotire_init_target("${_targetName}")
3528         endif()
3529         cotire_setup_clean_all_target()
3530         add_dependencies(${_targetName} ${_pchTargetName})
3531 endfunction()
3532
3533 function (cotire_add_to_unity_all_target _unityTargetName)
3534         set (_targetName "${COTIRE_UNITY_BUILD_ALL_TARGET_NAME}")
3535         if (NOT TARGET "${_targetName}")
3536                 add_custom_target("${_targetName}"
3537                         WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
3538                         VERBATIM)
3539                 cotire_init_target("${_targetName}")
3540         endif()
3541         cotire_setup_clean_all_target()
3542         add_dependencies(${_targetName} ${_unityTargetName})
3543 endfunction()
3544
3545 function (cotire_setup_clean_all_target)
3546         set (_targetName "${COTIRE_CLEAN_ALL_TARGET_NAME}")
3547         if (NOT TARGET "${_targetName}")
3548                 cotire_set_cmd_to_prologue(_cmds)
3549                 list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "cleanup" "${CMAKE_BINARY_DIR}" "${COTIRE_INTDIR}")
3550                 add_custom_target(${_targetName}
3551                         COMMAND ${_cmds}
3552                         WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
3553                         COMMENT "Cleaning up all cotire generated files"
3554                         VERBATIM)
3555                 cotire_init_target("${_targetName}")
3556         endif()
3557 endfunction()
3558
3559 function (cotire)
3560         set(_options "")
3561         set(_oneValueArgs "")
3562         set(_multiValueArgs LANGUAGES CONFIGURATIONS)
3563         cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
3564         set (_targets ${_option_UNPARSED_ARGUMENTS})
3565         foreach (_target ${_targets})
3566                 if (TARGET ${_target})
3567                         cotire_target(${_target} LANGUAGES ${_option_LANGUAGES} CONFIGURATIONS ${_option_CONFIGURATIONS})
3568                 else()
3569                         message (WARNING "cotire: ${_target} is not a target.")
3570                 endif()
3571         endforeach()
3572         foreach (_target ${_targets})
3573                 if (TARGET ${_target})
3574                         cotire_target_link_libraries(${_target})
3575                 endif()
3576         endforeach()
3577 endfunction()
3578
3579 if (CMAKE_SCRIPT_MODE_FILE)
3580
3581         # cotire is being run in script mode
3582         # locate -P on command args
3583         set (COTIRE_ARGC -1)
3584         foreach (_index RANGE ${CMAKE_ARGC})
3585                 if (COTIRE_ARGC GREATER -1)
3586                         set (COTIRE_ARGV${COTIRE_ARGC} "${CMAKE_ARGV${_index}}")
3587                         math (EXPR COTIRE_ARGC "${COTIRE_ARGC} + 1")
3588                 elseif ("${CMAKE_ARGV${_index}}" STREQUAL "-P")
3589                         set (COTIRE_ARGC 0)
3590                 endif()
3591         endforeach()
3592
3593         # include target script if available
3594         if ("${COTIRE_ARGV2}" MATCHES "\\.cmake$")
3595                 # the included target scripts sets up additional variables relating to the target (e.g., COTIRE_TARGET_SOURCES)
3596                 include("${COTIRE_ARGV2}")
3597         endif()
3598
3599         if (COTIRE_DEBUG)
3600                 message (STATUS "${COTIRE_ARGV0} ${COTIRE_ARGV1} ${COTIRE_ARGV2} ${COTIRE_ARGV3} ${COTIRE_ARGV4} ${COTIRE_ARGV5}")
3601         endif()
3602
3603         if (NOT COTIRE_BUILD_TYPE)
3604                 set (COTIRE_BUILD_TYPE "None")
3605         endif()
3606         string (TOUPPER "${COTIRE_BUILD_TYPE}" _upperConfig)
3607         set (_includeDirs ${COTIRE_TARGET_INCLUDE_DIRECTORIES_${_upperConfig}})
3608         set (_systemIncludeDirs ${COTIRE_TARGET_SYSTEM_INCLUDE_DIRECTORIES_${_upperConfig}})
3609         set (_compileDefinitions ${COTIRE_TARGET_COMPILE_DEFINITIONS_${_upperConfig}})
3610         set (_compileFlags ${COTIRE_TARGET_COMPILE_FLAGS_${_upperConfig}})
3611         # check if target has been cotired for actual build type COTIRE_BUILD_TYPE
3612         list (FIND COTIRE_TARGET_CONFIGURATION_TYPES "${COTIRE_BUILD_TYPE}" _index)
3613         if (_index GREATER -1)
3614                 set (_sources ${COTIRE_TARGET_SOURCES})
3615                 set (_sourcesDefinitions ${COTIRE_TARGET_SOURCES_COMPILE_DEFINITIONS_${_upperConfig}})
3616         else()
3617                 if (COTIRE_DEBUG)
3618                         message (STATUS "COTIRE_BUILD_TYPE=${COTIRE_BUILD_TYPE} not cotired (${COTIRE_TARGET_CONFIGURATION_TYPES})")
3619                 endif()
3620                 set (_sources "")
3621                 set (_sourcesDefinitions "")
3622         endif()
3623         set (_targetPreUndefs ${COTIRE_TARGET_PRE_UNDEFS})
3624         set (_targetPostUndefs ${COTIRE_TARGET_POST_UNDEFS})
3625         set (_sourcesPreUndefs ${COTIRE_TARGET_SOURCES_PRE_UNDEFS})
3626         set (_sourcesPostUndefs ${COTIRE_TARGET_SOURCES_POST_UNDEFS})
3627
3628         if ("${COTIRE_ARGV1}" STREQUAL "unity")
3629
3630                 if (XCODE)
3631                         # executing pre-build action under Xcode, check dependency on target script
3632                         set (_dependsOption DEPENDS "${COTIRE_ARGV2}")
3633                 else()
3634                         # executing custom command, no need to re-check for dependencies
3635                         set (_dependsOption "")
3636                 endif()
3637
3638                 cotire_select_unity_source_files("${COTIRE_ARGV3}" _sources ${_sources})
3639
3640                 cotire_generate_unity_source(
3641                         "${COTIRE_ARGV3}" ${_sources}
3642                         LANGUAGE "${COTIRE_TARGET_LANGUAGE}"
3643                         SOURCES_COMPILE_DEFINITIONS ${_sourcesDefinitions}
3644                         PRE_UNDEFS ${_targetPreUndefs}
3645                         POST_UNDEFS ${_targetPostUndefs}
3646                         SOURCES_PRE_UNDEFS ${_sourcesPreUndefs}
3647                         SOURCES_POST_UNDEFS ${_sourcesPostUndefs}
3648                         ${_dependsOption})
3649
3650         elseif ("${COTIRE_ARGV1}" STREQUAL "prefix")
3651
3652                 if (XCODE)
3653                         # executing pre-build action under Xcode, check dependency on unity file and prefix dependencies
3654                         set (_dependsOption DEPENDS "${COTIRE_ARGV4}" ${COTIRE_TARGET_PREFIX_DEPENDS})
3655                 else()
3656                         # executing custom command, no need to re-check for dependencies
3657                         set (_dependsOption "")
3658                 endif()
3659
3660                 set (_files "")
3661                 foreach (_index RANGE 4 ${COTIRE_ARGC})
3662                         if (COTIRE_ARGV${_index})
3663                                 list (APPEND _files "${COTIRE_ARGV${_index}}")
3664                         endif()
3665                 endforeach()
3666
3667                 cotire_generate_prefix_header(
3668                         "${COTIRE_ARGV3}" ${_files}
3669                         COMPILER_LAUNCHER "${COTIRE_TARGET_${COTIRE_TARGET_LANGUAGE}_COMPILER_LAUNCHER}"
3670                         COMPILER_EXECUTABLE "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER}"
3671                         COMPILER_ARG1 ${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ARG1}
3672                         COMPILER_ID "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ID}"
3673                         COMPILER_VERSION "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_VERSION}"
3674                         LANGUAGE "${COTIRE_TARGET_LANGUAGE}"
3675                         IGNORE_PATH "${COTIRE_TARGET_IGNORE_PATH};${COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH}"
3676                         INCLUDE_PATH ${COTIRE_TARGET_INCLUDE_PATH}
3677                         IGNORE_EXTENSIONS "${CMAKE_${COTIRE_TARGET_LANGUAGE}_SOURCE_FILE_EXTENSIONS};${COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS}"
3678                         INCLUDE_PRIORITY_PATH ${COTIRE_TARGET_INCLUDE_PRIORITY_PATH}
3679                         INCLUDE_DIRECTORIES ${_includeDirs}
3680                         SYSTEM_INCLUDE_DIRECTORIES ${_systemIncludeDirs}
3681                         COMPILE_DEFINITIONS ${_compileDefinitions}
3682                         COMPILE_FLAGS ${_compileFlags}
3683                         ${_dependsOption})
3684
3685         elseif ("${COTIRE_ARGV1}" STREQUAL "precompile")
3686
3687                 set (_files "")
3688                 foreach (_index RANGE 5 ${COTIRE_ARGC})
3689                         if (COTIRE_ARGV${_index})
3690                                 list (APPEND _files "${COTIRE_ARGV${_index}}")
3691                         endif()
3692                 endforeach()
3693
3694                 cotire_precompile_prefix_header(
3695                         "${COTIRE_ARGV3}" "${COTIRE_ARGV4}" "${COTIRE_ARGV5}"
3696                         COMPILER_LAUNCHER "${COTIRE_TARGET_${COTIRE_TARGET_LANGUAGE}_COMPILER_LAUNCHER}"
3697                         COMPILER_EXECUTABLE "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER}"
3698                         COMPILER_ARG1 ${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ARG1}
3699                         COMPILER_ID "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ID}"
3700                         COMPILER_VERSION "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_VERSION}"
3701                         LANGUAGE "${COTIRE_TARGET_LANGUAGE}"
3702                         INCLUDE_DIRECTORIES ${_includeDirs}
3703                         SYSTEM_INCLUDE_DIRECTORIES ${_systemIncludeDirs}
3704                         COMPILE_DEFINITIONS ${_compileDefinitions}
3705                         COMPILE_FLAGS ${_compileFlags})
3706
3707         elseif ("${COTIRE_ARGV1}" STREQUAL "combine")
3708
3709                 if (COTIRE_TARGET_LANGUAGE)
3710                         set (_combinedFile "${COTIRE_ARGV3}")
3711                         set (_startIndex 4)
3712                 else()
3713                         set (_combinedFile "${COTIRE_ARGV2}")
3714                         set (_startIndex 3)
3715                 endif()
3716                 set (_files "")
3717                 foreach (_index RANGE ${_startIndex} ${COTIRE_ARGC})
3718                         if (COTIRE_ARGV${_index})
3719                                 list (APPEND _files "${COTIRE_ARGV${_index}}")
3720                         endif()
3721                 endforeach()
3722
3723                 if (XCODE)
3724                         # executing pre-build action under Xcode, check dependency on files to be combined
3725                         set (_dependsOption DEPENDS ${_files})
3726                 else()
3727                         # executing custom command, no need to re-check for dependencies
3728                         set (_dependsOption "")
3729                 endif()
3730
3731                 if (COTIRE_TARGET_LANGUAGE)
3732                         cotire_generate_unity_source(
3733                                 "${_combinedFile}" ${_files}
3734                                 LANGUAGE "${COTIRE_TARGET_LANGUAGE}"
3735                                 ${_dependsOption})
3736                 else()
3737                         cotire_generate_unity_source("${_combinedFile}" ${_files} ${_dependsOption})
3738                 endif()
3739
3740         elseif ("${COTIRE_ARGV1}" STREQUAL "cleanup")
3741
3742                 cotire_cleanup("${COTIRE_ARGV2}" "${COTIRE_ARGV3}" "${COTIRE_ARGV4}")
3743
3744         else()
3745                 message (FATAL_ERROR "cotire: unknown command \"${COTIRE_ARGV1}\".")
3746         endif()
3747
3748 else()
3749
3750         # cotire is being run in include mode
3751         # set up all variable and property definitions
3752
3753         if (NOT DEFINED COTIRE_DEBUG_INIT)
3754                 if (DEFINED COTIRE_DEBUG)
3755                         set (COTIRE_DEBUG_INIT ${COTIRE_DEBUG})
3756                 else()
3757                         set (COTIRE_DEBUG_INIT FALSE)
3758                 endif()
3759         endif()
3760         option (COTIRE_DEBUG "Enable cotire debugging output?" ${COTIRE_DEBUG_INIT})
3761
3762         if (NOT DEFINED COTIRE_VERBOSE_INIT)
3763                 if (DEFINED COTIRE_VERBOSE)
3764                         set (COTIRE_VERBOSE_INIT ${COTIRE_VERBOSE})
3765                 else()
3766                         set (COTIRE_VERBOSE_INIT FALSE)
3767                 endif()
3768         endif()
3769         option (COTIRE_VERBOSE "Enable cotire verbose output?" ${COTIRE_VERBOSE_INIT})
3770
3771         set (COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS "inc;inl;ipp" CACHE STRING
3772                 "Ignore headers with the listed file extensions from the generated prefix header.")
3773
3774         set (COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH "" CACHE STRING
3775                 "Ignore headers from these directories when generating the prefix header.")
3776
3777         set (COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS "m;mm" CACHE STRING
3778                 "Ignore sources with the listed file extensions from the generated unity source.")
3779
3780         set (COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES "2" CACHE STRING
3781                 "Minimum number of sources in target required to enable use of precompiled header.")
3782
3783         if (NOT DEFINED COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT)
3784                 if (DEFINED COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES)
3785                         set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT ${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES})
3786                 elseif ("${CMAKE_GENERATOR}" MATCHES "JOM|Ninja|Visual Studio")
3787                         # enable parallelization for generators that run multiple jobs by default
3788                         set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT "-j")
3789                 else()
3790                         set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT "0")
3791                 endif()
3792         endif()
3793         set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES "${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT}" CACHE STRING
3794                 "Maximum number of source files to include in a single unity source file.")
3795
3796         if (NOT COTIRE_PREFIX_HEADER_FILENAME_SUFFIX)
3797                 set (COTIRE_PREFIX_HEADER_FILENAME_SUFFIX "_prefix")
3798         endif()
3799         if (NOT COTIRE_UNITY_SOURCE_FILENAME_SUFFIX)
3800                 set (COTIRE_UNITY_SOURCE_FILENAME_SUFFIX "_unity")
3801         endif()
3802         if (NOT COTIRE_INTDIR)
3803                 set (COTIRE_INTDIR "cotire")
3804         endif()
3805         if (NOT COTIRE_PCH_ALL_TARGET_NAME)
3806                 set (COTIRE_PCH_ALL_TARGET_NAME "all_pch")
3807         endif()
3808         if (NOT COTIRE_UNITY_BUILD_ALL_TARGET_NAME)
3809                 set (COTIRE_UNITY_BUILD_ALL_TARGET_NAME "all_unity")
3810         endif()
3811         if (NOT COTIRE_CLEAN_ALL_TARGET_NAME)
3812                 set (COTIRE_CLEAN_ALL_TARGET_NAME "clean_cotire")
3813         endif()
3814         if (NOT COTIRE_CLEAN_TARGET_SUFFIX)
3815                 set (COTIRE_CLEAN_TARGET_SUFFIX "_clean_cotire")
3816         endif()
3817         if (NOT COTIRE_PCH_TARGET_SUFFIX)
3818                 set (COTIRE_PCH_TARGET_SUFFIX "_pch")
3819         endif()
3820         if (MSVC)
3821                 # MSVC default PCH memory scaling factor of 100 percent (75 MB) is too small for template heavy C++ code
3822                 # use a bigger default factor of 170 percent (128 MB)
3823                 if (NOT DEFINED COTIRE_PCH_MEMORY_SCALING_FACTOR)
3824                         set (COTIRE_PCH_MEMORY_SCALING_FACTOR "170")
3825                 endif()
3826         endif()
3827         if (NOT COTIRE_UNITY_BUILD_TARGET_SUFFIX)
3828                 set (COTIRE_UNITY_BUILD_TARGET_SUFFIX "_unity")
3829         endif()
3830         if (NOT DEFINED COTIRE_TARGETS_FOLDER)
3831                 set (COTIRE_TARGETS_FOLDER "cotire")
3832         endif()
3833         if (NOT DEFINED COTIRE_UNITY_OUTPUT_DIRECTORY)
3834                 if ("${CMAKE_GENERATOR}" MATCHES "Ninja")
3835                         # generated Ninja build files do not work if the unity target produces the same output file as the cotired target
3836                         set (COTIRE_UNITY_OUTPUT_DIRECTORY "unity")
3837                 else()
3838                         set (COTIRE_UNITY_OUTPUT_DIRECTORY "")
3839                 endif()
3840         endif()
3841
3842         # define cotire cache variables
3843
3844         define_property(
3845                 CACHED_VARIABLE PROPERTY "COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH"
3846                 BRIEF_DOCS "Ignore headers from these directories when generating the prefix header."
3847                 FULL_DOCS
3848                         "The variable can be set to a semicolon separated list of include directories."
3849                         "If a header file is found in one of these directories or sub-directories, it will be excluded from the generated prefix header."
3850                         "If not defined, defaults to empty list."
3851         )
3852
3853         define_property(
3854                 CACHED_VARIABLE PROPERTY "COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS"
3855                 BRIEF_DOCS "Ignore includes with the listed file extensions from the generated prefix header."
3856                 FULL_DOCS
3857                         "The variable can be set to a semicolon separated list of file extensions."
3858                         "If a header file extension matches one in the list, it will be excluded from the generated prefix header."
3859                         "Includes with an extension in CMAKE_<LANG>_SOURCE_FILE_EXTENSIONS are always ignored."
3860                         "If not defined, defaults to inc;inl;ipp."
3861         )
3862
3863         define_property(
3864                 CACHED_VARIABLE PROPERTY "COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS"
3865                 BRIEF_DOCS "Exclude sources with the listed file extensions from the generated unity source."
3866                 FULL_DOCS
3867                         "The variable can be set to a semicolon separated list of file extensions."
3868                         "If a source file extension matches one in the list, it will be excluded from the generated unity source file."
3869                         "Source files with an extension in CMAKE_<LANG>_IGNORE_EXTENSIONS are always excluded."
3870                         "If not defined, defaults to m;mm."
3871         )
3872
3873         define_property(
3874                 CACHED_VARIABLE PROPERTY "COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES"
3875                 BRIEF_DOCS "Minimum number of sources in target required to enable use of precompiled header."
3876                 FULL_DOCS
3877                         "The variable can be set to an integer > 0."
3878                         "If a target contains less than that number of source files, cotire will not enable the use of the precompiled header for the target."
3879                         "If not defined, defaults to 2."
3880         )
3881
3882         define_property(
3883                 CACHED_VARIABLE PROPERTY "COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES"
3884                 BRIEF_DOCS "Maximum number of source files to include in a single unity source file."
3885                 FULL_DOCS
3886                         "This may be set to an integer >= 0."
3887                         "If 0, cotire will only create a single unity source file."
3888                         "If a target contains more than that number of source files, cotire will create multiple unity source files for it."
3889                         "Can be set to \"-j\" to optimize the count of unity source files for the number of available processor cores."
3890                         "Can be set to \"-j jobs\" to optimize the number of unity source files for the given number of simultaneous jobs."
3891                         "Is used to initialize the target property COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES."
3892                         "Defaults to \"-j\" for the generators Visual Studio, JOM or Ninja. Defaults to 0 otherwise."
3893         )
3894
3895         # define cotire directory properties
3896
3897         define_property(
3898                 DIRECTORY PROPERTY "COTIRE_ENABLE_PRECOMPILED_HEADER"
3899                 BRIEF_DOCS "Modify build command of cotired targets added in this directory to make use of the generated precompiled header."
3900                 FULL_DOCS
3901                         "See target property COTIRE_ENABLE_PRECOMPILED_HEADER."
3902         )
3903
3904         define_property(
3905                 DIRECTORY PROPERTY "COTIRE_ADD_UNITY_BUILD"
3906                 BRIEF_DOCS "Add a new target that performs a unity build for cotired targets added in this directory."
3907                 FULL_DOCS
3908                         "See target property COTIRE_ADD_UNITY_BUILD."
3909         )
3910
3911         define_property(
3912                 DIRECTORY PROPERTY "COTIRE_ADD_CLEAN"
3913                 BRIEF_DOCS "Add a new target that cleans all cotire generated files for cotired targets added in this directory."
3914                 FULL_DOCS
3915                         "See target property COTIRE_ADD_CLEAN."
3916         )
3917
3918         define_property(
3919                 DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_IGNORE_PATH"
3920                 BRIEF_DOCS "Ignore headers from these directories when generating the prefix header."
3921                 FULL_DOCS
3922                         "See target property COTIRE_PREFIX_HEADER_IGNORE_PATH."
3923         )
3924
3925         define_property(
3926                 DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PATH"
3927                 BRIEF_DOCS "Honor headers from these directories when generating the prefix header."
3928                 FULL_DOCS
3929                         "See target property COTIRE_PREFIX_HEADER_INCLUDE_PATH."
3930         )
3931
3932         define_property(
3933                 DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH"
3934                 BRIEF_DOCS "Header paths matching one of these directories are put at the top of the prefix header."
3935                 FULL_DOCS
3936                         "See target property COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH."
3937         )
3938
3939         define_property(
3940                 DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS"
3941                 BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of each source file."
3942                 FULL_DOCS
3943                         "See target property COTIRE_UNITY_SOURCE_PRE_UNDEFS."
3944         )
3945
3946         define_property(
3947                 DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS"
3948                 BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of each source file."
3949                 FULL_DOCS
3950                         "See target property COTIRE_UNITY_SOURCE_POST_UNDEFS."
3951         )
3952
3953         define_property(
3954                 DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES"
3955                 BRIEF_DOCS "Maximum number of source files to include in a single unity source file."
3956                 FULL_DOCS
3957                         "See target property COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES."
3958         )
3959
3960         define_property(
3961                 DIRECTORY PROPERTY "COTIRE_UNITY_LINK_LIBRARIES_INIT"
3962                 BRIEF_DOCS "Define strategy for setting up the unity target's link libraries."
3963                 FULL_DOCS
3964                         "See target property COTIRE_UNITY_LINK_LIBRARIES_INIT."
3965         )
3966
3967         # define cotire target properties
3968
3969         define_property(
3970                 TARGET PROPERTY "COTIRE_ENABLE_PRECOMPILED_HEADER" INHERITED
3971                 BRIEF_DOCS "Modify this target's build command to make use of the generated precompiled header."
3972                 FULL_DOCS
3973                         "If this property is set to TRUE, cotire will modify the build command to make use of the generated precompiled header."
3974                         "Irrespective of the value of this property, cotire will setup custom commands to generate the unity source and prefix header for the target."
3975                         "For makefile based generators cotire will also set up a custom target to manually invoke the generation of the precompiled header."
3976                         "The target name will be set to this target's name with the suffix _pch appended."
3977                         "Inherited from directory."
3978                         "Defaults to TRUE."
3979         )
3980
3981         define_property(
3982                 TARGET PROPERTY "COTIRE_ADD_UNITY_BUILD" INHERITED
3983                 BRIEF_DOCS "Add a new target that performs a unity build for this target."
3984                 FULL_DOCS
3985                         "If this property is set to TRUE, cotire creates a new target of the same type that uses the generated unity source file instead of the target sources."
3986                         "Most of the relevant target properties will be copied from this target to the new unity build target."
3987                         "Target dependencies and linked libraries have to be manually set up for the new unity build target."
3988                         "The unity target name will be set to this target's name with the suffix _unity appended."
3989                         "Inherited from directory."
3990                         "Defaults to TRUE."
3991         )
3992
3993         define_property(
3994                 TARGET PROPERTY "COTIRE_ADD_CLEAN" INHERITED
3995                 BRIEF_DOCS "Add a new target that cleans all cotire generated files for this target."
3996                 FULL_DOCS
3997                         "If this property is set to TRUE, cotire creates a new target that clean all files (unity source, prefix header, precompiled header)."
3998                         "The clean target name will be set to this target's name with the suffix _clean_cotire appended."
3999                         "Inherited from directory."
4000                         "Defaults to FALSE."
4001         )
4002
4003         define_property(
4004                 TARGET PROPERTY "COTIRE_PREFIX_HEADER_IGNORE_PATH" INHERITED
4005                 BRIEF_DOCS "Ignore headers from these directories when generating the prefix header."
4006                 FULL_DOCS
4007                         "The property can be set to a list of directories."
4008                         "If a header file is found in one of these directories or sub-directories, it will be excluded from the generated prefix header."
4009                         "Inherited from directory."
4010                         "If not set, this property is initialized to \${CMAKE_SOURCE_DIR};\${CMAKE_BINARY_DIR}."
4011         )
4012
4013         define_property(
4014                 TARGET PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PATH" INHERITED
4015                 BRIEF_DOCS "Honor headers from these directories when generating the prefix header."
4016                 FULL_DOCS
4017                         "The property can be set to a list of directories."
4018                         "If a header file is found in one of these directories or sub-directories, it will be included in the generated prefix header."
4019                         "If a header file is both selected by COTIRE_PREFIX_HEADER_IGNORE_PATH and COTIRE_PREFIX_HEADER_INCLUDE_PATH,"
4020                         "the option which yields the closer relative path match wins."
4021                         "Inherited from directory."
4022                         "If not set, this property is initialized to the empty list."
4023         )
4024
4025         define_property(
4026                 TARGET PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH" INHERITED
4027                 BRIEF_DOCS "Header paths matching one of these directories are put at the top of prefix header."
4028                 FULL_DOCS
4029                         "The property can be set to a list of directories."
4030                         "Header file paths matching one of these directories will be inserted at the beginning of the generated prefix header."
4031                         "Header files are sorted according to the order of the directories in the property."
4032                         "If not set, this property is initialized to the empty list."
4033         )
4034
4035         define_property(
4036                 TARGET PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" INHERITED
4037                 BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of each target source file."
4038                 FULL_DOCS
4039                         "This may be set to a semicolon-separated list of preprocessor symbols."
4040                         "cotire will add corresponding #undef directives to the generated unit source file before each target source file."
4041                         "Inherited from directory."
4042                         "Defaults to empty string."
4043         )
4044
4045         define_property(
4046                 TARGET PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" INHERITED
4047                 BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of each target source file."
4048                 FULL_DOCS
4049                         "This may be set to a semicolon-separated list of preprocessor symbols."
4050                         "cotire will add corresponding #undef directives to the generated unit source file after each target source file."
4051                         "Inherited from directory."
4052                         "Defaults to empty string."
4053         )
4054
4055         define_property(
4056                 TARGET PROPERTY "COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES" INHERITED
4057                 BRIEF_DOCS "Maximum number of source files to include in a single unity source file."
4058                 FULL_DOCS
4059                         "This may be set to an integer > 0."
4060                         "If a target contains more than that number of source files, cotire will create multiple unity build files for it."
4061                         "If not set, cotire will only create a single unity source file."
4062                         "Inherited from directory."
4063                         "Defaults to empty."
4064         )
4065
4066         define_property(
4067                 TARGET PROPERTY "COTIRE_<LANG>_UNITY_SOURCE_INIT"
4068                 BRIEF_DOCS "User provided unity source file to be used instead of the automatically generated one."
4069                 FULL_DOCS
4070                         "If set, cotire will only add the given file(s) to the generated unity source file."
4071                         "If not set, cotire will add all the target source files to the generated unity source file."
4072                         "The property can be set to a user provided unity source file."
4073                         "Defaults to empty."
4074         )
4075
4076         define_property(
4077                 TARGET PROPERTY "COTIRE_<LANG>_PREFIX_HEADER_INIT"
4078                 BRIEF_DOCS "User provided prefix header file to be used instead of the automatically generated one."
4079                 FULL_DOCS
4080                         "If set, cotire will add the given header file(s) to the generated prefix header file."
4081                         "If not set, cotire will generate a prefix header by tracking the header files included by the unity source file."
4082                         "The property can be set to a user provided prefix header file (e.g., stdafx.h)."
4083                         "Defaults to empty."
4084         )
4085
4086         define_property(
4087                 TARGET PROPERTY "COTIRE_UNITY_LINK_LIBRARIES_INIT" INHERITED
4088                 BRIEF_DOCS "Define strategy for setting up unity target's link libraries."
4089                 FULL_DOCS
4090                         "If this property is empty or set to NONE, the generated unity target's link libraries have to be set up manually."
4091                         "If this property is set to COPY, the unity target's link libraries will be copied from this target."
4092                         "If this property is set to COPY_UNITY, the unity target's link libraries will be copied from this target with considering existing unity targets."
4093                         "Inherited from directory."
4094                         "Defaults to empty."
4095         )
4096
4097         define_property(
4098                 TARGET PROPERTY "COTIRE_<LANG>_UNITY_SOURCE"
4099                 BRIEF_DOCS "Read-only property. The generated <LANG> unity source file(s)."
4100                 FULL_DOCS
4101                         "cotire sets this property to the path of the generated <LANG> single computation unit source file for the target."
4102                         "Defaults to empty string."
4103         )
4104
4105         define_property(
4106                 TARGET PROPERTY "COTIRE_<LANG>_PREFIX_HEADER"
4107                 BRIEF_DOCS "Read-only property. The generated <LANG> prefix header file."
4108                 FULL_DOCS
4109                         "cotire sets this property to the full path of the generated <LANG> language prefix header for the target."
4110                         "Defaults to empty string."
4111         )
4112
4113         define_property(
4114                 TARGET PROPERTY "COTIRE_<LANG>_PRECOMPILED_HEADER"
4115                 BRIEF_DOCS "Read-only property. The generated <LANG> precompiled header file."
4116                 FULL_DOCS
4117                         "cotire sets this property to the full path of the generated <LANG> language precompiled header binary for the target."
4118                         "Defaults to empty string."
4119         )
4120
4121         define_property(
4122                 TARGET PROPERTY "COTIRE_UNITY_TARGET_NAME"
4123                 BRIEF_DOCS "The name of the generated unity build target corresponding to this target."
4124                 FULL_DOCS
4125                         "This property can be set to the desired name of the unity target that will be created by cotire."
4126                         "If not set, the unity target name will be set to this target's name with the suffix _unity appended."
4127                         "After this target has been processed by cotire, the property is set to the actual name of the generated unity target."
4128                         "Defaults to empty string."
4129         )
4130
4131         # define cotire source properties
4132
4133         define_property(
4134                 SOURCE PROPERTY "COTIRE_EXCLUDED"
4135                 BRIEF_DOCS "Do not modify source file's build command."
4136                 FULL_DOCS
4137                         "If this property is set to TRUE, the source file's build command will not be modified to make use of the precompiled header."
4138                         "The source file will also be excluded from the generated unity source file."
4139                         "Source files that have their COMPILE_FLAGS property set will be excluded by default."
4140                         "Defaults to FALSE."
4141         )
4142
4143         define_property(
4144                 SOURCE PROPERTY "COTIRE_DEPENDENCY"
4145                 BRIEF_DOCS "Add this source file to dependencies of the automatically generated prefix header file."
4146                 FULL_DOCS
4147                         "If this property is set to TRUE, the source file is added to dependencies of the generated prefix header file."
4148                         "If the file is modified, cotire will re-generate the prefix header source upon build."
4149                         "Defaults to FALSE."
4150         )
4151
4152         define_property(
4153                 SOURCE PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS"
4154                 BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of this source file."
4155                 FULL_DOCS
4156                         "This may be set to a semicolon-separated list of preprocessor symbols."
4157                         "cotire will add corresponding #undef directives to the generated unit source file before this file is included."
4158                         "Defaults to empty string."
4159         )
4160
4161         define_property(
4162                 SOURCE PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS"
4163                 BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of this source file."
4164                 FULL_DOCS
4165                         "This may be set to a semicolon-separated list of preprocessor symbols."
4166                         "cotire will add corresponding #undef directives to the generated unit source file after this file is included."
4167                         "Defaults to empty string."
4168         )
4169
4170         define_property(
4171                 SOURCE PROPERTY "COTIRE_START_NEW_UNITY_SOURCE"
4172                 BRIEF_DOCS "Start a new unity source file which includes this source file as the first one."
4173                 FULL_DOCS
4174                         "If this property is set to TRUE, cotire will complete the current unity file and start a new one."
4175                         "The new unity source file will include this source file as the first one."
4176                         "This property essentially works as a separator for unity source files."
4177                         "Defaults to FALSE."
4178         )
4179
4180         define_property(
4181                 SOURCE PROPERTY "COTIRE_TARGET"
4182                 BRIEF_DOCS "Read-only property. Mark this source file as cotired for the given target."
4183                 FULL_DOCS
4184                         "cotire sets this property to the name of target, that the source file's build command has been altered for."
4185                         "Defaults to empty string."
4186         )
4187
4188         message (STATUS "cotire ${COTIRE_CMAKE_MODULE_VERSION} loaded.")
4189
4190 endif()