Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for the C(XX)_STANDARD and C(XX)_EXTENSIONS properties. #17

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions .travis.yml
@@ -0,0 +1,4 @@
sudo: true

script:
- bash runall.sh
190 changes: 123 additions & 67 deletions PrecompiledHeader.cmake
Expand Up @@ -63,7 +63,14 @@ macro(combine_arguments _variable)
set(${_variable} "${_result}")
endmacro()

function(export_all_flags _filename)
function(export_all_flags _filename mode)
get_target_property(_target_type ${_target} TYPE)
if(_target_type STREQUAL "EXECUTABLE")
set(_pic "$<$<BOOL:$<TARGET_PROPERTY:${_target},POSITION_INDEPENDENT_CODE>>:-fPIE\n>")
else()
set(_pic "$<$<BOOL:$<TARGET_PROPERTY:${_target},POSITION_INDEPENDENT_CODE>>:-fPIC\n>")
endif()

set(_include_directories "$<TARGET_PROPERTY:${_target},INCLUDE_DIRECTORIES>")
set(_compile_definitions "$<TARGET_PROPERTY:${_target},COMPILE_DEFINITIONS>")
set(_compile_flags "$<TARGET_PROPERTY:${_target},COMPILE_FLAGS>")
Expand All @@ -72,11 +79,120 @@ function(export_all_flags _filename)
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>")
file(GENERATE OUTPUT "${_filename}" CONTENT "${_compile_definitions}${_include_directories}${_compile_flags}${_compile_options}\n")

set(_standard_check "")
if("${mode}" STREQUAL "CXX")
set(_cxx_standard "$<TARGET_PROPERTY:${_target},CXX_STANDARD>")
set(_cxx_extensions "$<TARGET_PROPERTY:${_target},CXX_EXTENSIONS>")
set(_has_extensions "$<OR:$<STREQUAL:${_cxx_extensions},>,$<BOOL:${_cxx_extensions}>>") # CXX_EXTENSIONS defaults to true
set(_standard_check "${_standard_check}$<$<AND:$<STREQUAL:${_cxx_standard},17>,$<NOT:${_has_extensions}>>:${CMAKE_CXX17_STANDARD_COMPILE_OPTION}>")
set(_standard_check "${_standard_check}$<$<AND:$<STREQUAL:${_cxx_standard},14>,$<NOT:${_has_extensions}>>:${CMAKE_CXX14_STANDARD_COMPILE_OPTION}>")
set(_standard_check "${_standard_check}$<$<AND:$<STREQUAL:${_cxx_standard},11>,$<NOT:${_has_extensions}>>:${CMAKE_CXX11_STANDARD_COMPILE_OPTION}>")
set(_standard_check "${_standard_check}$<$<AND:$<STREQUAL:${_cxx_standard},98>,$<NOT:${_has_extensions}>>:${CMAKE_CXX98_STANDARD_COMPILE_OPTION}>")
set(_standard_check "${_standard_check}$<$<AND:$<STREQUAL:${_cxx_standard},17>,${_has_extensions}>:${CMAKE_CXX17_EXTENSION_COMPILE_OPTION}>")
set(_standard_check "${_standard_check}$<$<AND:$<STREQUAL:${_cxx_standard},14>,${_has_extensions}>:${CMAKE_CXX14_EXTENSION_COMPILE_OPTION}>")
set(_standard_check "${_standard_check}$<$<AND:$<STREQUAL:${_cxx_standard},11>,${_has_extensions}>:${CMAKE_CXX11_EXTENSION_COMPILE_OPTION}>")
set(_standard_check "${_standard_check}$<$<AND:$<STREQUAL:${_cxx_standard},98>,${_has_extensions}>:${CMAKE_CXX98_EXTENSION_COMPILE_OPTION}>")
endif()
if("${mode}" STREQUAL "C")
set(_c_standard "$<TARGET_PROPERTY:${_target},C_STANDARD>")
set(_c_extensions "$<TARGET_PROPERTY:${_target},C_EXTENSIONS>")
set(_has_extensions "$<OR:$<STREQUAL:${_c_extensions},>,$<BOOL:${_c_extensions}>>") # C_EXTENSIONS defaults to true
set(_standard_check "${_standard_check}$<$<AND:$<STREQUAL:${_c_standard},11>,$<NOT:${_has_extensions}>>:${CMAKE_C11_STANDARD_COMPILE_OPTION}>")
set(_standard_check "${_standard_check}$<$<AND:$<STREQUAL:${_c_standard},99>,$<NOT:${_has_extensions}>>:${CMAKE_C99_STANDARD_COMPILE_OPTION}>")
set(_standard_check "${_standard_check}$<$<AND:$<STREQUAL:${_c_standard},90>,$<NOT:${_has_extensions}>>:${CMAKE_C90_STANDARD_COMPILE_OPTION}>")
set(_standard_check "${_standard_check}$<$<AND:$<STREQUAL:${_c_standard},11>,${_has_extensions}>:${CMAKE_C11_EXTENSION_COMPILE_OPTION}>")
set(_standard_check "${_standard_check}$<$<AND:$<STREQUAL:${_c_standard},99>,${_has_extensions}>:${CMAKE_C99_EXTENSION_COMPILE_OPTION}>")
set(_standard_check "${_standard_check}$<$<AND:$<STREQUAL:${_c_standard},90>,${_has_extensions}>:${CMAKE_C90_EXTENSION_COMPILE_OPTION}>")
endif()
set(_standard_check "${_standard_check}\n")

