1 # taken from http://public.kitware.com/Bug/view.php?id=1260 and slightly adjusted
3 # - Try to find precompiled headers support for GCC 3.4 and 4.x
4 # Once done this will define:
10 # ADD_PRECOMPILED_HEADER _targetName _input _dowarn
11 # ADD_PRECOMPILED_HEADER_TO_TARGET _targetName _input _pch_output_to_use _dowarn
12 # ADD_NATIVE_PRECOMPILED_HEADER _targetName _input _dowarn
13 # GET_NATIVE_PRECOMPILED_HEADER _targetName _input
17 IF(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.2.0")
18 SET(PCHSupport_FOUND TRUE)
21 SET(_PCH_include_prefix "-I")
22 SET(_PCH_isystem_prefix "-isystem")
23 SET(_PCH_define_prefix "-D")
25 ELSEIF(CMAKE_GENERATOR MATCHES "^Visual.*$")
26 SET(PCHSupport_FOUND TRUE)
27 SET(_PCH_include_prefix "/I")
28 SET(_PCH_isystem_prefix "/I")
29 SET(_PCH_define_prefix "/D")
31 SET(PCHSupport_FOUND FALSE)
34 MACRO(_PCH_GET_COMPILE_FLAGS _out_compile_flags)
36 STRING(TOUPPER "CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}" _flags_var_name)
37 SET(${_out_compile_flags} ${${_flags_var_name}} )
41 GET_TARGET_PROPERTY(_targetType ${_PCH_current_target} TYPE)
42 IF(${_targetType} STREQUAL SHARED_LIBRARY AND NOT WIN32)
43 LIST(APPEND ${_out_compile_flags} "-fPIC")
46 GET_PROPERTY(_definitions DIRECTORY PROPERTY COMPILE_DEFINITIONS)
48 foreach(_def ${_definitions})
49 LIST(APPEND ${_out_compile_flags} "\"-D${_def}\"")
52 GET_TARGET_PROPERTY(_target_definitions ${_PCH_current_target} COMPILE_DEFINITIONS)
53 if(_target_definitions)
54 foreach(_def ${_target_definitions})
55 LIST(APPEND ${_out_compile_flags} "\"-D${_def}\"")
59 GET_TARGET_PROPERTY(_cxx_standard ${_PCH_current_target} CXX_STANDARD)
61 GET_TARGET_PROPERTY(_cxx_extensions ${_PCH_current_target} CXX_EXTENSIONS)
63 LIST(APPEND ${_out_compile_flags} "${CMAKE_CXX${_cxx_standard}_EXTENSION_COMPILE_OPTION}")
65 LIST(APPEND ${_out_compile_flags} "${CMAKE_CXX${_cxx_standard}_STANDARD_COMPILE_OPTION}")
69 ## TODO ... ? or does it work out of the box
72 GET_DIRECTORY_PROPERTY(DIRINC INCLUDE_DIRECTORIES )
73 FOREACH(item ${DIRINC})
74 ocv_is_opencv_directory(__result ${item})
76 LIST(APPEND ${_out_compile_flags} "${_PCH_include_prefix}\"${item}\"")
77 elseif(CV_GCC AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "6.0" AND
78 item MATCHES "/usr/include$")
79 # workaround for GCC 6.x bug
81 LIST(APPEND ${_out_compile_flags} "${_PCH_isystem_prefix}\"${item}\"")
85 get_target_property(DIRINC ${_PCH_current_target} INCLUDE_DIRECTORIES )
86 FOREACH(item ${DIRINC})
87 ocv_is_opencv_directory(__result ${item})
89 LIST(APPEND ${_out_compile_flags} "${_PCH_include_prefix}\"${item}\"")
90 elseif(CV_GCC AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "6.0" AND
91 item MATCHES "/usr/include$")
92 # workaround for GCC 6.x bug
94 LIST(APPEND ${_out_compile_flags} "${_PCH_isystem_prefix}\"${item}\"")
98 LIST(APPEND ${_out_compile_flags} ${CMAKE_CXX_FLAGS})
100 SEPARATE_ARGUMENTS(${_out_compile_flags})
102 ENDMACRO(_PCH_GET_COMPILE_FLAGS)
105 MACRO(_PCH_WRITE_PCHDEP_CXX _targetName _include_file _dephelp)
107 set(${_dephelp} "${CMAKE_CURRENT_BINARY_DIR}/${_targetName}_pch_dephelp.cxx")
109 if(EXISTS "${${_dephelp}}")
110 file(READ "${${_dephelp}}" _content)
113 "#include \"${_include_file}\"
120 if(NOT _content STREQUAL _dummy_str)
121 file(WRITE "${${_dephelp}}" "${_dummy_str}")
124 ENDMACRO(_PCH_WRITE_PCHDEP_CXX )
126 MACRO(_PCH_GET_COMPILE_COMMAND out_command _input _output)
128 FILE(TO_NATIVE_PATH ${_input} _native_input)
129 FILE(TO_NATIVE_PATH ${_output} _native_output)
132 IF(CMAKE_CXX_COMPILER_ARG1)
133 # remove leading space in compiler argument
134 STRING(REGEX REPLACE "^ +" "" pchsupport_compiler_cxx_arg1 ${CMAKE_CXX_COMPILER_ARG1})
137 ${CMAKE_CXX_COMPILER} ${pchsupport_compiler_cxx_arg1} ${_compile_FLAGS} -x c++-header -o ${_output} ${_input}
139 ELSE(CMAKE_CXX_COMPILER_ARG1)
141 ${CMAKE_CXX_COMPILER} ${_compile_FLAGS} -x c++-header -o ${_output} ${_input}
143 ENDIF(CMAKE_CXX_COMPILER_ARG1)
146 SET(_dummy_str "#include <${_input}>")
147 FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/pch_dummy.cpp ${_dummy_str})
150 ${CMAKE_CXX_COMPILER} ${_compile_FLAGS} /c /Fp${_native_output} /Yc${_native_input} pch_dummy.cpp
156 ENDMACRO(_PCH_GET_COMPILE_COMMAND )
159 MACRO(_PCH_GET_TARGET_COMPILE_FLAGS _cflags _header_name _pch_path _dowarn )
161 FILE(TO_NATIVE_PATH ${_pch_path} _native_pch_path)
164 # for use with distcc and gcc >4.0.1 if preprocessed files are accessible
165 # on all remote machines set
166 # PCH_ADDITIONAL_COMPILER_FLAGS to -fpch-preprocess
167 # if you want warnings for invalid header files (which is very inconvenient
168 # if you have different versions of the headers for different build types
169 # you may set _pch_dowarn
171 SET(${_cflags} "${PCH_ADDITIONAL_COMPILER_FLAGS} -Winvalid-pch " )
173 SET(${_cflags} "${PCH_ADDITIONAL_COMPILER_FLAGS} " )
178 set(${_cflags} "/Fp${_native_pch_path} /Yu${_header_name}" )
182 ENDMACRO(_PCH_GET_TARGET_COMPILE_FLAGS )
185 MACRO(GET_PRECOMPILED_HEADER_OUTPUT _targetName _input _output)
187 GET_FILENAME_COMPONENT(_name ${_input} NAME)
188 GET_FILENAME_COMPONENT(_path ${_input} PATH)
189 SET(${_output} "${CMAKE_CURRENT_BINARY_DIR}/${_name}.gch/${_targetName}_${CMAKE_BUILD_TYPE}.gch")
191 ENDMACRO(GET_PRECOMPILED_HEADER_OUTPUT _targetName _input)
194 MACRO(ADD_PRECOMPILED_HEADER_TO_TARGET _targetName _input _pch_output_to_use )
196 # to do: test whether compiler flags match between target _targetName
197 # and _pch_output_to_use
198 GET_FILENAME_COMPONENT(_name ${_input} NAME)
200 IF(ARGN STREQUAL "0")
206 _PCH_GET_TARGET_COMPILE_FLAGS(_target_cflags ${_name} ${_pch_output_to_use} ${_dowarn})
207 #MESSAGE("Add flags ${_target_cflags} to ${_targetName} " )
209 set(_target_cflags "${_target_cflags} -include \"${CMAKE_CURRENT_BINARY_DIR}/${_name}\"")
212 GET_TARGET_PROPERTY(_sources ${_targetName} SOURCES)
213 FOREACH(src ${_sources})
214 if(NOT "${src}" MATCHES "\\.mm$" AND NOT "${src}" MATCHES "\\.rc$")
215 get_source_file_property(_flags "${src}" COMPILE_FLAGS)
216 get_source_file_property(_flags2 "${src}" COMPILE_DEFINITIONS)
217 if(NOT _flags AND NOT _flags2)
218 set_source_files_properties("${src}" PROPERTIES COMPILE_FLAGS "${_target_cflags}")
220 #ocv_debug_message("Skip PCH, flags: ${oldProps} defines: ${oldProps2}, file: ${src}")
225 ADD_CUSTOM_TARGET(pch_Generate_${_targetName}
226 DEPENDS ${_pch_output_to_use}
229 ADD_DEPENDENCIES(${_targetName} pch_Generate_${_targetName} )
231 ENDMACRO(ADD_PRECOMPILED_HEADER_TO_TARGET)
233 MACRO(ADD_PRECOMPILED_HEADER _targetName _input)
235 SET(_PCH_current_target ${_targetName})
237 IF(NOT CMAKE_BUILD_TYPE)
239 "This is the ADD_PRECOMPILED_HEADER macro. "
240 "You must set CMAKE_BUILD_TYPE!"
244 IF(ARGN STREQUAL "0")
250 GET_FILENAME_COMPONENT(_name ${_input} NAME)
251 GET_FILENAME_COMPONENT(_path ${_input} PATH)
252 GET_PRECOMPILED_HEADER_OUTPUT( ${_targetName} ${_input} _output)
254 _PCH_WRITE_PCHDEP_CXX(${_targetName} "${_input}" _pch_dephelp_cxx)
256 ADD_LIBRARY(${_targetName}_pch_dephelp STATIC "${_pch_dephelp_cxx}" "${_input}" )
258 set_target_properties(${_targetName}_pch_dephelp PROPERTIES
259 DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}"
260 ARCHIVE_OUTPUT_DIRECTORY "${LIBRARY_OUTPUT_PATH}"
263 _PCH_GET_COMPILE_FLAGS(_compile_FLAGS)
265 get_target_property(type ${_targetName} TYPE)
266 if(type STREQUAL "SHARED_LIBRARY")
267 get_target_property(__DEFINES ${_targetName} DEFINE_SYMBOL)
268 if(NOT __DEFINES MATCHES __DEFINES-NOTFOUND)
269 list(APPEND _compile_FLAGS "${_PCH_define_prefix}${__DEFINES}")
273 if(type STREQUAL "SHARED_LIBRARY" OR type STREQUAL "STATIC_LIBRARY")
274 get_target_property(__pic ${_targetName} POSITION_INDEPENDENT_CODE)
275 if(__pic AND CMAKE_CXX_COMPILE_OPTIONS_PIC
276 AND NOT OPENCV_SKIP_PCH_PIC_HANDLING
277 AND NOT OPENCV_SKIP_PCH_PIC_HANDLING_${_targetName}
279 list(APPEND _compile_FLAGS "${CMAKE_CXX_COMPILE_OPTIONS_PIC}")
281 elseif(type STREQUAL "EXECUTABLE")
282 get_target_property(__pie ${_targetName} POSITION_INDEPENDENT_CODE)
283 if(__pie AND CMAKE_CXX_COMPILE_OPTIONS_PIE
284 AND NOT OPENCV_SKIP_PCH_PIE_HANDLING
285 AND NOT OPENCV_SKIP_PCH_PIE_HANDLING_${_targetName}
287 list(APPEND _compile_FLAGS "${CMAKE_CXX_COMPILE_OPTIONS_PIE}")
291 get_target_property(DIRINC ${_targetName} INCLUDE_DIRECTORIES)
292 set_target_properties(${_targetName}_pch_dephelp PROPERTIES INCLUDE_DIRECTORIES "${DIRINC}")
294 #MESSAGE("_compile_FLAGS: ${_compile_FLAGS}")
295 #message("COMMAND ${CMAKE_CXX_COMPILER} ${_compile_FLAGS} -x c++-header -o ${_output} ${_input}")
298 OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${_name}"
299 COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_input}" "${CMAKE_CURRENT_BINARY_DIR}/${_name}" # ensure same directory! Required by gcc
303 #message("_command ${_input} ${_output}")
304 _PCH_GET_COMPILE_COMMAND(_command ${CMAKE_CURRENT_BINARY_DIR}/${_name} ${_output} )
306 GET_FILENAME_COMPONENT(_outdir ${_output} PATH)
309 COMMAND ${CMAKE_COMMAND} -E make_directory "${_outdir}"
312 DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${_name}"
313 DEPENDS ${_targetName}_pch_dephelp
316 ADD_PRECOMPILED_HEADER_TO_TARGET(${_targetName} ${_input} ${_output} ${_dowarn})
318 ENDMACRO(ADD_PRECOMPILED_HEADER)
321 # Generates the use of precompiled in a target,
322 # without using dependency targets (2 extra for each target)
323 # Using Visual, must also add ${_targetName}_pch to sources
324 # Not needed by Xcode
326 MACRO(GET_NATIVE_PRECOMPILED_HEADER _targetName _input)
328 if(ENABLE_PRECOMPILED_HEADERS)
329 if(CMAKE_GENERATOR MATCHES "^Visual.*$")
330 set(${_targetName}_pch ${CMAKE_CURRENT_BINARY_DIR}/${_targetName}_pch.cpp)
334 ENDMACRO(GET_NATIVE_PRECOMPILED_HEADER)
337 MACRO(ADD_NATIVE_PRECOMPILED_HEADER _targetName _input)
339 IF(ARGN STREQUAL "0")
345 if(CMAKE_GENERATOR MATCHES "^Visual.*$")
347 # Auto include the precompile (useful for moc processing, since the use of
348 # precompiled is specified at the target level
349 # and I don't want to specify /F- for each moc/res/ui generated files (using Qt)
351 get_target_property(_sources ${_targetName} SOURCES)
352 foreach(src ${_sources})
353 if("${src}" MATCHES "\\.c(pp|xx)?$")
354 get_source_file_property(oldProps "${src}" COMPILE_FLAGS)
355 get_source_file_property(oldProps2 "${src}" COMPILE_DEFINITIONS)
356 if(NOT oldProps AND NOT oldProps2)
357 set(newProperties "/Yu\"${_input}\" /FI\"${_input}\"")
358 set_source_files_properties("${src}" PROPERTIES COMPILE_FLAGS "${newProperties}")
360 ocv_debug_message("Skip PCH, flags: ${oldProps} defines: ${oldProps2}, file: ${src}")
365 #also inlude ${oldProps} to have the same compile options
366 GET_TARGET_PROPERTY(oldProps ${_targetName} COMPILE_FLAGS)
367 if (oldProps MATCHES NOTFOUND)
370 SET_SOURCE_FILES_PROPERTIES(${${_targetName}_pch} PROPERTIES COMPILE_FLAGS "${oldProps} /Yc\"${_input}\"")
372 set(_dummy_str "#include \"${_input}\"\n")
373 set(${_targetName}_pch ${CMAKE_CURRENT_BINARY_DIR}/${_targetName}_pch.cpp)
374 if(EXISTS ${${_targetName}_pch})
375 file(READ "${${_targetName}_pch}" _contents)
377 if(NOT _dummy_str STREQUAL "${_contents}")
378 file(WRITE ${${_targetName}_pch} ${_dummy_str})
381 elseif (CMAKE_GENERATOR MATCHES Xcode)
383 # For Xcode, cmake needs my patch to process
384 # GCC_PREFIX_HEADER and GCC_PRECOMPILE_PREFIX_HEADER as target properties
386 # When building out of the tree, precompiled may not be located
387 # Use full path instead.
388 GET_FILENAME_COMPONENT(fullPath ${_input} ABSOLUTE)
390 SET_TARGET_PROPERTIES(${_targetName} PROPERTIES XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${fullPath}")
391 SET_TARGET_PROPERTIES(${_targetName} PROPERTIES XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER "YES")
395 #Fallback to the "old" precompiled support
396 #ADD_PRECOMPILED_HEADER(${_targetName} ${_input} ${_dowarn})
400 ENDMACRO(ADD_NATIVE_PRECOMPILED_HEADER)
402 macro(ocv_add_precompiled_header_to_target the_target pch_header)
403 if(PCHSupport_FOUND AND ENABLE_PRECOMPILED_HEADERS AND EXISTS "${pch_header}")
404 if(CMAKE_GENERATOR MATCHES "^Visual" OR CMAKE_GENERATOR MATCHES Xcode)
405 add_native_precompiled_header(${the_target} ${pch_header})
406 elseif(CV_GCC AND CMAKE_GENERATOR MATCHES "Makefiles|Ninja")
407 add_precompiled_header(${the_target} ${pch_header})