CheckIPOSupported.cmake 7.3 KB

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