file(GENERATE OUTPUT "${_filename}" CONTENT "${_compile_definitions}${_include_directories}${_compile_flags}${_compile_options}${_standard_check}${_pic}\n")
endfunction()

function (gcc_pch_targets_for_mode _input _pch_path mode)
get_filename_component(_name ${_input} NAME)
set(_pch_header "${CMAKE_CURRENT_SOURCE_DIR}/${_input}")
set(_pch_binary_dir "${CMAKE_CURRENT_BINARY_DIR}/${_target}_${mode}_pch")
set(_pchfile "${_pch_binary_dir}/${_input}")

string(REGEX MATCH "\.\.[/\\]" _has_parent_access "${_input}")
if( "${_pch_path}" STREQUAL "" AND _has_parent_access)
message(FATAL_ERROR "Precompiled header name contains ../, please specify an outputh path with the PCH_PATH option")
endif()

if( NOT "${_pch_path}" STREQUAL "" )
set(_pchfile "${_pch_binary_dir}/${_pch_path}")
endif()
set(_output "${_pch_binary_dir}/${_input}.gch")
if( NOT "${_pch_path}" STREQUAL "" )
set(_output "${_pch_binary_dir}/${_pch_path}.gch")
endif()

set(_pch_flags_file "${_pch_binary_dir}/compile_flags.rsp")
export_all_flags("${_pch_flags_file}" ${mode})
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} (${mode})")
if("${mode}" STREQUAL "CXX")
add_custom_command(
OUTPUT "${_output}"
COMMAND "${CMAKE_CXX_COMPILER}" ${_compiler_FLAGS} -x c++-header -o "${_output}" "${_pchfile}"
DEPENDS "${_pchfile}" "${_pch_flags_file}"
COMMENT "Precompiling ${_name} for ${_target} (C++)")
endif()
if("${mode}" STREQUAL "C")
add_custom_command(
OUTPUT "${_output}"
COMMAND "${CMAKE_C_COMPILER}" ${_compiler_FLAGS_c} -x c-header -o "${_output}" "${_pchfile}"
DEPENDS "${_pchfile}" "${_pch_flags_file}"
COMMENT "Precompiling ${_name} for ${_target} (C)")
endif()

set(_extensions "")
if("${mode}" STREQUAL "CXX")
set(_extensions "cc|cxx|cpp")
endif()
if("${mode}" STREQUAL "C")
set(_extensions "c")
endif()

