فهرست منبع

CheckIPOSupported: New module to check for compiler/cmake IPO support

Ruslan Baratov 8 سال پیش
والد
کامیت
fdb2ba2521

+ 1 - 0
Help/manual/cmake-modules.7.rst

@@ -27,6 +27,7 @@ All Modules
    /module/CheckFortranFunctionExists
    /module/CheckFortranSourceCompiles
    /module/CheckFunctionExists
+   /module/CheckIPOSupported
    /module/CheckIncludeFileCXX
    /module/CheckIncludeFile
    /module/CheckIncludeFiles

+ 1 - 0
Help/module/CheckIPOSupported.rst

@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckIPOSupported.cmake

+ 6 - 0
Help/release/dev/CheckIPOSupported.rst

@@ -0,0 +1,6 @@
+CheckIPOSupported
+-----------------
+
+* A :module:`CheckIPOSupported` module was added to help projects
+  check whether interprocedural optimization (IPO) is supported by
+  the current toolchain and CMake version.

+ 215 - 0
Modules/CheckIPOSupported.cmake

@@ -0,0 +1,215 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckIPOSupported
+-----------------
+
+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`` and ``CXX`` are supported.
+
+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()
+
+#]=======================================================================]
+
+include(CMakeParseArguments) # cmake_parse_arguments
+
+# X_RESULT - name of the final result variable
+# X_OUTPUT - name of the variable with information about error
+macro(_ipo_not_supported output)
+  string(COMPARE EQUAL "${X_RESULT}" "" is_empty)
+  if(is_empty)
+    message(FATAL_ERROR "IPO is not supported (${output}).")
+  endif()
+
+  set("${X_RESULT}" NO PARENT_SCOPE)
+  set("${X_OUTPUT}" "${output}" PARENT_SCOPE)
+endmacro()
+
+# Run IPO/LTO test
+macro(_ipo_run_language_check language)
+  set(testdir "${CMAKE_CURRENT_BINARY_DIR}/_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
+  )
+
+  string(COMPARE EQUAL "${language}" "C" is_c)
+  string(COMPARE EQUAL "${language}" "CXX" is_cxx)
+
+  if(is_c)
+    set(copy_sources foo.c main.c)
+  elseif(is_cxx)
+    set(copy_sources foo.cpp main.cpp)
+  else()
+    message(FATAL_ERROR "Language not supported")
+  endif()
+
+  foreach(x ${copy_sources})
+    configure_file(
+        "${try_compile_src}/${x}"
+        "${srcdir}/${x}"
+        COPYONLY
+    )
+  endforeach()
+
+  try_compile(
+      result
+      "${bindir}"
+      "${srcdir}"
+      "${TRY_COMPILE_PROJECT_NAME}"
+      CMAKE_FLAGS
+      "-DCMAKE_VERBOSE_MAKEFILE=ON"
+      "-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON"
+      OUTPUT_VARIABLE output
+  )
+
+  if(NOT result)
+    _ipo_not_supported("${output}")
+    return()
+  endif()
+endmacro()
+
+function(check_ipo_supported)
+  # TODO: IPO policy
+
+  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 "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/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" "Fortran")
+    string(COMPARE NOTEQUAL "${unsupported_languages}" "" has_unsupported)
+    if(has_unsupported)
+      _ipo_not_supported(
+          "language(s) '${unsupported_languages}' not supported"
+      )
+      return()
+    endif()
+  endif()
+
+  list(FIND languages "Fortran" result)
+  if(NOT result EQUAL -1)
+    _ipo_not_supported("Fortran is not supported")
+    return()
+  endif()
+
+  if(NOT _CMAKE_IPO_SUPPORTED_BY_CMAKE)
+    _ipo_not_supported("CMake doesn't support IPO for current compiler")
+    return()
+  endif()
+
+  if(NOT _CMAKE_IPO_MAY_BE_SUPPORTED_BY_COMPILER)
+    _ipo_not_supported("compiler doesn't support IPO")
+    return()
+  endif()
+
+  foreach(x ${languages})
+    _ipo_run_language_check(${x})
+  endforeach()
+
+  set("${X_RESULT}" YES PARENT_SCOPE)
+endfunction()

+ 8 - 0
Modules/CheckIPOSupported/CMakeLists-C.txt.in

@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION "@CMAKE_VERSION@")
+project("@TRY_COMPILE_PROJECT_NAME@" LANGUAGES C)
+
+# TODO: IPO policy
+
+add_library(foo foo.c)
+add_executable(boo main.c)
+target_link_libraries(boo PUBLIC foo)

+ 8 - 0
Modules/CheckIPOSupported/CMakeLists-CXX.txt.in

@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION "@CMAKE_VERSION@")
+project("@TRY_COMPILE_PROJECT_NAME@" LANGUAGES CXX)
+
+# TODO: IPO policy
+
+add_library(foo foo.cpp)
+add_executable(boo main.cpp)
+target_link_libraries(boo PUBLIC foo)

+ 4 - 0
Modules/CheckIPOSupported/foo.c

@@ -0,0 +1,4 @@
+int foo()
+{
+  return 0x42;
+}

+ 4 - 0
Modules/CheckIPOSupported/foo.cpp

@@ -0,0 +1,4 @@
+int foo()
+{
+  return 0x42;
+}

+ 6 - 0
Modules/CheckIPOSupported/main.c

@@ -0,0 +1,6 @@
+int foo();
+
+int main()
+{
+  return foo();
+}

+ 6 - 0
Modules/CheckIPOSupported/main.cpp

@@ -0,0 +1,6 @@
+int foo();
+
+int main()
+{
+  return foo();
+}

+ 5 - 0
Modules/Platform/Linux-Intel.cmake

@@ -30,12 +30,17 @@ macro(__linux_compiler_intel lang)
   # executables that use dlopen but do not set ENABLE_EXPORTS.
   set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-rdynamic")
 
+  set(_CMAKE_IPO_SUPPORTED_BY_CMAKE YES)
+
   if(XIAR)
     # INTERPROCEDURAL_OPTIMIZATION
     set(CMAKE_${lang}_COMPILE_OPTIONS_IPO -ipo)
     set(CMAKE_${lang}_CREATE_STATIC_LIBRARY_IPO
       "${XIAR} cr <TARGET> <LINK_FLAGS> <OBJECTS> "
       "${XIAR} -s <TARGET> ")
+    set(_CMAKE_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES)
+  else()
+    set(_CMAKE_IPO_MAY_BE_SUPPORTED_BY_COMPILER NO)
   endif()
 
   if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 12.0)