File: UsePrecompHeaders.cmake

package info (click to toggle)
opm-common 2022.10%2Bds-7
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 78,468 kB
  • sloc: cpp: 164,554; python: 2,872; sh: 216; xml: 174; ansic: 149; pascal: 136; makefile: 12
file content (171 lines) | stat: -rw-r--r-- 6,353 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# - Use precompiled headers
#
# precompile_header takes these parameters
#
#	language      Language in which the header is written; C or CXX.
#
#	type          Type of target being build, SHARED_LIBRARY, STATIC_LIBRARY
#	              or EXECUTABLE.
#
#	header        Relative path within the source tree to the header
#	              that contains the list of includes to be precompiled.
#	              This header should not be added to the installation,
#	              as it will be specific for this project.
#
#	target        Name of target to be created. All targets that
#	              use the precompiled header should depend on this target
#	              so that it is built before them. A variable with this
#	              name will also be created which contains the file name.
#
#	flags_name    Name of variable to receive the flags that should be
#                 added to the command-line.
#
# Example:
#	get_target_property (type opmcore TYPE)
#	precompile_header (CXX ${type}
#		HEADER "opm/core/opm-core-pch.hpp"
#		TARGET opmcore_CXX_pch
#		FLAGS  opmcore_PRECOMP_CXX_FLAGS
#	)
#	set_source_files_properties (${opmcore_CXX_SOURCES} PROPERTIES
#		OBJECT_DEPENDS "${opmcore_CXX_pch}"
#		COMPILE_FLAGS  "${opmcore_PRECOMP_CXX_FLAGS}"
#	)

# get compiler version
include (UseCompVer)
is_compiler_gcc_compatible ()

# reconstruct the compiler command line; this does NOT include the
# DEFINE_SYMBOL that is added for shared libraries. type is the TYPE
# target property.
# see larsch's PrecompiledHeader.cmake: <https://gist.github.com/573926>
# and <https://github.com/loaden/qtcreator/blob/wip/cmake/cmake/PrecompiledHeader.cmake>
function (compiler_cmdline language type cmd_name args_name)
  # get the compiler for this particular language
  set (${cmd_name} "${CMAKE_${language}_COMPILER}" PARENT_SCOPE)
  
  # in case someone has overridden the compiler (e.g. ccache)
  set (_args "${CMAKE_${language}_COMPILER_ARG1}")

  # macro definitions
  get_directory_property (_defs DEFINITIONS)
  list (APPEND _args "${_defs}")

  # global flags (such as -std=c++11); notice that there are both
  # release-dependent and non-release-dependent ones
  string (TOUPPER "CMAKE_${language}_FLAGS" _flags)
  list (APPEND _args "${${_flags}}")
  string (TOUPPER "CMAKE_${language}_FLAGS_${CMAKE_BUILD_TYPE}" _flags)
  list (APPEND _args "${${_flags}}")

  # assume that we are always generating position-independent code
  # when compiling for a shared library
  if (type STREQUAL "SHARED_LIBRARY")
	list (APPEND _args "${CMAKE_SHARED_LIBRARY_${language}_FLAGS}")
  endif (type STREQUAL "SHARED_LIBRARY")

  # directories included
  get_directory_property (_dirs INCLUDE_DIRECTORIES)
  foreach (_dir ${_dirs})
	list (APPEND _args "-I${_dir}")
  endforeach (_dir)

  # make arguments a real list, and write to output variable
  separate_arguments (_args)
  set (${args_name} "${_args}" PARENT_SCOPE)
endfunction (compiler_cmdline language type cmd_name args_name)