get_property(_sources TARGET ${_target} PROPERTY SOURCES)
foreach(_source ${_sources})
set(_pch_compile_flags "")
if(_source MATCHES \\.\(${_extensions}\)$)
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)
if(_PCH_FORCEINCLUDE)
list(APPEND _pch_compile_flags -include "${_pchfile}")
else(_PCH_FORCEINCLUDE)
list(APPEND _pch_compile_flags "-I${_pch_binary_dir}")
endif(_PCH_FORCEINCLUDE)

get_source_file_property(_object_depends "${_source}" OBJECT_DEPENDS)
if(NOT _object_depends)
set(_object_depends)
endif()
list(APPEND _object_depends "${_pchfile}")
list(APPEND _object_depends "${_output}")

combine_arguments(_pch_compile_flags)
set_source_files_properties(${_source} PROPERTIES
COMPILE_FLAGS "${_pch_compile_flags}"
OBJECT_DEPENDS "${_object_depends}")
endif()
endforeach()
endfunction()

function(add_precompiled_header _target _input)
cmake_parse_arguments(_PCH "FORCEINCLUDE" "SOURCE_CXX;SOURCE_C" "" ${ARGN})
cmake_parse_arguments(_PCH "FORCEINCLUDE" "SOURCE_CXX;SOURCE_C;PCH_PATH" "" ${ARGN})

get_filename_component(_input_we ${_input} NAME_WE)
if(NOT _PCH_SOURCE_CXX)
Expand Down Expand Up @@ -147,68 +263,8 @@ function(add_precompiled_header _target _input)
endif()
endif(MSVC)

