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