]> sigrok.org Git - pulseview.git/blob - CMake/cotire.cmake
SamplingBar: Improved event loop protection
[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."
2891         )
2892
2893         define_property(
2894                 CACHED_VARIABLE PROPERTY "COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS"
2895                 BRIEF_DOCS "Exclude sources with the listed file extensions from the generated unity source."
2896                 FULL_DOCS
2897                         "The variable can be set to a semicolon separated list of file extensions."
2898                         "If a source file extension matches one in the list, it will be excluded from the generated unity source file."
2899                         "Source files with an extension in CMAKE_<LANG>_IGNORE_EXTENSIONS are always excluded."
2900                         "If not defined, defaults to m;mm."
2901         )
2902
2903         define_property(
2904                 CACHED_VARIABLE PROPERTY "COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES"
2905                 BRIEF_DOCS "Minimum number of sources in target required to enable use of precompiled header."
2906                 FULL_DOCS
2907                         "The variable can be set to an integer > 0."
2908                         "If a target contains less than that number of source files, cotire will not enable the use of the precompiled header for the target."
2909                         "If not defined, defaults to 3."
2910         )
2911
2912         define_property(
2913                 CACHED_VARIABLE PROPERTY "COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES"
2914                 BRIEF_DOCS "Maximum number of source files to include in a single unity source file."
2915                 FULL_DOCS
2916                         "This may be set to an integer >= 0."
2917                         "If 0, cotire will only create a single unity source file."
2918                         "If a target contains more than that number of source files, cotire will create multiple unity source files for it."
2919                         "Can be set to \"-j\" to optimize the count of unity source files for the number of available processor cores."
2920                         "Can be set to \"-j jobs\" to optimize the number of unity source files for the given number of simultaneous jobs."
2921                         "Is used to initialize the target property COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES."
2922                         "Defaults to \"-j\" for the generators Visual Studio, JOM or Ninja. Defaults to 0 otherwise."
2923         )
2924
2925         # define cotire directory properties
2926
2927         define_property(
2928                 DIRECTORY PROPERTY "COTIRE_ENABLE_PRECOMPILED_HEADER"
2929                 BRIEF_DOCS "Modify build command of cotired targets added in this directory to make use of the generated precompiled header."
2930                 FULL_DOCS
2931                         "See target property COTIRE_ENABLE_PRECOMPILED_HEADER."
2932         )
2933
2934         define_property(
2935                 DIRECTORY PROPERTY "COTIRE_ADD_UNITY_BUILD"
2936                 BRIEF_DOCS "Add a new target that performs a unity build for cotired targets added in this directory."
2937                 FULL_DOCS
2938                         "See target property COTIRE_ADD_UNITY_BUILD."
2939         )
2940
2941         define_property(
2942                 DIRECTORY PROPERTY "COTIRE_ADD_CLEAN"
2943                 BRIEF_DOCS "Add a new target that cleans all cotire generated files for cotired targets added in this directory."
2944                 FULL_DOCS
2945                         "See target property COTIRE_ADD_CLEAN."
2946         )
2947
2948         define_property(
2949                 DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_IGNORE_PATH"
2950                 BRIEF_DOCS "Ignore headers from these directories when generating the prefix header."
2951                 FULL_DOCS
2952                         "See target property COTIRE_PREFIX_HEADER_IGNORE_PATH."
2953         )
2954
2955         define_property(
2956                 DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PATH"
2957                 BRIEF_DOCS "Honor headers from these directories when generating the prefix header."
2958                 FULL_DOCS
2959                         "See target property COTIRE_PREFIX_HEADER_INCLUDE_PATH."
2960         )
2961
2962         define_property(
2963                 DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS"
2964                 BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of each source file."
2965                 FULL_DOCS
2966                         "See target property COTIRE_UNITY_SOURCE_PRE_UNDEFS."
2967         )
2968
2969         define_property(
2970                 DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS"
2971                 BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of each source file."
2972                 FULL_DOCS
2973                         "See target property COTIRE_UNITY_SOURCE_POST_UNDEFS."
2974         )
2975
2976         define_property(
2977                 DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES"
2978                 BRIEF_DOCS "Maximum number of source files to include in a single unity source file."
2979                 FULL_DOCS
2980                         "See target property COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES."
2981         )
2982
2983         # define cotire target properties
2984
2985         define_property(
2986                 TARGET PROPERTY "COTIRE_ENABLE_PRECOMPILED_HEADER" INHERITED
2987                 BRIEF_DOCS "Modify this target's build command to make use of the generated precompiled header."
2988                 FULL_DOCS
2989                         "If this property is set to TRUE, cotire will modify the build command to make use of the generated precompiled header."
2990                         "Irrespective of the value of this property, cotire will setup custom commands to generate the unity source and prefix header for the target."
2991                         "For makefile based generators cotire will also set up a custom target to manually invoke the generation of the precompiled header."
2992                         "The target name will be set to this target's name with the suffix _pch appended."
2993                         "Inherited from directory."
2994                         "Defaults to TRUE."
2995         )
2996
2997         define_property(
2998                 TARGET PROPERTY "COTIRE_ADD_UNITY_BUILD" INHERITED
2999                 BRIEF_DOCS "Add a new target that performs a unity build for this target."
3000                 FULL_DOCS
3001                         "If this property is set to TRUE, cotire creates a new target of the same type that uses the generated unity source file instead of the target sources."
3002                         "Most of the relevant target properties will be copied from this target to the new unity build target."
3003                         "Target dependencies and linked libraries have to be manually set up for the new unity build target."
3004                         "The unity target name will be set to this target's name with the suffix _unity appended."
3005                         "Inherited from directory."
3006                         "Defaults to TRUE."
3007         )
3008
3009         define_property(
3010                 TARGET PROPERTY "COTIRE_ADD_CLEAN" INHERITED
3011                 BRIEF_DOCS "Add a new target that cleans all cotire generated files for this target."
3012                 FULL_DOCS
3013                         "If this property is set to TRUE, cotire creates a new target that clean all files (unity source, prefix header, precompiled header)."
3014                         "The clean target name will be set to this target's name with the suffix _clean_cotire appended."
3015                         "Inherited from directory."
3016                         "Defaults to FALSE."
3017         )
3018
3019         define_property(
3020                 TARGET PROPERTY "COTIRE_PREFIX_HEADER_IGNORE_PATH" INHERITED
3021                 BRIEF_DOCS "Ignore headers from these directories when generating the prefix header."
3022                 FULL_DOCS
3023                         "The property can be set to a list of directories."
3024                         "If a header file is found in one of these directories or sub-directories, it will be excluded from the generated prefix header."
3025                         "Inherited from directory."
3026                         "If not set, this property is initialized to \${CMAKE_SOURCE_DIR};\${CMAKE_BINARY_DIR}."
3027         )
3028
3029         define_property(
3030                 TARGET PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PATH" INHERITED
3031                 BRIEF_DOCS "Honor headers from these directories when generating the prefix header."
3032                 FULL_DOCS
3033                         "The property can be set to a list of directories."
3034                         "If a header file is found in one of these directories or sub-directories, it will be included in the generated prefix header."
3035                         "If a header file is both selected by COTIRE_PREFIX_HEADER_IGNORE_PATH and COTIRE_PREFIX_HEADER_INCLUDE_PATH,"
3036                         "the option which yields the closer relative path match wins."
3037                         "Inherited from directory."
3038                         "If not set, this property is initialized to the empty list."
3039         )
3040
3041         define_property(
3042                 TARGET PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" INHERITED
3043                 BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of each target source file."
3044                 FULL_DOCS
3045                         "This may be set to a semicolon-separated list of preprocessor symbols."
3046                         "cotire will add corresponding #undef directives to the generated unit source file before each target source file."
3047                         "Inherited from directory."
3048                         "Defaults to empty string."
3049         )
3050
3051         define_property(
3052                 TARGET PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" INHERITED
3053                 BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of each target source file."
3054                 FULL_DOCS
3055                         "This may be set to a semicolon-separated list of preprocessor symbols."
3056                         "cotire will add corresponding #undef directives to the generated unit source file after each target source file."
3057                         "Inherited from directory."
3058                         "Defaults to empty string."
3059         )
3060
3061         define_property(
3062                 TARGET PROPERTY "COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES" INHERITED
3063                 BRIEF_DOCS "Maximum number of source files to include in a single unity source file."
3064                 FULL_DOCS
3065                         "This may be set to an integer > 0."
3066                         "If a target contains more than that number of source files, cotire will create multiple unity build files for it."
3067                         "If not set, cotire will only create a single unity source file."
3068                         "Inherited from directory."
3069                         "Defaults to empty."
3070         )
3071
3072         define_property(
3073                 TARGET PROPERTY "COTIRE_<LANG>_UNITY_SOURCE_INIT"
3074                 BRIEF_DOCS "User provided unity source file to be used instead of the automatically generated one."
3075                 FULL_DOCS
3076                         "If set, cotire will only add the given file(s) to the generated unity source file."
3077                         "If not set, cotire will add all the target source files to the generated unity source file."
3078                         "The property can be set to a user provided unity source file."
3079                         "Defaults to empty."
3080         )
3081
3082         define_property(
3083                 TARGET PROPERTY "COTIRE_<LANG>_PREFIX_HEADER_INIT"
3084                 BRIEF_DOCS "User provided prefix header file to be used instead of the automatically generated one."
3085                 FULL_DOCS
3086                         "If set, cotire will add the given header file(s) to the generated prefix header file."
3087                         "If not set, cotire will generate a prefix header by tracking the header files included by the unity source file."
3088                         "The property can be set to a user provided prefix header file (e.g., stdafx.h)."
3089                         "Defaults to empty."
3090         )
3091
3092         define_property(
3093                 TARGET PROPERTY "COTIRE_<LANG>_UNITY_SOURCE"
3094                 BRIEF_DOCS "Read-only property. The generated <LANG> unity source file(s)."
3095                 FULL_DOCS
3096                         "cotire sets this property to the path of the generated <LANG> single computation unit source file for the target."
3097                         "Defaults to empty string."
3098         )
3099
3100         define_property(
3101                 TARGET PROPERTY "COTIRE_<LANG>_PREFIX_HEADER"
3102                 BRIEF_DOCS "Read-only property. The generated <LANG> prefix header file."
3103                 FULL_DOCS
3104                         "cotire sets this property to the full path of the generated <LANG> language prefix header for the target."
3105                         "Defaults to empty string."
3106         )
3107
3108         define_property(
3109                 TARGET PROPERTY "COTIRE_<LANG>_PRECOMPILED_HEADER"
3110                 BRIEF_DOCS "Read-only property. The generated <LANG> precompiled header file."
3111                 FULL_DOCS
3112                         "cotire sets this property to the full path of the generated <LANG> language precompiled header binary for the target."
3113                         "Defaults to empty string."
3114         )
3115
3116         define_property(
3117                 TARGET PROPERTY "COTIRE_UNITY_TARGET_NAME"
3118                 BRIEF_DOCS "The name of the generated unity build target corresponding to this target."
3119                 FULL_DOCS
3120                         "This property can be set to the desired name of the unity target that will be created by cotire."
3121                         "If not set, the unity target name will be set to this target's name with the suffix _unity appended."
3122                         "After this target has been processed by cotire, the property is set to the actual name of the generated unity target."
3123                         "Defaults to empty string."
3124         )
3125
3126         # define cotire source properties
3127
3128         define_property(
3129                 SOURCE PROPERTY "COTIRE_EXCLUDED"
3130                 BRIEF_DOCS "Do not modify source file's build command."
3131                 FULL_DOCS
3132                         "If this property is set to TRUE, the source file's build command will not be modified to make use of the precompiled header."
3133                         "The source file will also be excluded from the generated unity source file."
3134                         "Source files that have their COMPILE_FLAGS property set will be excluded by default."
3135                         "Defaults to FALSE."
3136         )
3137
3138         define_property(
3139                 SOURCE PROPERTY "COTIRE_DEPENDENCY"
3140                 BRIEF_DOCS "Add this source file to dependencies of the automatically generated prefix header file."
3141                 FULL_DOCS
3142                         "If this property is set to TRUE, the source file is added to dependencies of the generated prefix header file."
3143                         "If the file is modified, cotire will re-generate the prefix header source upon build."
3144                         "Defaults to FALSE."
3145         )
3146
3147         define_property(
3148                 SOURCE PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS"
3149                 BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of this source file."
3150                 FULL_DOCS
3151                         "This may be set to a semicolon-separated list of preprocessor symbols."
3152                         "cotire will add corresponding #undef directives to the generated unit source file before this file is included."
3153                         "Defaults to empty string."
3154         )
3155
3156         define_property(
3157                 SOURCE PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS"
3158                 BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of this source file."
3159                 FULL_DOCS
3160                         "This may be set to a semicolon-separated list of preprocessor symbols."
3161                         "cotire will add corresponding #undef directives to the generated unit source file after this file is included."
3162                         "Defaults to empty string."
3163         )
3164
3165         define_property(
3166                 SOURCE PROPERTY "COTIRE_START_NEW_UNITY_SOURCE"
3167                 BRIEF_DOCS "Start a new unity source file which includes this source file as the first one."
3168                 FULL_DOCS
3169                         "If this property is set to TRUE, cotire will complete the current unity file and start a new one."
3170                         "The new unity source file will include this source file as the first one."
3171                         "This property essentially works as a separator for unity source files."
3172                         "Defaults to FALSE."
3173         )
3174
3175         define_property(
3176                 SOURCE PROPERTY "COTIRE_TARGET"
3177                 BRIEF_DOCS "Read-only property. Mark this source file as cotired for the given target."
3178                 FULL_DOCS
3179                         "cotire sets this property to the name of target, that the source file's build command has been altered for."
3180                         "Defaults to empty string."
3181         )
3182
3183         message (STATUS "cotire ${COTIRE_CMAKE_MODULE_VERSION} loaded.")
3184
3185 endif()