if(CMAKE_COMPILER_IS_GNUCXX)
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")
file(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} -x c++-header -o "${_output_cxx}" "${_pchfile}"
DEPENDS "${_pchfile}" "${_pch_flags_file}"
COMMENT "Precompiling ${_name} for ${_target} (C++)")
add_custom_command(
OUTPUT "${_output_c}"
COMMAND "${CMAKE_C_COMPILER}" ${_compiler_FLAGS} -x c-header -o "${_output_c}" "${_pchfile}"
DEPENDS "${_pchfile}" "${_pch_flags_file}"
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)
if(_PCH_FORCEINCLUDE)
list(APPEND _pch_compile_flags -include "${_pchfile}")
else(_PCH_FORCEINCLUDE)
list(APPEND _pch_compile_flags "-I${_pch_binary_dir}")
endif(_PCH_FORCEINCLUDE)

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_COMPILER_IS_GNUCXX)
if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU|Clang")
gcc_pch_targets_for_mode("${_input}" "${_PCH_PCH_PATH}" "C")
gcc_pch_targets_for_mode("${_input}" "${_PCH_PCH_PATH}" "CXX")
endif(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU|Clang")
endfunction()
2 changes: 2 additions & 0 deletions runall.sh
@@ -1,4 +1,6 @@
#!/bin/sh -exu
set -e

buildroot=$(dirname $(readlink -f $0))/build
generator="Unix Makefiles"
mkdir -p "$buildroot"
Expand Down
2 changes: 2 additions & 0 deletions test/c-force/CMakeLists.txt
Expand Up @@ -7,6 +7,8 @@ if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
set(pch_source test-pch.c)
endif()
set(CMAKE_CXX_FLAGS "${CMAKH_CXX_FLAGS} -Werror")
set(CMAKE_C_FLAGS "${CMAKH_CXX_FLAGS} -Werror")
add_executable(test-c-force test-c-force.c test-pch.h ${pch_source})
add_precompiled_header(test-c-force test-pch.h FORCEINCLUDE)
add_test(test-c-force test-c-force)
2 changes: 2 additions & 0 deletions test/c/CMakeLists.txt
Expand Up @@ -7,6 +7,8 @@ if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
set(pch_source test-pch.c)
endif()
set(CMAKE_CXX_FLAGS "${CMAKH_CXX_FLAGS} -Werror")
set(CMAKE_C_FLAGS "${CMAKH_CXX_FLAGS} -Werror")
add_executable(test-c test-c.c test-pch.h ${pch_source})
add_precompiled_header(test-c test-pch.h)
add_test(test-c test-c)
2 changes: 2 additions & 0 deletions test/cxx-force/CMakeLists.txt
Expand Up @@ -7,6 +7,8 @@ if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
set(pch_source test-pch.cpp)
endif()
set(CMAKE_CXX_FLAGS "${CMAKH_CXX_FLAGS} -Werror")
set(CMAKE_C_FLAGS "${CMAKH_CXX_FLAGS} -Werror")
add_executable(test-cxx-force test-cxx-force.cpp test-pch.h ${pch_source})
add_precompiled_header(test-cxx-force test-pch.h FORCEINCLUDE)
add_test(test-cxx-force test-cxx-force)
16 changes: 16 additions & 0 deletions test/cxx-pic-shared/CMakeLists.txt
@@ -0,0 +1,16 @@
cmake_minimum_required(VERSION 3.3)
cmake_policy(SET CMP0058 NEW)
enable_testing()
project(test-cxx-pic-shared)
include(../../PrecompiledHeader.cmake)
if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
set(pch_source test-pch.cpp)
endif()
set(CMAKE_CXX_FLAGS "${CMAKH_CXX_FLAGS} -Werror")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: CMAKH ===> CMAKE

Copy link
Author

@dutow dutow Apr 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ops, thanks, I'll fix that

set(CMAKE_C_FLAGS "${CMAKH_CXX_FLAGS} -Werror")
add_library(test-cxx-pic-lib SHARED test-cxx-lib.cpp test-pch.h ${pch_source})
add_precompiled_header(test-cxx-pic-lib test-pch.h FORCEINCLUDE)
add_executable(test-cxx-pic-shared test-cxx.cpp)
target_link_libraries(test-cxx-pic-shared test-cxx-pic-lib)
add_test(test-cxx-pic-shared test-cxx-pic-shared)
4 changes: 4 additions & 0 deletions test/cxx-pic-shared/test-cxx-lib.cpp
@@ -0,0 +1,4 @@
#ifndef PCH
#error Missing precompiled header
#endif
int foo() { return 1; }
5 changes: 5 additions & 0 deletions test/cxx-pic-shared/test-cxx.cpp
@@ -0,0 +1,5 @@
#include "test-pch.h"
#ifndef PCH
#error Missing precompiled header
#endif
int main() { return foo() == 1 && !(PCH == atoi(getenv("EXPECTED_PCH"))); }
1 change: 1 addition & 0 deletions test/cxx-pic-shared/test-pch.cpp
@@ -0,0 +1 @@
#include "test-pch.h"
7 changes: 7 additions & 0 deletions test/cxx-pic-shared/test-pch.h
@@ -0,0 +1,7 @@
#define PCH 1
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
int foo();
17 changes: 17 additions & 0 deletions test/cxx-pic/CMakeLists.txt
@@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 3.3)
cmake_policy(SET CMP0058 NEW)
enable_testing()
project(test-cxx-pic)
include(../../PrecompiledHeader.cmake)
if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
set(pch_source test-pch.cpp)
endif()
set(CMAKE_CXX_FLAGS "${CMAKH_CXX_FLAGS} -Werror")
set(CMAKE_C_FLAGS "${CMAKH_CXX_FLAGS} -Werror")
add_library(test-cxx-pic-lib STATIC test-cxx-lib.cpp test-pch.h ${pch_source})
set_target_properties(test-cxx-pic-lib PROPERTIES POSITION_INDEPENDENT_CODE ON)
add_precompiled_header(test-cxx-pic-lib test-pch.h FORCEINCLUDE)
add_executable(test-cxx-pic test-cxx.cpp)
target_link_libraries(test-cxx-pic test-cxx-pic-lib)
add_test(test-cxx-pic test-cxx-pic)
4 changes: 4 additions & 0 deletions test/cxx-pic/test-cxx-lib.cpp
@@ -0,0 +1,4 @@
#ifndef PCH
#error Missing precompiled header
#endif
int foo() { return 1; }
5 changes: 5 additions & 0 deletions test/cxx-pic/test-cxx.cpp
@@ -0,0 +1,5 @@
#include "test-pch.h"
#ifndef PCH
#error Missing precompiled header
#endif
int main() { return foo() == 1 && !(PCH == atoi(getenv("EXPECTED_PCH"))); }
1 change: 1 addition & 0 deletions test/cxx-pic/test-pch.cpp
@@ -0,0 +1 @@
#include "test-pch.h"
7 changes: 7 additions & 0 deletions test/cxx-pic/test-pch.h
@@ -0,0 +1,7 @@
#define PCH 1
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
int foo();
15 changes: 15 additions & 0 deletions test/cxx-pie/CMakeLists.txt
@@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.3)
cmake_policy(SET CMP0058 NEW)
enable_testing()
project(test-cxx-pie)
include(../../PrecompiledHeader.cmake)
if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
set(pch_source test-pch.cpp)
endif()
set(CMAKE_CXX_FLAGS "${CMAKH_CXX_FLAGS} -Werror")
set(CMAKE_C_FLAGS "${CMAKH_CXX_FLAGS} -Werror")
add_executable(test-cxx-pie test-cxx.cpp test-pch.h ${pch_source})
set_target_properties(test-cxx-pie PROPERTIES POSITION_INDEPENDENT_CODE ON)
add_precompiled_header(test-cxx-pie test-pch.h FORCEINCLUDE)
add_test(test-cxx-pie test-cxx-pie)
4 changes: 4 additions & 0 deletions test/cxx-pie/test-cxx.cpp
@@ -0,0 +1,4 @@
#ifndef PCH
#error Missing precompiled header
#endif
int main() { return !(PCH == atoi(getenv("EXPECTED_PCH"))); }
1 change: 1 addition & 0 deletions test/cxx-pie/test-pch.cpp
@@ -0,0 +1 @@
#include "test-pch.h"
6 changes: 6 additions & 0 deletions test/cxx-pie/test-pch.h
@@ -0,0 +1,6 @@
#define PCH 1
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
2 changes: 2 additions & 0 deletions test/cxx/CMakeLists.txt
Expand Up @@ -7,6 +7,8 @@ if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
set(pch_source test-pch.cpp)
endif()
set(CMAKE_CXX_FLAGS "${CMAKH_CXX_FLAGS} -Werror")
set(CMAKE_C_FLAGS "${CMAKH_CXX_FLAGS} -Werror")
add_executable(test-cxx test-cxx.cpp test-pch.h ${pch_source})
add_precompiled_header(test-cxx test-pch.h)
add_test(test-cxx test-cxx)
15 changes: 15 additions & 0 deletions test/cxx11/CMakeLists.txt
@@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.3)
cmake_policy(SET CMP0058 NEW)
enable_testing()
project(test-cxx11)
include(../../PrecompiledHeader.cmake)
if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
set(pch_source test-pch.cpp)
endif()
set(CMAKE_CXX_FLAGS "${CMAKH_CXX_FLAGS} -Werror")
set(CMAKE_C_FLAGS "${CMAKH_CXX_FLAGS} -Werror")
set(CMAKE_CXX_STANDARD 11)
add_executable(test-cxx11 test-cxx.cpp test-pch.h ${pch_source})
add_precompiled_header(test-cxx11 test-pch.h)
add_test(test-cxx11 test-cxx11)
5 changes: 5 additions & 0 deletions test/cxx11/test-cxx.cpp
@@ -0,0 +1,5 @@
#include "test-pch.h"
#ifndef PCH
#error Missing precompiled header
#endif
int main() { return !(PCH == atoi(getenv("EXPECTED_PCH"))); }
1 change: 1 addition & 0 deletions test/cxx11/test-pch.cpp
@@ -0,0 +1 @@
#include "test-pch.h"