Skip to content

Instantly share code, notes, and snippets.

@leeor
Forked from larsch/PrecompiledHeader.cmake
Last active January 22, 2018 04:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save leeor/316168500765cf51ae97 to your computer and use it in GitHub Desktop.
Save leeor/316168500765cf51ae97 to your computer and use it in GitHub Desktop.
CMake module for GCC/Clang precompiled headers support
include(CMakeParseArguments)
macro(combine_arguments _variable)
set(_result "")
foreach(_element ${${_variable}})
set(_result "${_result} \"${_element}\"")
endforeach()
string(STRIP "${_result}" _result)
set(${_variable} "${_result}")
endmacro()
function(export_all_flags _filename)
set(_include_directories "$<TARGET_PROPERTY:${_target},INCLUDE_DIRECTORIES>")
set(_compile_definitions "$<TARGET_PROPERTY:${_target},COMPILE_DEFINITIONS>")
set(_compile_flags "$<TARGET_PROPERTY:${_target},COMPILE_FLAGS>")
set(_compile_options "$<TARGET_PROPERTY:${_target},COMPILE_OPTIONS>")
set(_include_directories "$<$<BOOL:${_include_directories}>:-I$<JOIN:${_include_directories},\n-I>\n>")
set(_compile_definitions "$<$<BOOL:${_compile_definitions}>:-D$<JOIN:${_compile_definitions},\n-D>\n>")
set(_compile_flags "$<$<BOOL:${_compile_flags}>:$<JOIN:${_compile_flags},\n>\n>")
set(_compile_options "$<$<BOOL:${_compile_options}>:$<JOIN:${_compile_options},\n>\n>")
set(_cmake_cxx_flags "$<$<BOOL:${CMAKE_CXX_FLAGS}>:$<JOIN:${CMAKE_CXX_FLAGS},\n>\n>")
file(GENERATE OUTPUT "${_filename}" CONTENT "${_compile_definitions}${_include_directories}${_compile_flags}${_compile_options}${_cmake_cxx_flags}\n")
endfunction()
function(add_precompiled_header _target _input)
cmake_parse_arguments(_PCH "FORCEINCLUDE" "SOURCE_CXX:SOURCE_C" "EXCLUDEFORCED" ${ARGN})
get_filename_component(_input_we ${_input} NAME_WE)
if(NOT _PCH_SOURCE_CXX)
set(_PCH_SOURCE_CXX "${_input_we}.cpp")
endif()
if(NOT _PCH_SOURCE_C)
set(_PCH_SOURCE_C "${_input_we}.c")
endif()
if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES ".*Clang"))
get_filename_component(_name ${_input} NAME)
set(_pch_header "${CMAKE_CURRENT_SOURCE_DIR}/${_input}")
set(_pch_binary_dir "${CMAKE_CURRENT_BINARY_DIR}/${_target}_pch")
set(_pchfile "${_pch_binary_dir}/${_input}")
set(_outdir "${CMAKE_CURRENT_BINARY_DIR}/${_target}_pch/${_name}.gch")
make_directory(${_pch_binary_dir})
make_directory(${_outdir})
set(_output_cxx "${_outdir}/.c++")
set(_output_c "${_outdir}/.c")
set(_pch_flags_file "${_pch_binary_dir}/compile_flags.rsp")
export_all_flags("${_pch_flags_file}")
set(_compiler_FLAGS "@${_pch_flags_file}")
add_custom_command(
OUTPUT "${_pchfile}"
COMMAND "${CMAKE_COMMAND}" -E copy "${_pch_header}" "${_pchfile}"
DEPENDS "${_pch_header}"
COMMENT "Updating ${_name}")
add_custom_command(
OUTPUT "${_output_cxx}"
COMMAND "${CMAKE_CXX_COMPILER}" ${_compiler_FLAGS} "-I${_pch_binary_dir}" -Winvalid-pch -x c++-header -o "${_output_cxx}" "${_pch_header}"
IMPLICIT_DEPENDS CXX "${_pch_header}"
COMMENT "Precompiling ${_name} for ${_target} (C++)")
add_custom_command(
OUTPUT "${_output_c}"
COMMAND "${CMAKE_C_COMPILER}" ${_compiler_FLAGS} "-I${_pch_binary_dir}" -Winvalid-pch -x c-header -o "${_output_c}" "${_pch_header}"
IMPLICIT_DEPENDS C "${_pch_header}"
COMMENT "Precompiling ${_name} for ${_target} (C)")
get_property(_sources TARGET ${_target} PROPERTY SOURCES)
foreach(_source ${_sources})
set(_pch_compile_flags "")
if(_source MATCHES \\.\(cc|cxx|cpp|c\)$)
get_source_file_property(_pch_compile_flags "${_source}" COMPILE_FLAGS)
if(NOT _pch_compile_flags)
set(_pch_compile_flags)
endif()
separate_arguments(_pch_compile_flags)
list(APPEND _pch_compile_flags -Winvalid-pch)
list(APPEND _pch_compile_flags "-I${_pch_binary_dir}")
# add the forced -include option, if requested, and source is
# not in the exclusion list
get_filename_component(_source_base ${_source} NAME)
list(FIND _PCH_EXCLUDEFORCED ${_source_base} _exclude_idx)
if(_PCH_FORCEINCLUDE AND (_exclude_idx EQUAL -1))
list(APPEND _pch_compile_flags -include "${_pchfile}")
endif(_PCH_FORCEINCLUDE AND (_exclude_idx EQUAL -1))
get_source_file_property(_object_depends "${_source}" OBJECT_DEPENDS)
if(NOT _object_depends)
set(_object_depends)
endif()
list(APPEND _object_depends "${_pchfile}")
if(_source MATCHES \\.\(cc|cxx|cpp\)$)
list(APPEND _object_depends "${_output_cxx}")
else()
list(APPEND _object_depends "${_output_c}")
endif()
combine_arguments(_pch_compile_flags)
set_source_files_properties(${_source} PROPERTIES
COMPILE_FLAGS "${_pch_compile_flags}"
OBJECT_DEPENDS "${_object_depends}")
endif()
endforeach()
endif((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES ".*Clang"))
endfunction()
@guilhemvors
Copy link

Hello and thank you for the clang compatibility, however, some CMAKE_CXX_FLAGS triggers an error in the export_all_flags function:

CMake Error at cmake/Modules/android/PrecompiledHeader.cmake:22 (file):
  Error evaluating generator expression:
    $<BOOL:-isystem /Users/XXXXX/Library/Android/sdk/ndk-bundle/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=24 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -fno-integrated-as -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -std=c++11 -frtti -fexceptions -std=c++14 -pthread -DUSE_FILE32API=1 -DCC_ENABLE_CHIPMUNK_INTEGRATION=0 -DCC_ENABLE_SCRIPT_BINDING=0 -DCC_USE_PHYSICS=0 -DCC_LUA_ENGINE_DEBUG=0 -DCC_USE_3D_PHYSICS=0 -DCC_ENABLE_BULLET_INTEGRATION=0 -DCC_USE_NAVMESH=0 -DCC_USE_TIFF=0 -DCC_USE_WEBP=0 -DRAPIDJSON_HAS_STDSTRING=1 -std=c++11 -Wno-deprecated-declarations -Wno-reorder -Wno-invalid-offsetof -fPIC -stdlib=libc++ -fsigned-char -latomic>
  $<BOOL> expression requires exactly one parameter.

Do you know how I could solve this error?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment