Ryan Prichard | 7aea7e9 | 2022-01-13 17:30:17 -0800 | [diff] [blame] | 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 | Examples |
| 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 |
| 61 | macro(_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() |
| 70 | endmacro() |
| 71 | |
| 72 | # Run IPO/LTO test |
| 73 | macro(_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() |
| 143 | endmacro() |
| 144 | |
| 145 | function(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) |
| 244 | endfunction() |