Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/pch/cmake/PrecompiledHeaderFiles.cmake @ 3141

Last change on this file since 3141 was 3117, checked in by rgrieder, 15 years ago

Adding experimental precompiled header file support. It seems to work quite well with MSVC, but has a performance penalty when used with GCC

  • Property svn:eol-style set to native
File size: 6.3 KB
Line 
1 #
2 #             ORXONOX - the hottest 3D action shooter ever to exist
3 #                             > www.orxonox.net <
4 #
5 #        This program is free software; you can redistribute it and/or
6 #         modify it under the terms of the GNU General Public License
7 #        as published by the Free Software Foundation; either version 2
8 #            of the License, or (at your option) any later version.
9 #
10 #       This program is distributed in the hope that it will be useful,
11 #        but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 #                 GNU General Public License for more details.
14 #
15 #   You should have received a copy of the GNU General Public License along
16 #      with this program; if not, write to the Free Software Foundation,
17 #     Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 #
19 #
20 #  Author:
21 #    Reto Grieder
22 #
23
24INCLUDE(GetGCCCompilerFlags)
25 
26MACRO(PRECOMPILED_HEADER_FILES_PRE_TARGET _target_name _header_file_arg _sourcefile_var)
27
28  GET_FILENAME_COMPONENT(_pch_header_file ${_header_file_arg} ABSOLUTE)
29  GET_FILENAME_COMPONENT(_pch_header_filename ${_pch_header_file} NAME)
30  GET_FILENAME_COMPONENT(_pch_header_filename_we ${_pch_header_file} NAME_WE)
31
32  IF(NOT EXISTS ${_pch_header_file})
33    MESSAGE(FATAL_ERROR "Specified precompiled headerfile '${_header_file_arg}' does not exist.")
34  ENDIF()
35
36  # Extract arguments from ARGN
37  FOREACH(_arg ${ARGN})
38    IF(NOT "${_arg}" STREQUAL "EXCLUDE")
39      IF(NOT _arg_second)
40        # Source files with PCH support
41        SET(_included_files ${_included_files} ${_arg})
42      ELSE()
43        # Source files to be excluded from PCH support (easier syntax this way)
44        SET(_excluded files ${_excluded_files} ${_arg})
45      ENDIF()
46    ELSE()
47      SET(_arg_second TRUE)
48    ENDIF()
49  ENDFOREACH(_arg)
50
51  # Use ${_sourcefile_var} if no files were specified explicitely
52  IF(NOT _included_files)
53    SET(_source_files ${${_sourcefile_var}})
54  ELSE()
55    SET(_source_files ${_included_files})
56  ENDIF()
57
58  # Exclude files (if specified)
59  FOREACH(_file ${_excluded_files})
60    LIST(FIND _source_files ${_file} _list_index)
61    IF(_list_index GREATER -1)
62      LIST(REMOVE_AT _source_files _list_index)
63    ELSE()
64      MESSAGE(FATAL_ERROR "Could not exclude file ${_file} in target ${_target_name}")
65    ENDIF()
66  ENDFOREACH(_file)
67
68  LIST(FIND ${_sourcefile_var} ${_pch_header_file} _list_index)
69  IF(_list_index EQUAL -1) # Header file could already be included with GET_ALL_HEADER_FILES
70    LIST(APPEND ${_sourcefile_var} ${_pch_header_file})
71  ENDIF()
72  SOURCE_GROUP("PCH" FILES ${_pch_header_file})
73
74  IF(MSVC)
75
76    # Write and add one source file, which generates the precompiled header file
77    SET(_pch_source_file "${CMAKE_CURRENT_BINARY_DIR}/${_pch_header_filename_we}.cc")
78    IF(NOT EXISTS ${_pch_source_file})
79      FILE(WRITE ${_pch_source_file} "#include \"${_pch_header_file}\"\n")
80    ENDIF()
81    SET_SOURCE_FILES_PROPERTIES(_pch_source_file PROPERTIES GENERATED TRUE)
82    LIST(APPEND ${_sourcefile_var} ${_pch_source_file})
83    SOURCE_GROUP("PCH" FILES ${_pch_source_file})
84
85    SET(_pch_file "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${_pch_header_filename}.pch")
86    # Set compile flags for generated source file
87    SET_SOURCE_FILES_PROPERTIES(${_pch_source_file} PROPERTIES COMPILE_FLAGS "/c /Yc\"${_pch_header_file}\" /Fp\"${_pch_file}\"")
88    # Set Compile flags for the other source files
89    FOREACH(_file ${_source_files})
90      GET_SOURCE_FILE_PROPERTY(_is_header ${_file} HEADER_FILE_ONLY)
91      IF(NOT _is_header)
92        GET_SOURCE_FILE_PROPERTY(_old_flags ${_file} COMPILE_FLAGS)
93        IF(NOT _old_flags)
94          SET(_old_flags "")
95        ENDIF()
96        SET_SOURCE_FILES_PROPERTIES(${_file} PROPERTIES COMPILE_FLAGS "${_old_flags} /FI\"${_pch_header_file}\" /Yu\"${_pch_header_file}\" /Fp\"${_pch_file}\"")
97      ENDIF(NOT _is_header)
98    ENDFOREACH(_file)
99
100  ELSEIF(CMAKE_COMPILER_IS_GNU)
101
102    SET(_pch_file "${CMAKE_CURRENT_BINARY_DIR}/${_pch_header_filename}.gch")
103    SET(_pch_dep_helper_file "${CMAKE_CURRENT_BINARY_DIR}/${_target_name}_pch_dependency_helper.cc")
104
105    # Append the gch-dir to make sure gcc finds the pch file
106    INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
107
108    # Get compiler flags of the source files (target does not yet exist!)
109    # This is just the best possible opportunity to address this dependency issue
110    GET_GCC_COMPILER_FLAGS(${_target_name} _pch_gcc_flags)
111    # Make sure we recompile the pch file even if only the flags change
112    FILE(WRITE ${_pch_dep_helper_file} "/* ${_pch_gcc_flags} */")
113
114    # Set Compile flags for the other source files
115    FOREACH(_file ${_source_files})
116      GET_SOURCE_FILE_PROPERTY(_is_header ${_file} HEADER_FILE_ONLY)
117      IF(NOT _is_header)
118        GET_SOURCE_FILE_PROPERTY(_old_flags ${_file} COMPILE_FLAGS)
119        IF(NOT _old_flags)
120          SET(_old_flags "")
121        ENDIF()
122        SET_SOURCE_FILES_PROPERTIES(${_file} PROPERTIES
123          COMPILE_FLAGS "${_old_flags} -include ${_pch_header_filename}"
124          OBJECT_DEPENDS "${_pch_header_file};${_pch_file}"
125        )
126      ENDIF(NOT _is_header)
127    ENDFOREACH(_file)
128
129  ENDIF()
130
131ENDMACRO(PRECOMPILED_HEADER_FILES_PRE_TARGET)
132
133FUNCTION(PRECOMPILED_HEADER_FILES_POST_TARGET _target_name)
134    # This macro is only necessary for GCC
135    IF(CMAKE_COMPILER_IS_GNU)
136
137      # Workaround for distcc
138      IF(CMAKE_CXX_COMPILER_ARG1)
139        # remove leading space in compiler argument
140        STRING(REGEX REPLACE "^ +" "" _pch_cmake_cxx_compiler_arg1 "${CMAKE_CXX_COMPILER_ARG1}")
141      ENDIF()
142
143      # Get compiler flags of the source files again (target exists this time)
144      GET_GCC_COMPILER_FLAGS(${_target_name} _pch_gcc_flags)
145
146      # Compile the header file
147      ADD_CUSTOM_COMMAND(
148        OUTPUT ${_pch_file}
149        COMMAND ${CMAKE_CXX_COMPILER}
150        ARGS ${pchsupport_compiler_cxx_arg1} ${_pch_gcc_flags} -c -x c++-header -o ${_pch_file} ${_pch_header_file}
151        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
152        DEPENDS ${_pch_header_file} ${_pch_dep_helper_file}
153        IMPLICIT_DEPENDS ${_pch_header_file}
154        VERBATIM
155      )
156
157    ENDIF(CMAKE_COMPILER_IS_GNU)
158ENDFUNCTION(PRECOMPILED_HEADER_FILES_POST_TARGET)
159
160# TODO: Investigate what happens when we suddenly disable PCH for a library
161# TODO: C and CXX
Note: See TracBrowser for help on using the repository browser.