blob: 0bc3c92338fd1599342d283da3a3fe0b05af4eb7 [file] [log] [blame]
Ryan Prichard7aea7e92022-01-13 17:30:17 -08001# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2# file Copyright.txt or https://cmake.org/licensing for details.
3
4#[=======================================================================[.rst:
5CheckIPOSupported
6-----------------
7
8.. versionadded:: 3.9
9
10Check whether the compiler supports an interprocedural optimization (IPO/LTO).
11Use this before enabling the :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION` target
12property.
13
14.. command:: check_ipo_supported
15
16 ::
17
18 check_ipo_supported([RESULT <result>] [OUTPUT <output>]
19 [LANGUAGES <lang>...])
20
21 Options are:
22
23 ``RESULT <result>``
24 Set ``<result>`` variable to ``YES`` if IPO is supported by the
25 compiler and ``NO`` otherwise. If this option is not given then
26 the command will issue a fatal error if IPO is not supported.
27 ``OUTPUT <output>``
28 Set ``<output>`` variable with details about any error.
29 ``LANGUAGES <lang>...``
30 Specify languages whose compilers to check.
31 Languages ``C``, ``CXX``, and ``Fortran`` are supported.
32
33It makes no sense to use this module when :policy:`CMP0069` is set to ``OLD`` so
34module will return error in this case. See policy :policy:`CMP0069` for details.
35
36.. versionadded:: 3.13
37 Add support for Visual Studio generators.
38
39Examples
40^^^^^^^^
41
42.. code-block:: cmake
43
44 check_ipo_supported() # fatal error if IPO is not supported
45 set_property(TARGET foo PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
46
47.. code-block:: cmake
48
49 # Optional IPO. Do not use IPO if it's not supported by compiler.
50 check_ipo_supported(RESULT result OUTPUT output)
51 if(result)
52 set_property(TARGET foo PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
53 else()
54 message(WARNING "IPO is not supported: ${output}")
55 endif()
56
57#]=======================================================================]
58
59# X_RESULT - name of the final result variable
60# X_OUTPUT - name of the variable with information about error
61macro(_ipo_not_supported output)
62 if(NOT X_RESULT)
63 message(FATAL_ERROR "IPO is not supported (${output}).")
64 endif()
65
66 set("${X_RESULT}" NO PARENT_SCOPE)
67 if(X_OUTPUT)
68 set("${X_OUTPUT}" "${output}" PARENT_SCOPE)
69 endif()
70endmacro()
71
72# Run IPO/LTO test
73macro(_ipo_run_language_check language)
74 set(testdir "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/_CMakeLTOTest-${language}")
75
76 file(REMOVE_RECURSE "${testdir}")
77 file(MAKE_DIRECTORY "${testdir}")
78
79 set(bindir "${testdir}/bin")
80 set(srcdir "${testdir}/src")
81
82 file(MAKE_DIRECTORY "${bindir}")
83 file(MAKE_DIRECTORY "${srcdir}")
84
85 set(TRY_COMPILE_PROJECT_NAME "lto-test")
86
87 set(try_compile_src "${CMAKE_ROOT}/Modules/CheckIPOSupported")
88
89 # Use:
90 # * TRY_COMPILE_PROJECT_NAME
91 # * CMAKE_VERSION
92 configure_file(
93 "${try_compile_src}/CMakeLists-${language}.txt.in"
94 "${srcdir}/CMakeLists.txt"
95 @ONLY
96 )
97
98 string(COMPARE EQUAL "${language}" "C" is_c)
99 string(COMPARE EQUAL "${language}" "CXX" is_cxx)
100 string(COMPARE EQUAL "${language}" "Fortran" is_fortran)
101
102 if(is_c)
103 set(copy_sources foo.c main.c)
104 elseif(is_cxx)
105 set(copy_sources foo.cpp main.cpp)
106 elseif(is_fortran)
107 set(copy_sources foo.f main.f)
108 else()
109 message(FATAL_ERROR "Language not supported")
110 endif()
111
112 foreach(x ${copy_sources})
113 configure_file(
114 "${try_compile_src}/${x}"
115 "${srcdir}/${x}"
116 COPYONLY
117 )
118 endforeach()
119
120 try_compile(
121 _IPO_LANGUAGE_CHECK_RESULT
122 "${bindir}"
123 "${srcdir}"
124 "${TRY_COMPILE_PROJECT_NAME}"
125 CMAKE_FLAGS
126 "-DCMAKE_VERBOSE_MAKEFILE=ON"
127 "-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON"
128 OUTPUT_VARIABLE output
129 )
130 set(_IPO_LANGUAGE_CHECK_RESULT "${_IPO_LANGUAGE_CHECK_RESULT}")
131 unset(_IPO_LANGUAGE_CHECK_RESULT CACHE)
132
133 if(NOT _IPO_LANGUAGE_CHECK_RESULT)
134 file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
135 "${language} compiler IPO check failed with the following output:\n"
136 "${output}\n")
137 _ipo_not_supported("check failed to compile")
138 if(X_OUTPUT)
139 set("${X_OUTPUT}" "${output}" PARENT_SCOPE)
140 endif()
141 return()
142 endif()
143endmacro()
144
145function(check_ipo_supported)
146 cmake_policy(GET CMP0069 x)
147
148 string(COMPARE EQUAL "${x}" "" not_set)
149 if(not_set)
150 message(FATAL_ERROR "Policy CMP0069 is not set")
151 endif()
152
153 string(COMPARE EQUAL "${x}" "OLD" is_old)
154 if(is_old)
155 message(FATAL_ERROR "Policy CMP0069 set to OLD")
156 endif()
157
158 set(optional)
159 set(one RESULT OUTPUT)
160 set(multiple LANGUAGES)
161
162 # Introduce:
163 # * X_RESULT
164 # * X_OUTPUT
165 # * X_LANGUAGES
166 cmake_parse_arguments(X "${optional}" "${one}" "${multiple}" "${ARGV}")
167
168 string(COMPARE NOTEQUAL "${X_UNPARSED_ARGUMENTS}" "" has_unparsed)
169 if(has_unparsed)
170 message(FATAL_ERROR "Unparsed arguments: ${X_UNPARSED_ARGUMENTS}")
171 endif()
172
173 string(COMPARE EQUAL "${X_LANGUAGES}" "" no_languages)
174 if(no_languages)
175 # User did not set any languages, use defaults
176 get_property(enabled_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
177 string(COMPARE EQUAL "${enabled_languages}" "" no_languages)
178 if(no_languages)
179 _ipo_not_supported(
180 "no languages found in ENABLED_LANGUAGES global property"
181 )
182 return()
183 endif()
184
185 set(languages "")
186 list(FIND enabled_languages "CXX" result)
187 if(NOT result EQUAL -1)
188 list(APPEND languages "CXX")
189 endif()
190
191 list(FIND enabled_languages "C" result)
192 if(NOT result EQUAL -1)
193 list(APPEND languages "C")
194 endif()
195
196 list(FIND enabled_languages "Fortran" result)
197 if(NOT result EQUAL -1)
198 list(APPEND languages "Fortran")
199 endif()
200
201 string(COMPARE EQUAL "${languages}" "" no_languages)
202 if(no_languages)
203 _ipo_not_supported(
204 "no C/CXX/Fortran languages found in ENABLED_LANGUAGES global property"
205 )
206 return()
207 endif()
208 else()
209 set(languages "${X_LANGUAGES}")
210
211 set(unsupported_languages "${languages}")
212 list(REMOVE_ITEM unsupported_languages "C" "CXX" "Fortran")
213 string(COMPARE NOTEQUAL "${unsupported_languages}" "" has_unsupported)
214 if(has_unsupported)
215 _ipo_not_supported(
216 "language(s) '${unsupported_languages}' not supported"
217 )
218 return()
219 endif()
220 endif()
221
222 foreach(lang ${languages})
223 if(NOT _CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE)
224 _ipo_not_supported("CMake doesn't support IPO for current ${lang} compiler")
225 return()
226 endif()
227
228 if(NOT _CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER)
229 _ipo_not_supported("${lang} compiler doesn't support IPO")
230 return()
231 endif()
232 endforeach()
233
234 if(CMAKE_GENERATOR MATCHES "^Visual Studio 9 ")
235 _ipo_not_supported("CMake doesn't support IPO for current generator")
236 return()
237 endif()
238
239 foreach(x ${languages})
240 _ipo_run_language_check(${x})
241 endforeach()
242
243 set("${X_RESULT}" YES PARENT_SCOPE)
244endfunction()