Browse Source

Merge topic 'FindOpenACC'

d3b6f291 FindOpenACC: Add module to detect compiler support for OpenACC

Acked-by: Kitware Robot <[email protected]>
Merge-request: !1209
Brad King 8 years ago
parent
commit
10fb805987

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

@@ -153,6 +153,7 @@ All Modules
    /module/FindMPEG2
    /module/FindMPEG
    /module/FindMPI
+   /module/FindOpenACC
    /module/FindOpenAL
    /module/FindOpenCL
    /module/FindOpenGL

+ 1 - 0
Help/module/FindOpenACC.rst

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

+ 5 - 0
Help/release/dev/FindOpenACC.rst

@@ -0,0 +1,5 @@
+FindOpenACC
+-----------
+
+* A :module:`FindOpenACC` module was added to detect compiler support
+  for OpenACC.  Currently only supports PGI, GNU and Cray compilers.

+ 252 - 0
Modules/FindOpenACC.cmake

@@ -0,0 +1,252 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindOpenACC
+-----------
+
+Detect OpenACC support by the compiler.
+
+This module can be used to detect OpenACC support in a compiler.
+If the compiler supports OpenACC, the flags required to compile with
+OpenACC support are returned in variables for the different languages.
+Currently, only PGI, GNU and Cray compilers are supported.
+
+Variables
+^^^^^^^^^
+
+This module will set the following variables per language in your
+project, where ``<lang>`` is one of C, CXX, or Fortran:
+
+``OpenACC_<lang>_FOUND``
+  Variable indicating if OpenACC support for ``<lang>`` was detected.
+``OpenACC_<lang>_FLAGS``
+  OpenACC compiler flags for ``<lang>``, separated by spaces.
+
+The module will also try to provide the OpenACC version variables:
+
+``OpenACC_<lang>_SPEC_DATE``
+  Date of the OpenACC specification implemented by the ``<lang>`` compiler.
+``OpenACC_<lang>_VERSION_MAJOR``
+  Major version of OpenACC implemented by the ``<lang>`` compiler.
+``OpenACC_<lang>_VERSION_MINOR``
+  Minor version of OpenACC implemented by the ``<lang>`` compiler.
+``OpenACC_<lang>_VERSION``
+  OpenACC version implemented by the ``<lang>`` compiler.
+
+The specification date is formatted as given in the OpenACC standard:
+``yyyymm`` where ``yyyy`` and ``mm`` represents the year and month of
+the OpenACC specification implemented by the ``<lang>`` compiler.
+
+Input Variables
+^^^^^^^^^^^^^^^
+
+``OpenACC_ACCEL_TARGET=<target>``
+If set, will the correct target accelerator flag set to the <target> will
+be returned with OpenACC_<lang>_FLAGS.
+#]=======================================================================]
+
+set(OpenACC_C_CXX_TEST_SOURCE
+"
+int main(){
+#ifndef _OPENACC
+  breaks_on_purpose
+#endif
+}
+"
+)
+set(OpenACC_Fortran_TEST_SOURCE
+"
+program test
+#ifndef _OPENACC
+  breaks_on_purpose
+#endif
+endprogram test
+"
+)
+set(OpenACC_C_CXX_CHECK_VERSION_SOURCE
+"
+#include <stdio.h>
+const char accver_str[] = { 'I', 'N', 'F', 'O', ':', 'O', 'p', 'e', 'n', 'A',
+                            'C', 'C', '-', 'd', 'a', 't', 'e', '[',
+                            ('0' + ((_OPENACC/100000)%10)),
+                            ('0' + ((_OPENACC/10000)%10)),
+                            ('0' + ((_OPENACC/1000)%10)),
+                            ('0' + ((_OPENACC/100)%10)),
+                            ('0' + ((_OPENACC/10)%10)),
+                            ('0' + ((_OPENACC/1)%10)),
+                            ']', '\\0' };
+int main()
+{
+  puts(accver_str);
+}
+")
+set(OpenACC_Fortran_CHECK_VERSION_SOURCE
+"
+      program acc_ver
+      implicit none
+      integer, parameter :: zero = ichar('0')
+      character, dimension(25), parameter :: accver_str =&
+      (/ 'I', 'N', 'F', 'O', ':', 'O', 'p', 'e', 'n', 'A', 'C', 'C', '-',&
+         'd', 'a', 't', 'e', '[',&
+         char(zero + mod(_OPENACC/100000, 10)),&
+         char(zero + mod(_OPENACC/10000, 10)),&
+         char(zero + mod(_OPENACC/1000, 10)),&
+         char(zero + mod(_OPENACC/100, 10)),&
+         char(zero + mod(_OPENACC/10, 10)),&
+         char(zero + mod(_OPENACC/1, 10)), ']' /)
+      print *, accver_str
+      end program acc_ver
+"
+)
+
+
+function(_OPENACC_WRITE_SOURCE_FILE LANG SRC_FILE_CONTENT_VAR SRC_FILE_NAME SRC_FILE_FULLPATH)
+  set(WORK_DIR ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindOpenACC)
+  if("${LANG}" STREQUAL "C")
+    set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.c")
+    file(WRITE "${SRC_FILE}" "${OpenACC_C_CXX_${SRC_FILE_CONTENT_VAR}}")
+  elseif("${LANG}" STREQUAL "CXX")
+    set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.cpp")
+    file(WRITE "${SRC_FILE}" "${OpenACC_C_CXX_${SRC_FILE_CONTENT_VAR}}")
+  elseif("${LANG}" STREQUAL "Fortran")
+    set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.F90")
+    file(WRITE "${SRC_FILE}_in" "${OpenACC_Fortran_${SRC_FILE_CONTENT_VAR}}")
+    configure_file("${SRC_FILE}_in" "${SRC_FILE}" @ONLY)
+  endif()
+  set(${SRC_FILE_FULLPATH} "${SRC_FILE}" PARENT_SCOPE)
+endfunction()
+
+
+function(_OPENACC_GET_FLAGS_CANDIDATE LANG FLAG_VAR)
+  set(ACC_FLAG_PGI "-acc")
+  set(ACC_FLAG_GNU "-fopenacc")
+  set(ACC_FLAG_Cray "-h acc")
+
+  if(DEFINED ACC_FLAG_${CMAKE_${LANG}_COMPILER_ID})
+    set("${FLAG_VAR}" "${ACC_FLAG_${CMAKE_${LANG}_COMPILER_ID}}" PARENT_SCOPE)
+  else()
+    # Fall back to a few common flags.
+    set("${FLAG_VAR}" ${ACC_FLAG_GNU} ${ACC_FLAG_PGI})
+  endif()
+
+endfunction()
+
+
+function(_OPENACC_GET_ACCEL_TARGET_FLAG LANG TARGET FLAG_VAR)
+  # Find target accelerator flags.
+  set(ACC_TARGET_FLAG_PGI "-ta")
+  if(DEFINED ACC_TARGET_FLAG_${CMAKE_${LANG}_COMPILER_ID})
+    set("${FLAG_VAR}" "${ACC_TARGET_FLAG_${CMAKE_${LANG}_COMPILER_ID}}=${TARGET}" PARENT_SCOPE)
+  endif()
+endfunction()
+
+
+function(_OPENACC_GET_VERBOSE_FLAG LANG FLAG_VAR)
+  # Find compiler's verbose flag for OpenACC.
+  set(ACC_VERBOSE_FLAG_PGI "-Minfo=accel")
+  if(DEFINED ACC_VERBOSE_FLAG_${CMAKE_${LANG}_COMPILER_ID})
+    set("${FLAG_VAR}" "${ACC_VERBOSE_FLAG_${CMAKE_${LANG}_COMPILER_ID}}" PARENT_SCOPE)
+  endif()
+endfunction()
+
+
+function(_OPENACC_GET_FLAGS LANG FLAG_VAR)
+  set(FLAG_CANDIDATES "")
+  _OPENACC_GET_FLAGS_CANDIDATE("${LANG}" FLAG_CANDIDATES)
+  _OPENACC_WRITE_SOURCE_FILE("${LANG}" "TEST_SOURCE" OpenACCTryFlag _OPENACC_TEST_SRC)
+
+  foreach(FLAG IN LISTS FLAG_CANDIDATES)
+    try_compile(OpenACC_FLAG_TEST_RESULT ${CMAKE_BINARY_DIR} ${_OPENACC_TEST_SRC}
+      CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${FLAG}"
+      OUTPUT_VARIABLE OpenACC_TRY_COMPILE_OUTPUT
+    )
+    if(OpenACC_FLAG_TEST_RESULT)
+      set("${FLAG_VAR}" "${FLAG}")
+      if(DEFINED OpenACC_ACCEL_TARGET)
+        _OPENACC_GET_ACCEL_TARGET_FLAG("${LANG}" "${OpenACC_ACCEL_TARGET}" TARGET_FLAG)
+        string(APPEND "${FLAG_VAR}" " ${TARGET_FLAG}")
+      endif()
+
+      if(CMAKE_VERBOSE_MAKEFILE)
+        # -Minfo=accel prints out OpenACC's messages on optimizations.
+        _OPENACC_GET_VERBOSE_FLAG("${LANG}" OpenACC_VERBOSE_FLAG)
+        string(APPEND "${FLAG_VAR}" " ${OpenACC_VERBOSE_FLAG}")
+      endif()
+      set("${FLAG_VAR}" "${${FLAG_VAR}}" PARENT_SCOPE)
+      break()
+    endif()
+  endforeach()
+
+endfunction()
+
+
+function(_OPENACC_GET_SPEC_DATE LANG SPEC_DATE)
+  _OPENACC_WRITE_SOURCE_FILE("${LANG}" "CHECK_VERSION_SOURCE" OpenACCCheckVersion _OPENACC_TEST_SRC)
+
+  set(BIN_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindOpenACC/accver_${LANG}.bin")
+  try_compile(OpenACC_SPECTEST_${LANG} "${CMAKE_BINARY_DIR}" "${_OPENACC_TEST_SRC}"
+              CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OpenACC_${LANG}_FLAGS}"
+              COPY_FILE ${BIN_FILE}
+              OUTPUT_VARIABLE OUTPUT)
+
+  if(${OpenACC_SPECTEST_${LANG}})
+    file(STRINGS ${BIN_FILE} specstr LIMIT_COUNT 1 REGEX "INFO:OpenACC-date")
+    set(regex_spec_date ".*INFO:OpenACC-date\\[0*([^]]*)\\].*")
+    if("${specstr}" MATCHES "${regex_spec_date}")
+      set(${SPEC_DATE} "${CMAKE_MATCH_1}" PARENT_SCOPE)
+    endif()
+  endif()
+endfunction()
+
+
+macro(_OPENACC_SET_VERSION_BY_SPEC_DATE LANG)
+  set(OpenACC_SPEC_DATE_MAP
+    # Combined versions, 2.5 onwards
+    "201510=2.5"
+    # 2013 08 is the corrected version.
+    "201308=2.0"
+    "201306=2.0"
+    "201111=1.0"
+  )
+
+  string(REGEX MATCHALL "${OpenACC_${LANG}_SPEC_DATE}=([0-9]+)\\.([0-9]+)" _version_match "${OpenACC_SPEC_DATE_MAP}")
+  if(NOT _version_match STREQUAL "")
+    set(OpenACC_${LANG}_VERSION_MAJOR ${CMAKE_MATCH_1})
+    set(OpenACC_${LANG}_VERSION_MINOR ${CMAKE_MATCH_2})
+    set(OpenACC_${LANG}_VERSION "${OpenACC_${LANG}_VERSION_MAJOR}.${OpenACC_${LANG}_VERSION_MINOR}")
+  else()
+    unset(OpenACC_${LANG}_VERSION_MAJOR)
+    unset(OpenACC_${LANG}_VERSION_MINOR)
+    unset(OpenACC_${LANG}_VERSION)
+  endif()
+  unset(_version_match)
+  unset(OpenACC_SPEC_DATE_MAP)
+endmacro()
+
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+foreach (LANG IN ITEMS C CXX Fortran)
+  if(CMAKE_${LANG}_COMPILER_LOADED)
+    set(OpenACC_${LANG}_FIND_QUIETLY ${OpenACC_FIND_QUIETLY})
+    set(OpenACC_${LANG}_FIND_REQUIRED ${OpenACC_FIND_REQUIRED})
+    set(OpenACC_${LANG}_FIND_VERSION ${OpenACC_FIND_VERSION})
+    set(OpenACC_${LANG}_FIND_VERSION_EXACT ${OpenACC_FIND_VERSION_EXACT})
+
+    if(NOT DEFINED OpenACC_${LANG}_FLAGS)
+      _OPENACC_GET_FLAGS("${LANG}" OpenACC_${LANG}_FLAGS)
+    endif()
+    _OPENACC_GET_SPEC_DATE("${LANG}" OpenACC_${LANG}_SPEC_DATE)
+    _OPENACC_SET_VERSION_BY_SPEC_DATE("${LANG}")
+
+    find_package_handle_standard_args(OpenACC_${LANG}
+      REQUIRED_VARS OpenACC_${LANG}_FLAGS
+      VERSION_VAR OpenACC_${LANG}_VERSION
+    )
+  endif()
+endforeach()
+
+unset(OpenACC_C_CXX_TEST_SOURCE)
+unset(OpenACC_Fortran_TEST_SOURCE)
+unset(OpenACC_C_CXX_CHECK_VERSION_SOURCE)
+unset(OpenACC_Fortran_CHECK_VERSION_SOURCE)