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