function (precompile_header
	language type hdr_kw header tgt_kw target flgs_kw flags_name)
  
  # check "syntax"
  if (NOT hdr_kw STREQUAL "HEADER")
	message (FATAL "Third token to precompile_header shoulde be \"HEADER\"")
  endif (NOT hdr_kw STREQUAL "HEADER")
  if (NOT tgt_kw STREQUAL "TARGET")
	message (FATAL "Fifth token to precompile_header should be \"TARGET\"")
  endif (NOT tgt_kw STREQUAL "TARGET")
  if (NOT flgs_kw STREQUAL "FLAGS")
	message (FATAL "Seventh token to precompile_header should be \"FLAGS\"")
  endif (NOT flgs_kw STREQUAL "FLAGS")

  # check language
  if (language STREQUAL "CXX")
	set (gcc_lang "c++-header")
  elseif (language STREQUAL "C")
	set (gcc_lang "c-header")
  else (language STREQUAL "CXX")
	message (FATAL "Only C or C++ can have precompiled headers")
  endif (language STREQUAL "CXX")

  # if no precompiled header was found, then we shouldn't do anything here
  if (NOT header)
	return ()
  endif (NOT header)
  
  # only support precompiled headers if the compiler is gcc >= 3.4 or clang
  if (CXX_COMPAT_GCC)
	if (CMAKE_COMPILER_IS_GNUCXX)
	  # genuine GCC; must test version
	  get_gcc_version (${language} GCC_VERSION)
	  if (GCC_VERSION VERSION_EQUAL 3.4 OR GCC_VERSION VERSION_GREATER 3.4)
		set (_do_pch TRUE)
	  else ()
		set (_do_pch FALSE)
	  endif ()
	elseif (CMAKE_COMPILER_IS_CLANGXX)
	  # any Clang version that is new enough to compile us can do this
	  set (_do_pch TRUE)
	else ()
	  set (_do_pch FALSE)
	endif ()
	if (_do_pch)
	  # command-line used to compile modules in this kind of target
	  compiler_cmdline (${language} ${type} _cmd _args)

	  # gcc will include any configurations which are in a directory
	  # with the same name as the header included
	  set (_pch_dir "CMakeFiles/pch")
	  set (_pch_file "${_pch_dir}/${header}.gch/${target}")

	  # make sure that output directory exists
	  get_filename_component (_outdir "${PROJECT_BINARY_DIR}/${_pch_file}" PATH)
	  file (MAKE_DIRECTORY ${_outdir})

	  # we need to generate the precompiled header in the output tree, but
	  # at the same time prevent the compiler to pick up the header from the
	  # source tree. getting the order of the include paths right is fragile
	  # in CMake. by copying the header, we can put the precompile dump
	  # right next to it and have the compiler pick it up there
	  add_custom_command (
		OUTPUT "${_pch_dir}/${header}"
		COMMAND ${CMAKE_COMMAND}
		ARGS    -E copy "${PROJECT_SOURCE_DIR}/${header}" "${_pch_dir}/${header}"
		DEPENDS "${PROJECT_SOURCE_DIR}/${header}"
		)

	  # add a makefile rule to create the precompiled header
	  add_custom_command (
		OUTPUT  ${PROJECT_BINARY_DIR}/${_pch_file}
		COMMAND ${_cmd}
		ARGS    ${_args} "-o" "${_pch_file}" "-x" "${gcc_lang}" "-c" "${_pch_dir}/${header}"
		DEPENDS "${_pch_dir}/${header}"
		COMMENT "Precompiling headers ${_pch_file}"
		)

	  # create a phony target that is always built, but which only checks
	  # if the header file is OK (i.e. the header only gets rebuilt if
	  # necessary)
	  add_custom_target (${target} ALL
		DEPENDS ${PROJECT_BINARY_DIR}/${_pch_file}
		)

	  # these flags need to be added to the target
	  set (${target} "${_pch_file}" PARENT_SCOPE)
	  set (${flags_name} "-Winvalid-pch -include ${_pch_dir}/${header}" PARENT_SCOPE)
	endif ()
  endif ()
  
endfunction (precompile_header
  language type header tgt_kw target flgs_kw flags_name)