Imported Upstream version 3.25.0
[platform/upstream/cmake.git] / Modules / FindOpenACC.cmake
1 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2 # file Copyright.txt or https://cmake.org/licensing for details.
3
4 #[=======================================================================[.rst:
5 FindOpenACC
6 -----------
7
8 .. versionadded:: 3.10
9
10 Detect OpenACC support by the compiler.
11
12 This module can be used to detect OpenACC support in a compiler.
13 If the compiler supports OpenACC, the flags required to compile with
14 OpenACC support are returned in variables for the different languages.
15 Currently, only NVHPC, PGI, GNU and Cray compilers are supported.
16
17 Imported Targets
18 ^^^^^^^^^^^^^^^^
19
20 .. versionadded:: 3.16
21
22 The module provides :prop_tgt:`IMPORTED` targets:
23
24 ``OpenACC::OpenACC_<lang>``
25   Target for using OpenACC from ``<lang>``.
26
27 Variables
28 ^^^^^^^^^
29
30 The module defines the following variables:
31
32 ``OpenACC_FOUND``
33   .. versionadded:: 3.25
34
35   Variable indicating that OpenACC flags for at least one languages have been found.
36
37 This module will set the following variables per language in your
38 project, where ``<lang>`` is one of C, CXX, or Fortran:
39
40 ``OpenACC_<lang>_FOUND``
41   Variable indicating if OpenACC support for ``<lang>`` was detected.
42 ``OpenACC_<lang>_FLAGS``
43   OpenACC compiler flags for ``<lang>``, separated by spaces.
44 ``OpenACC_<lang>_OPTIONS``
45   .. versionadded:: 3.16
46
47   OpenACC compiler flags for ``<lang>``, as a list. Suitable for usage
48   with target_compile_options or target_link_options.
49
50 The module will also try to provide the OpenACC version variables:
51
52 ``OpenACC_<lang>_SPEC_DATE``
53   Date of the OpenACC specification implemented by the ``<lang>`` compiler.
54 ``OpenACC_<lang>_VERSION_MAJOR``
55   Major version of OpenACC implemented by the ``<lang>`` compiler.
56 ``OpenACC_<lang>_VERSION_MINOR``
57   Minor version of OpenACC implemented by the ``<lang>`` compiler.
58 ``OpenACC_<lang>_VERSION``
59   OpenACC version implemented by the ``<lang>`` compiler.
60
61 The specification date is formatted as given in the OpenACC standard:
62 ``yyyymm`` where ``yyyy`` and ``mm`` represents the year and month of
63 the OpenACC specification implemented by the ``<lang>`` compiler.
64
65 Input Variables
66 ^^^^^^^^^^^^^^^
67
68 ``OpenACC_ACCEL_TARGET=<target>``
69 If set, will the correct target accelerator flag set to the <target> will
70 be returned with OpenACC_<lang>_FLAGS.
71 #]=======================================================================]
72
73 set(OpenACC_C_CXX_TEST_SOURCE
74 "
75 int main(){
76 #ifdef _OPENACC
77   return 0;
78 #else
79   breaks_on_purpose
80 #endif
81 }
82 "
83 )
84 set(OpenACC_Fortran_TEST_SOURCE
85 "
86 program test
87 #ifndef _OPENACC
88   breaks_on_purpose
89 #endif
90 endprogram test
91 "
92 )
93 set(OpenACC_C_CXX_CHECK_VERSION_SOURCE
94 "
95 #include <stdio.h>
96 const char accver_str[] = { 'I', 'N', 'F', 'O', ':', 'O', 'p', 'e', 'n', 'A',
97                             'C', 'C', '-', 'd', 'a', 't', 'e', '[',
98                             ('0' + ((_OPENACC/100000)%10)),
99                             ('0' + ((_OPENACC/10000)%10)),
100                             ('0' + ((_OPENACC/1000)%10)),
101                             ('0' + ((_OPENACC/100)%10)),
102                             ('0' + ((_OPENACC/10)%10)),
103                             ('0' + ((_OPENACC/1)%10)),
104                             ']', '\\0' };
105 int main()
106 {
107   puts(accver_str);
108   return 0;
109 }
110 ")
111 set(OpenACC_Fortran_CHECK_VERSION_SOURCE
112 "
113       program acc_ver
114       implicit none
115       integer, parameter :: zero = ichar('0')
116       character, dimension(25), parameter :: accver_str =&
117       (/ 'I', 'N', 'F', 'O', ':', 'O', 'p', 'e', 'n', 'A', 'C', 'C', '-',&
118          'd', 'a', 't', 'e', '[',&
119          char(zero + mod(_OPENACC/100000, 10)),&
120          char(zero + mod(_OPENACC/10000, 10)),&
121          char(zero + mod(_OPENACC/1000, 10)),&
122          char(zero + mod(_OPENACC/100, 10)),&
123          char(zero + mod(_OPENACC/10, 10)),&
124          char(zero + mod(_OPENACC/1, 10)), ']' /)
125       print *, accver_str
126       end program acc_ver
127 "
128 )
129
130
131 macro(_OPENACC_PREPARE_SOURCE LANG CONTENT_ID NAME_PREFIX FULLNAME_VAR CONTENT_VAR)
132   if("${LANG}" STREQUAL "C")
133     set(${FULLNAME_VAR} "${NAME_PREFIX}.c")
134     set(${CONTENT_VAR} "${OpenACC_C_CXX_${CONTENT_ID}}")
135   elseif("${LANG}" STREQUAL "CXX")
136     set(${FULLNAME_VAR} "${NAME_PREFIX}.cpp")
137     set(${CONTENT_VAR} "${OpenACC_C_CXX_${CONTENT_ID}}")
138   elseif("${LANG}" STREQUAL "Fortran")
139     set(${FULLNAME_VAR} "${NAME_PREFIX}.F90")
140     set(${CONTENT_VAR} "${OpenACC_Fortran_${CONTENT_ID}}")
141   endif()
142 endmacro()
143
144
145 function(_OPENACC_GET_FLAGS_CANDIDATE LANG FLAG_VAR)
146   set(ACC_FLAG_NVHPC "-acc")
147   set(ACC_FLAG_PGI "-acc")
148   set(ACC_FLAG_GNU "-fopenacc")
149   set(ACC_FLAG_Cray "-h acc")
150
151   if(DEFINED ACC_FLAG_${CMAKE_${LANG}_COMPILER_ID})
152     set("${FLAG_VAR}" "${ACC_FLAG_${CMAKE_${LANG}_COMPILER_ID}}" PARENT_SCOPE)
153   else()
154     # Fall back to a few common flags.
155     set("${FLAG_VAR}" ${ACC_FLAG_GNU} ${ACC_FLAG_PGI})
156   endif()
157
158 endfunction()
159
160
161 function(_OPENACC_GET_ACCEL_TARGET_FLAG LANG TARGET FLAG_VAR)
162   # Find target accelerator flags.
163   set(ACC_TARGET_FLAG_NVHPC "-ta")
164   set(ACC_TARGET_FLAG_PGI "-ta")
165   if(DEFINED ACC_TARGET_FLAG_${CMAKE_${LANG}_COMPILER_ID})
166     set("${FLAG_VAR}" "${ACC_TARGET_FLAG_${CMAKE_${LANG}_COMPILER_ID}}=${TARGET}" PARENT_SCOPE)
167   endif()
168 endfunction()
169
170
171 function(_OPENACC_GET_VERBOSE_FLAG LANG FLAG_VAR)
172   # Find compiler's verbose flag for OpenACC.
173   set(ACC_VERBOSE_FLAG_NVHPC "-Minfo=accel")
174   set(ACC_VERBOSE_FLAG_PGI "-Minfo=accel")
175   if(DEFINED ACC_VERBOSE_FLAG_${CMAKE_${LANG}_COMPILER_ID})
176     set("${FLAG_VAR}" "${ACC_VERBOSE_FLAG_${CMAKE_${LANG}_COMPILER_ID}}" PARENT_SCOPE)
177   endif()
178 endfunction()
179
180
181 function(_OPENACC_GET_FLAGS LANG FLAG_VAR)
182   set(FLAG_CANDIDATES "")
183   _OPENACC_GET_FLAGS_CANDIDATE("${LANG}" FLAG_CANDIDATES)
184   _OPENACC_PREPARE_SOURCE("${LANG}" TEST_SOURCE OpenACCTryFlag
185     _OPENACC_TEST_SRC_NAME _OPENACC_TEST_SRC_CONTENT)
186
187   foreach(FLAG IN LISTS FLAG_CANDIDATES)
188     try_compile(OpenACC_FLAG_TEST_RESULT
189       SOURCE_FROM_VAR "${_OPENACC_TEST_SRC_NAME}" _OPENACC_TEST_SRC_CONTENT
190       CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${FLAG}"
191       OUTPUT_VARIABLE OpenACC_TRY_COMPILE_OUTPUT
192     )
193     if(OpenACC_FLAG_TEST_RESULT)
194       set("${FLAG_VAR}" "${FLAG}")
195       if(DEFINED OpenACC_ACCEL_TARGET)
196         _OPENACC_GET_ACCEL_TARGET_FLAG("${LANG}" "${OpenACC_ACCEL_TARGET}" TARGET_FLAG)
197         string(APPEND "${FLAG_VAR}" " ${TARGET_FLAG}")
198       endif()
199
200       if(CMAKE_VERBOSE_MAKEFILE)
201         # -Minfo=accel prints out OpenACC's messages on optimizations.
202         _OPENACC_GET_VERBOSE_FLAG("${LANG}" OpenACC_VERBOSE_FLAG)
203         string(APPEND "${FLAG_VAR}" " ${OpenACC_VERBOSE_FLAG}")
204       endif()
205       set("${FLAG_VAR}" "${${FLAG_VAR}}" PARENT_SCOPE)
206       break()
207     endif()
208   endforeach()
209
210 endfunction()
211
212
213 function(_OPENACC_GET_SPEC_DATE LANG SPEC_DATE)
214   _OPENACC_PREPARE_SOURCE(${LANG} CHECK_VERSION_SOURCE OpenACCCheckVersion
215     _OPENACC_TEST_SRC_NAME _OPENACC_TEST_SRC_CONTENT)
216
217   set(BIN_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindOpenACC/accver_${LANG}.bin")
218   try_compile(OpenACC_SPECTEST_${LANG}
219     SOURCE_FROM_VAR "${_OPENACC_TEST_SRC_NAME}" _OPENACC_TEST_SRC_CONTENT
220     CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OpenACC_${LANG}_FLAGS}"
221     COPY_FILE "${BIN_FILE}"
222     OUTPUT_VARIABLE OUTPUT)
223
224   if(${OpenACC_SPECTEST_${LANG}})
225     file(STRINGS ${BIN_FILE} specstr LIMIT_COUNT 1 REGEX "INFO:OpenACC-date")
226     set(regex_spec_date ".*INFO:OpenACC-date\\[0*([^]]*)\\].*")
227     if("${specstr}" MATCHES "${regex_spec_date}")
228       set(${SPEC_DATE} "${CMAKE_MATCH_1}" PARENT_SCOPE)
229     endif()
230   endif()
231 endfunction()
232
233
234 macro(_OPENACC_SET_VERSION_BY_SPEC_DATE LANG)
235   set(OpenACC_SPEC_DATE_MAP
236     # Combined versions, 2.5 onwards
237     "201510=2.5"
238     # 2013 08 is the corrected version.
239     "201308=2.0"
240     "201306=2.0"
241     "201111=1.0"
242   )
243
244   string(REGEX MATCHALL "${OpenACC_${LANG}_SPEC_DATE}=([0-9]+)\\.([0-9]+)" _version_match "${OpenACC_SPEC_DATE_MAP}")
245   if(NOT _version_match STREQUAL "")
246     set(OpenACC_${LANG}_VERSION_MAJOR ${CMAKE_MATCH_1})
247     set(OpenACC_${LANG}_VERSION_MINOR ${CMAKE_MATCH_2})
248     set(OpenACC_${LANG}_VERSION "${OpenACC_${LANG}_VERSION_MAJOR}.${OpenACC_${LANG}_VERSION_MINOR}")
249   else()
250     unset(OpenACC_${LANG}_VERSION_MAJOR)
251     unset(OpenACC_${LANG}_VERSION_MINOR)
252     unset(OpenACC_${LANG}_VERSION)
253   endif()
254   unset(_version_match)
255   unset(OpenACC_SPEC_DATE_MAP)
256 endmacro()
257
258
259 include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
260 foreach (LANG IN ITEMS C CXX Fortran)
261   if(CMAKE_${LANG}_COMPILER_LOADED)
262     set(OpenACC_${LANG}_FIND_QUIETLY ${OpenACC_FIND_QUIETLY})
263     set(OpenACC_${LANG}_FIND_REQUIRED ${OpenACC_FIND_REQUIRED})
264     set(OpenACC_${LANG}_FIND_VERSION ${OpenACC_FIND_VERSION})
265     set(OpenACC_${LANG}_FIND_VERSION_EXACT ${OpenACC_FIND_VERSION_EXACT})
266
267     if(NOT DEFINED OpenACC_${LANG}_FLAGS)
268       _OPENACC_GET_FLAGS("${LANG}" OpenACC_${LANG}_FLAGS)
269     endif()
270     if(NOT DEFINED OpenACC_${LANG}_OPTIONS)
271       separate_arguments(OpenACC_${LANG}_OPTIONS NATIVE_COMMAND "${OpenACC_${LANG}_FLAGS}")
272     endif()
273     _OPENACC_GET_SPEC_DATE("${LANG}" OpenACC_${LANG}_SPEC_DATE)
274     _OPENACC_SET_VERSION_BY_SPEC_DATE("${LANG}")
275
276     find_package_handle_standard_args(OpenACC_${LANG}
277       NAME_MISMATCHED
278       REQUIRED_VARS OpenACC_${LANG}_FLAGS
279       VERSION_VAR OpenACC_${LANG}_VERSION
280     )
281     if(OpenACC_${LANG}_FOUND)
282       set(OpenACC_FOUND TRUE)
283     endif()
284   endif()
285 endforeach()
286
287 foreach (LANG IN ITEMS C CXX Fortran)
288   if(OpenACC_${LANG}_FOUND AND NOT TARGET OpenACC::OpenACC_${LANG})
289     add_library(OpenACC::OpenACC_${LANG} INTERFACE IMPORTED)
290   endif()
291   if(OpenACC_${LANG}_LIBRARIES)
292     set_property(TARGET OpenACC::OpenACC_${LANG} PROPERTY
293       INTERFACE_LINK_LIBRARIES "${OpenACC_${LANG}_LIBRARIES}")
294   endif()
295   if(OpenACC_${LANG}_FLAGS)
296     set_property(TARGET OpenACC::OpenACC_${LANG} PROPERTY
297       INTERFACE_COMPILE_OPTIONS "$<$<COMPILE_LANGUAGE:${LANG}>:${OpenACC_${LANG}_OPTIONS}>")
298     set_property(TARGET OpenACC::OpenACC_${LANG} PROPERTY
299       INTERFACE_LINK_OPTIONS "$<$<COMPILE_LANGUAGE:${LANG}>:${OpenACC_${LANG}_OPTIONS}>")
300     unset(_OpenACC_${LANG}_OPTIONS)
301   endif()
302 endforeach()
303
304 unset(OpenACC_C_CXX_TEST_SOURCE)
305 unset(OpenACC_Fortran_TEST_SOURCE)
306 unset(OpenACC_C_CXX_CHECK_VERSION_SOURCE)
307 unset(OpenACC_Fortran_CHECK_VERSION_SOURCE)