CheckIPOSupported.cmake 6.4 KB

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