From b330b46ee366399c9339ed1f65924608c964d7f8 Mon Sep 17 00:00:00 2001 From: kervala Date: Sat, 8 Dec 2012 11:34:39 +0100 Subject: [PATCH] Fixed: PCH finally working under Linux and Mac OS X (never worked before) --- code/CMakeModules/PCHSupport.cmake | 582 ++++++++++++++++++----------- 1 file changed, 358 insertions(+), 224 deletions(-) diff --git a/code/CMakeModules/PCHSupport.cmake b/code/CMakeModules/PCHSupport.cmake index 0ef2243d6..d444bfa3d 100644 --- a/code/CMakeModules/PCHSupport.cmake +++ b/code/CMakeModules/PCHSupport.cmake @@ -9,250 +9,384 @@ # ADD_NATIVE_PRECOMPILED_HEADER _targetName _inputh _inputcpp IF(MSVC) - SET(PCHSupport_FOUND TRUE) - SET(_PCH_include_prefix "/I") + SET(PCHSupport_FOUND TRUE) + SET(_PCH_include_prefix "/I") ELSE(MSVC) - IF(CMAKE_COMPILER_IS_GNUCXX) - EXEC_PROGRAM(${CMAKE_CXX_COMPILER} - ARGS ${CMAKE_CXX_COMPILER_ARG1} -dumpversion - OUTPUT_VARIABLE gcc_compiler_version) - - IF(gcc_compiler_version MATCHES "4\\.[0-9]\\.[0-9]") - SET(PCHSupport_FOUND TRUE) - ELSE(gcc_compiler_version MATCHES "4\\.[0-9]\\.[0-9]") - IF(gcc_compiler_version MATCHES "3\\.4\\.[0-9]") - SET(PCHSupport_FOUND TRUE) - ENDIF(gcc_compiler_version MATCHES "3\\.4\\.[0-9]") - ENDIF(gcc_compiler_version MATCHES "4\\.[0-9]\\.[0-9]") - ELSE(CMAKE_COMPILER_IS_GNUCXX) - # TODO: make tests for other compilers than GCC - SET(PCHSupport_FOUND TRUE) - ENDIF(CMAKE_COMPILER_IS_GNUCXX) - - SET(_PCH_include_prefix "-I") + IF(CMAKE_COMPILER_IS_GNUCXX) + EXEC_PROGRAM(${CMAKE_CXX_COMPILER} + ARGS ${CMAKE_CXX_COMPILER_ARG1} -dumpversion + OUTPUT_VARIABLE gcc_compiler_version) + + IF(gcc_compiler_version MATCHES "^4\\.1(\\.[0-9]+)?") + SET(PCHSupport_FOUND FALSE) + ELSEIF(gcc_compiler_version MATCHES "^4\\.[0-9]+(\\.[0-9]+)?") + SET(PCHSupport_FOUND TRUE) + ENDIF(gcc_compiler_version MATCHES "^4\\.1(\\.[0-9]+)?") + ELSE(CMAKE_COMPILER_IS_GNUCXX) + # TODO: make tests for other compilers than GCC + SET(PCHSupport_FOUND TRUE) + ENDIF(CMAKE_COMPILER_IS_GNUCXX) + + SET(_PCH_include_prefix "-I") ENDIF(MSVC) -MACRO(_PCH_GET_COMPILE_FLAGS _out_compile_flags) - STRING(TOUPPER "CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}" _flags_var_name) - SET(_FLAGS ${${_flags_var_name}} ) - - IF(NOT MSVC) - GET_TARGET_PROPERTY(_targetType ${_PCH_current_target} TYPE) - IF(${_targetType} STREQUAL SHARED_LIBRARY OR ${_targetType} STREQUAL MODULE_LIBRARY) - LIST(APPEND _FLAGS "-fPIC") - ENDIF(${_targetType} STREQUAL SHARED_LIBRARY OR ${_targetType} STREQUAL MODULE_LIBRARY) - ENDIF(NOT MSVC) - - GET_DIRECTORY_PROPERTY(DIRINC INCLUDE_DIRECTORIES ) - FOREACH(item ${DIRINC}) - LIST(APPEND _FLAGS " ${_PCH_include_prefix}\"${item}\"") - ENDFOREACH(item) - - # Required for CMake 2.6 - SET(GLOBAL_DEFINITIONS "") - GET_DIRECTORY_PROPERTY(DEFINITIONS COMPILE_DEFINITIONS) - FOREACH(item ${DEFINITIONS}) - LIST(APPEND GLOBAL_DEFINITIONS -D${item}) - ENDFOREACH(item) - - GET_DIRECTORY_PROPERTY(_directory_flags DEFINITIONS) - GET_DIRECTORY_PROPERTY(_directory_definitions DIRECTORY ${CMAKE_SOURCE_DIR} DEFINITIONS) - LIST(APPEND _FLAGS ${GLOBAL_DEFINITIONS}) - LIST(APPEND _FLAGS ${_directory_flags}) - LIST(APPEND _FLAGS ${_directory_definitions}) - LIST(APPEND _FLAGS ${CMAKE_CXX_FLAGS}) - - # Format definitions - SEPARATE_ARGUMENTS(_FLAGS) - - IF(CLANG) - SET(_IGNORE_NEXT OFF) - FOREACH(item ${_FLAGS}) - IF(_IGNORE_NEXT) - SET(_IGNORE_NEXT OFF) - ELSE(_IGNORE_NEXT) - IF(item MATCHES "^-Xarch") - SET(_IGNORE_NEXT ON) - ELSEIF(item MATCHES "^-arch") - SET(_IGNORE_NEXT ON) - ELSE(item MATCHES "^-Xarch") - LIST(APPEND ${_out_compile_flags} ${item}) - ENDIF(item MATCHES "^-Xarch") - ENDIF(_IGNORE_NEXT) - ENDFOREACH(item) - ELSE(CLANG) - SET(${_out_compile_flags} ${_FLAGS}) - ENDIF(CLANG) -ENDMACRO(_PCH_GET_COMPILE_FLAGS) - -MACRO(_PCH_GET_PDB_FILENAME out_filename _target) - # determine output directory based on target type - GET_TARGET_PROPERTY(_targetType ${_target} TYPE) - IF(${_targetType} STREQUAL EXECUTABLE) - SET(_targetOutput ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) - ELSEIF(${_targetType} STREQUAL STATIC_LIBRARY) - SET(_targetOutput ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) - ELSE(${_targetType} STREQUAL EXECUTABLE) - SET(_targetOutput ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) - ENDIF(${_targetType} STREQUAL EXECUTABLE) - - # determine target postfix - STRING(TOUPPER "${CMAKE_BUILD_TYPE}_POSTFIX" _postfix_var_name) - GET_TARGET_PROPERTY(_targetPostfix ${_target} ${_postfix_var_name}) - IF(${_targetPostfix} MATCHES NOTFOUND) - SET(_targetPostfix "") - ENDIF(${_targetPostfix} MATCHES NOTFOUND) - - SET(${out_filename} "${_targetOutput}/${_target}${_targetPostfix}.pdb") -ENDMACRO(_PCH_GET_PDB_FILENAME) - -MACRO(_PCH_GET_COMPILE_COMMAND out_command _input _inputcpp _output) - IF(CMAKE_CXX_COMPILER_ARG1) - # remove leading space in compiler argument - STRING(REGEX REPLACE "^ +" "" pchsupport_compiler_cxx_arg1 ${CMAKE_CXX_COMPILER_ARG1}) - ELSE(CMAKE_CXX_COMPILER_ARG1) - SET(pchsupport_compiler_cxx_arg1 "") - ENDIF(CMAKE_CXX_COMPILER_ARG1) - - IF(MSVC) - _PCH_GET_PDB_FILENAME(PDB_FILE ${_PCH_current_target}) - SET(${out_command} ${CMAKE_CXX_COMPILER} ${pchsupport_compiler_cxx_arg1} ${_compile_FLAGS} /Yc /Fp\"${_output}\" ${_inputcpp} /c /Fd\"${PDB_FILE}\") - ELSE(MSVC) - SET(HEADER_FORMAT "c++-header") - IF(APPLE) - SET(HEADER_FORMAT "objective-${HEADER_FORMAT}") - ENDIF(APPLE) - SET(${out_command} ${CMAKE_CXX_COMPILER} ${pchsupport_compiler_cxx_arg1} ${_compile_FLAGS} -x ${HEADER_FORMAT} -o ${_output} -c ${_input}) - ENDIF(MSVC) -ENDMACRO(_PCH_GET_COMPILE_COMMAND) - -MACRO(GET_PRECOMPILED_HEADER_OUTPUT _targetName _input _output) - IF(MSVC) - GET_FILENAME_COMPONENT(_name ${_input} NAME_WE) - SET(_output "${CMAKE_CURRENT_BINARY_DIR}/${_name}.pch") - ELSE(MSVC) - GET_FILENAME_COMPONENT(_name ${_input} NAME) - SET(_output "${CMAKE_CURRENT_BINARY_DIR}/${_name}.gch") - ENDIF(MSVC) -ENDMACRO(GET_PRECOMPILED_HEADER_OUTPUT _targetName _input) - -MACRO(ADD_PRECOMPILED_HEADER_TO_TARGET _targetName _input _pch_output_to_use ) - GET_TARGET_PROPERTY(oldProps ${_targetName} COMPILE_FLAGS) - IF(${oldProps} MATCHES NOTFOUND) - SET(oldProps "") - ENDIF(${oldProps} MATCHES NOTFOUND) - - IF(MSVC) - SET(_target_cflags "${oldProps} /Yu\"${_input}\" /FI\"${_input}\" /Fp\"${_pch_output_to_use}\"") - ELSE(MSVC) - # to do: test whether compiler flags match between target _targetName - # and _pch_output_to_use - FILE(TO_NATIVE_PATH ${_pch_output_to_use} _native_pch_path) - - # for use with distcc and gcc >4.0.1 if preprocessed files are accessible - # on all remote machines set - # PCH_ADDITIONAL_COMPILER_FLAGS to -fpch-preprocess - SET(_target_cflags "${oldProps} ${PCH_ADDITIONAL_COMPILER_FLAGS}-include ${_input} -Winvalid-pch") - ENDIF(MSVC) - - SET_TARGET_PROPERTIES(${_targetName} PROPERTIES COMPILE_FLAGS ${_target_cflags}) - IF(oldProps) - SET_TARGET_PROPERTIES(${_targetName}_pch_dephelp PROPERTIES COMPILE_FLAGS ${oldProps}) - ENDIF(oldProps) - ADD_CUSTOM_TARGET(pch_Generate_${_targetName} DEPENDS ${_pch_output_to_use}) - ADD_DEPENDENCIES(${_targetName} pch_Generate_${_targetName}) +# Set PCH_FLAGS for common flags, PCH_ARCH_XXX_FLAGS for specific archs flags and PCH_ARCHS for archs +MACRO(PCH_SET_COMPILE_FLAGS _target) + SET(PCH_FLAGS) + SET(PCH_ARCHS) + + SET(FLAGS) + LIST(APPEND _FLAGS ${CMAKE_CXX_FLAGS}) + + STRING(TOUPPER "${CMAKE_BUILD_TYPE}" _UPPER_BUILD) + LIST(APPEND _FLAGS " ${CMAKE_CXX_FLAGS_${_UPPER_BUILD}}") + + IF(NOT MSVC) + GET_TARGET_PROPERTY(_targetType ${_target} TYPE) + IF(${_targetType} STREQUAL SHARED_LIBRARY OR ${_targetType} STREQUAL MODULE_LIBRARY) + LIST(APPEND _FLAGS " -fPIC") + ENDIF(${_targetType} STREQUAL SHARED_LIBRARY OR ${_targetType} STREQUAL MODULE_LIBRARY) + ENDIF(NOT MSVC) + + GET_DIRECTORY_PROPERTY(DIRINC INCLUDE_DIRECTORIES) + FOREACH(item ${DIRINC}) + LIST(APPEND _FLAGS " ${_PCH_include_prefix}\"${item}\"") + ENDFOREACH(item) + + # Required for CMake 2.6 + SET(GLOBAL_DEFINITIONS) + GET_DIRECTORY_PROPERTY(DEFINITIONS COMPILE_DEFINITIONS) + FOREACH(item ${DEFINITIONS}) + LIST(APPEND GLOBAL_DEFINITIONS " -D${item}") + ENDFOREACH(item) + + GET_DIRECTORY_PROPERTY(DEFINITIONS COMPILE_DEFINITIONS_${_UPPER_BUILD}) + FOREACH(item ${DEFINITIONS}) + LIST(APPEND GLOBAL_DEFINITIONS " -D${item}") + ENDFOREACH(item) + + GET_TARGET_PROPERTY(oldProps ${_target} COMPILE_FLAGS) + IF(oldProps) + LIST(APPEND _FLAGS " ${oldProps}") + ENDIF(oldProps) + + GET_TARGET_PROPERTY(oldPropsBuild ${_target} COMPILE_FLAGS_${_UPPER_BUILD}) + IF(oldPropsBuild) + LIST(APPEND _FLAGS " ${oldPropsBuild}") + ENDIF(oldPropsBuild) + + GET_DIRECTORY_PROPERTY(_directory_flags DEFINITIONS) + GET_DIRECTORY_PROPERTY(_directory_definitions DIRECTORY ${CMAKE_SOURCE_DIR} DEFINITIONS) + LIST(APPEND _FLAGS " ${GLOBAL_DEFINITIONS}") + LIST(APPEND _FLAGS " ${_directory_flags}") + LIST(APPEND _FLAGS " ${_directory_definitions}") + + STRING(REGEX REPLACE " +" " " _FLAGS ${_FLAGS}) + + # Format definitions + SEPARATE_ARGUMENTS(_FLAGS) + + IF(CLANG) + # Determining all architectures and get common flags + SET(_ARCH_NEXT) + SET(_XARCH_NEXT) + FOREACH(item ${_FLAGS}) + IF(_ARCH_NEXT) + LIST(FIND PCH_ARCHS ${item} ITEM_FOUND) + IF(ITEM_FOUND EQUAL -1) + LIST(APPEND PCH_ARCHS ${item}) + STRING(TOUPPER "${item}" _UPPER_ARCH) + SET(PCH_ARCH_${_UPPER_ARCH}_FLAGS "-arch" ${item}) + ENDIF(ITEM_FOUND EQUAL -1) + SET(_ARCH_NEXT OFF) + ELSEIF(_XARCH_NEXT) + SET(_XARCH_NEXT OFF) + ELSE(_ARCH_NEXT) + IF(item MATCHES "^-arch") + SET(_ARCH_NEXT ON) + ELSEIF(item MATCHES "^-Xarch_") + STRING(REGEX REPLACE "-Xarch_([a-z0-9_]+)" "\\1" item ${item}) + LIST(FIND PCH_ARCHS ${item} ITEM_FOUND) + IF(ITEM_FOUND EQUAL -1) + LIST(APPEND PCH_ARCHS ${item}) + STRING(TOUPPER "${item}" _UPPER_ARCH) + SET(PCH_ARCH_${_UPPER_ARCH}_FLAGS "-arch" ${item}) + ENDIF(ITEM_FOUND EQUAL -1) + SET(_XARCH_NEXT ON) + ELSE(item MATCHES "^-arch") + LIST(APPEND PCH_FLAGS ${item}) + ENDIF(item MATCHES "^-arch") + ENDIF(_ARCH_NEXT) + ENDFOREACH(item) + + # Get architcture specific flags + SET(_XARCH_NEXT) + FOREACH(item ${_FLAGS}) + IF(_XARCH_NEXT) + STRING(TOUPPER "${_XARCH_NEXT}" _UPPER_XARCH) + LIST(APPEND PCH_ARCH_${_UPPER_XARCH}_FLAGS ${item}) + SET(_XARCH_NEXT OFF) + ELSE(_XARCH_NEXT) + IF(item MATCHES "^-Xarch_") + STRING(SUBSTRING "${item}" 7 -1 _XARCH_NEXT) + ENDIF(item MATCHES "^-Xarch_") + ENDIF(_XARCH_NEXT) + ENDFOREACH(item) + + # Remove duplicated architectures + IF(_ARCHS AND PCH_ARCHS) + LIST(REMOVE_DUPLICATES PCH_ARCHS) + ENDIF(_ARCHS AND PCH_ARCHS) + ELSE(CLANG) + SET(PCH_FLAGS ${_FLAGS}) + ENDIF(CLANG) + + IF(PCH_FLAGS) + LIST(REMOVE_DUPLICATES PCH_FLAGS) + ENDIF(PCH_FLAGS) +ENDMACRO(PCH_SET_COMPILE_FLAGS) + +MACRO(GET_PDB_FILENAME _out_filename _target) + # determine output directory based on target type + GET_TARGET_PROPERTY(_targetType ${_target} TYPE) + IF(${_targetType} STREQUAL EXECUTABLE) + SET(_targetOutput ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + ELSEIF(${_targetType} STREQUAL STATIC_LIBRARY) + SET(_targetOutput ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) + ELSE(${_targetType} STREQUAL EXECUTABLE) + SET(_targetOutput ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) + ENDIF(${_targetType} STREQUAL EXECUTABLE) + + # determine target postfix + STRING(TOUPPER "${CMAKE_BUILD_TYPE}_POSTFIX" _postfix_var_name) + GET_TARGET_PROPERTY(_targetPostfix ${_target} ${_postfix_var_name}) + IF(${_targetPostfix} MATCHES NOTFOUND) + SET(_targetPostfix "") + ENDIF(${_targetPostfix} MATCHES NOTFOUND) + + SET(${_out_filename} "${_targetOutput}/${_target}${_targetPostfix}.pdb") +ENDMACRO(GET_PDB_FILENAME) + +MACRO(PCH_SET_COMPILE_COMMAND _inputcpp _compile_FLAGS) + IF(CMAKE_CXX_COMPILER_ARG1) + # remove leading space in compiler argument + STRING(REGEX REPLACE "^ +" "" pchsupport_compiler_cxx_arg1 ${CMAKE_CXX_COMPILER_ARG1}) + ELSE(CMAKE_CXX_COMPILER_ARG1) + SET(pchsupport_compiler_cxx_arg1 "") + ENDIF(CMAKE_CXX_COMPILER_ARG1) + + IF(MSVC) + GET_PDB_FILENAME(PDB_FILE ${_PCH_current_target}) + SET(PCH_COMMAND ${CMAKE_CXX_COMPILER} ${pchsupport_compiler_cxx_arg1} ${_compile_FLAGS} /Yc /Fp"${PCH_OUTPUT}" ${_inputcpp} /Fd"${PDB_FILE}" /c /Fo"${PCH_OUTPUT}.obj") + ELSE(MSVC) + SET(HEADER_FORMAT "c++-header") + SET(_FLAGS "") + IF(APPLE) + SET(HEADER_FORMAT "objective-${HEADER_FORMAT}") + SET(_FLAGS -fobjc-abi-version=2 -fobjc-legacy-dispatch) + ENDIF(APPLE) + SET(PCH_COMMAND ${CMAKE_CXX_COMPILER} ${pchsupport_compiler_cxx_arg1} ${_compile_FLAGS} ${_FLAGS} -x ${HEADER_FORMAT} -o ${PCH_OUTPUT} -c ${PCH_INPUT}) + ENDIF(MSVC) +ENDMACRO(PCH_SET_COMPILE_COMMAND) + +MACRO(PCH_SET_PRECOMPILED_HEADER_OUTPUT _targetName _input _arch _language) + SET(_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/${_targetName}_pch") + + IF(MSVC) + FILE(MAKE_DIRECTORY ${_OUTPUT_DIR}) + GET_FILENAME_COMPONENT(_name ${_input} NAME_WE) + SET(PCH_INPUT ${_input}) + SET(PCH_OUTPUT "${_OUTPUT_DIR}/${_name}.pch") + ELSE(MSVC) + IF(NOT "${_arch}" STREQUAL "") + SET(_OUTPUT_DIR "${_OUTPUT_DIR}_${_arch}") + ENDIF(NOT "${_arch}" STREQUAL "") + + IF(NOT "${_language}" STREQUAL "") + SET(_OUTPUT_DIR "${_OUTPUT_DIR}_${_language}") + ENDIF(NOT "${_language}" STREQUAL "") + + GET_FILENAME_COMPONENT(_name ${_input} NAME) + + # Copy .h to output dir + SET(PCH_INPUT "${_OUTPUT_DIR}/${_name}") + ADD_CUSTOM_COMMAND(OUTPUT ${PCH_INPUT} + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${_input} ${PCH_INPUT} + DEPENDS ${_input} + COMMENT "[${_targetName}] Update precompiled header - done" + ) + + IF(CLANG) + SET(PCH_EXT "pth") + ELSE(CLANG) + SET(PCH_EXT "gch") + ENDIF(CLANG) + + # For GCC and Clang, PCH needs to be in the same directory as .h + SET(PCH_OUTPUT "${_OUTPUT_DIR}/${_name}.${PCH_EXT}") + ENDIF(MSVC) +ENDMACRO(PCH_SET_PRECOMPILED_HEADER_OUTPUT) + +# Add common flags +MACRO(ADD_PRECOMPILED_HEADER_TO_TARGET _targetName) + GET_TARGET_PROPERTY(oldProps ${_targetName} COMPILE_FLAGS) + + IF(${oldProps} MATCHES NOTFOUND) + SET(oldProps "") + ENDIF(${oldProps} MATCHES NOTFOUND) + + IF(MSVC) + SET(_target_cflags "${oldProps} /Yu\"${PCH_INPUT}\" /FI\"${PCH_INPUT}\" /Fp\"${PCH_OUTPUT}\"") + ELSE(MSVC) + # for use with distcc and gcc >4.0.1 if preprocessed files are accessible + # on all remote machines set + # PCH_ADDITIONAL_COMPILER_FLAGS to -fpch-preprocess + SET(PCH_ADDITIONAL_COMPILER_FLAGS) + LIST(LENGTH PCH_ARCHS PCH_ARCHS_COUNT) + + # If no arch is specified, create common flags + IF(PCH_ARCHS_COUNT LESS 2) + SET(PCH_ADDITIONAL_COMPILER_FLAGS "-include ${PCH_INPUT} ${PCH_ADDITIONAL_COMPILER_FLAGS}") + ENDIF(PCH_ARCHS_COUNT LESS 2) + + IF(APPLE) + SET(PCH_ADDITIONAL_COMPILER_FLAGS "-fobjc-abi-version=2 -fobjc-legacy-dispatch -x objective-c++ ${PCH_ADDITIONAL_COMPILER_FLAGS}") + ENDIF(APPLE) + + IF(WITH_PCH_DEBUG) + SET(PCH_ADDITIONAL_COMPILER_FLAGS "-H ${PCH_ADDITIONAL_COMPILER_FLAGS}") + ENDIF(WITH_PCH_DEBUG) + + SET(_target_cflags "${oldProps} ${PCH_ADDITIONAL_COMPILER_FLAGS} -Winvalid-pch") + ENDIF(MSVC) + + SET_TARGET_PROPERTIES(${_targetName} PROPERTIES COMPILE_FLAGS ${_target_cflags}) ENDMACRO(ADD_PRECOMPILED_HEADER_TO_TARGET) -MACRO(ADD_PRECOMPILED_HEADER _targetName _inputh _inputcpp) +# Add specific flags for an arch +MACRO(ADD_PRECOMPILED_HEADER_TO_TARGET_ARCH _targetName _arch) + LIST(LENGTH PCH_ARCHS PCH_ARCHS_COUNT) + + IF(PCH_ARCHS_COUNT GREATER 1) + GET_TARGET_PROPERTY(_FLAGS ${_targetName} COMPILE_FLAGS) + + IF(${_FLAGS} MATCHES NOTFOUND) + SET(_FLAGS "") + ENDIF(${_FLAGS} MATCHES NOTFOUND) + + SET(_FLAGS "${_FLAGS} -Xarch_${_arch} -include${PCH_INPUT}") - SET(_PCH_current_target ${_targetName}) + SET_TARGET_PROPERTIES(${_targetName} PROPERTIES COMPILE_FLAGS ${_FLAGS}) + ENDIF(PCH_ARCHS_COUNT GREATER 1) +ENDMACRO(ADD_PRECOMPILED_HEADER_TO_TARGET_ARCH) - IF(NOT CMAKE_BUILD_TYPE) - MESSAGE(FATAL_ERROR - "This is the ADD_PRECOMPILED_HEADER macro. " - "You must set CMAKE_BUILD_TYPE!" - ) - ENDIF(NOT CMAKE_BUILD_TYPE) +MACRO(PCH_CREATE_TARGET _targetName _targetNamePCH) + ADD_CUSTOM_COMMAND(OUTPUT ${PCH_OUTPUT} COMMAND ${PCH_COMMAND} COMMENT "Generating ${_targetNamePCH}" DEPENDS ${PCH_INPUT}) + ADD_CUSTOM_TARGET(${_targetNamePCH} DEPENDS ${PCH_INPUT} ${PCH_OUTPUT}) + ADD_DEPENDENCIES(${_targetName} ${_targetNamePCH}) +ENDMACRO(PCH_CREATE_TARGET _targetName _inputh _inputcpp) - GET_PRECOMPILED_HEADER_OUTPUT( ${_targetName} ${_inputh} _output) +MACRO(ADD_PRECOMPILED_HEADER _targetName _inputh _inputcpp) + SET(_PCH_current_target ${_targetName}) + + IF(NOT CMAKE_BUILD_TYPE) + MESSAGE(FATAL_ERROR + "This is the ADD_PRECOMPILED_HEADER macro. " + "You must set CMAKE_BUILD_TYPE!" + ) + ENDIF(NOT CMAKE_BUILD_TYPE) - GET_TARGET_PROPERTY(_targetType ${_PCH_current_target} TYPE) + PCH_SET_COMPILE_FLAGS(${_targetName}) - # always build static library because it doesn't need linking - ADD_LIBRARY(${_targetName}_pch_dephelp STATIC ${_inputcpp}) + IF(PCH_ARCHS) + SET(PCH_OUTPUTS) + FOREACH(_ARCH ${PCH_ARCHS}) + STRING(TOUPPER "${_ARCH}" _UPPER_ARCH) - _PCH_GET_COMPILE_FLAGS(_compile_FLAGS) + PCH_SET_PRECOMPILED_HEADER_OUTPUT(${_targetName} ${_inputh} ${_ARCH} "") + LIST(APPEND PCH_OUTPUTS ${PCH_OUTPUT}) - SET_SOURCE_FILES_PROPERTIES(${_inputh} PROPERTIES GENERATED 1) + PCH_SET_COMPILE_COMMAND(${_inputcpp} "${PCH_ARCH_${_UPPER_ARCH}_FLAGS};${PCH_FLAGS}") + PCH_CREATE_TARGET(${_targetName} ${_targetName}_pch_${_ARCH}) - _PCH_GET_COMPILE_COMMAND(_command ${_inputh} ${_inputcpp} ${_output}) + ADD_PRECOMPILED_HEADER_TO_TARGET_ARCH(${_targetName} ${_ARCH}) + ENDFOREACH(_ARCH) + ELSE(PCH_ARCHS) + PCH_SET_PRECOMPILED_HEADER_OUTPUT(${_targetName} ${_inputh} "" "") + LIST(APPEND PCH_OUTPUTS ${PCH_OUTPUT}) - ADD_CUSTOM_COMMAND( - OUTPUT ${_output} - COMMAND ${_command} - DEPENDS ${_inputh} ${_targetName}_pch_dephelp - ) + PCH_SET_COMPILE_COMMAND(${_inputcpp} "${PCH_FLAGS}") + PCH_CREATE_TARGET(${_targetName} ${_targetName}_pch) + ENDIF(PCH_ARCHS) - ADD_PRECOMPILED_HEADER_TO_TARGET(${_targetName} ${_inputh} ${_output}) + ADD_PRECOMPILED_HEADER_TO_TARGET(${_targetName}) + + SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${PCH_OUTPUTS}") ENDMACRO(ADD_PRECOMPILED_HEADER) # Macro to move PCH creation file to the front of files list +# or remove .cpp from library/executable to avoid warning MACRO(FIX_PRECOMPILED_HEADER _files _pch) - # Remove .cpp creating PCH from the list - LIST(REMOVE_ITEM ${_files} ${_pch}) - # Prepend .cpp creating PCH to the list - LIST(INSERT ${_files} 0 ${_pch}) + # Remove .cpp creating PCH from the list + LIST(REMOVE_ITEM ${_files} ${_pch}) + IF(MSVC) + # Prepend .cpp creating PCH to the list + LIST(INSERT ${_files} 0 ${_pch}) + ENDIF(MSVC) ENDMACRO(FIX_PRECOMPILED_HEADER) MACRO(ADD_NATIVE_PRECOMPILED_HEADER _targetName _inputh _inputcpp) - SET(PCH_METHOD 0) - - # 0 => creating a new target for PCH, works for all makefiles - # 1 => setting PCH for VC++ project, works for VC++ projects - # 2 => setting PCH for XCode project, works for XCode projects - IF(CMAKE_GENERATOR MATCHES "Visual Studio") - SET(PCH_METHOD 1) - ELSEIF(CMAKE_GENERATOR MATCHES "NMake Makefiles" AND MFC_FOUND AND CMAKE_MFC_FLAG) - # To fix a bug with MFC - # Don't forget to use FIX_PRECOMPILED_HEADER before creating the target -# SET(PCH_METHOD 1) - ELSEIF(CMAKE_GENERATOR MATCHES "Xcode") - SET(PCH_METHOD 2) - ENDIF(CMAKE_GENERATOR MATCHES "Visual Studio") - - IF(PCH_METHOD EQUAL 1) - # Auto include the precompile (useful for moc processing, since the use of - # precompiled is specified at the target level - # and I don't want to specifiy /F- for each moc/res/ui generated files (using Qt) - - GET_TARGET_PROPERTY(oldProps ${_targetName} COMPILE_FLAGS) - IF(${oldProps} MATCHES NOTFOUND) - SET(oldProps "") - ENDIF(${oldProps} MATCHES NOTFOUND) - - SET(newProperties "${oldProps} /Yu\"${_inputh}\" /FI\"${_inputh}\"") - SET_TARGET_PROPERTIES(${_targetName} PROPERTIES COMPILE_FLAGS "${newProperties}") - - #also inlude ${oldProps} to have the same compile options - SET_SOURCE_FILES_PROPERTIES(${_inputcpp} PROPERTIES COMPILE_FLAGS "${oldProps} /Yc\"${_inputh}\"") - ELSEIF(PCH_METHOD EQUAL 2) - # For Xcode, cmake needs my patch to process - # GCC_PREFIX_HEADER and GCC_PRECOMPILE_PREFIX_HEADER as target properties - - GET_TARGET_PROPERTY(oldProps ${_targetName} COMPILE_FLAGS) - IF(${oldProps} MATCHES NOTFOUND) - SET(oldProps "") - ENDIF(${oldProps} MATCHES NOTFOUND) - - # When buiding out of the tree, precompiled may not be located - # Use full path instead. - GET_FILENAME_COMPONENT(fullPath ${_inputh} ABSOLUTE) - - SET_TARGET_PROPERTIES(${_targetName} PROPERTIES XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${fullPath}") - SET_TARGET_PROPERTIES(${_targetName} PROPERTIES XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER "YES") - ELSE(PCH_METHOD EQUAL 1) - #Fallback to the "old" precompiled suppport - ADD_PRECOMPILED_HEADER(${_targetName} ${_inputh} ${_inputcpp}) - ENDIF(PCH_METHOD EQUAL 1) - + IF(NOT PCHSupport_FOUND) + MESSAGE(STATUS "PCH disabled because compiler doesn't support them") + RETURN() + ENDIF(NOT PCHSupport_FOUND) + + # 0 => creating a new target for PCH, works for all makefiles + # 1 => setting PCH for VC++ project, works for VC++ projects + # 2 => setting PCH for XCode project, works for XCode projects + IF(CMAKE_GENERATOR MATCHES "Visual Studio") + SET(PCH_METHOD 1) + ELSEIF(CMAKE_GENERATOR MATCHES "NMake Makefiles" AND MFC_FOUND AND CMAKE_MFC_FLAG) + # To fix a bug with MFC + # Don't forget to use FIX_PRECOMPILED_HEADER before creating the target +# SET(PCH_METHOD 1) + ELSEIF(CMAKE_GENERATOR MATCHES "Xcode") + SET(PCH_METHOD 2) + ELSE(CMAKE_GENERATOR MATCHES "Visual Studio") + SET(PCH_METHOD 0) + ENDIF(CMAKE_GENERATOR MATCHES "Visual Studio") + + IF(PCH_METHOD EQUAL 1) + # Auto include the precompile (useful for moc processing, since the use of + # precompiled is specified at the target level + # and I don't want to specifiy /F- for each moc/res/ui generated files (using Qt) + + GET_TARGET_PROPERTY(oldProps ${_targetName} COMPILE_FLAGS) + IF(${oldProps} MATCHES NOTFOUND) + SET(oldProps "") + ENDIF(${oldProps} MATCHES NOTFOUND) + + SET(newProperties "${oldProps} /Yu\"${_inputh}\" /FI\"${_inputh}\"") + SET_TARGET_PROPERTIES(${_targetName} PROPERTIES COMPILE_FLAGS "${newProperties}") + + #also inlude ${oldProps} to have the same compile options + SET_SOURCE_FILES_PROPERTIES(${_inputcpp} PROPERTIES COMPILE_FLAGS "${oldProps} /Yc\"${_inputh}\"") + ELSEIF(PCH_METHOD EQUAL 2) + # For Xcode, cmake needs my patch to process + # GCC_PREFIX_HEADER and GCC_PRECOMPILE_PREFIX_HEADER as target properties + + # When buiding out of the tree, precompiled may not be located + # Use full path instead. + GET_FILENAME_COMPONENT(fullPath ${_inputh} ABSOLUTE) + + SET_TARGET_PROPERTIES(${_targetName} PROPERTIES XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${fullPath}") + SET_TARGET_PROPERTIES(${_targetName} PROPERTIES XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER "YES") + ELSE(PCH_METHOD EQUAL 1) + #Fallback to the "old" precompiled suppport + ADD_PRECOMPILED_HEADER(${_targetName} ${_inputh} ${_inputcpp}) + ENDIF(PCH_METHOD EQUAL 1) + + IF(TARGET ${_targetName}_static) + ADD_NATIVE_PRECOMPILED_HEADER(${_targetName}_static ${_inputh} ${_inputcpp}) + ENDIF(TARGET ${_targetName}_static) ENDMACRO(ADD_NATIVE_PRECOMPILED_HEADER)