You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cmake/Modules/CheckIPOSupported.cmake

274 lines
7.5 KiB

# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
CheckIPOSupported
-----------------
.. versionadded:: 3.9
Check whether the compiler supports an interprocedural optimization (IPO/LTO).
Use this before enabling the :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION` target
property.
.. command:: check_ipo_supported
::
check_ipo_supported([RESULT <result>] [OUTPUT <output>]
[LANGUAGES <lang>...])
Options are:
``RESULT <result>``
Set ``<result>`` variable to ``YES`` if IPO is supported by the
compiler and ``NO`` otherwise. If this option is not given then
the command will issue a fatal error if IPO is not supported.
``OUTPUT <output>``
Set ``<output>`` variable with details about any error.
``LANGUAGES <lang>...``
Specify languages whose compilers to check.
Languages ``C``, ``CXX``, and ``Fortran`` are supported.
It makes no sense to use this module when :policy:`CMP0069` is set to ``OLD`` so
module will return error in this case. See policy :policy:`CMP0069` for details.
.. versionadded:: 3.13
Add support for Visual Studio generators.
.. versionadded:: 3.24
The check uses the caller's :variable:`CMAKE_<LANG>_FLAGS`
and :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` values.
See policy :policy:`CMP0138`.
Examples
^^^^^^^^
.. code-block:: cmake
check_ipo_supported() # fatal error if IPO is not supported
set_property(TARGET foo PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
.. code-block:: cmake
# Optional IPO. Do not use IPO if it's not supported by compiler.
check_ipo_supported(RESULT result OUTPUT output)
if(result)
set_property(TARGET foo PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
else()
message(WARNING "IPO is not supported: ${output}")
endif()
#]=======================================================================]
# X_RESULT - name of the final result variable
# X_OUTPUT - name of the variable with information about error
macro(_ipo_not_supported output)
if(NOT X_RESULT)
message(FATAL_ERROR "IPO is not supported (${output}).")
endif()
set("${X_RESULT}" NO PARENT_SCOPE)
if(X_OUTPUT)
set("${X_OUTPUT}" "${output}" PARENT_SCOPE)
endif()
endmacro()
# Run IPO/LTO test
macro(_ipo_run_language_check language)
set(_C_ext "c")
set(_CXX_ext "cpp")
set(_Fortran_ext "f")
string(COMPARE EQUAL "${language}" "CUDA" is_cuda)
set(ext ${_${language}_ext})
if(NOT "${ext}" STREQUAL "")
set(copy_sources foo.${ext} main.${ext})
elseif(is_cuda)
if(_CMAKE_CUDA_IPO_SUPPORTED_BY_CMAKE)
set("${X_RESULT}" YES PARENT_SCOPE)
endif()
return()
else()
message(FATAL_ERROR "Language not supported")
endif()
set(testdir "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/_CMakeLTOTest-${language}")
file(REMOVE_RECURSE "${testdir}")
file(MAKE_DIRECTORY "${testdir}")
set(bindir "${testdir}/bin")
set(srcdir "${testdir}/src")
file(MAKE_DIRECTORY "${bindir}")
file(MAKE_DIRECTORY "${srcdir}")
set(TRY_COMPILE_PROJECT_NAME "lto-test")
set(try_compile_src "${CMAKE_ROOT}/Modules/CheckIPOSupported")
# Use:
# * TRY_COMPILE_PROJECT_NAME
# * CMAKE_VERSION
configure_file(
"${try_compile_src}/CMakeLists-${language}.txt.in"
"${srcdir}/CMakeLists.txt"
@ONLY
)
foreach(x ${copy_sources})
configure_file(
"${try_compile_src}/${x}"
"${srcdir}/${x}"
COPYONLY
)
endforeach()
if(ipo_CMP0138 STREQUAL "NEW")
set(CMAKE_TRY_COMPILE_CONFIGURATION Debug)
set(_CMAKE_LANG_FLAGS
"-DCMAKE_${language}_FLAGS:STRING=${CMAKE_${language}_FLAGS}"
"-DCMAKE_${language}_FLAGS_DEBUG:STRING=${CMAKE_${language}_FLAGS_DEBUG}"
)
else()
set(_CMAKE_LANG_FLAGS "")
endif()
try_compile(
_IPO_LANGUAGE_CHECK_RESULT
PROJECT "${TRY_COMPILE_PROJECT_NAME}"
SOURCE_DIR "${srcdir}"
BINARY_DIR "${bindir}"
CMAKE_FLAGS
"-DCMAKE_VERBOSE_MAKEFILE=ON"
"-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON"
${_CMAKE_LANG_FLAGS}
OUTPUT_VARIABLE output
)
set(_IPO_LANGUAGE_CHECK_RESULT "${_IPO_LANGUAGE_CHECK_RESULT}")
unset(_IPO_LANGUAGE_CHECK_RESULT CACHE)
if(NOT _IPO_LANGUAGE_CHECK_RESULT)
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"${language} compiler IPO check failed with the following output:\n"
"${output}\n")
_ipo_not_supported("check failed to compile")
if(X_OUTPUT)
set("${X_OUTPUT}" "${output}" PARENT_SCOPE)
endif()
return()
endif()
endmacro()
function(check_ipo_supported)
cmake_policy(GET CMP0069 x)
string(COMPARE EQUAL "${x}" "" not_set)
if(not_set)
message(FATAL_ERROR "Policy CMP0069 is not set")
endif()
string(COMPARE EQUAL "${x}" "OLD" is_old)
if(is_old)
message(FATAL_ERROR "Policy CMP0069 set to OLD")
endif()
# Save policy setting for condition in _ipo_run_language_check.
cmake_policy(GET CMP0138 ipo_CMP0138
PARENT_SCOPE # undocumented, do not use outside of CMake
)
set(optional)
set(one RESULT OUTPUT)
set(multiple LANGUAGES)
# Introduce:
# * X_RESULT
# * X_OUTPUT
# * X_LANGUAGES
cmake_parse_arguments(X "${optional}" "${one}" "${multiple}" "${ARGV}")
string(COMPARE NOTEQUAL "${X_UNPARSED_ARGUMENTS}" "" has_unparsed)
if(has_unparsed)
message(FATAL_ERROR "Unparsed arguments: ${X_UNPARSED_ARGUMENTS}")
endif()
string(COMPARE EQUAL "${X_LANGUAGES}" "" no_languages)
if(no_languages)
# User did not set any languages, use defaults
get_property(enabled_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
string(COMPARE EQUAL "${enabled_languages}" "" no_languages)
if(no_languages)
_ipo_not_supported(
"no languages found in ENABLED_LANGUAGES global property"
)
return()
endif()
set(languages "")
list(FIND enabled_languages "CXX" result)
if(NOT result EQUAL -1)
list(APPEND languages "CXX")
endif()
list(FIND enabled_languages "C" result)
if(NOT result EQUAL -1)
list(APPEND languages "C")
endif()
list(FIND enabled_languages "CUDA" result)
if(NOT result EQUAL -1)
list(APPEND languages "CUDA")
endif()
list(FIND enabled_languages "Fortran" result)
if(NOT result EQUAL -1)
list(APPEND languages "Fortran")
endif()
string(COMPARE EQUAL "${languages}" "" no_languages)
if(no_languages)
_ipo_not_supported(
"no C/CXX/CUDA/Fortran languages found in ENABLED_LANGUAGES global property"
)
return()
endif()
else()
set(languages "${X_LANGUAGES}")
set(unsupported_languages "${languages}")
list(REMOVE_ITEM unsupported_languages "C" "CXX" "CUDA" "Fortran")
string(COMPARE NOTEQUAL "${unsupported_languages}" "" has_unsupported)
if(has_unsupported)
_ipo_not_supported(
"language(s) '${unsupported_languages}' not supported"
)
return()
endif()
endif()
foreach(lang ${languages})
if(NOT _CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE)
_ipo_not_supported("CMake doesn't support IPO for current ${lang} compiler")
return()
endif()
if(NOT _CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER)
_ipo_not_supported("${lang} compiler doesn't support IPO")
return()
endif()
endforeach()
if(CMAKE_GENERATOR MATCHES "^Visual Studio 9 ")
_ipo_not_supported("CMake doesn't support IPO for current generator")
return()
endif()
foreach(x ${languages})
_ipo_run_language_check(${x})
endforeach()
set("${X_RESULT}" YES PARENT_SCOPE)
endfunction()