Merge pull request #171 from pefoley2/lto
[dyninst.git] / 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.8")
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 (_target)
454                 get_target_property(_targetLanguageStandard ${_target} ${_language}_STANDARD)
455                 get_target_property(_targetLanguageExtensions ${_target} ${_language}_EXTENSIONS)
456                 get_target_property(_targetLanguageStandardRequired ${_target} ${_language}_STANDARD_REQUIRED)
457                 if (_targetLanguageExtensions)
458                         if (CMAKE_${_language}${_targetLanguageExtensions}_EXTENSION_COMPILE_OPTION)
459                                 list (APPEND _compileFlags "${CMAKE_${_language}${_targetLanguageExtensions}_EXTENSION_COMPILE_OPTION}")
460                         endif()
461                 elseif (_targetLanguageStandard)
462                         if (_targetLanguageStandardRequired)
463                                 if (CMAKE_${_language}${_targetLanguageStandard}_STANDARD_COMPILE_OPTION)
464                                         list (APPEND _compileFlags "${CMAKE_${_language}${_targetLanguageStandard}_STANDARD_COMPILE_OPTION}")
465                                 endif()
466                         else()
467                                 if (CMAKE_${_language}${_targetLanguageStandard}_EXTENSION_COMPILE_OPTION)
468                                         list (APPEND _compileFlags "${CMAKE_${_language}${_targetLanguageStandard}_EXTENSION_COMPILE_OPTION}")
469                                 endif()
470                         endif()
471                 endif()
472         endif()
473         # handle the POSITION_INDEPENDENT_CODE target property
474         if (_target)
475                 get_target_property(_targetPIC ${_target} POSITION_INDEPENDENT_CODE)
476                 if (_targetPIC)
477                         get_target_property(_targetType ${_target} TYPE)
478                         if (_targetType STREQUAL "EXECUTABLE" AND CMAKE_${_language}_COMPILE_OPTIONS_PIE)
479                                 list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_PIE}")
480                         elseif (CMAKE_${_language}_COMPILE_OPTIONS_PIC)
481                                 list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_PIC}")
482                         endif()
483                 endif()
484         endif()
485         # handle visibility target properties
486         if (_target)
487                 get_target_property(_targetVisibility ${_target} ${_language}_VISIBILITY_PRESET)
488                 if (_targetVisibility AND CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY)
489                         list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY}${_targetVisibility}")
490                 endif()
491                 get_target_property(_targetVisibilityInlines ${_target} VISIBILITY_INLINES_HIDDEN)
492                 if (_targetVisibilityInlines AND CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN)
493                         list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN}")
494                 endif()
495         endif()
496         # platform specific flags
497         if (APPLE)
498                 get_target_property(_architectures ${_target} OSX_ARCHITECTURES_${_upperConfig})
499                 if (NOT _architectures)
500                         get_target_property(_architectures ${_target} OSX_ARCHITECTURES)
501                 endif()
502                 if (_architectures)
503                         foreach (_arch ${_architectures})
504                                 list (APPEND _compileFlags "-arch" "${_arch}")
505                         endforeach()
506                 endif()
507                 if (CMAKE_OSX_SYSROOT)
508                         if (CMAKE_${_language}_SYSROOT_FLAG)
509                                 list (APPEND _compileFlags "${CMAKE_${_language}_SYSROOT_FLAG}" "${CMAKE_OSX_SYSROOT}")
510                         else()
511                                 list (APPEND _compileFlags "-isysroot" "${CMAKE_OSX_SYSROOT}")
512                         endif()
513                 endif()
514                 if (CMAKE_OSX_DEPLOYMENT_TARGET)
515                         if (CMAKE_${_language}_OSX_DEPLOYMENT_TARGET_FLAG)
516                                 list (APPEND _compileFlags "${CMAKE_${_language}_OSX_DEPLOYMENT_TARGET_FLAG}${CMAKE_OSX_DEPLOYMENT_TARGET}")
517                         else()
518                                 list (APPEND _compileFlags "-mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}")
519                         endif()
520                 endif()
521         endif()
522         if (COTIRE_DEBUG AND _compileFlags)
523                 message (STATUS "Target ${_target} compile flags: ${_compileFlags}")
524         endif()
525         set (${_flagsVar} ${_compileFlags} PARENT_SCOPE)
526 endfunction()
527
528 function (cotire_get_target_include_directories _config _language _target _includeDirsVar _systemIncludeDirsVar)
529         set (_includeDirs "")
530         set (_systemIncludeDirs "")
531         # default include dirs
532         if (CMAKE_INCLUDE_CURRENT_DIR)
533                 list (APPEND _includeDirs "${CMAKE_CURRENT_BINARY_DIR}")
534                 list (APPEND _includeDirs "${CMAKE_CURRENT_SOURCE_DIR}")
535         endif()
536         set (_targetFlags "")
537         cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags)
538         # parse additional include directories from target compile flags
539         if (CMAKE_INCLUDE_FLAG_${_language})
540                 string (STRIP "${CMAKE_INCLUDE_FLAG_${_language}}" _includeFlag)
541                 string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}")
542                 if (_includeFlag)
543                         set (_dirs "")
544                         cotire_filter_compile_flags("${_language}" "${_includeFlag}" _dirs _ignore ${_targetFlags})
545                         if (_dirs)
546                                 list (APPEND _includeDirs ${_dirs})
547                         endif()
548                 endif()
549         endif()
550         # parse additional system include directories from target compile flags
551         if (CMAKE_INCLUDE_SYSTEM_FLAG_${_language})
552                 string (STRIP "${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}" _includeFlag)
553                 string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}")
554                 if (_includeFlag)
555                         set (_dirs "")
556                         cotire_filter_compile_flags("${_language}" "${_includeFlag}" _dirs _ignore ${_targetFlags})
557                         if (_dirs)
558                                 list (APPEND _systemIncludeDirs ${_dirs})
559                         endif()
560                 endif()
561         endif()
562         # target include directories
563         get_directory_property(_dirs DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" INCLUDE_DIRECTORIES)
564         if (_target)
565                 get_target_property(_targetDirs ${_target} INCLUDE_DIRECTORIES)
566                 if (_targetDirs)
567                         list (APPEND _dirs ${_targetDirs})
568                 endif()
569                 get_target_property(_targetDirs ${_target} INTERFACE_SYSTEM_INCLUDE_DIRECTORIES)
570                 if (_targetDirs)
571                         list (APPEND _systemIncludeDirs ${_targetDirs})
572                 endif()
573         endif()
574         # interface include directories from linked library targets
575         if (_target)
576                 set (_linkedTargets "")
577                 cotire_get_target_usage_requirements(${_target} _linkedTargets)
578                 foreach (_linkedTarget ${_linkedTargets})
579                         get_target_property(_linkedTargetType ${_linkedTarget} TYPE)
580                         if (CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE AND NOT CMAKE_VERSION VERSION_LESS "3.4.0" AND
581                                 _linkedTargetType MATCHES "(STATIC|SHARED|MODULE|OBJECT)_LIBRARY")
582                                 # CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE refers to CMAKE_CURRENT_BINARY_DIR and CMAKE_CURRENT_SOURCE_DIR
583                                 # at the time, when the target was created. These correspond to the target properties BINARY_DIR and SOURCE_DIR
584                                 # which are only available with CMake 3.4 or later.
585                                 get_target_property(_targetDirs ${_linkedTarget} BINARY_DIR)
586                                 if (_targetDirs)
587                                         list (APPEND _dirs ${_targetDirs})
588                                 endif()
589                                 get_target_property(_targetDirs ${_linkedTarget} SOURCE_DIR)
590                                 if (_targetDirs)
591                                         list (APPEND _dirs ${_targetDirs})
592                                 endif()
593                         endif()
594                         get_target_property(_targetDirs ${_linkedTarget} INTERFACE_INCLUDE_DIRECTORIES)
595                         if (_targetDirs)
596                                 list (APPEND _dirs ${_targetDirs})
597                         endif()
598                         get_target_property(_targetDirs ${_linkedTarget} INTERFACE_SYSTEM_INCLUDE_DIRECTORIES)
599                         if (_targetDirs)
600                                 list (APPEND _systemIncludeDirs ${_targetDirs})
601                         endif()
602                 endforeach()
603         endif()
604         if (dirs)
605                 list (REMOVE_DUPLICATES _dirs)
606         endif()
607         list (LENGTH _includeDirs _projectInsertIndex)
608         foreach (_dir ${_dirs})
609                 if (CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE)
610                         cotire_check_is_path_relative_to("${_dir}" _isRelative "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}")
611                         if (_isRelative)
612                                 list (LENGTH _includeDirs _len)
613                                 if (_len EQUAL _projectInsertIndex)
614                                         list (APPEND _includeDirs "${_dir}")
615                                 else()
616                                         list (INSERT _includeDirs _projectInsertIndex "${_dir}")
617                                 endif()
618                                 math (EXPR _projectInsertIndex "${_projectInsertIndex} + 1")
619                         else()
620                                 list (APPEND _includeDirs "${_dir}")
621                         endif()
622                 else()
623                         list (APPEND _includeDirs "${_dir}")
624                 endif()
625         endforeach()
626         list (REMOVE_DUPLICATES _includeDirs)
627         list (REMOVE_DUPLICATES _systemIncludeDirs)
628         if (CMAKE_${_language}_IMPLICIT_INCLUDE_DIRECTORIES)
629                 list (REMOVE_ITEM _includeDirs ${CMAKE_${_language}_IMPLICIT_INCLUDE_DIRECTORIES})
630         endif()
631         if (COTIRE_DEBUG AND _includeDirs)
632                 message (STATUS "Target ${_target} include dirs: ${_includeDirs}")
633         endif()
634         set (${_includeDirsVar} ${_includeDirs} PARENT_SCOPE)
635         if (COTIRE_DEBUG AND _systemIncludeDirs)
636                 message (STATUS "Target ${_target} system include dirs: ${_systemIncludeDirs}")
637         endif()
638         set (${_systemIncludeDirsVar} ${_systemIncludeDirs} PARENT_SCOPE)
639 endfunction()
640
641 function (cotire_get_target_export_symbol _target _exportSymbolVar)
642         set (_exportSymbol "")
643         get_target_property(_targetType ${_target} TYPE)
644         get_target_property(_enableExports ${_target} ENABLE_EXPORTS)
645         if (_targetType MATCHES "(SHARED|MODULE)_LIBRARY" OR
646                 (_targetType STREQUAL "EXECUTABLE" AND _enableExports))
647                 get_target_property(_exportSymbol ${_target} DEFINE_SYMBOL)
648                 if (NOT _exportSymbol)
649                         set (_exportSymbol "${_target}_EXPORTS")
650                 endif()
651                 string (MAKE_C_IDENTIFIER "${_exportSymbol}" _exportSymbol)
652         endif()
653         set (${_exportSymbolVar} ${_exportSymbol} PARENT_SCOPE)
654 endfunction()
655
656 function (cotire_get_target_compile_definitions _config _language _target _definitionsVar)
657         string (TOUPPER "${_config}" _upperConfig)
658         set (_configDefinitions "")
659         # CMAKE_INTDIR for multi-configuration build systems
660         if (NOT "${CMAKE_CFG_INTDIR}" STREQUAL ".")
661                 list (APPEND _configDefinitions "CMAKE_INTDIR=\"${_config}\"")
662         endif()
663         # target export define symbol
664         cotire_get_target_export_symbol("${_target}" _defineSymbol)
665         if (_defineSymbol)
666                 list (APPEND _configDefinitions "${_defineSymbol}")
667         endif()
668         # directory compile definitions
669         get_directory_property(_definitions DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMPILE_DEFINITIONS)
670         if (_definitions)
671                 list (APPEND _configDefinitions ${_definitions})
672         endif()
673         get_directory_property(_definitions DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMPILE_DEFINITIONS_${_upperConfig})
674         if (_definitions)
675                 list (APPEND _configDefinitions ${_definitions})
676         endif()
677         # target compile definitions
678         get_target_property(_definitions ${_target} COMPILE_DEFINITIONS)
679         if (_definitions)
680                 list (APPEND _configDefinitions ${_definitions})
681         endif()
682         get_target_property(_definitions ${_target} COMPILE_DEFINITIONS_${_upperConfig})
683         if (_definitions)
684                 list (APPEND _configDefinitions ${_definitions})
685         endif()
686         # interface compile definitions from linked library targets
687         set (_linkedTargets "")
688         cotire_get_target_usage_requirements(${_target} _linkedTargets)
689         foreach (_linkedTarget ${_linkedTargets})
690                 get_target_property(_definitions ${_linkedTarget} INTERFACE_COMPILE_DEFINITIONS)
691                 if (_definitions)
692                         list (APPEND _configDefinitions ${_definitions})
693                 endif()
694         endforeach()
695         # parse additional compile definitions from target compile flags
696         # and don't look at directory compile definitions, which we already handled
697         set (_targetFlags "")
698         cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags)
699         cotire_filter_compile_flags("${_language}" "D" _definitions _ignore ${_targetFlags})
700         if (_definitions)
701                 list (APPEND _configDefinitions ${_definitions})
702         endif()
703         list (REMOVE_DUPLICATES _configDefinitions)
704         if (COTIRE_DEBUG AND _configDefinitions)
705                 message (STATUS "Target ${_target} compile definitions: ${_configDefinitions}")
706         endif()
707         set (${_definitionsVar} ${_configDefinitions} PARENT_SCOPE)
708 endfunction()
709
710 function (cotire_get_target_compiler_flags _config _language _target _compilerFlagsVar)
711         # parse target compile flags omitting compile definitions and include directives
712         set (_targetFlags "")
713         cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags)
714         set (_flagFilter "D")
715         if (CMAKE_INCLUDE_FLAG_${_language})
716                 string (STRIP "${CMAKE_INCLUDE_FLAG_${_language}}" _includeFlag)
717                 string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}")
718                 if (_includeFlag)
719                         set (_flagFilter "${_flagFilter}|${_includeFlag}")
720                 endif()
721         endif()
722         if (CMAKE_INCLUDE_SYSTEM_FLAG_${_language})
723                 string (STRIP "${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}" _includeFlag)
724                 string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}")
725                 if (_includeFlag)
726                         set (_flagFilter "${_flagFilter}|${_includeFlag}")
727                 endif()
728         endif()
729         set (_compilerFlags "")
730         cotire_filter_compile_flags("${_language}" "${_flagFilter}" _ignore _compilerFlags ${_targetFlags})
731         if (COTIRE_DEBUG AND _compilerFlags)
732                 message (STATUS "Target ${_target} compiler flags: ${_compilerFlags}")
733         endif()
734         set (${_compilerFlagsVar} ${_compilerFlags} PARENT_SCOPE)
735 endfunction()
736
737 function (cotire_add_sys_root_paths _pathsVar)
738         if (APPLE)
739                 if (CMAKE_OSX_SYSROOT AND CMAKE_${_language}_HAS_ISYSROOT)
740                         foreach (_path IN LISTS ${_pathsVar})
741                                 if (IS_ABSOLUTE "${_path}")
742                                         get_filename_component(_path "${CMAKE_OSX_SYSROOT}/${_path}" ABSOLUTE)
743                                         if (EXISTS "${_path}")
744                                                 list (APPEND ${_pathsVar} "${_path}")
745                                         endif()
746                                 endif()
747                         endforeach()
748                 endif()
749         endif()
750         set (${_pathsVar} ${${_pathsVar}} PARENT_SCOPE)
751 endfunction()
752
753 function (cotire_get_source_extra_properties _sourceFile _pattern _resultVar)
754         set (_extraProperties ${ARGN})
755         set (_result "")
756         if (_extraProperties)
757                 list (FIND _extraProperties "${_sourceFile}" _index)
758                 if (_index GREATER -1)
759                         math (EXPR _index "${_index} + 1")
760                         list (LENGTH _extraProperties _len)
761                         math (EXPR _len "${_len} - 1")
762                         foreach (_index RANGE ${_index} ${_len})
763                                 list (GET _extraProperties ${_index} _value)
764                                 if (_value MATCHES "${_pattern}")
765                                         list (APPEND _result "${_value}")
766                                 else()
767                                         break()
768                                 endif()
769                         endforeach()
770                 endif()
771         endif()
772         set (${_resultVar} ${_result} PARENT_SCOPE)
773 endfunction()
774
775 function (cotire_get_source_compile_definitions _config _language _sourceFile _definitionsVar)
776         set (_compileDefinitions "")
777         if (NOT CMAKE_SCRIPT_MODE_FILE)
778                 string (TOUPPER "${_config}" _upperConfig)
779                 get_source_file_property(_definitions "${_sourceFile}" COMPILE_DEFINITIONS)
780                 if (_definitions)
781                         list (APPEND _compileDefinitions ${_definitions})
782                 endif()
783                 get_source_file_property(_definitions "${_sourceFile}" COMPILE_DEFINITIONS_${_upperConfig})
784                 if (_definitions)
785                         list (APPEND _compileDefinitions ${_definitions})
786                 endif()
787         endif()
788         cotire_get_source_extra_properties("${_sourceFile}" "^[a-zA-Z0-9_]+(=.*)?$" _definitions ${ARGN})
789         if (_definitions)
790                 list (APPEND _compileDefinitions ${_definitions})
791         endif()
792         if (COTIRE_DEBUG AND _compileDefinitions)
793                 message (STATUS "Source ${_sourceFile} compile definitions: ${_compileDefinitions}")
794         endif()
795         set (${_definitionsVar} ${_compileDefinitions} PARENT_SCOPE)
796 endfunction()
797
798 function (cotire_get_source_files_compile_definitions _config _language _definitionsVar)
799         set (_configDefinitions "")
800         foreach (_sourceFile ${ARGN})
801                 cotire_get_source_compile_definitions("${_config}" "${_language}" "${_sourceFile}" _sourceDefinitions)
802                 if (_sourceDefinitions)
803                         list (APPEND _configDefinitions "${_sourceFile}" ${_sourceDefinitions} "-")
804                 endif()
805         endforeach()
806         set (${_definitionsVar} ${_configDefinitions} PARENT_SCOPE)
807 endfunction()
808
809 function (cotire_get_source_undefs _sourceFile _property _sourceUndefsVar)
810         set (_sourceUndefs "")
811         if (NOT CMAKE_SCRIPT_MODE_FILE)
812                 get_source_file_property(_undefs "${_sourceFile}" ${_property})
813                 if (_undefs)
814                         list (APPEND _sourceUndefs ${_undefs})
815                 endif()
816         endif()
817         cotire_get_source_extra_properties("${_sourceFile}" "^[a-zA-Z0-9_]+$" _undefs ${ARGN})
818         if (_undefs)
819                 list (APPEND _sourceUndefs ${_undefs})
820         endif()
821         if (COTIRE_DEBUG AND _sourceUndefs)
822                 message (STATUS "Source ${_sourceFile} ${_property} undefs: ${_sourceUndefs}")
823         endif()
824         set (${_sourceUndefsVar} ${_sourceUndefs} PARENT_SCOPE)
825 endfunction()
826
827 function (cotire_get_source_files_undefs _property _sourceUndefsVar)
828         set (_sourceUndefs "")
829         foreach (_sourceFile ${ARGN})
830                 cotire_get_source_undefs("${_sourceFile}" ${_property} _undefs)
831                 if (_undefs)
832                         list (APPEND _sourceUndefs "${_sourceFile}" ${_undefs} "-")
833                 endif()
834         endforeach()
835         set (${_sourceUndefsVar} ${_sourceUndefs} PARENT_SCOPE)
836 endfunction()
837
838 macro (cotire_set_cmd_to_prologue _cmdVar)
839         set (${_cmdVar} "${CMAKE_COMMAND}")
840         if (COTIRE_DEBUG)
841                 list (APPEND ${_cmdVar} "--warn-uninitialized")
842         endif()
843         list (APPEND ${_cmdVar} "-DCOTIRE_BUILD_TYPE:STRING=$<CONFIGURATION>")
844         if (COTIRE_VERBOSE)
845                 list (APPEND ${_cmdVar} "-DCOTIRE_VERBOSE:BOOL=ON")
846         elseif("${CMAKE_GENERATOR}" MATCHES "Makefiles")
847                 list (APPEND ${_cmdVar} "-DCOTIRE_VERBOSE:BOOL=$(VERBOSE)")
848         endif()
849 endmacro()
850
851 function (cotire_init_compile_cmd _cmdVar _language _compilerLauncher _compilerExe _compilerArg1)
852         if (NOT _compilerLauncher)
853                 set (_compilerLauncher ${CMAKE_${_language}_COMPILER_LAUNCHER})
854         endif()
855         if (NOT _compilerExe)
856                 set (_compilerExe "${CMAKE_${_language}_COMPILER}")
857         endif()
858         if (NOT _compilerArg1)
859                 set (_compilerArg1 ${CMAKE_${_language}_COMPILER_ARG1})
860         endif()
861         string (STRIP "${_compilerArg1}" _compilerArg1)
862         if ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
863                 # compiler launcher is only supported for Makefile and Ninja
864                 set (${_cmdVar} ${_compilerLauncher} "${_compilerExe}" ${_compilerArg1} PARENT_SCOPE)
865         else()
866                 set (${_cmdVar} "${_compilerExe}" ${_compilerArg1} PARENT_SCOPE)
867         endif()
868 endfunction()
869
870 macro (cotire_add_definitions_to_cmd _cmdVar _language)
871         foreach (_definition ${ARGN})
872                 if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
873                         list (APPEND ${_cmdVar} "/D${_definition}")
874                 else()
875                         list (APPEND ${_cmdVar} "-D${_definition}")
876                 endif()
877         endforeach()
878 endmacro()
879
880 function (cotire_add_includes_to_cmd _cmdVar _language _includesVar _systemIncludesVar)
881         set (_includeDirs ${${_includesVar}} ${${_systemIncludesVar}})
882         if (_includeDirs)
883                 list (REMOVE_DUPLICATES _includeDirs)
884                 foreach (_include ${_includeDirs})
885                         if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
886                                 file (TO_NATIVE_PATH "${_include}" _include)
887                                 list (APPEND ${_cmdVar} "${CMAKE_INCLUDE_FLAG_${_language}}${CMAKE_INCLUDE_FLAG_${_language}_SEP}${_include}")
888                         else()
889                                 set (_index -1)
890                                 if ("${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}" MATCHES ".+")
891                                         list (FIND ${_systemIncludesVar} "${_include}" _index)
892                                 endif()
893                                 if (_index GREATER -1)
894                                         list (APPEND ${_cmdVar} "${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}${_include}")
895                                 else()
896                                         list (APPEND ${_cmdVar} "${CMAKE_INCLUDE_FLAG_${_language}}${CMAKE_INCLUDE_FLAG_${_language}_SEP}${_include}")
897                                 endif()
898                         endif()
899                 endforeach()
900         endif()
901         set (${_cmdVar} ${${_cmdVar}} PARENT_SCOPE)
902 endfunction()
903
904 function (cotire_add_frameworks_to_cmd _cmdVar _language _includesVar _systemIncludesVar)
905         if (APPLE)
906                 set (_frameworkDirs "")
907                 foreach (_include ${${_includesVar}})
908                         if (IS_ABSOLUTE "${_include}" AND _include MATCHES "\\.framework$")
909                                 get_filename_component(_frameworkDir "${_include}" DIRECTORY)
910                                 list (APPEND _frameworkDirs "${_frameworkDir}")
911                         endif()
912                 endforeach()
913                 set (_systemFrameworkDirs "")
914                 foreach (_include ${${_systemIncludesVar}})
915                         if (IS_ABSOLUTE "${_include}" AND _include MATCHES "\\.framework$")
916                                 get_filename_component(_frameworkDir "${_include}" DIRECTORY)
917                                 list (APPEND _systemFrameworkDirs "${_frameworkDir}")
918                         endif()
919                 endforeach()
920                 if (_systemFrameworkDirs)
921                         list (APPEND _frameworkDirs ${_systemFrameworkDirs})
922                 endif()
923                 if (_frameworkDirs)
924                         list (REMOVE_DUPLICATES _frameworkDirs)
925                         foreach (_frameworkDir ${_frameworkDirs})
926                                 set (_index -1)
927                                 if ("${CMAKE_${_language}_SYSTEM_FRAMEWORK_SEARCH_FLAG}" MATCHES ".+")
928                                         list (FIND _systemFrameworkDirs "${_frameworkDir}" _index)
929                                 endif()
930                                 if (_index GREATER -1)
931                                         list (APPEND ${_cmdVar} "${CMAKE_${_language}_SYSTEM_FRAMEWORK_SEARCH_FLAG}${_frameworkDir}")
932                                 else()
933                                         list (APPEND ${_cmdVar} "${CMAKE_${_language}_FRAMEWORK_SEARCH_FLAG}${_frameworkDir}")
934                                 endif()
935                         endforeach()
936                 endif()
937         endif()
938         set (${_cmdVar} ${${_cmdVar}} PARENT_SCOPE)
939 endfunction()
940
941 macro (cotire_add_compile_flags_to_cmd _cmdVar)
942         foreach (_flag ${ARGN})
943                 list (APPEND ${_cmdVar} "${_flag}")
944         endforeach()
945 endmacro()
946
947 function (cotire_check_file_up_to_date _fileIsUpToDateVar _file)
948         if (EXISTS "${_file}")
949                 set (_triggerFile "")
950                 foreach (_dependencyFile ${ARGN})
951                         if (EXISTS "${_dependencyFile}")
952                                 # IS_NEWER_THAN returns TRUE if both files have the same timestamp
953                                 # thus we do the comparison in both directions to exclude ties
954                                 if ("${_dependencyFile}" IS_NEWER_THAN "${_file}" AND
955                                         NOT "${_file}" IS_NEWER_THAN "${_dependencyFile}")
956                                         set (_triggerFile "${_dependencyFile}")
957                                         break()
958                                 endif()
959                         endif()
960                 endforeach()
961                 if (_triggerFile)
962                         if (COTIRE_VERBOSE)
963                                 get_filename_component(_fileName "${_file}" NAME)
964                                 message (STATUS "${_fileName} update triggered by ${_triggerFile} change.")
965                         endif()
966                         set (${_fileIsUpToDateVar} FALSE PARENT_SCOPE)
967                 else()
968                         if (COTIRE_VERBOSE)
969                                 get_filename_component(_fileName "${_file}" NAME)
970                                 message (STATUS "${_fileName} is up-to-date.")
971                         endif()
972                         set (${_fileIsUpToDateVar} TRUE PARENT_SCOPE)
973                 endif()
974         else()
975                 if (COTIRE_VERBOSE)
976                         get_filename_component(_fileName "${_file}" NAME)
977                         message (STATUS "${_fileName} does not exist yet.")
978                 endif()
979                 set (${_fileIsUpToDateVar} FALSE PARENT_SCOPE)
980         endif()
981 endfunction()
982
983 macro (cotire_find_closest_relative_path _headerFile _includeDirs _relPathVar)
984         set (${_relPathVar} "")
985         foreach (_includeDir ${_includeDirs})
986                 if (IS_DIRECTORY "${_includeDir}")
987                         file (RELATIVE_PATH _relPath "${_includeDir}" "${_headerFile}")
988                         if (NOT IS_ABSOLUTE "${_relPath}" AND NOT "${_relPath}" MATCHES "^\\.\\.")
989                                 string (LENGTH "${${_relPathVar}}" _closestLen)
990                                 string (LENGTH "${_relPath}" _relLen)
991                                 if (_closestLen EQUAL 0 OR _relLen LESS _closestLen)
992                                         set (${_relPathVar} "${_relPath}")
993                                 endif()
994                         endif()
995                 elseif ("${_includeDir}" STREQUAL "${_headerFile}")
996                         # if path matches exactly, return short non-empty string
997                         set (${_relPathVar} "1")
998                         break()
999                 endif()
1000         endforeach()
1001 endmacro()
1002
1003 macro (cotire_check_header_file_location _headerFile _insideIncludeDirs _outsideIncludeDirs _headerIsInside)
1004         # check header path against ignored and honored include directories
1005         cotire_find_closest_relative_path("${_headerFile}" "${_insideIncludeDirs}" _insideRelPath)
1006         if (_insideRelPath)
1007                 # header is inside, but could be become outside if there is a shorter outside match
1008                 cotire_find_closest_relative_path("${_headerFile}" "${_outsideIncludeDirs}" _outsideRelPath)
1009                 if (_outsideRelPath)
1010                         string (LENGTH "${_insideRelPath}" _insideRelPathLen)
1011                         string (LENGTH "${_outsideRelPath}" _outsideRelPathLen)
1012                         if (_outsideRelPathLen LESS _insideRelPathLen)
1013                                 set (${_headerIsInside} FALSE)
1014                         else()
1015                                 set (${_headerIsInside} TRUE)
1016                         endif()
1017                 else()
1018                         set (${_headerIsInside} TRUE)
1019                 endif()
1020         else()
1021                 # header is outside
1022                 set (${_headerIsInside} FALSE)
1023         endif()
1024 endmacro()
1025
1026 macro (cotire_check_ignore_header_file_path _headerFile _headerIsIgnoredVar)
1027         if (NOT EXISTS "${_headerFile}")
1028                 set (${_headerIsIgnoredVar} TRUE)
1029         elseif (IS_DIRECTORY "${_headerFile}")
1030                 set (${_headerIsIgnoredVar} TRUE)
1031         elseif ("${_headerFile}" MATCHES "\\.\\.|[_-]fixed" AND "${_headerFile}" MATCHES "\\.h$")
1032                 # heuristic: ignore C headers with embedded parent directory references or "-fixed" or "_fixed" in path
1033                 # these often stem from using GCC #include_next tricks, which may break the precompiled header compilation
1034                 # with the error message "error: no include path in which to search for header.h"
1035                 set (${_headerIsIgnoredVar} TRUE)
1036         else()
1037                 set (${_headerIsIgnoredVar} FALSE)
1038         endif()
1039 endmacro()
1040
1041 macro (cotire_check_ignore_header_file_ext _headerFile _ignoreExtensionsVar _headerIsIgnoredVar)
1042         # check header file extension
1043         cotire_get_source_file_extension("${_headerFile}" _headerFileExt)
1044         set (${_headerIsIgnoredVar} FALSE)
1045         if (_headerFileExt)
1046                 list (FIND ${_ignoreExtensionsVar} "${_headerFileExt}" _index)
1047                 if (_index GREATER -1)
1048                         set (${_headerIsIgnoredVar} TRUE)
1049                 endif()
1050         endif()
1051 endmacro()
1052
1053 macro (cotire_parse_line _line _headerFileVar _headerDepthVar)
1054         if (MSVC)
1055                 # cl.exe /showIncludes output looks different depending on the language pack used, e.g.:
1056                 # English: "Note: including file:   C:\directory\file"
1057                 # German: "Hinweis: Einlesen der Datei:   C:\directory\file"
1058                 # We use a very general regular expression, relying on the presence of the : characters
1059                 if (_line MATCHES "( +)([a-zA-Z]:[^:]+)$")
1060                         # Visual Studio compiler output
1061                         string (LENGTH "${CMAKE_MATCH_1}" ${_headerDepthVar})
1062                         get_filename_component(${_headerFileVar} "${CMAKE_MATCH_2}" ABSOLUTE)
1063                 else()
1064                         set (${_headerFileVar} "")
1065                         set (${_headerDepthVar} 0)
1066                 endif()
1067         else()
1068                 if (_line MATCHES "^(\\.+) (.*)$")
1069                         # GCC like output
1070                         string (LENGTH "${CMAKE_MATCH_1}" ${_headerDepthVar})
1071                         if (IS_ABSOLUTE "${CMAKE_MATCH_2}")
1072                                 set (${_headerFileVar} "${CMAKE_MATCH_2}")
1073                         else()
1074                                 get_filename_component(${_headerFileVar} "${CMAKE_MATCH_2}" REALPATH)
1075                         endif()
1076                 else()
1077                         set (${_headerFileVar} "")
1078                         set (${_headerDepthVar} 0)
1079                 endif()
1080         endif()
1081 endmacro()
1082
1083 function (cotire_parse_includes _language _scanOutput _ignoredIncludeDirs _honoredIncludeDirs _ignoredExtensions _selectedIncludesVar _unparsedLinesVar)
1084         if (WIN32)
1085                 # prevent CMake macro invocation errors due to backslash characters in Windows paths
1086                 string (REPLACE "\\" "/" _scanOutput "${_scanOutput}")
1087         endif()
1088         # canonize slashes
1089         string (REPLACE "//" "/" _scanOutput "${_scanOutput}")
1090         # prevent semicolon from being interpreted as a line separator
1091         string (REPLACE ";" "\\;" _scanOutput "${_scanOutput}")
1092         # then separate lines
1093         string (REGEX REPLACE "\n" ";" _scanOutput "${_scanOutput}")
1094         list (LENGTH _scanOutput _len)
1095         # remove duplicate lines to speed up parsing
1096         list (REMOVE_DUPLICATES _scanOutput)
1097         list (LENGTH _scanOutput _uniqueLen)
1098         if (COTIRE_VERBOSE OR COTIRE_DEBUG)
1099                 message (STATUS "Scanning ${_uniqueLen} unique lines of ${_len} for includes")
1100                 if (_ignoredExtensions)
1101                         message (STATUS "Ignored extensions: ${_ignoredExtensions}")
1102                 endif()
1103                 if (_ignoredIncludeDirs)
1104                         message (STATUS "Ignored paths: ${_ignoredIncludeDirs}")
1105                 endif()
1106                 if (_honoredIncludeDirs)
1107                         message (STATUS "Included paths: ${_honoredIncludeDirs}")
1108                 endif()
1109         endif()
1110         set (_sourceFiles ${ARGN})
1111         set (_selectedIncludes "")
1112         set (_unparsedLines "")
1113         # stack keeps track of inside/outside project status of processed header files
1114         set (_headerIsInsideStack "")
1115         foreach (_line IN LISTS _scanOutput)
1116                 if (_line)
1117                         cotire_parse_line("${_line}" _headerFile _headerDepth)
1118                         if (_headerFile)
1119                                 cotire_check_header_file_location("${_headerFile}" "${_ignoredIncludeDirs}" "${_honoredIncludeDirs}" _headerIsInside)
1120                                 if (COTIRE_DEBUG)
1121                                         message (STATUS "${_headerDepth}: ${_headerFile} ${_headerIsInside}")
1122                                 endif()
1123                                 # update stack
1124                                 list (LENGTH _headerIsInsideStack _stackLen)
1125                                 if (_headerDepth GREATER _stackLen)
1126                                         math (EXPR _stackLen "${_stackLen} + 1")
1127                                         foreach (_index RANGE ${_stackLen} ${_headerDepth})
1128                                                 list (APPEND _headerIsInsideStack ${_headerIsInside})
1129                                         endforeach()
1130                                 else()
1131                                         foreach (_index RANGE ${_headerDepth} ${_stackLen})
1132                                                 list (REMOVE_AT _headerIsInsideStack -1)
1133                                         endforeach()
1134                                         list (APPEND _headerIsInsideStack ${_headerIsInside})
1135                                 endif()
1136                                 if (COTIRE_DEBUG)
1137                                         message (STATUS "${_headerIsInsideStack}")
1138                                 endif()
1139                                 # header is a candidate if it is outside project
1140                                 if (NOT _headerIsInside)
1141                                         # get parent header file's inside/outside status
1142                                         if (_headerDepth GREATER 1)
1143                                                 math (EXPR _index "${_headerDepth} - 2")
1144                                                 list (GET _headerIsInsideStack ${_index} _parentHeaderIsInside)
1145                                         else()
1146                                                 set (_parentHeaderIsInside TRUE)
1147                                         endif()
1148                                         # select header file if parent header file is inside project
1149                                         # (e.g., a project header file that includes a standard header file)
1150                                         if (_parentHeaderIsInside)
1151                                                 cotire_check_ignore_header_file_path("${_headerFile}" _headerIsIgnored)
1152                                                 if (NOT _headerIsIgnored)
1153                                                         cotire_check_ignore_header_file_ext("${_headerFile}" _ignoredExtensions _headerIsIgnored)
1154                                                         if (NOT _headerIsIgnored)
1155                                                                 list (APPEND _selectedIncludes "${_headerFile}")
1156                                                         else()
1157                                                                 # fix header's inside status on stack, it is ignored by extension now
1158                                                                 list (REMOVE_AT _headerIsInsideStack -1)
1159                                                                 list (APPEND _headerIsInsideStack TRUE)
1160                                                         endif()
1161                                                 endif()
1162                                                 if (COTIRE_DEBUG)
1163                                                         message (STATUS "${_headerFile} ${_ignoredExtensions} ${_headerIsIgnored}")
1164                                                 endif()
1165                                         endif()
1166                                 endif()
1167                         else()
1168                                 if (MSVC)
1169                                         # for cl.exe do not keep unparsed lines which solely consist of a source file name
1170                                         string (FIND "${_sourceFiles}" "${_line}" _index)
1171                                         if (_index LESS 0)
1172                                                 list (APPEND _unparsedLines "${_line}")
1173                                         endif()
1174                                 else()
1175                                         list (APPEND _unparsedLines "${_line}")
1176                                 endif()
1177                         endif()
1178                 endif()
1179         endforeach()
1180         list (REMOVE_DUPLICATES _selectedIncludes)
1181         set (${_selectedIncludesVar} ${_selectedIncludes} PARENT_SCOPE)
1182         set (${_unparsedLinesVar} ${_unparsedLines} PARENT_SCOPE)
1183 endfunction()
1184
1185 function (cotire_scan_includes _includesVar)
1186         set(_options "")
1187         set(_oneValueArgs COMPILER_ID COMPILER_EXECUTABLE COMPILER_ARG1 COMPILER_VERSION LANGUAGE UNPARSED_LINES)
1188         set(_multiValueArgs COMPILE_DEFINITIONS COMPILE_FLAGS INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES
1189                 IGNORE_PATH INCLUDE_PATH IGNORE_EXTENSIONS INCLUDE_PRIORITY_PATH COMPILER_LAUNCHER)
1190         cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
1191         set (_sourceFiles ${_option_UNPARSED_ARGUMENTS})
1192         if (NOT _option_LANGUAGE)
1193                 set (_option_LANGUAGE "CXX")
1194         endif()
1195         if (NOT _option_COMPILER_ID)
1196                 set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}")
1197         endif()
1198         if (NOT _option_COMPILER_VERSION)
1199                 set (_option_COMPILER_VERSION "${CMAKE_${_option_LANGUAGE}_COMPILER_VERSION}")
1200         endif()
1201         cotire_init_compile_cmd(_cmd "${_option_LANGUAGE}" "${_option_COMPILER_LAUNCHER}" "${_option_COMPILER_EXECUTABLE}" "${_option_COMPILER_ARG1}")
1202         cotire_add_definitions_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_COMPILE_DEFINITIONS})
1203         cotire_add_compile_flags_to_cmd(_cmd ${_option_COMPILE_FLAGS})
1204         cotire_add_includes_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES)
1205         cotire_add_frameworks_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES)
1206         cotire_add_makedep_flags("${_option_LANGUAGE}" "${_option_COMPILER_ID}" "${_option_COMPILER_VERSION}" _cmd)
1207         # only consider existing source files for scanning
1208         set (_existingSourceFiles "")
1209         foreach (_sourceFile ${_sourceFiles})
1210                 if (EXISTS "${_sourceFile}")
1211                         list (APPEND _existingSourceFiles "${_sourceFile}")
1212                 endif()
1213         endforeach()
1214         if (NOT _existingSourceFiles)
1215                 set (${_includesVar} "" PARENT_SCOPE)
1216                 return()
1217         endif()
1218         list (APPEND _cmd ${_existingSourceFiles})
1219         if (COTIRE_VERBOSE)
1220                 message (STATUS "execute_process: ${_cmd}")
1221         endif()
1222         if (_option_COMPILER_ID MATCHES "MSVC")
1223                 # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared
1224                 unset (ENV{VS_UNICODE_OUTPUT})
1225         endif()
1226         execute_process(
1227                 COMMAND ${_cmd}
1228                 WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
1229                 RESULT_VARIABLE _result
1230                 OUTPUT_QUIET
1231                 ERROR_VARIABLE _output)
1232         if (_result)
1233                 message (STATUS "Result ${_result} scanning includes of ${_existingSourceFiles}.")
1234         endif()
1235         cotire_parse_includes(
1236                 "${_option_LANGUAGE}" "${_output}"
1237                 "${_option_IGNORE_PATH}" "${_option_INCLUDE_PATH}"
1238                 "${_option_IGNORE_EXTENSIONS}"
1239                 _includes _unparsedLines
1240                 ${_sourceFiles})
1241         if (_option_INCLUDE_PRIORITY_PATH)
1242                 set (_sortedIncludes "")
1243                 foreach (_priorityPath ${_option_INCLUDE_PRIORITY_PATH})
1244                         foreach (_include ${_includes})
1245                                 string (FIND ${_include} ${_priorityPath} _position)
1246                                 if (_position GREATER -1)
1247                                         list (APPEND _sortedIncludes ${_include})
1248                                 endif()
1249                         endforeach()
1250                 endforeach()
1251                 if (_sortedIncludes)
1252                         list (INSERT _includes 0 ${_sortedIncludes})
1253                         list (REMOVE_DUPLICATES _includes)
1254                 endif()
1255         endif()
1256         set (${_includesVar} ${_includes} PARENT_SCOPE)
1257         if (_option_UNPARSED_LINES)
1258                 set (${_option_UNPARSED_LINES} ${_unparsedLines} PARENT_SCOPE)
1259         endif()
1260 endfunction()
1261
1262 macro (cotire_append_undefs _contentsVar)
1263         set (_undefs ${ARGN})
1264         if (_undefs)
1265                 list (REMOVE_DUPLICATES _undefs)
1266                 foreach (_definition ${_undefs})
1267                         list (APPEND ${_contentsVar} "#undef ${_definition}")
1268                 endforeach()
1269         endif()
1270 endmacro()
1271
1272 macro (cotire_comment_str _language _commentText _commentVar)
1273         if ("${_language}" STREQUAL "CMAKE")
1274                 set (${_commentVar} "# ${_commentText}")
1275         else()
1276                 set (${_commentVar} "/* ${_commentText} */")
1277         endif()
1278 endmacro()
1279
1280 function (cotire_write_file _language _file _contents _force)
1281         get_filename_component(_moduleName "${COTIRE_CMAKE_MODULE_FILE}" NAME)
1282         cotire_comment_str("${_language}" "${_moduleName} ${COTIRE_CMAKE_MODULE_VERSION} generated file" _header1)
1283         cotire_comment_str("${_language}" "${_file}" _header2)
1284         set (_contents "${_header1}\n${_header2}\n${_contents}")
1285         if (COTIRE_DEBUG)
1286                 message (STATUS "${_contents}")
1287         endif()
1288         if (_force OR NOT EXISTS "${_file}")
1289                 file (WRITE "${_file}" "${_contents}")
1290         else()
1291                 file (READ "${_file}" _oldContents)
1292                 if (NOT "${_oldContents}" STREQUAL "${_contents}")
1293                         file (WRITE "${_file}" "${_contents}")
1294                 else()
1295                         if (COTIRE_DEBUG)
1296                                 message (STATUS "${_file} unchanged")
1297                         endif()
1298                 endif()
1299         endif()
1300 endfunction()
1301
1302 function (cotire_generate_unity_source _unityFile)
1303         set(_options "")
1304         set(_oneValueArgs LANGUAGE)
1305         set(_multiValueArgs
1306                 DEPENDS SOURCES_COMPILE_DEFINITIONS
1307                 PRE_UNDEFS SOURCES_PRE_UNDEFS POST_UNDEFS SOURCES_POST_UNDEFS PROLOGUE EPILOGUE)
1308         cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
1309         if (_option_DEPENDS)
1310                 cotire_check_file_up_to_date(_unityFileIsUpToDate "${_unityFile}" ${_option_DEPENDS})
1311                 if (_unityFileIsUpToDate)
1312                         return()
1313                 endif()
1314         endif()
1315         set (_sourceFiles ${_option_UNPARSED_ARGUMENTS})
1316         if (NOT _option_PRE_UNDEFS)
1317                 set (_option_PRE_UNDEFS "")
1318         endif()
1319         if (NOT _option_SOURCES_PRE_UNDEFS)
1320                 set (_option_SOURCES_PRE_UNDEFS "")
1321         endif()
1322         if (NOT _option_POST_UNDEFS)
1323                 set (_option_POST_UNDEFS "")
1324         endif()
1325         if (NOT _option_SOURCES_POST_UNDEFS)
1326                 set (_option_SOURCES_POST_UNDEFS "")
1327         endif()
1328         set (_contents "")
1329         if (_option_PROLOGUE)
1330                 list (APPEND _contents ${_option_PROLOGUE})
1331         endif()
1332         if (_option_LANGUAGE AND _sourceFiles)
1333                 if ("${_option_LANGUAGE}" STREQUAL "CXX")
1334                         list (APPEND _contents "#ifdef __cplusplus")
1335                 elseif ("${_option_LANGUAGE}" STREQUAL "C")
1336                         list (APPEND _contents "#ifndef __cplusplus")
1337                 endif()
1338         endif()
1339         set (_compileUndefinitions "")
1340         foreach (_sourceFile ${_sourceFiles})
1341                 cotire_get_source_compile_definitions(
1342                         "${_option_CONFIGURATION}" "${_option_LANGUAGE}" "${_sourceFile}" _compileDefinitions
1343                         ${_option_SOURCES_COMPILE_DEFINITIONS})
1344                 cotire_get_source_undefs("${_sourceFile}" COTIRE_UNITY_SOURCE_PRE_UNDEFS _sourcePreUndefs ${_option_SOURCES_PRE_UNDEFS})
1345                 cotire_get_source_undefs("${_sourceFile}" COTIRE_UNITY_SOURCE_POST_UNDEFS _sourcePostUndefs ${_option_SOURCES_POST_UNDEFS})
1346                 if (_option_PRE_UNDEFS)
1347                         list (APPEND _compileUndefinitions ${_option_PRE_UNDEFS})
1348                 endif()
1349                 if (_sourcePreUndefs)
1350                         list (APPEND _compileUndefinitions ${_sourcePreUndefs})
1351                 endif()
1352                 if (_compileUndefinitions)
1353                         cotire_append_undefs(_contents ${_compileUndefinitions})
1354                         set (_compileUndefinitions "")
1355                 endif()
1356                 if (_sourcePostUndefs)
1357                         list (APPEND _compileUndefinitions ${_sourcePostUndefs})
1358                 endif()
1359                 if (_option_POST_UNDEFS)
1360                         list (APPEND _compileUndefinitions ${_option_POST_UNDEFS})
1361                 endif()
1362                 foreach (_definition ${_compileDefinitions})
1363                         if (_definition MATCHES "^([a-zA-Z0-9_]+)=(.+)$")
1364                                 list (APPEND _contents "#define ${CMAKE_MATCH_1} ${CMAKE_MATCH_2}")
1365                                 list (INSERT _compileUndefinitions 0 "${CMAKE_MATCH_1}")
1366                         else()
1367                                 list (APPEND _contents "#define ${_definition}")
1368                                 list (INSERT _compileUndefinitions 0 "${_definition}")
1369                         endif()
1370                 endforeach()
1371                 # use absolute path as source file location
1372                 get_filename_component(_sourceFileLocation "${_sourceFile}" ABSOLUTE)
1373                 if (WIN32)
1374                         file (TO_NATIVE_PATH "${_sourceFileLocation}" _sourceFileLocation)
1375                 endif()
1376                 list (APPEND _contents "#include \"${_sourceFileLocation}\"")
1377         endforeach()
1378         if (_compileUndefinitions)
1379                 cotire_append_undefs(_contents ${_compileUndefinitions})
1380                 set (_compileUndefinitions "")
1381         endif()
1382         if (_option_LANGUAGE AND _sourceFiles)
1383                 list (APPEND _contents "#endif")
1384         endif()
1385         if (_option_EPILOGUE)
1386                 list (APPEND _contents ${_option_EPILOGUE})
1387         endif()
1388         list (APPEND _contents "")
1389         string (REPLACE ";" "\n" _contents "${_contents}")
1390         if (COTIRE_VERBOSE)
1391                 message ("${_contents}")
1392         endif()
1393         cotire_write_file("${_option_LANGUAGE}" "${_unityFile}" "${_contents}" TRUE)
1394 endfunction()
1395
1396 function (cotire_generate_prefix_header _prefixFile)
1397         set(_options "")
1398         set(_oneValueArgs LANGUAGE COMPILER_EXECUTABLE COMPILER_ARG1 COMPILER_ID COMPILER_VERSION)
1399         set(_multiValueArgs DEPENDS COMPILE_DEFINITIONS COMPILE_FLAGS
1400                 INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES IGNORE_PATH INCLUDE_PATH
1401                 IGNORE_EXTENSIONS INCLUDE_PRIORITY_PATH COMPILER_LAUNCHER)
1402         cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
1403         if (NOT _option_COMPILER_ID)
1404                 set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}")
1405         endif()
1406         if (NOT _option_COMPILER_VERSION)
1407                 set (_option_COMPILER_VERSION "${CMAKE_${_option_LANGUAGE}_COMPILER_VERSION}")
1408         endif()
1409         if (_option_DEPENDS)
1410                 cotire_check_file_up_to_date(_prefixFileIsUpToDate "${_prefixFile}" ${_option_DEPENDS})
1411                 if (_prefixFileIsUpToDate)
1412                         # create empty log file
1413                         set (_unparsedLinesFile "${_prefixFile}.log")
1414                         file (WRITE "${_unparsedLinesFile}" "")
1415                         return()
1416                 endif()
1417         endif()
1418         set (_prologue "")
1419         set (_epilogue "")
1420         if (_option_COMPILER_ID MATCHES "Clang")
1421                 set (_prologue "#pragma clang system_header")
1422         elseif (_option_COMPILER_ID MATCHES "GNU")
1423                 set (_prologue "#pragma GCC system_header")
1424         elseif (_option_COMPILER_ID MATCHES "MSVC")
1425                 set (_prologue "#pragma warning(push, 0)")
1426                 set (_epilogue "#pragma warning(pop)")
1427         elseif (_option_COMPILER_ID MATCHES "Intel")
1428                 # Intel compiler requires hdrstop pragma to stop generating PCH file
1429                 set (_epilogue "#pragma hdrstop")
1430         endif()
1431         set (_sourceFiles ${_option_UNPARSED_ARGUMENTS})
1432         cotire_scan_includes(_selectedHeaders ${_sourceFiles}
1433                 LANGUAGE "${_option_LANGUAGE}"
1434                 COMPILER_LAUNCHER "${_option_COMPILER_LAUNCHER}"
1435                 COMPILER_EXECUTABLE "${_option_COMPILER_EXECUTABLE}"
1436                 COMPILER_ARG1 "${_option_COMPILER_ARG1}"
1437                 COMPILER_ID "${_option_COMPILER_ID}"
1438                 COMPILER_VERSION "${_option_COMPILER_VERSION}"
1439                 COMPILE_DEFINITIONS ${_option_COMPILE_DEFINITIONS}
1440                 COMPILE_FLAGS ${_option_COMPILE_FLAGS}
1441                 INCLUDE_DIRECTORIES ${_option_INCLUDE_DIRECTORIES}
1442                 SYSTEM_INCLUDE_DIRECTORIES ${_option_SYSTEM_INCLUDE_DIRECTORIES}
1443                 IGNORE_PATH ${_option_IGNORE_PATH}
1444                 INCLUDE_PATH ${_option_INCLUDE_PATH}
1445                 IGNORE_EXTENSIONS ${_option_IGNORE_EXTENSIONS}
1446                 INCLUDE_PRIORITY_PATH ${_option_INCLUDE_PRIORITY_PATH}
1447                 UNPARSED_LINES _unparsedLines)
1448         cotire_generate_unity_source("${_prefixFile}"
1449                 PROLOGUE ${_prologue} EPILOGUE ${_epilogue} LANGUAGE "${_option_LANGUAGE}" ${_selectedHeaders})
1450         set (_unparsedLinesFile "${_prefixFile}.log")
1451         if (_unparsedLines)
1452                 if (COTIRE_VERBOSE OR NOT _selectedHeaders)
1453                         list (LENGTH _unparsedLines _skippedLineCount)
1454                         message (STATUS "${_skippedLineCount} line(s) skipped, see ${_unparsedLinesFile}")
1455                 endif()
1456                 string (REPLACE ";" "\n" _unparsedLines "${_unparsedLines}")
1457         endif()
1458         file (WRITE "${_unparsedLinesFile}" "${_unparsedLines}")
1459 endfunction()
1460
1461 function (cotire_add_makedep_flags _language _compilerID _compilerVersion _flagsVar)
1462         set (_flags ${${_flagsVar}})
1463         if (_compilerID MATCHES "MSVC")
1464                 # cl.exe options used
1465                 # /nologo suppresses display of sign-on banner
1466                 # /TC treat all files named on the command line as C source files
1467                 # /TP treat all files named on the command line as C++ source files
1468                 # /EP preprocess to stdout without #line directives
1469                 # /showIncludes list include files
1470                 set (_sourceFileTypeC "/TC")
1471                 set (_sourceFileTypeCXX "/TP")
1472                 if (_flags)
1473                         # append to list
1474                         list (APPEND _flags /nologo "${_sourceFileType${_language}}" /EP /showIncludes)
1475                 else()
1476                         # return as a flag string
1477                         set (_flags "${_sourceFileType${_language}} /EP /showIncludes")
1478                 endif()
1479         elseif (_compilerID MATCHES "GNU")
1480                 # GCC options used
1481                 # -H print the name of each header file used
1482                 # -E invoke preprocessor
1483                 # -fdirectives-only do not expand macros, requires GCC >= 4.3
1484                 if (_flags)
1485                         # append to list
1486                         list (APPEND _flags -H -E)
1487                         if (NOT "${_compilerVersion}" VERSION_LESS "4.3.0")
1488                                 list (APPEND _flags "-fdirectives-only")
1489                         endif()
1490                 else()
1491                         # return as a flag string
1492                         set (_flags "-H -E")
1493                         if (NOT "${_compilerVersion}" VERSION_LESS "4.3.0")
1494                                 set (_flags "${_flags} -fdirectives-only")
1495                         endif()
1496                 endif()
1497         elseif (_compilerID MATCHES "Clang")
1498                 # Clang options used
1499                 # -H print the name of each header file used
1500                 # -E invoke preprocessor
1501                 # -fno-color-diagnostics don't prints diagnostics in color
1502                 if (_flags)
1503                         # append to list
1504                         list (APPEND _flags -H -E -fno-color-diagnostics)
1505                 else()
1506                         # return as a flag string
1507                         set (_flags "-H -E -fno-color-diagnostics")
1508                 endif()
1509         elseif (_compilerID MATCHES "Intel")
1510                 if (WIN32)
1511                         # Windows Intel options used
1512                         # /nologo do not display compiler version information
1513                         # /QH display the include file order
1514                         # /EP preprocess to stdout, omitting #line directives
1515                         # /TC process all source or unrecognized file types as C source files
1516                         # /TP process all source or unrecognized file types as C++ source files
1517                         set (_sourceFileTypeC "/TC")
1518                         set (_sourceFileTypeCXX "/TP")
1519                         if (_flags)
1520                                 # append to list
1521                                 list (APPEND _flags /nologo "${_sourceFileType${_language}}" /EP /QH)
1522                         else()
1523                                 # return as a flag string
1524                                 set (_flags "${_sourceFileType${_language}} /EP /QH")
1525                         endif()
1526                 else()
1527                         # Linux / Mac OS X Intel options used
1528                         # -H print the name of each header file used
1529                         # -EP preprocess to stdout, omitting #line directives
1530                         # -Kc++ process all source or unrecognized file types as C++ source files
1531                         if (_flags)
1532                                 # append to list
1533                                 if ("${_language}" STREQUAL "CXX")
1534                                         list (APPEND _flags -Kc++)
1535                                 endif()
1536                                 list (APPEND _flags -H -EP)
1537                         else()
1538                                 # return as a flag string
1539                                 if ("${_language}" STREQUAL "CXX")
1540                                         set (_flags "-Kc++ ")
1541                                 endif()
1542                                 set (_flags "${_flags}-H -EP")
1543                         endif()
1544                 endif()
1545         else()
1546                 message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.")
1547         endif()
1548         set (${_flagsVar} ${_flags} PARENT_SCOPE)
1549 endfunction()
1550
1551 function (cotire_add_pch_compilation_flags _language _compilerID _compilerVersion _prefixFile _pchFile _hostFile _flagsVar)
1552         set (_flags ${${_flagsVar}})
1553         if (_compilerID MATCHES "MSVC")
1554                 file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative)
1555                 file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative)
1556                 file (TO_NATIVE_PATH "${_hostFile}" _hostFileNative)
1557                 # cl.exe options used
1558                 # /Yc creates a precompiled header file
1559                 # /Fp specifies precompiled header binary file name
1560                 # /FI forces inclusion of file
1561                 # /TC treat all files named on the command line as C source files
1562                 # /TP treat all files named on the command line as C++ source files
1563                 # /Zs syntax check only
1564                 # /Zm precompiled header memory allocation scaling factor
1565                 set (_sourceFileTypeC "/TC")
1566                 set (_sourceFileTypeCXX "/TP")
1567                 if (_flags)
1568                         # append to list
1569                         list (APPEND _flags /nologo "${_sourceFileType${_language}}"
1570                                 "/Yc${_prefixFileNative}" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}" /Zs "${_hostFileNative}")
1571                         if (COTIRE_PCH_MEMORY_SCALING_FACTOR)
1572                                 list (APPEND _flags "/Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}")
1573                         endif()
1574                 else()
1575                         # return as a flag string
1576                         set (_flags "/Yc\"${_prefixFileNative}\" /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"")
1577                         if (COTIRE_PCH_MEMORY_SCALING_FACTOR)
1578                                 set (_flags "${_flags} /Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}")
1579                         endif()
1580                 endif()
1581         elseif (_compilerID MATCHES "GNU|Clang")
1582                 # GCC / Clang options used
1583                 # -x specify the source language
1584                 # -c compile but do not link
1585                 # -o place output in file
1586                 # note that we cannot use -w to suppress all warnings upon pre-compiling, because turning off a warning may
1587                 # alter compile flags as a side effect (e.g., -Wwrite-string implies -fconst-strings)
1588                 set (_xLanguage_C "c-header")
1589                 set (_xLanguage_CXX "c++-header")
1590                 if (_flags)
1591                         # append to list
1592                         list (APPEND _flags "-x" "${_xLanguage_${_language}}" "-c" "${_prefixFile}" -o "${_pchFile}")
1593                 else()
1594                         # return as a flag string
1595                         set (_flags "-x ${_xLanguage_${_language}} -c \"${_prefixFile}\" -o \"${_pchFile}\"")
1596                 endif()
1597         elseif (_compilerID MATCHES "Intel")
1598                 if (WIN32)
1599                         file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative)
1600                         file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative)
1601                         file (TO_NATIVE_PATH "${_hostFile}" _hostFileNative)
1602                         # Windows Intel options used
1603                         # /nologo do not display compiler version information
1604                         # /Yc create a precompiled header (PCH) file
1605                         # /Fp specify a path or file name for precompiled header files
1606                         # /FI tells the preprocessor to include a specified file name as the header file
1607                         # /TC process all source or unrecognized file types as C source files
1608                         # /TP process all source or unrecognized file types as C++ source files
1609                         # /Zs syntax check only
1610                         # /Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2)
1611                         set (_sourceFileTypeC "/TC")
1612                         set (_sourceFileTypeCXX "/TP")
1613                         if (_flags)
1614                                 # append to list
1615                                 list (APPEND _flags /nologo "${_sourceFileType${_language}}"
1616                                         "/Yc" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}" /Zs "${_hostFileNative}")
1617                                 if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
1618                                         list (APPEND _flags "/Wpch-messages")
1619                                 endif()
1620                         else()
1621                                 # return as a flag string
1622                                 set (_flags "/Yc /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"")
1623                                 if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
1624                                         set (_flags "${_flags} /Wpch-messages")
1625                                 endif()
1626                         endif()
1627                 else()
1628                         # Linux / Mac OS X Intel options used
1629                         # -pch-dir location for precompiled header files
1630                         # -pch-create name of the precompiled header (PCH) to create
1631                         # -Kc++ process all source or unrecognized file types as C++ source files
1632                         # -fsyntax-only check only for correct syntax
1633                         # -Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2)
1634                         get_filename_component(_pchDir "${_pchFile}" DIRECTORY)
1635                         get_filename_component(_pchName "${_pchFile}" NAME)
1636                         set (_xLanguage_C "c-header")
1637                         set (_xLanguage_CXX "c++-header")
1638                         if (_flags)
1639                                 # append to list
1640                                 if ("${_language}" STREQUAL "CXX")
1641                                         list (APPEND _flags -Kc++)
1642                                 endif()
1643                                 list (APPEND _flags "-include" "${_prefixFile}" "-pch-dir" "${_pchDir}" "-pch-create" "${_pchName}" "-fsyntax-only" "${_hostFile}")
1644                                 if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
1645                                         list (APPEND _flags "-Wpch-messages")
1646                                 endif()
1647                         else()
1648                                 # return as a flag string
1649                                 set (_flags "-include \"${_prefixFile}\" -pch-dir \"${_pchDir}\" -pch-create \"${_pchName}\"")
1650                                 if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
1651                                         set (_flags "${_flags} -Wpch-messages")
1652                                 endif()
1653                         endif()
1654                 endif()
1655         else()
1656                 message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.")
1657         endif()
1658         set (${_flagsVar} ${_flags} PARENT_SCOPE)
1659 endfunction()
1660
1661 function (cotire_add_prefix_pch_inclusion_flags _language _compilerID _compilerVersion _prefixFile _pchFile _flagsVar)
1662         set (_flags ${${_flagsVar}})
1663         if (_compilerID MATCHES "MSVC")
1664                 file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative)
1665                 # cl.exe options used
1666                 # /Yu uses a precompiled header file during build
1667                 # /Fp specifies precompiled header binary file name
1668                 # /FI forces inclusion of file
1669                 # /Zm precompiled header memory allocation scaling factor
1670                 if (_pchFile)
1671                         file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative)
1672                         if (_flags)
1673                                 # append to list
1674                                 list (APPEND _flags "/Yu${_prefixFileNative}" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}")
1675                                 if (COTIRE_PCH_MEMORY_SCALING_FACTOR)
1676                                         list (APPEND _flags "/Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}")
1677                                 endif()
1678                         else()
1679                                 # return as a flag string
1680                                 set (_flags "/Yu\"${_prefixFileNative}\" /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"")
1681                                 if (COTIRE_PCH_MEMORY_SCALING_FACTOR)
1682                                         set (_flags "${_flags} /Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}")
1683                                 endif()
1684                         endif()
1685                 else()
1686                         # no precompiled header, force inclusion of prefix header
1687                         if (_flags)
1688                                 # append to list
1689                                 list (APPEND _flags "/FI${_prefixFileNative}")
1690                         else()
1691                                 # return as a flag string
1692                                 set (_flags "/FI\"${_prefixFileNative}\"")
1693                         endif()
1694                 endif()
1695         elseif (_compilerID MATCHES "GNU")
1696                 # GCC options used
1697                 # -include process include file as the first line of the primary source file
1698                 # -Winvalid-pch warns if precompiled header is found but cannot be used
1699                 # note: ccache requires the -include flag to be used in order to process precompiled header correctly
1700                 if (_flags)
1701                         # append to list
1702                         list (APPEND _flags "-Winvalid-pch" "-include" "${_prefixFile}")
1703                 else()
1704                         # return as a flag string
1705                         set (_flags "-Winvalid-pch -include \"${_prefixFile}\"")
1706                 endif()
1707         elseif (_compilerID MATCHES "Clang")
1708                 # Clang options used
1709                 # -include process include file as the first line of the primary source file
1710                 # -include-pch include precompiled header file
1711                 # -Qunused-arguments don't emit warning for unused driver arguments
1712                 # note: ccache requires the -include flag to be used in order to process precompiled header correctly
1713                 if (_flags)
1714                         # append to list
1715                         list (APPEND _flags "-Qunused-arguments" "-include" "${_prefixFile}")
1716                 else()
1717                         # return as a flag string
1718                         set (_flags "-Qunused-arguments -include \"${_prefixFile}\"")
1719                 endif()
1720         elseif (_compilerID MATCHES "Intel")
1721                 if (WIN32)
1722                         file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative)
1723                         # Windows Intel options used
1724                         # /Yu use a precompiled header (PCH) file
1725                         # /Fp specify a path or file name for precompiled header files
1726                         # /FI tells the preprocessor to include a specified file name as the header file
1727                         # /Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2)
1728                         if (_pchFile)
1729                                 file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative)
1730                                 if (_flags)
1731                                         # append to list
1732                                         list (APPEND _flags "/Yu" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}")
1733                                         if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
1734                                                 list (APPEND _flags "/Wpch-messages")
1735                                         endif()
1736                                 else()
1737                                         # return as a flag string
1738                                         set (_flags "/Yu /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"")
1739                                         if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
1740                                                 set (_flags "${_flags} /Wpch-messages")
1741                                         endif()
1742                                 endif()
1743                         else()
1744                                 # no precompiled header, force inclusion of prefix header
1745                                 if (_flags)
1746                                         # append to list
1747                                         list (APPEND _flags "/FI${_prefixFileNative}")
1748                                 else()
1749                                         # return as a flag string
1750                                         set (_flags "/FI\"${_prefixFileNative}\"")
1751                                 endif()
1752                         endif()
1753                 else()
1754                         # Linux / Mac OS X Intel options used
1755                         # -pch-dir location for precompiled header files
1756                         # -pch-use name of the precompiled header (PCH) to use
1757                         # -include process include file as the first line of the primary source file
1758                         # -Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2)
1759                         if (_pchFile)
1760                                 get_filename_component(_pchDir "${_pchFile}" DIRECTORY)
1761                                 get_filename_component(_pchName "${_pchFile}" NAME)
1762                                 if (_flags)
1763                                         # append to list
1764                                         list (APPEND _flags "-include" "${_prefixFile}" "-pch-dir" "${_pchDir}" "-pch-use" "${_pchName}")
1765                                         if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
1766                                                 list (APPEND _flags "-Wpch-messages")
1767                                         endif()
1768                                 else()
1769                                         # return as a flag string
1770                                         set (_flags "-include \"${_prefixFile}\" -pch-dir \"${_pchDir}\" -pch-use \"${_pchName}\"")
1771                                         if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0")
1772                                                 set (_flags "${_flags} -Wpch-messages")
1773                                         endif()
1774                                 endif()
1775                         else()
1776                                 # no precompiled header, force inclusion of prefix header
1777                                 if (_flags)
1778                                         # append to list
1779                                         list (APPEND _flags "-include" "${_prefixFile}")
1780                                 else()
1781                                         # return as a flag string
1782                                         set (_flags "-include \"${_prefixFile}\"")
1783                                 endif()
1784                         endif()
1785                 endif()
1786         else()
1787                 message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.")
1788         endif()
1789         set (${_flagsVar} ${_flags} PARENT_SCOPE)
1790 endfunction()
1791
1792 function (cotire_precompile_prefix_header _prefixFile _pchFile _hostFile)
1793         set(_options "")
1794         set(_oneValueArgs COMPILER_EXECUTABLE COMPILER_ARG1 COMPILER_ID COMPILER_VERSION LANGUAGE)
1795         set(_multiValueArgs COMPILE_DEFINITIONS COMPILE_FLAGS INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES SYS COMPILER_LAUNCHER)
1796         cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
1797         if (NOT _option_LANGUAGE)
1798                 set (_option_LANGUAGE "CXX")
1799         endif()
1800         if (NOT _option_COMPILER_ID)
1801                 set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}")
1802         endif()
1803         if (NOT _option_COMPILER_VERSION)
1804                 set (_option_COMPILER_VERSION "${CMAKE_${_option_LANGUAGE}_COMPILER_VERSION}")
1805         endif()
1806         cotire_init_compile_cmd(_cmd "${_option_LANGUAGE}" "${_option_COMPILER_LAUNCHER}" "${_option_COMPILER_EXECUTABLE}" "${_option_COMPILER_ARG1}")
1807         cotire_add_definitions_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_COMPILE_DEFINITIONS})
1808         cotire_add_compile_flags_to_cmd(_cmd ${_option_COMPILE_FLAGS})
1809         cotire_add_includes_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES)
1810         cotire_add_frameworks_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES)
1811         cotire_add_pch_compilation_flags(
1812                 "${_option_LANGUAGE}" "${_option_COMPILER_ID}" "${_option_COMPILER_VERSION}"
1813                 "${_prefixFile}" "${_pchFile}" "${_hostFile}" _cmd)
1814         if (COTIRE_VERBOSE)
1815                 message (STATUS "execute_process: ${_cmd}")
1816         endif()
1817         if (_option_COMPILER_ID MATCHES "MSVC")
1818                 # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared
1819                 unset (ENV{VS_UNICODE_OUTPUT})
1820         endif()
1821         execute_process(
1822                 COMMAND ${_cmd}
1823                 WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
1824                 RESULT_VARIABLE _result)
1825         if (_result)
1826                 message (FATAL_ERROR "cotire: error ${_result} precompiling ${_prefixFile}.")
1827         endif()
1828 endfunction()
1829
1830 function (cotire_check_precompiled_header_support _language _target _msgVar)
1831         set (_unsupportedCompiler
1832                 "Precompiled headers not supported for ${_language} compiler ${CMAKE_${_language}_COMPILER_ID}")
1833         if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC")
1834                 # supported since Visual Studio C++ 6.0
1835                 # and CMake does not support an earlier version
1836                 set (${_msgVar} "" PARENT_SCOPE)
1837         elseif (CMAKE_${_language}_COMPILER_ID MATCHES "GNU")
1838                 # GCC PCH support requires version >= 3.4
1839                 if ("${CMAKE_${_language}_COMPILER_VERSION}" VERSION_LESS "3.4.0")
1840                         set (${_msgVar} "${_unsupportedCompiler} version ${CMAKE_${_language}_COMPILER_VERSION}." PARENT_SCOPE)
1841                 else()
1842                         set (${_msgVar} "" PARENT_SCOPE)
1843                 endif()
1844         elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Clang")
1845                 # all Clang versions have PCH support
1846                 set (${_msgVar} "" PARENT_SCOPE)
1847         elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Intel")
1848                 # Intel PCH support requires version >= 8.0.0
1849                 if ("${CMAKE_${_language}_COMPILER_VERSION}" VERSION_LESS "8.0.0")
1850                         set (${_msgVar} "${_unsupportedCompiler} version ${CMAKE_${_language}_COMPILER_VERSION}." PARENT_SCOPE)
1851                 else()
1852                         set (${_msgVar} "" PARENT_SCOPE)
1853                 endif()
1854         else()
1855                 set (${_msgVar} "${_unsupportedCompiler}." PARENT_SCOPE)
1856         endif()
1857         get_target_property(_launcher ${_target} ${_language}_COMPILER_LAUNCHER)
1858         if (CMAKE_${_language}_COMPILER MATCHES "ccache" OR _launcher MATCHES "ccache")
1859                 if (NOT "$ENV{CCACHE_SLOPPINESS}" MATCHES "time_macros|pch_defines")
1860                         set (${_msgVar}
1861                                 "ccache requires the environment variable CCACHE_SLOPPINESS to be set to \"pch_defines,time_macros\"."
1862                                 PARENT_SCOPE)
1863                 endif()
1864         endif()
1865         if (APPLE)
1866                 # PCH compilation not supported by GCC / Clang for multi-architecture builds (e.g., i386, x86_64)
1867                 cotire_get_configuration_types(_configs)
1868                 foreach (_config ${_configs})
1869                         set (_targetFlags "")
1870                         cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags)
1871                         cotire_filter_compile_flags("${_language}" "arch" _architectures _ignore ${_targetFlags})
1872                         list (LENGTH _architectures _numberOfArchitectures)
1873                         if (_numberOfArchitectures GREATER 1)
1874                                 string (REPLACE ";" ", " _architectureStr "${_architectures}")
1875                                 set (${_msgVar}
1876                                         "Precompiled headers not supported on Darwin for multi-architecture builds (${_architectureStr})."
1877                                         PARENT_SCOPE)
1878                                 break()
1879                         endif()
1880                 endforeach()
1881         endif()
1882 endfunction()
1883
1884 macro (cotire_get_intermediate_dir _cotireDir)
1885         # ${CMAKE_CFG_INTDIR} may reference a build-time variable when using a generator which supports configuration types
1886         get_filename_component(${_cotireDir} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${COTIRE_INTDIR}" ABSOLUTE)
1887 endmacro()
1888
1889 macro (cotire_setup_file_extension_variables)
1890         set (_unityFileExt_C ".c")
1891         set (_unityFileExt_CXX ".cxx")
1892         set (_prefixFileExt_C ".h")
1893         set (_prefixFileExt_CXX ".hxx")
1894         set (_prefixSourceFileExt_C ".c")
1895         set (_prefixSourceFileExt_CXX ".cxx")
1896 endmacro()
1897
1898 function (cotire_make_single_unity_source_file_path _language _target _unityFileVar)
1899         cotire_setup_file_extension_variables()
1900         if (NOT DEFINED _unityFileExt_${_language})
1901                 set (${_unityFileVar} "" PARENT_SCOPE)
1902                 return()
1903         endif()
1904         set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}")
1905         set (_unityFileName "${_unityFileBaseName}${_unityFileExt_${_language}}")
1906         cotire_get_intermediate_dir(_baseDir)
1907         set (_unityFile "${_baseDir}/${_unityFileName}")
1908         set (${_unityFileVar} "${_unityFile}" PARENT_SCOPE)
1909 endfunction()
1910
1911 function (cotire_make_unity_source_file_paths _language _target _maxIncludes _unityFilesVar)
1912         cotire_setup_file_extension_variables()
1913         if (NOT DEFINED _unityFileExt_${_language})
1914                 set (${_unityFileVar} "" PARENT_SCOPE)
1915                 return()
1916         endif()
1917         set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}")
1918         cotire_get_intermediate_dir(_baseDir)
1919         set (_startIndex 0)
1920         set (_index 0)
1921         set (_unityFiles "")
1922         set (_sourceFiles ${ARGN})
1923         foreach (_sourceFile ${_sourceFiles})
1924                 get_source_file_property(_startNew "${_sourceFile}" COTIRE_START_NEW_UNITY_SOURCE)
1925                 math (EXPR _unityFileCount "${_index} - ${_startIndex}")
1926                 if (_startNew OR (_maxIncludes GREATER 0 AND NOT _unityFileCount LESS _maxIncludes))
1927                         if (_index GREATER 0)
1928                                 # start new unity file segment
1929                                 math (EXPR _endIndex "${_index} - 1")
1930                                 set (_unityFileName "${_unityFileBaseName}_${_startIndex}_${_endIndex}${_unityFileExt_${_language}}")
1931                                 list (APPEND _unityFiles "${_baseDir}/${_unityFileName}")
1932                         endif()
1933                         set (_startIndex ${_index})
1934                 endif()
1935                 math (EXPR _index "${_index} + 1")
1936         endforeach()
1937         list (LENGTH _sourceFiles _numberOfSources)
1938         if (_startIndex EQUAL 0)
1939                 # there is only a single unity file
1940                 cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFiles)
1941         elseif (_startIndex LESS _numberOfSources)
1942                 # end with final unity file segment
1943                 math (EXPR _endIndex "${_index} - 1")
1944                 set (_unityFileName "${_unityFileBaseName}_${_startIndex}_${_endIndex}${_unityFileExt_${_language}}")
1945                 list (APPEND _unityFiles "${_baseDir}/${_unityFileName}")
1946         endif()
1947         set (${_unityFilesVar} ${_unityFiles} PARENT_SCOPE)
1948         if (COTIRE_DEBUG AND _unityFiles)
1949                 message (STATUS "unity files: ${_unityFiles}")
1950         endif()
1951 endfunction()
1952
1953 function (cotire_unity_to_prefix_file_path _language _target _unityFile _prefixFileVar)
1954         cotire_setup_file_extension_variables()
1955         if (NOT DEFINED _unityFileExt_${_language})
1956                 set (${_prefixFileVar} "" PARENT_SCOPE)
1957                 return()
1958         endif()
1959         set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}")
1960         set (_prefixFileBaseName "${_target}_${_language}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}")
1961         string (REPLACE "${_unityFileBaseName}" "${_prefixFileBaseName}" _prefixFile "${_unityFile}")
1962         string (REGEX REPLACE "${_unityFileExt_${_language}}$" "${_prefixFileExt_${_language}}" _prefixFile "${_prefixFile}")
1963         set (${_prefixFileVar} "${_prefixFile}" PARENT_SCOPE)
1964 endfunction()
1965
1966 function (cotire_prefix_header_to_source_file_path _language _prefixHeaderFile _prefixSourceFileVar)
1967         cotire_setup_file_extension_variables()
1968         if (NOT DEFINED _prefixSourceFileExt_${_language})
1969                 set (${_prefixSourceFileVar} "" PARENT_SCOPE)
1970                 return()
1971         endif()
1972         string (REGEX REPLACE "${_prefixFileExt_${_language}}$" "${_prefixSourceFileExt_${_language}}" _prefixSourceFile "${_prefixHeaderFile}")
1973         set (${_prefixSourceFileVar} "${_prefixSourceFile}" PARENT_SCOPE)
1974 endfunction()
1975
1976 function (cotire_make_prefix_file_name _language _target _prefixFileBaseNameVar _prefixFileNameVar)
1977         cotire_setup_file_extension_variables()
1978         if (NOT _language)
1979                 set (_prefixFileBaseName "${_target}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}")
1980                 set (_prefixFileName "${_prefixFileBaseName}${_prefixFileExt_C}")
1981         elseif (DEFINED _prefixFileExt_${_language})
1982                 set (_prefixFileBaseName "${_target}_${_language}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}")
1983                 set (_prefixFileName "${_prefixFileBaseName}${_prefixFileExt_${_language}}")
1984         else()
1985                 set (_prefixFileBaseName "")
1986                 set (_prefixFileName "")
1987         endif()
1988         set (${_prefixFileBaseNameVar} "${_prefixFileBaseName}" PARENT_SCOPE)
1989         set (${_prefixFileNameVar} "${_prefixFileName}" PARENT_SCOPE)
1990 endfunction()
1991
1992 function (cotire_make_prefix_file_path _language _target _prefixFileVar)
1993         cotire_make_prefix_file_name("${_language}" "${_target}" _prefixFileBaseName _prefixFileName)
1994         set (${_prefixFileVar} "" PARENT_SCOPE)
1995         if (_prefixFileName)
1996                 if (NOT _language)
1997                         set (_language "C")
1998                 endif()
1999                 if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang|Intel|MSVC")
2000                         cotire_get_intermediate_dir(_baseDir)
2001                         set (${_prefixFileVar} "${_baseDir}/${_prefixFileName}" PARENT_SCOPE)
2002                 endif()
2003         endif()
2004 endfunction()
2005
2006 function (cotire_make_pch_file_path _language _target _pchFileVar)
2007         cotire_make_prefix_file_name("${_language}" "${_target}" _prefixFileBaseName _prefixFileName)
2008         set (${_pchFileVar} "" PARENT_SCOPE)
2009         if (_prefixFileBaseName AND _prefixFileName)
2010                 cotire_check_precompiled_header_support("${_language}" "${_target}" _msg)
2011                 if (NOT _msg)
2012                         if (XCODE)
2013                                 # For Xcode, we completely hand off the compilation of the prefix header to the IDE
2014                                 return()
2015                         endif()
2016                         cotire_get_intermediate_dir(_baseDir)
2017                         if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC")
2018                                 # MSVC uses the extension .pch added to the prefix header base name
2019                                 set (${_pchFileVar} "${_baseDir}/${_prefixFileBaseName}.pch" PARENT_SCOPE)
2020                         elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Clang")
2021                                 # Clang looks for a precompiled header corresponding to the prefix header with the extension .pch appended
2022                                 set (${_pchFileVar} "${_baseDir}/${_prefixFileName}.pch" PARENT_SCOPE)
2023                         elseif (CMAKE_${_language}_COMPILER_ID MATCHES "GNU")
2024                                 # GCC looks for a precompiled header corresponding to the prefix header with the extension .gch appended
2025                                 set (${_pchFileVar} "${_baseDir}/${_prefixFileName}.gch" PARENT_SCOPE)
2026                         elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Intel")
2027                                 # Intel uses the extension .pchi added to the prefix header base name
2028                                 set (${_pchFileVar} "${_baseDir}/${_prefixFileBaseName}.pchi" PARENT_SCOPE)
2029                         endif()
2030                 endif()
2031         endif()
2032 endfunction()
2033
2034 function (cotire_select_unity_source_files _unityFile _sourcesVar)
2035         set (_sourceFiles ${ARGN})
2036         if (_sourceFiles AND "${_unityFile}" MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}_([0-9]+)_([0-9]+)")
2037                 set (_startIndex ${CMAKE_MATCH_1})
2038                 set (_endIndex ${CMAKE_MATCH_2})
2039                 list (LENGTH _sourceFiles _numberOfSources)
2040                 if (NOT _startIndex LESS _numberOfSources)
2041                         math (EXPR _startIndex "${_numberOfSources} - 1")
2042                 endif()
2043                 if (NOT _endIndex LESS _numberOfSources)
2044                         math (EXPR _endIndex "${_numberOfSources} - 1")
2045                 endif()
2046                 set (_files "")
2047                 foreach (_index RANGE ${_startIndex} ${_endIndex})
2048                         list (GET _sourceFiles ${_index} _file)
2049                         list (APPEND _files "${_file}")
2050                 endforeach()
2051         else()
2052                 set (_files ${_sourceFiles})
2053         endif()
2054         set (${_sourcesVar} ${_files} PARENT_SCOPE)
2055 endfunction()
2056
2057 function (cotire_get_unity_source_dependencies _language _target _dependencySourcesVar)
2058         set (_dependencySources "")
2059         # depend on target's generated source files
2060         get_target_property(_targetSourceFiles ${_target} SOURCES)
2061         cotire_get_objects_with_property_on(_generatedSources GENERATED SOURCE ${_targetSourceFiles})
2062         if (_generatedSources)
2063                 # but omit all generated source files that have the COTIRE_EXCLUDED property set to true
2064                 cotire_get_objects_with_property_on(_excludedGeneratedSources COTIRE_EXCLUDED SOURCE ${_generatedSources})
2065                 if (_excludedGeneratedSources)
2066                         list (REMOVE_ITEM _generatedSources ${_excludedGeneratedSources})
2067                 endif()
2068                 # and omit all generated source files that have the COTIRE_DEPENDENCY property set to false explicitly
2069                 cotire_get_objects_with_property_off(_excludedNonDependencySources COTIRE_DEPENDENCY SOURCE ${_generatedSources})
2070                 if (_excludedNonDependencySources)
2071                         list (REMOVE_ITEM _generatedSources ${_excludedNonDependencySources})
2072                 endif()
2073                 if (_generatedSources)
2074                         list (APPEND _dependencySources ${_generatedSources})
2075                 endif()
2076         endif()
2077         if (COTIRE_DEBUG AND _dependencySources)
2078                 message (STATUS "${_language} ${_target} unity source dependencies: ${_dependencySources}")
2079         endif()
2080         set (${_dependencySourcesVar} ${_dependencySources} PARENT_SCOPE)
2081 endfunction()
2082
2083 function (cotire_get_prefix_header_dependencies _language _target _dependencySourcesVar)
2084         set (_dependencySources "")
2085         # depend on target source files marked with custom COTIRE_DEPENDENCY property
2086         get_target_property(_targetSourceFiles ${_target} SOURCES)
2087         cotire_get_objects_with_property_on(_dependencySources COTIRE_DEPENDENCY SOURCE ${_targetSourceFiles})
2088         if (COTIRE_DEBUG AND _dependencySources)
2089                 message (STATUS "${_language} ${_target} prefix header dependencies: ${_dependencySources}")
2090         endif()
2091         set (${_dependencySourcesVar} ${_dependencySources} PARENT_SCOPE)
2092 endfunction()
2093
2094 function (cotire_generate_target_script _language _configurations _target _targetScriptVar _targetConfigScriptVar)
2095         set (_targetSources ${ARGN})
2096         cotire_get_prefix_header_dependencies(${_language} ${_target} COTIRE_TARGET_PREFIX_DEPENDS ${_targetSources})
2097         cotire_get_unity_source_dependencies(${_language} ${_target} COTIRE_TARGET_UNITY_DEPENDS ${_targetSources})
2098         # set up variables to be configured
2099         set (COTIRE_TARGET_LANGUAGE "${_language}")
2100         get_target_property(COTIRE_TARGET_IGNORE_PATH ${_target} COTIRE_PREFIX_HEADER_IGNORE_PATH)
2101         cotire_add_sys_root_paths(COTIRE_TARGET_IGNORE_PATH)
2102         get_target_property(COTIRE_TARGET_INCLUDE_PATH ${_target} COTIRE_PREFIX_HEADER_INCLUDE_PATH)
2103         cotire_add_sys_root_paths(COTIRE_TARGET_INCLUDE_PATH)
2104         get_target_property(COTIRE_TARGET_PRE_UNDEFS ${_target} COTIRE_UNITY_SOURCE_PRE_UNDEFS)
2105         get_target_property(COTIRE_TARGET_POST_UNDEFS ${_target} COTIRE_UNITY_SOURCE_POST_UNDEFS)
2106         get_target_property(COTIRE_TARGET_MAXIMUM_NUMBER_OF_INCLUDES ${_target} COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES)
2107         get_target_property(COTIRE_TARGET_INCLUDE_PRIORITY_PATH ${_target} COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH)
2108         cotire_get_source_files_undefs(COTIRE_UNITY_SOURCE_PRE_UNDEFS COTIRE_TARGET_SOURCES_PRE_UNDEFS ${_targetSources})
2109         cotire_get_source_files_undefs(COTIRE_UNITY_SOURCE_POST_UNDEFS COTIRE_TARGET_SOURCES_POST_UNDEFS ${_targetSources})
2110         set (COTIRE_TARGET_CONFIGURATION_TYPES "${_configurations}")
2111         foreach (_config ${_configurations})
2112                 string (TOUPPER "${_config}" _upperConfig)
2113                 cotire_get_target_include_directories(
2114                         "${_config}" "${_language}" "${_target}" COTIRE_TARGET_INCLUDE_DIRECTORIES_${_upperConfig} COTIRE_TARGET_SYSTEM_INCLUDE_DIRECTORIES_${_upperConfig})
2115                 cotire_get_target_compile_definitions(
2116                         "${_config}" "${_language}" "${_target}" COTIRE_TARGET_COMPILE_DEFINITIONS_${_upperConfig})
2117                 cotire_get_target_compiler_flags(
2118                         "${_config}" "${_language}" "${_target}" COTIRE_TARGET_COMPILE_FLAGS_${_upperConfig})
2119                 cotire_get_source_files_compile_definitions(
2120                         "${_config}" "${_language}" COTIRE_TARGET_SOURCES_COMPILE_DEFINITIONS_${_upperConfig} ${_targetSources})
2121         endforeach()
2122         get_target_property(COTIRE_TARGET_${_language}_COMPILER_LAUNCHER ${_target} ${_language}_COMPILER_LAUNCHER)
2123         # set up COTIRE_TARGET_SOURCES
2124         set (COTIRE_TARGET_SOURCES "")
2125         foreach (_sourceFile ${_targetSources})
2126                 get_source_file_property(_generated "${_sourceFile}" GENERATED)
2127                 if (_generated)
2128                         # use absolute paths for generated files only, retrieving the LOCATION property is an expensive operation
2129                         get_source_file_property(_sourceLocation "${_sourceFile}" LOCATION)
2130                         list (APPEND COTIRE_TARGET_SOURCES "${_sourceLocation}")
2131                 else()
2132                         list (APPEND COTIRE_TARGET_SOURCES "${_sourceFile}")
2133                 endif()
2134         endforeach()
2135         # copy variable definitions to cotire target script
2136         get_cmake_property(_vars VARIABLES)
2137         string (REGEX MATCHALL "COTIRE_[A-Za-z0-9_]+" _matchVars "${_vars}")
2138         # omit COTIRE_*_INIT variables
2139         string (REGEX MATCHALL "COTIRE_[A-Za-z0-9_]+_INIT" _initVars "${_matchVars}")
2140         if (_initVars)
2141                 list (REMOVE_ITEM _matchVars ${_initVars})
2142         endif()
2143         # omit COTIRE_VERBOSE which is passed as a CMake define on command line
2144         list (REMOVE_ITEM _matchVars COTIRE_VERBOSE)
2145         set (_contents "")
2146         set (_contentsHasGeneratorExpressions FALSE)
2147         foreach (_var IN LISTS _matchVars ITEMS
2148                 XCODE MSVC CMAKE_GENERATOR CMAKE_BUILD_TYPE CMAKE_CONFIGURATION_TYPES
2149                 CMAKE_${_language}_COMPILER_ID CMAKE_${_language}_COMPILER_VERSION
2150                 CMAKE_${_language}_COMPILER_LAUNCHER CMAKE_${_language}_COMPILER CMAKE_${_language}_COMPILER_ARG1
2151                 CMAKE_INCLUDE_FLAG_${_language} CMAKE_INCLUDE_FLAG_${_language}_SEP
2152                 CMAKE_INCLUDE_SYSTEM_FLAG_${_language}
2153                 CMAKE_${_language}_FRAMEWORK_SEARCH_FLAG
2154                 CMAKE_${_language}_SYSTEM_FRAMEWORK_SEARCH_FLAG
2155                 CMAKE_${_language}_SOURCE_FILE_EXTENSIONS)
2156                 if (DEFINED ${_var})
2157                         string (REPLACE "\"" "\\\"" _value "${${_var}}")
2158                         set (_contents "${_contents}set (${_var} \"${_value}\")\n")
2159                         if (NOT _contentsHasGeneratorExpressions)
2160                                 if ("${_value}" MATCHES "\\$<.*>")
2161                                         set (_contentsHasGeneratorExpressions TRUE)
2162                                 endif()
2163                         endif()
2164                 endif()
2165         endforeach()
2166         # generate target script file
2167         get_filename_component(_moduleName "${COTIRE_CMAKE_MODULE_FILE}" NAME)
2168         set (_targetCotireScript "${CMAKE_CURRENT_BINARY_DIR}/${_target}_${_language}_${_moduleName}")
2169         cotire_write_file("CMAKE" "${_targetCotireScript}" "${_contents}" FALSE)
2170         if (_contentsHasGeneratorExpressions)
2171                 # use file(GENERATE ...) to expand generator expressions in the target script at CMake generate-time
2172                 set (_configNameOrNoneGeneratorExpression "$<$<CONFIG:>:None>$<$<NOT:$<CONFIG:>>:$<CONFIGURATION>>")
2173                 set (_targetCotireConfigScript "${CMAKE_CURRENT_BINARY_DIR}/${_target}_${_language}_${_configNameOrNoneGeneratorExpression}_${_moduleName}")
2174                 file (GENERATE OUTPUT "${_targetCotireConfigScript}" INPUT "${_targetCotireScript}")
2175         else()
2176                 set (_targetCotireConfigScript "${_targetCotireScript}")
2177         endif()
2178         set (${_targetScriptVar} "${_targetCotireScript}" PARENT_SCOPE)
2179         set (${_targetConfigScriptVar} "${_targetCotireConfigScript}" PARENT_SCOPE)
2180 endfunction()
2181
2182 function (cotire_setup_pch_file_compilation _language _target _targetScript _prefixFile _pchFile _hostFile)
2183         set (_sourceFiles ${ARGN})
2184         if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
2185                 # for Visual Studio and Intel, we attach the precompiled header compilation to the host file
2186                 # the remaining files include the precompiled header, see cotire_setup_pch_file_inclusion
2187                 if (_sourceFiles)
2188                         set (_flags "")
2189                         cotire_add_pch_compilation_flags(
2190                                 "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}"
2191                                 "${_prefixFile}" "${_pchFile}" "${_hostFile}" _flags)
2192                         set_property (SOURCE ${_hostFile} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ")
2193                         set_property (SOURCE ${_hostFile} APPEND PROPERTY OBJECT_OUTPUTS "${_pchFile}")
2194                         # make object file generated from host file depend on prefix header
2195                         set_property (SOURCE ${_hostFile} APPEND PROPERTY OBJECT_DEPENDS "${_prefixFile}")
2196                         # mark host file as cotired to prevent it from being used in another cotired target
2197                         set_property (SOURCE ${_hostFile} PROPERTY COTIRE_TARGET "${_target}")
2198                 endif()
2199         elseif ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
2200                 # for makefile based generator, we add a custom command to precompile the prefix header
2201                 if (_targetScript)
2202                         cotire_set_cmd_to_prologue(_cmds)
2203                         list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "precompile" "${_targetScript}" "${_prefixFile}" "${_pchFile}" "${_hostFile}")
2204                         if (MSVC_IDE)
2205                                 file (TO_NATIVE_PATH "${_pchFile}" _pchFileLogPath)
2206                         else()
2207                                 file (RELATIVE_PATH _pchFileLogPath "${CMAKE_BINARY_DIR}" "${_pchFile}")
2208                         endif()
2209                         if (COTIRE_DEBUG)
2210                                 message (STATUS "add_custom_command: OUTPUT ${_pchFile} ${_cmds} DEPENDS ${_prefixFile} IMPLICIT_DEPENDS ${_language} ${_prefixFile}")
2211                         endif()
2212                         set_property (SOURCE "${_pchFile}" PROPERTY GENERATED TRUE)
2213                         add_custom_command(
2214                                 OUTPUT "${_pchFile}"
2215                                 COMMAND ${_cmds}
2216                                 DEPENDS "${_prefixFile}"
2217                                 IMPLICIT_DEPENDS ${_language} "${_prefixFile}"
2218                                 WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
2219                                 COMMENT "Building ${_language} precompiled header ${_pchFileLogPath}"
2220                                 VERBATIM)
2221                 endif()
2222         endif()
2223 endfunction()
2224
2225 function (cotire_setup_pch_file_inclusion _language _target _wholeTarget _prefixFile _pchFile _hostFile)
2226         if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
2227                 # for Visual Studio and Intel, we include the precompiled header in all but the host file
2228                 # the host file does the precompiled header compilation, see cotire_setup_pch_file_compilation
2229                 set (_sourceFiles ${ARGN})
2230                 list (LENGTH _sourceFiles _numberOfSourceFiles)
2231                 if (_numberOfSourceFiles GREATER 0)
2232                         # mark sources as cotired to prevent them from being used in another cotired target
2233                         set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}")
2234                         set (_flags "")
2235                         cotire_add_prefix_pch_inclusion_flags(
2236                                 "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}"
2237                                 "${_prefixFile}" "${_pchFile}" _flags)
2238                         set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ")
2239                         # make object files generated from source files depend on precompiled header
2240                         set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_pchFile}")
2241                 endif()
2242         elseif ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
2243                 set (_sourceFiles ${_hostFile} ${ARGN})
2244                 if (NOT _wholeTarget)
2245                         # for makefile based generator, we force the inclusion of the prefix header for a subset
2246                         # of the source files, if this is a multi-language target or has excluded files
2247                         set (_flags "")
2248                         cotire_add_prefix_pch_inclusion_flags(
2249                                 "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}"
2250                                 "${_prefixFile}" "${_pchFile}" _flags)
2251                         set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ")
2252                         # mark sources as cotired to prevent them from being used in another cotired target
2253                         set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}")
2254                 endif()
2255                 # make object files generated from source files depend on precompiled header
2256                 set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_pchFile}")
2257         endif()
2258 endfunction()
2259
2260 function (cotire_setup_prefix_file_inclusion _language _target _prefixFile)
2261         set (_sourceFiles ${ARGN})
2262         # force the inclusion of the prefix header for the given source files
2263         set (_flags "")
2264         set (_pchFile "")
2265         cotire_add_prefix_pch_inclusion_flags(
2266                 "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}"
2267                 "${_prefixFile}" "${_pchFile}" _flags)
2268         set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ")
2269         # mark sources as cotired to prevent them from being used in another cotired target
2270         set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}")
2271         # make object files generated from source files depend on prefix header
2272         set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_prefixFile}")
2273 endfunction()
2274
2275 function (cotire_get_first_set_property_value _propertyValueVar _type _object)
2276         set (_properties ${ARGN})
2277         foreach (_property ${_properties})
2278                 get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property})
2279                 if (_propertyValue)
2280                         set (${_propertyValueVar} ${_propertyValue} PARENT_SCOPE)
2281                         return()
2282                 endif()
2283         endforeach()
2284         set (${_propertyValueVar} "" PARENT_SCOPE)
2285 endfunction()
2286
2287 function (cotire_setup_combine_command _language _targetScript _joinedFile _cmdsVar)
2288         set (_files ${ARGN})
2289         set (_filesPaths "")
2290         foreach (_file ${_files})
2291                 get_filename_component(_filePath "${_file}" ABSOLUTE)
2292                 list (APPEND _filesPaths "${_filePath}")
2293         endforeach()
2294         cotire_set_cmd_to_prologue(_prefixCmd)
2295         list (APPEND _prefixCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "combine")
2296         if (_targetScript)
2297                 list (APPEND _prefixCmd "${_targetScript}")
2298         endif()
2299         list (APPEND _prefixCmd "${_joinedFile}" ${_filesPaths})
2300         if (COTIRE_DEBUG)
2301                 message (STATUS "add_custom_command: OUTPUT ${_joinedFile} COMMAND ${_prefixCmd} DEPENDS ${_files}")
2302         endif()
2303         set_property (SOURCE "${_joinedFile}" PROPERTY GENERATED TRUE)
2304         if (MSVC_IDE)
2305                 file (TO_NATIVE_PATH "${_joinedFile}" _joinedFileLogPath)
2306         else()
2307                 file (RELATIVE_PATH _joinedFileLogPath "${CMAKE_BINARY_DIR}" "${_joinedFile}")
2308         endif()
2309         get_filename_component(_joinedFileBaseName "${_joinedFile}" NAME_WE)
2310         get_filename_component(_joinedFileExt "${_joinedFile}" EXT)
2311         if (_language AND _joinedFileBaseName MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}$")
2312                 set (_comment "Generating ${_language} unity source ${_joinedFileLogPath}")
2313         elseif (_language AND _joinedFileBaseName MATCHES "${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}$")
2314                 if (_joinedFileExt MATCHES "^\\.c")
2315                         set (_comment "Generating ${_language} prefix source ${_joinedFileLogPath}")
2316                 else()
2317                         set (_comment "Generating ${_language} prefix header ${_joinedFileLogPath}")
2318                 endif()
2319         else()
2320                 set (_comment "Generating ${_joinedFileLogPath}")
2321         endif()
2322         add_custom_command(
2323                 OUTPUT "${_joinedFile}"
2324                 COMMAND ${_prefixCmd}
2325                 DEPENDS ${_files}
2326                 COMMENT "${_comment}"
2327                 WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
2328                 VERBATIM)
2329         list (APPEND ${_cmdsVar} COMMAND ${_prefixCmd})
2330         set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE)
2331 endfunction()
2332
2333 function (cotire_setup_target_pch_usage _languages _target _wholeTarget)
2334         if (XCODE)
2335                 # for Xcode, we attach a pre-build action to generate the unity sources and prefix headers
2336                 set (_prefixFiles "")
2337                 foreach (_language ${_languages})
2338                         get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER)
2339                         if (_prefixFile)
2340                                 list (APPEND _prefixFiles "${_prefixFile}")
2341                         endif()
2342                 endforeach()
2343                 set (_cmds ${ARGN})
2344                 list (LENGTH _prefixFiles _numberOfPrefixFiles)
2345                 if (_numberOfPrefixFiles GREATER 1)
2346                         # we also generate a generic, single prefix header which includes all language specific prefix headers
2347                         set (_language "")
2348                         set (_targetScript "")
2349                         cotire_make_prefix_file_path("${_language}" ${_target} _prefixHeader)
2350                         cotire_setup_combine_command("${_language}" "${_targetScript}" "${_prefixHeader}" _cmds ${_prefixFiles})
2351                 else()
2352                         set (_prefixHeader "${_prefixFiles}")
2353                 endif()
2354                 if (COTIRE_DEBUG)
2355                         message (STATUS "add_custom_command: TARGET ${_target} PRE_BUILD ${_cmds}")
2356                 endif()
2357                 # because CMake PRE_BUILD command does not support dependencies,
2358                 # we check dependencies explicity in cotire script mode when the pre-build action is run
2359                 add_custom_command(
2360                         TARGET "${_target}"
2361                         PRE_BUILD ${_cmds}
2362                         WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
2363                         COMMENT "Updating target ${_target} prefix headers"
2364                         VERBATIM)
2365                 # make Xcode precompile the generated prefix header with ProcessPCH and ProcessPCH++
2366                 set_target_properties(${_target} PROPERTIES XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER "YES")
2367                 set_target_properties(${_target} PROPERTIES XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${_prefixHeader}")
2368         elseif ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
2369                 # for makefile based generator, we force inclusion of the prefix header for all target source files
2370                 # if this is a single-language target without any excluded files
2371                 if (_wholeTarget)
2372                         set (_language "${_languages}")
2373                         # for Visual Studio and Intel, precompiled header inclusion is always done on the source file level
2374                         # see cotire_setup_pch_file_inclusion
2375                         if (NOT CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
2376                                 get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER)
2377                                 if (_prefixFile)
2378                                         get_property(_pchFile TARGET ${_target} PROPERTY COTIRE_${_language}_PRECOMPILED_HEADER)
2379                                         set (_options COMPILE_OPTIONS)
2380                                         cotire_add_prefix_pch_inclusion_flags(
2381                                                 "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}"
2382                                                 "${_prefixFile}" "${_pchFile}" _options)
2383                                         set_property(TARGET ${_target} APPEND PROPERTY ${_options})
2384                                 endif()
2385                         endif()
2386                 endif()
2387         endif()
2388 endfunction()
2389
2390 function (cotire_setup_unity_generation_commands _language _target _targetScript _targetConfigScript _unityFiles _cmdsVar)
2391         set (_dependencySources "")
2392         cotire_get_unity_source_dependencies(${_language} ${_target} _dependencySources ${ARGN})
2393         foreach (_unityFile ${_unityFiles})
2394                 set_property (SOURCE "${_unityFile}" PROPERTY GENERATED TRUE)
2395                 # set up compiled unity source dependencies via OBJECT_DEPENDS
2396                 # this ensures that missing source files are generated before the unity file is compiled
2397                 if (COTIRE_DEBUG AND _dependencySources)
2398                         message (STATUS "${_unityFile} OBJECT_DEPENDS ${_dependencySources}")
2399                 endif()
2400                 if (_dependencySources)
2401                         # the OBJECT_DEPENDS property requires a list of full paths
2402                         set (_objectDependsPaths "")
2403                         foreach (_sourceFile ${_dependencySources})
2404                                 get_source_file_property(_sourceLocation "${_sourceFile}" LOCATION)
2405                                 list (APPEND _objectDependsPaths "${_sourceLocation}")
2406                         endforeach()
2407                         set_property (SOURCE "${_unityFile}" PROPERTY OBJECT_DEPENDS ${_objectDependsPaths})
2408                 endif()
2409                 if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
2410                         # unity file compilation results in potentially huge object file, thus use /bigobj by default unter MSVC and Windows Intel
2411                         set_property (SOURCE "${_unityFile}" APPEND_STRING PROPERTY COMPILE_FLAGS "/bigobj")
2412                 endif()
2413                 cotire_set_cmd_to_prologue(_unityCmd)
2414                 list (APPEND _unityCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "unity" "${_targetConfigScript}" "${_unityFile}")
2415                 if (CMAKE_VERSION VERSION_LESS "3.1.0")
2416                         set (_unityCmdDepends "${_targetScript}")
2417                 else()
2418                         # CMake 3.1.0 supports generator expressions in arguments to DEPENDS
2419                         set (_unityCmdDepends "${_targetConfigScript}")
2420                 endif()
2421                 if (MSVC_IDE)
2422                         file (TO_NATIVE_PATH "${_unityFile}" _unityFileLogPath)
2423                 else()
2424                         file (RELATIVE_PATH _unityFileLogPath "${CMAKE_BINARY_DIR}" "${_unityFile}")
2425                 endif()
2426                 if (COTIRE_DEBUG)
2427                         message (STATUS "add_custom_command: OUTPUT ${_unityFile} COMMAND ${_unityCmd} DEPENDS ${_unityCmdDepends}")
2428                 endif()
2429                 add_custom_command(
2430                         OUTPUT "${_unityFile}"
2431                         COMMAND ${_unityCmd}
2432                         DEPENDS ${_unityCmdDepends}
2433                         COMMENT "Generating ${_language} unity source ${_unityFileLogPath}"
2434                         WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
2435                         VERBATIM)
2436                 list (APPEND ${_cmdsVar} COMMAND ${_unityCmd})
2437         endforeach()
2438         set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE)
2439 endfunction()
2440
2441 function (cotire_setup_prefix_generation_command _language _target _targetScript _prefixFile _unityFiles _cmdsVar)
2442         set (_sourceFiles ${ARGN})
2443         set (_dependencySources "")
2444         cotire_get_prefix_header_dependencies(${_language} ${_target} _dependencySources ${_sourceFiles})
2445         cotire_set_cmd_to_prologue(_prefixCmd)
2446         list (APPEND _prefixCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "prefix" "${_targetScript}" "${_prefixFile}" ${_unityFiles})
2447         set_property (SOURCE "${_prefixFile}" PROPERTY GENERATED TRUE)
2448         if (COTIRE_DEBUG)
2449                 message (STATUS "add_custom_command: OUTPUT ${_prefixFile} COMMAND ${_prefixCmd} DEPENDS ${_unityFile} ${_dependencySources}")
2450         endif()
2451         if (MSVC_IDE)
2452                 file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileLogPath)
2453         else()
2454                 file (RELATIVE_PATH _prefixFileLogPath "${CMAKE_BINARY_DIR}" "${_prefixFile}")
2455         endif()
2456         get_filename_component(_prefixFileExt "${_prefixFile}" EXT)
2457         if (_prefixFileExt MATCHES "^\\.c")
2458                 set (_comment "Generating ${_language} prefix source ${_prefixFileLogPath}")
2459         else()
2460                 set (_comment "Generating ${_language} prefix header ${_prefixFileLogPath}")
2461         endif()
2462         # prevent pre-processing errors upon generating the prefix header when a target's generated include file does not yet exist
2463         # we do not add a file-level dependency for the target's generated files though, because we only want to depend on their existence
2464         # thus we make the prefix header generation depend on a custom helper target which triggers the generation of the files
2465         set (_preTargetName "${_target}${COTIRE_PCH_TARGET_SUFFIX}_pre")
2466         if (TARGET ${_preTargetName})
2467                 # custom helper target has already been generated while processing a different language
2468                 list (APPEND _dependencySources ${_preTargetName})
2469         else()
2470                 get_target_property(_targetSourceFiles ${_target} SOURCES)
2471                 cotire_get_objects_with_property_on(_generatedSources GENERATED SOURCE ${_targetSourceFiles})
2472                 if (_generatedSources)
2473                         add_custom_target("${_preTargetName}" DEPENDS ${_generatedSources})
2474                         cotire_init_target("${_preTargetName}")
2475                         list (APPEND _dependencySources ${_preTargetName})
2476                 endif()
2477         endif()
2478         add_custom_command(
2479                 OUTPUT "${_prefixFile}" "${_prefixFile}.log"
2480                 COMMAND ${_prefixCmd}
2481                 DEPENDS ${_unityFiles} ${_dependencySources}
2482                 COMMENT "${_comment}"
2483                 WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
2484                 VERBATIM)
2485         list (APPEND ${_cmdsVar} COMMAND ${_prefixCmd})
2486         set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE)
2487 endfunction()
2488
2489 function (cotire_setup_prefix_generation_from_unity_command _language _target _targetScript _prefixFile _unityFiles _cmdsVar)
2490         set (_sourceFiles ${ARGN})
2491         if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang")
2492                 # GNU and Clang require indirect compilation of the prefix header to make them honor the system_header pragma
2493                 cotire_prefix_header_to_source_file_path(${_language} "${_prefixFile}" _prefixSourceFile)
2494         else()
2495                 set (_prefixSourceFile "${_prefixFile}")
2496         endif()
2497         cotire_setup_prefix_generation_command(
2498                 ${_language} ${_target} "${_targetScript}"
2499                 "${_prefixSourceFile}" "${_unityFiles}" ${_cmdsVar} ${_sourceFiles})
2500         if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang")
2501                 # set up generation of a prefix source file which includes the prefix header
2502                 cotire_setup_combine_command(${_language} "${_targetScript}" "${_prefixFile}" _cmds ${_prefixSourceFile})
2503         endif()
2504         set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE)
2505 endfunction()
2506
2507 function (cotire_setup_prefix_generation_from_provided_command _language _target _targetScript _prefixFile _cmdsVar)
2508         set (_prefixHeaderFiles ${ARGN})
2509         if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang")
2510                 # GNU and Clang require indirect compilation of the prefix header to make them honor the system_header pragma
2511                 cotire_prefix_header_to_source_file_path(${_language} "${_prefixFile}" _prefixSourceFile)
2512         else()
2513                 set (_prefixSourceFile "${_prefixFile}")
2514         endif()
2515         cotire_setup_combine_command(${_language} "${_targetScript}" "${_prefixSourceFile}" _cmds ${_prefixHeaderFiles})
2516         if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang")
2517                 # set up generation of a prefix source file which includes the prefix header
2518                 cotire_setup_combine_command(${_language} "${_targetScript}" "${_prefixFile}" _cmds ${_prefixSourceFile})
2519         endif()
2520         set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE)
2521 endfunction()
2522
2523 function (cotire_init_cotire_target_properties _target)
2524         get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER SET)
2525         if (NOT _isSet)
2526                 set_property(TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER TRUE)
2527         endif()
2528         get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD SET)
2529         if (NOT _isSet)
2530                 set_property(TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD TRUE)
2531         endif()
2532         get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ADD_CLEAN SET)
2533         if (NOT _isSet)
2534                 set_property(TARGET ${_target} PROPERTY COTIRE_ADD_CLEAN FALSE)
2535         endif()
2536         get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH SET)
2537         if (NOT _isSet)
2538                 set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH "${CMAKE_SOURCE_DIR}")
2539                 cotire_check_is_path_relative_to("${CMAKE_BINARY_DIR}" _isRelative "${CMAKE_SOURCE_DIR}")
2540                 if (NOT _isRelative)
2541                         set_property(TARGET ${_target} APPEND PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH "${CMAKE_BINARY_DIR}")
2542                 endif()
2543         endif()
2544         get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PATH SET)
2545         if (NOT _isSet)
2546                 set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PATH "")
2547         endif()
2548         get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH SET)
2549         if (NOT _isSet)
2550                 set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH "")
2551         endif()
2552         get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_PRE_UNDEFS SET)
2553         if (NOT _isSet)
2554                 set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_PRE_UNDEFS "")
2555         endif()
2556         get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_POST_UNDEFS SET)
2557         if (NOT _isSet)
2558                 set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_POST_UNDEFS "")
2559         endif()
2560         get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_LINK_LIBRARIES_INIT SET)
2561         if (NOT _isSet)
2562                 set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_LINK_LIBRARIES_INIT "COPY_UNITY")
2563         endif()
2564         get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES SET)
2565         if (NOT _isSet)
2566                 if (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES)
2567                         set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES}")
2568                 else()
2569                         set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "")
2570                 endif()
2571         endif()
2572 endfunction()
2573
2574 function (cotire_make_target_message _target _languages _disableMsg _targetMsgVar)
2575         get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER)
2576         get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD)
2577         string (REPLACE ";" " " _languagesStr "${_languages}")
2578         math (EXPR _numberOfExcludedFiles "${ARGC} - 4")
2579         if (_numberOfExcludedFiles EQUAL 0)
2580                 set (_excludedStr "")
2581         elseif (COTIRE_VERBOSE OR _numberOfExcludedFiles LESS 4)
2582                 string (REPLACE ";" ", " _excludedStr "excluding ${ARGN}")
2583         else()
2584                 set (_excludedStr "excluding ${_numberOfExcludedFiles} files")
2585         endif()
2586         set (_targetMsg "")
2587         if (NOT _languages)
2588                 set (_targetMsg "Target ${_target} cannot be cotired.")
2589                 if (_disableMsg)
2590                         set (_targetMsg "${_targetMsg} ${_disableMsg}")
2591                 endif()
2592         elseif (NOT _targetUsePCH AND NOT _targetAddSCU)
2593                 set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build and precompiled header.")
2594                 if (_disableMsg)
2595                         set (_targetMsg "${_targetMsg} ${_disableMsg}")
2596                 endif()
2597         elseif (NOT _targetUsePCH)
2598                 if (_excludedStr)
2599                         set (_targetMsg "${_languagesStr} target ${_target} cotired without precompiled header ${_excludedStr}.")
2600                 else()
2601                         set (_targetMsg "${_languagesStr} target ${_target} cotired without precompiled header.")
2602                 endif()
2603                 if (_disableMsg)
2604                         set (_targetMsg "${_targetMsg} ${_disableMsg}")
2605                 endif()
2606         elseif (NOT _targetAddSCU)
2607                 if (_excludedStr)
2608                         set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build ${_excludedStr}.")
2609                 else()
2610                         set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build.")
2611                 endif()
2612         else()
2613                 if (_excludedStr)
2614                         set (_targetMsg "${_languagesStr} target ${_target} cotired ${_excludedStr}.")
2615                 else()
2616                         set (_targetMsg "${_languagesStr} target ${_target} cotired.")
2617                 endif()
2618         endif()
2619         set (${_targetMsgVar} "${_targetMsg}" PARENT_SCOPE)
2620 endfunction()
2621
2622 function (cotire_choose_target_languages _target _targetLanguagesVar _wholeTargetVar)
2623         set (_languages ${ARGN})
2624         set (_allSourceFiles "")
2625         set (_allExcludedSourceFiles "")
2626         set (_allCotiredSourceFiles "")
2627         set (_targetLanguages "")
2628         set (_pchEligibleTargetLanguages "")
2629         get_target_property(_targetType ${_target} TYPE)
2630         get_target_property(_targetSourceFiles ${_target} SOURCES)
2631         get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER)
2632         get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD)
2633         set (_disableMsg "")
2634         foreach (_language ${_languages})
2635                 get_target_property(_prefixHeader ${_target} COTIRE_${_language}_PREFIX_HEADER)
2636                 get_target_property(_unityBuildFile ${_target} COTIRE_${_language}_UNITY_SOURCE)
2637                 if (_prefixHeader OR _unityBuildFile)
2638                         message (STATUS "cotire: target ${_target} has already been cotired.")
2639                         set (${_targetLanguagesVar} "" PARENT_SCOPE)
2640                         return()
2641                 endif()
2642                 if (_targetUsePCH AND "${_language}" MATCHES "^C|CXX$" AND NOT "${CMAKE_${_language}_COMPILER_ID}" STREQUAL "")
2643                         cotire_check_precompiled_header_support("${_language}" "${_target}" _disableMsg)
2644                         if (_disableMsg)
2645                                 set (_targetUsePCH FALSE)
2646                         endif()
2647                 endif()
2648                 set (_sourceFiles "")
2649                 set (_excludedSources "")
2650                 set (_cotiredSources "")
2651                 cotire_filter_language_source_files(${_language} ${_target} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles})
2652                 if (_sourceFiles OR _excludedSources OR _cotiredSources)
2653                         list (APPEND _targetLanguages ${_language})
2654                 endif()
2655                 if (_sourceFiles)
2656                         list (APPEND _allSourceFiles ${_sourceFiles})
2657                 endif()
2658                 list (LENGTH _sourceFiles _numberOfSources)
2659                 if (NOT _numberOfSources LESS ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES})
2660                         list (APPEND _pchEligibleTargetLanguages ${_language})
2661                 endif()
2662                 if (_excludedSources)
2663                         list (APPEND _allExcludedSourceFiles ${_excludedSources})
2664                 endif()
2665                 if (_cotiredSources)
2666                         list (APPEND _allCotiredSourceFiles ${_cotiredSources})
2667                 endif()
2668         endforeach()
2669         set (_targetMsgLevel STATUS)
2670         if (NOT _targetLanguages)
2671                 string (REPLACE ";" " or " _languagesStr "${_languages}")
2672                 set (_disableMsg "No ${_languagesStr} source files.")
2673                 set (_targetUsePCH FALSE)
2674                 set (_targetAddSCU FALSE)
2675         endif()
2676         if (_targetUsePCH)
2677                 if (_allCotiredSourceFiles)
2678                         cotire_get_source_file_property_values(_cotireTargets COTIRE_TARGET ${_allCotiredSourceFiles})
2679                         list (REMOVE_DUPLICATES _cotireTargets)
2680                         string (REPLACE ";" ", " _cotireTargetsStr "${_cotireTargets}")
2681                         set (_disableMsg "Target sources already include a precompiled header for target(s) ${_cotireTargets}.")
2682                         set (_disableMsg "${_disableMsg} Set target property COTIRE_ENABLE_PRECOMPILED_HEADER to FALSE for targets ${_target},")
2683                         set (_disableMsg "${_disableMsg} ${_cotireTargetsStr} to get a workable build system.")
2684                         set (_targetMsgLevel SEND_ERROR)
2685                         set (_targetUsePCH FALSE)
2686                 elseif (NOT _pchEligibleTargetLanguages)
2687                         set (_disableMsg "Too few applicable sources.")
2688                         set (_targetUsePCH FALSE)
2689                 elseif (XCODE AND _allExcludedSourceFiles)
2690                         # for Xcode, we cannot apply the precompiled header to individual sources, only to the whole target
2691                         set (_disableMsg "Exclusion of source files not supported for generator Xcode.")
2692                         set (_targetUsePCH FALSE)
2693                 elseif (XCODE AND "${_targetType}" STREQUAL "OBJECT_LIBRARY")
2694                         # for Xcode, we cannot apply the required PRE_BUILD action to generate the prefix header to an OBJECT_LIBRARY target
2695                         set (_disableMsg "Required PRE_BUILD action not supported for OBJECT_LIBRARY targets for generator Xcode.")
2696                         set (_targetUsePCH FALSE)
2697                 endif()
2698         endif()
2699         set_property(TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER ${_targetUsePCH})
2700         set_property(TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD ${_targetAddSCU})
2701         cotire_make_target_message(${_target} "${_targetLanguages}" "${_disableMsg}" _targetMsg ${_allExcludedSourceFiles})
2702         if (_targetMsg)
2703                 if (NOT DEFINED COTIREMSG_${_target})
2704                         set (COTIREMSG_${_target} "")
2705                 endif()
2706                 if (COTIRE_VERBOSE OR NOT "${_targetMsgLevel}" STREQUAL "STATUS" OR
2707                         NOT "${COTIREMSG_${_target}}" STREQUAL "${_targetMsg}")
2708                         # cache message to avoid redundant messages on re-configure
2709                         set (COTIREMSG_${_target} "${_targetMsg}" CACHE INTERNAL "${_target} cotire message.")
2710                         message (${_targetMsgLevel} "${_targetMsg}")
2711                 endif()
2712         endif()
2713         list (LENGTH _targetLanguages _numberOfLanguages)
2714         if (_numberOfLanguages GREATER 1 OR _allExcludedSourceFiles)
2715                 set (${_wholeTargetVar} FALSE PARENT_SCOPE)
2716         else()
2717                 set (${_wholeTargetVar} TRUE PARENT_SCOPE)
2718         endif()
2719         set (${_targetLanguagesVar} ${_targetLanguages} PARENT_SCOPE)
2720 endfunction()
2721
2722 function (cotire_compute_unity_max_number_of_includes _target _maxIncludesVar)
2723         set (_sourceFiles ${ARGN})
2724         get_target_property(_maxIncludes ${_target} COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES)
2725         if (_maxIncludes MATCHES "(-j|--parallel|--jobs) ?([0-9]*)")
2726                 set (_numberOfThreads "${CMAKE_MATCH_2}")
2727                 if (NOT _numberOfThreads)
2728                         # use all available cores
2729                         ProcessorCount(_numberOfThreads)
2730                 endif()
2731                 list (LENGTH _sourceFiles _numberOfSources)
2732                 math (EXPR _maxIncludes "(${_numberOfSources} + ${_numberOfThreads} - 1) / ${_numberOfThreads}")
2733         elseif (NOT _maxIncludes MATCHES "[0-9]+")
2734                 set (_maxIncludes 0)
2735         endif()
2736         if (COTIRE_DEBUG)
2737                 message (STATUS "${_target} unity source max includes: ${_maxIncludes}")
2738         endif()
2739         set (${_maxIncludesVar} ${_maxIncludes} PARENT_SCOPE)
2740 endfunction()
2741
2742 function (cotire_process_target_language _language _configurations _target _wholeTarget _cmdsVar)
2743         set (${_cmdsVar} "" PARENT_SCOPE)
2744         get_target_property(_targetSourceFiles ${_target} SOURCES)
2745         set (_sourceFiles "")
2746         set (_excludedSources "")
2747         set (_cotiredSources "")
2748         cotire_filter_language_source_files(${_language} ${_target} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles})
2749         if (NOT _sourceFiles AND NOT _cotiredSources)
2750                 return()
2751         endif()
2752         set (_cmds "")
2753         # check for user provided unity source file list
2754         get_property(_unitySourceFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE_INIT)
2755         if (NOT _unitySourceFiles)
2756                 set (_unitySourceFiles ${_sourceFiles} ${_cotiredSources})
2757         endif()
2758         cotire_generate_target_script(
2759                 ${_language} "${_configurations}" ${_target} _targetScript _targetConfigScript ${_unitySourceFiles})
2760         # set up unity files for parallel compilation
2761         cotire_compute_unity_max_number_of_includes(${_target} _maxIncludes ${_unitySourceFiles})
2762         cotire_make_unity_source_file_paths(${_language} ${_target} ${_maxIncludes} _unityFiles ${_unitySourceFiles})
2763         list (LENGTH _unityFiles _numberOfUnityFiles)
2764         if (_numberOfUnityFiles EQUAL 0)
2765                 return()
2766         elseif (_numberOfUnityFiles GREATER 1)
2767                 cotire_setup_unity_generation_commands(
2768                         ${_language} ${_target} "${_targetScript}" "${_targetConfigScript}" "${_unityFiles}" _cmds ${_unitySourceFiles})
2769         endif()
2770         # set up single unity file for prefix header generation
2771         cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFile)
2772         cotire_setup_unity_generation_commands(
2773                 ${_language} ${_target} "${_targetScript}" "${_targetConfigScript}" "${_unityFile}" _cmds ${_unitySourceFiles})
2774         cotire_make_prefix_file_path(${_language} ${_target} _prefixFile)
2775         # set up prefix header
2776         if (_prefixFile)
2777                 # check for user provided prefix header files
2778                 get_property(_prefixHeaderFiles TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER_INIT)
2779                 if (_prefixHeaderFiles)
2780                         cotire_setup_prefix_generation_from_provided_command(
2781                                 ${_language} ${_target} "${_targetConfigScript}" "${_prefixFile}" _cmds ${_prefixHeaderFiles})
2782                 else()
2783                         cotire_setup_prefix_generation_from_unity_command(
2784                                 ${_language} ${_target} "${_targetConfigScript}" "${_prefixFile}" "${_unityFile}" _cmds ${_unitySourceFiles})
2785                 endif()
2786                 # check if selected language has enough sources at all
2787                 list (LENGTH _sourceFiles _numberOfSources)
2788                 if (_numberOfSources LESS ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES})
2789                         set (_targetUsePCH FALSE)
2790                 else()
2791                         get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER)
2792                 endif()
2793                 if (_targetUsePCH)
2794                         cotire_make_pch_file_path(${_language} ${_target} _pchFile)
2795                         if (_pchFile)
2796                                 # first file in _sourceFiles is passed as the host file
2797                                 cotire_setup_pch_file_compilation(
2798                                         ${_language} ${_target} "${_targetConfigScript}" "${_prefixFile}" "${_pchFile}" ${_sourceFiles})
2799                                 cotire_setup_pch_file_inclusion(
2800                                         ${_language} ${_target} ${_wholeTarget} "${_prefixFile}" "${_pchFile}" ${_sourceFiles})
2801                         endif()
2802                 elseif (_prefixHeaderFiles)
2803                         # user provided prefix header must be included unconditionally
2804                         cotire_setup_prefix_file_inclusion(${_language} ${_target} "${_prefixFile}" ${_sourceFiles})
2805                 endif()
2806         endif()
2807         # mark target as cotired for language
2808         set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE "${_unityFiles}")
2809         if (_prefixFile)
2810                 set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER "${_prefixFile}")
2811                 if (_targetUsePCH AND _pchFile)
2812                         set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_PRECOMPILED_HEADER "${_pchFile}")
2813                 endif()
2814         endif()
2815         set (${_cmdsVar} ${_cmds} PARENT_SCOPE)
2816 endfunction()
2817
2818 function (cotire_setup_clean_target _target)
2819         set (_cleanTargetName "${_target}${COTIRE_CLEAN_TARGET_SUFFIX}")
2820         if (NOT TARGET "${_cleanTargetName}")
2821                 cotire_set_cmd_to_prologue(_cmds)
2822                 get_filename_component(_outputDir "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" ABSOLUTE)
2823                 list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "cleanup" "${_outputDir}" "${COTIRE_INTDIR}" "${_target}")
2824                 add_custom_target(${_cleanTargetName}
2825                         COMMAND ${_cmds}
2826                         WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
2827                         COMMENT "Cleaning up target ${_target} cotire generated files"
2828                         VERBATIM)
2829                 cotire_init_target("${_cleanTargetName}")
2830         endif()
2831 endfunction()
2832
2833 function (cotire_setup_pch_target _languages _configurations _target)
2834         if ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
2835                 # for makefile based generators, we add a custom target to trigger the generation of the cotire related files
2836                 set (_dependsFiles "")
2837                 foreach (_language ${_languages})
2838                         set (_props COTIRE_${_language}_PREFIX_HEADER COTIRE_${_language}_UNITY_SOURCE)
2839                         if (NOT CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel")
2840                                 # Visual Studio and Intel only create precompiled header as a side effect
2841                                 list (INSERT _props 0 COTIRE_${_language}_PRECOMPILED_HEADER)
2842                         endif()
2843                         cotire_get_first_set_property_value(_dependsFile TARGET ${_target} ${_props})
2844                         if (_dependsFile)
2845                                 list (APPEND _dependsFiles "${_dependsFile}")
2846                         endif()
2847                 endforeach()
2848                 if (_dependsFiles)
2849                         set (_pchTargetName "${_target}${COTIRE_PCH_TARGET_SUFFIX}")
2850                         add_custom_target("${_pchTargetName}" DEPENDS ${_dependsFiles})
2851                         cotire_init_target("${_pchTargetName}")
2852                         cotire_add_to_pch_all_target(${_pchTargetName})
2853                 endif()
2854         else()
2855                 # for other generators, we add the "clean all" target to clean up the precompiled header
2856                 cotire_setup_clean_all_target()
2857         endif()
2858 endfunction()
2859
2860 function (cotire_collect_unity_target_sources _target _languages _unityTargetSourcesVar)
2861         get_target_property(_targetSourceFiles ${_target} SOURCES)
2862         set (_unityTargetSources ${_targetSourceFiles})
2863         foreach (_language ${_languages})
2864                 get_property(_unityFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE)
2865                 if (_unityFiles)
2866                         # remove source files that are included in the unity source
2867                         set (_sourceFiles "")
2868                         set (_excludedSources "")
2869                         set (_cotiredSources "")
2870                         cotire_filter_language_source_files(${_language} ${_target} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles})
2871                         if (_sourceFiles OR _cotiredSources)
2872                                 list (REMOVE_ITEM _unityTargetSources ${_sourceFiles} ${_cotiredSources})
2873                         endif()
2874                         # add unity source files instead
2875                         list (APPEND _unityTargetSources ${_unityFiles})
2876                 endif()
2877         endforeach()
2878         set (${_unityTargetSourcesVar} ${_unityTargetSources} PARENT_SCOPE)
2879 endfunction()
2880
2881 function (cotire_setup_unity_target_pch_usage _languages _target)
2882         foreach (_language ${_languages})
2883                 get_property(_unityFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE)
2884                 if (_unityFiles)
2885                         get_property(_userPrefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER_INIT)
2886                         get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER)
2887                         if (_userPrefixFile AND _prefixFile)
2888                                 # user provided prefix header must be included unconditionally by unity sources
2889                                 cotire_setup_prefix_file_inclusion(${_language} ${_target} "${_prefixFile}" ${_unityFiles})
2890                         endif()
2891                 endif()
2892         endforeach()
2893 endfunction()
2894
2895 function (cotire_setup_unity_build_target _languages _configurations _target)
2896         get_target_property(_unityTargetName ${_target} COTIRE_UNITY_TARGET_NAME)
2897         if (NOT _unityTargetName)
2898                 set (_unityTargetName "${_target}${COTIRE_UNITY_BUILD_TARGET_SUFFIX}")
2899         endif()
2900         # determine unity target sub type
2901         get_target_property(_targetType ${_target} TYPE)
2902         if ("${_targetType}" STREQUAL "EXECUTABLE")
2903                 set (_unityTargetSubType "")
2904         elseif (_targetType MATCHES "(STATIC|SHARED|MODULE|OBJECT)_LIBRARY")
2905                 set (_unityTargetSubType "${CMAKE_MATCH_1}")
2906         else()
2907                 message (WARNING "cotire: target ${_target} has unknown target type ${_targetType}.")
2908                 return()
2909         endif()
2910         # determine unity target sources
2911         set (_unityTargetSources "")
2912         cotire_collect_unity_target_sources(${_target} "${_languages}" _unityTargetSources)
2913         # handle automatic Qt processing
2914         get_target_property(_targetAutoMoc ${_target} AUTOMOC)
2915         get_target_property(_targetAutoUic ${_target} AUTOUIC)
2916         get_target_property(_targetAutoRcc ${_target} AUTORCC)
2917         if (_targetAutoMoc OR _targetAutoUic OR _targetAutoRcc)
2918                 # if the original target sources are subject to CMake's automatic Qt processing,
2919                 # also include implicitly generated <targetname>_automoc.cpp file
2920                 list (APPEND _unityTargetSources "${_target}_automoc.cpp")
2921                 set_property (SOURCE "${_target}_automoc.cpp" PROPERTY GENERATED TRUE)
2922         endif()
2923         # prevent AUTOMOC, AUTOUIC and AUTORCC properties from being set when the unity target is created
2924         set (CMAKE_AUTOMOC OFF)
2925         set (CMAKE_AUTOUIC OFF)
2926         set (CMAKE_AUTORCC OFF)
2927         if (COTIRE_DEBUG)
2928                 message (STATUS "add target ${_targetType} ${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}")
2929         endif()
2930         # generate unity target
2931         if ("${_targetType}" STREQUAL "EXECUTABLE")
2932                 add_executable(${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources})
2933         else()
2934                 add_library(${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources})
2935