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