function(get_gcc_flags target_name)
  # CMake does not provide an easy way to get all compiler switches,
  # so this function is a fishing expedition to get them.
  # http://public.kitware.com/Bug/view.php?id=1260
  if(CMAKE_CXX_COMPILER_ARG1)
      set(compile_args ${CMAKE_CXX_COMPILER_ARG1})
  else()
      set(compile_args "")
  endif()
  if(CMAKE_CXX_COMPILER_ARG2)
      list(APPEND compile_args ${CMAKE_CXX_COMPILER_ARG2})
  endif()
  list(APPEND compile_args ${CMAKE_CXX_FLAGS})
  string(TOUPPER "${CMAKE_BUILD_TYPE}" buildtype_name)
  if(CMAKE_CXX_FLAGS_${buildtype_name})
      list(APPEND compile_args ${CMAKE_CXX_FLAGS_${buildtype_name}})
  endif()
  get_directory_property(dir_inc INCLUDE_DIRECTORIES)
  foreach(item ${dir_inc})
    LIST(APPEND compile_args "-I" ${item})
  endforeach()
  get_directory_property(dir_defs COMPILE_DEFINITIONS)
  foreach(item ${dir_defs})
      list(APPEND compile_args -D${item})
  endforeach()
  get_directory_property(dir_buildtype_defs COMPILE_DEFINITIONS_${buildtype_name})
  foreach(item ${dir_buildtype_defs})
      list(APPEND compile_args -D${item})
  endforeach()
  get_directory_property(buildtype_defs COMPILE_DEFINITIONS_${buildtype_name})
  foreach(item ${buildtype_defs})
     list(APPEND compile_args -D${item})
  endforeach()
  get_target_property(target_type ${target_name} TYPE)
  if(${target_type} STREQUAL SHARED_LIBRARY)
    list(APPEND compile_args ${CMAKE_CXX_COMPILE_OPTIONS_PIC})
  endif()
  get_target_property(target_defs ${target_name} COMPILE_DEFINITIONS)
  if(target_defs)
    foreach(item ${target_defs})
      list(APPEND compile_args -D${item})
    endforeach()
  endif()
  get_target_property(target_buildtype_defs ${target_name} COMPILE_DEFINITIONS_${buildtype_name})
  if(target_buildtype_defs)
    foreach(item ${target_buildtype_defs})
      list(APPEND compile_args -D${item})
    endforeach()
  endif()
  get_target_property(target_flags ${target_name} COMPILE_FLAGS)
  if(target_flags)
      list(APPEND compile_args ${target_flags})
  endif()
  set(compile_args ${compile_args} PARENT_SCOPE)
  #message(STATUS ${compile_args})
endfunction()

function(add_pch_linux header_filename target_name pch_suffix)
  set(gch_target_name "${target_name}_pch")
  get_filename_component(header_basename ${header_filename} NAME)
  set(gch_filename "${CMAKE_CURRENT_BINARY_DIR}/${header_basename}.${pch_suffix}")
  get_gcc_flags(${target_name}) # Sets compile_args in this scope. It's even better than Intercal's COME FROM!
  #message(STATUS ${compile_args})
  list(APPEND compile_args -c ${CMAKE_CURRENT_SOURCE_DIR}/${header_filename} -o ${gch_filename})
  separate_arguments(compile_args)
  add_custom_command(OUTPUT ${gch_filename}
    COMMAND ${CMAKE_CXX_COMPILER} ${compile_args}
    DEPENDS ${header_filename})
  add_custom_target(${gch_target_name} DEPENDS ${gch_filename})
  add_dependencies(${target_name} ${gch_target_name})
  
  # Add the PCH to every source file's include list.
  # This is the only way that is supported by both GCC and Clang.
  set_property(TARGET ${target_name} APPEND_STRING PROPERTY COMPILE_FLAGS " -include ${header_basename} ")
  set_property(TARGET ${target_name} APPEND_STRING PROPERTY COMPILE_FLAGS " -fpch-preprocess ")
  set_property(TARGET ${target_name} APPEND_STRING PROPERTY COMPILE_FLAGS " -Winvalid-pch ")
  set_property(TARGET ${target_name} APPEND PROPERTY INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR})
  
endfunction()

try_run(IS_CLANG did_build ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/cmake/isclang.cc)

if(UNIX)
  if(NOT APPLE)
    option(use_pch "Use precompiled headers." TRUE)
  endif()
endif()

if(use_pch)
  message(STATUS "Using precompiled headers.")
  if(IS_CLANG)
    set(precompiled_header_extension pch)
  else()
    set(precompiled_header_extension gch)
  endif()
  macro(add_pch _header_filename _target_name)
      add_pch_linux(${_header_filename} ${_target_name} ${precompiled_header_extension})
  endmacro()
else()
  message(STATUS "Not using precompiled headers.")
  macro(add_pch _header_filename _target_name)
  endmacro()
endif()
