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