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: 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() 245