0d6ad20ae07345b44001828acaabe953b0cd9ad5
[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       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
126   if(NOT result)
127     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
128       "${language} compiler IPO check failed with the following output:\n"
129       "${output}\n")
130     _ipo_not_supported("check failed to compile")
131     if(X_OUTPUT)
132       set("${X_OUTPUT}" "${output}" PARENT_SCOPE)
133     endif()
134     return()
135   endif()
136 endmacro()
137
138 function(check_ipo_supported)
139   cmake_policy(GET CMP0069 x)
140
141   string(COMPARE EQUAL "${x}" "" not_set)
142   if(not_set)
143     message(FATAL_ERROR "Policy CMP0069 is not set")
144   endif()
145
146   string(COMPARE EQUAL "${x}" "OLD" is_old)
147   if(is_old)
148     message(FATAL_ERROR "Policy CMP0069 set to OLD")
149   endif()
150
151   set(optional)
152   set(one RESULT OUTPUT)
153   set(multiple LANGUAGES)
154
155   # Introduce:
156   # * X_RESULT
157   # * X_OUTPUT
158   # * X_LANGUAGES
159   cmake_parse_arguments(X "${optional}" "${one}" "${multiple}" "${ARGV}")
160
161   string(COMPARE NOTEQUAL "${X_UNPARSED_ARGUMENTS}" "" has_unparsed)
162   if(has_unparsed)
163     message(FATAL_ERROR "Unparsed arguments: ${X_UNPARSED_ARGUMENTS}")
164   endif()
165
166   string(COMPARE EQUAL "${X_LANGUAGES}" "" no_languages)
167   if(no_languages)
168     # User did not set any languages, use defaults
169     get_property(enabled_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
170     string(COMPARE EQUAL "${enabled_languages}" "" no_languages)
171     if(no_languages)
172       _ipo_not_supported(
173           "no languages found in ENABLED_LANGUAGES global property"
174       )
175       return()
176     endif()
177
178     set(languages "")
179     list(FIND enabled_languages "CXX" result)
180     if(NOT result EQUAL -1)
181       list(APPEND languages "CXX")
182     endif()
183
184     list(FIND enabled_languages "C" result)
185     if(NOT result EQUAL -1)
186       list(APPEND languages "C")
187     endif()
188
189     list(FIND enabled_languages "Fortran" result)
190     if(NOT result EQUAL -1)
191       list(APPEND languages "Fortran")
192     endif()
193
194     string(COMPARE EQUAL "${languages}" "" no_languages)
195     if(no_languages)
196       _ipo_not_supported(
197           "no C/CXX/Fortran languages found in ENABLED_LANGUAGES global property"
198       )
199       return()
200     endif()
201   else()
202     set(languages "${X_LANGUAGES}")
203
204     set(unsupported_languages "${languages}")
205     list(REMOVE_ITEM unsupported_languages "C" "CXX" "Fortran")
206     string(COMPARE NOTEQUAL "${unsupported_languages}" "" has_unsupported)
207     if(has_unsupported)
208       _ipo_not_supported(
209           "language(s) '${unsupported_languages}' not supported"
210       )
211       return()
212     endif()
213   endif()
214
215   foreach(lang ${languages})
216     if(NOT _CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE)
217       _ipo_not_supported("CMake doesn't support IPO for current ${lang} compiler")
218       return()
219     endif()
220
221     if(NOT _CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER)
222       _ipo_not_supported("${lang} compiler doesn't support IPO")
223       return()
224     endif()
225   endforeach()
226
227   if(CMAKE_GENERATOR MATCHES "^Visual Studio 9 ")
228     _ipo_not_supported("CMake doesn't support IPO for current generator")
229     return()
230   endif()
231
232   foreach(x ${languages})
233     _ipo_run_language_check(${x})
234   endforeach()
235
236   set("${X_RESULT}" YES PARENT_SCOPE)
237 endfunction()