Imported Upstream version 3.25.0
[platform/upstream/cmake.git] / Modules / CheckIPOSupported.cmake
1 # 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:
5 CheckIPOSupported
6 -----------------
7
8 .. versionadded:: 3.9
9
10 Check whether the compiler supports an interprocedural optimization (IPO/LTO).
11 Use this before enabling the :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION` target
12 property.
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
33 It makes no sense to use this module when :policy:`CMP0069` is set to ``OLD`` so
34 module 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
39 .. versionadded:: 3.24
40   The check uses the caller's :variable:`CMAKE_<LANG>_FLAGS`
41   and :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` values.
42   See policy :policy:`CMP0138`.
43
44 Examples
45 ^^^^^^^^
46
47 .. code-block:: cmake
48
49   check_ipo_supported() # fatal error if IPO is not supported
50   set_property(TARGET foo PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
51
52 .. code-block:: cmake
53
54   # Optional IPO. Do not use IPO if it's not supported by compiler.
55   check_ipo_supported(RESULT result OUTPUT output)
56   if(result)
57     set_property(TARGET foo PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
58   else()
59     message(WARNING "IPO is not supported: ${output}")
60   endif()
61
62 #]=======================================================================]
63
64 # X_RESULT - name of the final result variable
65 # X_OUTPUT - name of the variable with information about error
66 macro(_ipo_not_supported output)
67   if(NOT X_RESULT)
68     message(FATAL_ERROR "IPO is not supported (${output}).")
69   endif()
70
71   set("${X_RESULT}" NO PARENT_SCOPE)
72   if(X_OUTPUT)
73     set("${X_OUTPUT}" "${output}" PARENT_SCOPE)
74   endif()
75 endmacro()
76
77 # Run IPO/LTO test
78 macro(_ipo_run_language_check language)
79   set(_C_ext "c")
80   set(_CXX_ext "cpp")
81   set(_Fortran_ext "f")
82   string(COMPARE EQUAL "${language}" "CUDA" is_cuda)
83
84   set(ext ${_${language}_ext})
85   if(NOT "${ext}" STREQUAL "")
86     set(copy_sources foo.${ext} main.${ext})
87   elseif(is_cuda)
88     if(_CMAKE_CUDA_IPO_SUPPORTED_BY_CMAKE)
89       set("${X_RESULT}" YES PARENT_SCOPE)
90     endif()
91     return()
92   else()
93     message(FATAL_ERROR "Language not supported")
94   endif()
95
96   set(testdir "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/_CMakeLTOTest-${language}")
97
98   file(REMOVE_RECURSE "${testdir}")
99   file(MAKE_DIRECTORY "${testdir}")
100
101   set(bindir "${testdir}/bin")
102   set(srcdir "${testdir}/src")
103
104   file(MAKE_DIRECTORY "${bindir}")
105   file(MAKE_DIRECTORY "${srcdir}")
106
107   set(TRY_COMPILE_PROJECT_NAME "lto-test")
108
109   set(try_compile_src "${CMAKE_ROOT}/Modules/CheckIPOSupported")
110
111   # Use:
112   # * TRY_COMPILE_PROJECT_NAME
113   # * CMAKE_VERSION
114   configure_file(
115       "${try_compile_src}/CMakeLists-${language}.txt.in"
116       "${srcdir}/CMakeLists.txt"
117       @ONLY
118   )
119
120   foreach(x ${copy_sources})
121     configure_file(
122         "${try_compile_src}/${x}"
123         "${srcdir}/${x}"
124         COPYONLY
125     )
126   endforeach()
127
128   if(ipo_CMP0138 STREQUAL "NEW")
129     set(CMAKE_TRY_COMPILE_CONFIGURATION Debug)
130     set(_CMAKE_LANG_FLAGS
131       "-DCMAKE_${language}_FLAGS:STRING=${CMAKE_${language}_FLAGS}"
132       "-DCMAKE_${language}_FLAGS_DEBUG:STRING=${CMAKE_${language}_FLAGS_DEBUG}"
133       )
134   else()
135     set(_CMAKE_LANG_FLAGS "")
136   endif()
137
138   try_compile(
139       _IPO_LANGUAGE_CHECK_RESULT
140       PROJECT "${TRY_COMPILE_PROJECT_NAME}"
141       SOURCE_DIR "${srcdir}"
142       BINARY_DIR "${bindir}"
143       CMAKE_FLAGS
144       "-DCMAKE_VERBOSE_MAKEFILE=ON"
145       "-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON"
146       ${_CMAKE_LANG_FLAGS}
147       OUTPUT_VARIABLE output
148   )
149   set(_IPO_LANGUAGE_CHECK_RESULT "${_IPO_LANGUAGE_CHECK_RESULT}")
150   unset(_IPO_LANGUAGE_CHECK_RESULT CACHE)
151
152   if(NOT _IPO_LANGUAGE_CHECK_RESULT)
153     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
154       "${language} compiler IPO check failed with the following output:\n"
155       "${output}\n")
156     _ipo_not_supported("check failed to compile")
157     if(X_OUTPUT)
158       set("${X_OUTPUT}" "${output}" PARENT_SCOPE)
159     endif()
160     return()
161   endif()
162 endmacro()
163
164 function(check_ipo_supported)
165   cmake_policy(GET CMP0069 x)
166
167   string(COMPARE EQUAL "${x}" "" not_set)
168   if(not_set)
169     message(FATAL_ERROR "Policy CMP0069 is not set")
170   endif()
171
172   string(COMPARE EQUAL "${x}" "OLD" is_old)
173   if(is_old)
174     message(FATAL_ERROR "Policy CMP0069 set to OLD")
175   endif()
176
177   # Save policy setting for condition in _ipo_run_language_check.
178   cmake_policy(GET CMP0138 ipo_CMP0138
179     PARENT_SCOPE # undocumented, do not use outside of CMake
180     )
181
182   set(optional)
183   set(one RESULT OUTPUT)
184   set(multiple LANGUAGES)
185
186   # Introduce:
187   # * X_RESULT
188   # * X_OUTPUT
189   # * X_LANGUAGES
190   cmake_parse_arguments(X "${optional}" "${one}" "${multiple}" "${ARGV}")
191
192   string(COMPARE NOTEQUAL "${X_UNPARSED_ARGUMENTS}" "" has_unparsed)
193   if(has_unparsed)
194     message(FATAL_ERROR "Unparsed arguments: ${X_UNPARSED_ARGUMENTS}")
195   endif()
196
197   string(COMPARE EQUAL "${X_LANGUAGES}" "" no_languages)
198   if(no_languages)
199     # User did not set any languages, use defaults
200     get_property(enabled_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
201     string(COMPARE EQUAL "${enabled_languages}" "" no_languages)
202     if(no_languages)
203       _ipo_not_supported(
204           "no languages found in ENABLED_LANGUAGES global property"
205       )
206       return()
207     endif()
208
209     set(languages "")
210     list(FIND enabled_languages "CXX" result)
211     if(NOT result EQUAL -1)
212       list(APPEND languages "CXX")
213     endif()
214
215     list(FIND enabled_languages "C" result)
216     if(NOT result EQUAL -1)
217       list(APPEND languages "C")
218     endif()
219
220     list(FIND enabled_languages "CUDA" result)
221     if(NOT result EQUAL -1)
222       list(APPEND languages "CUDA")
223     endif()
224
225     list(FIND enabled_languages "Fortran" result)
226     if(NOT result EQUAL -1)
227       list(APPEND languages "Fortran")
228     endif()
229
230     string(COMPARE EQUAL "${languages}" "" no_languages)
231     if(no_languages)
232       _ipo_not_supported(
233           "no C/CXX/CUDA/Fortran languages found in ENABLED_LANGUAGES global property"
234       )
235       return()
236     endif()
237   else()
238     set(languages "${X_LANGUAGES}")
239
240     set(unsupported_languages "${languages}")
241     list(REMOVE_ITEM unsupported_languages "C" "CXX" "CUDA" "Fortran")
242     string(COMPARE NOTEQUAL "${unsupported_languages}" "" has_unsupported)
243     if(has_unsupported)
244       _ipo_not_supported(
245           "language(s) '${unsupported_languages}' not supported"
246       )
247       return()
248     endif()
249   endif()
250
251   foreach(lang ${languages})
252     if(NOT _CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE)
253       _ipo_not_supported("CMake doesn't support IPO for current ${lang} compiler")
254       return()
255     endif()
256
257     if(NOT _CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER)
258       _ipo_not_supported("${lang} compiler doesn't support IPO")
259       return()
260     endif()
261   endforeach()
262
263   if(CMAKE_GENERATOR MATCHES "^Visual Studio 9 ")
264     _ipo_not_supported("CMake doesn't support IPO for current generator")
265     return()
266   endif()
267
268   foreach(x ${languages})
269     _ipo_run_language_check(${x})
270   endforeach()
271
272   set("${X_RESULT}" YES PARENT_SCOPE)
273 endfunction()