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