Imported Upstream version 3.25.0
[platform/upstream/cmake.git] / Modules / FindOpenMP.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 FindOpenMP
6 ----------
7
8 Finds Open Multi-Processing (OpenMP) support.
9
10 This module can be used to detect OpenMP support in a compiler.  If
11 the compiler supports OpenMP, the flags required to compile with
12 OpenMP support are returned in variables for the different languages.
13 The variables may be empty if the compiler does not need a special
14 flag to support OpenMP.
15
16 .. versionadded:: 3.5
17   Clang support.
18
19 Variables
20 ^^^^^^^^^
21
22 .. versionadded:: 3.10
23   The module exposes the components ``C``, ``CXX``, and ``Fortran``.
24   Each of these controls the various languages to search OpenMP support for.
25
26 Depending on the enabled components the following variables will be set:
27
28 ``OpenMP_FOUND``
29   Variable indicating that OpenMP flags for all requested languages have been found.
30   If no components are specified, this is true if OpenMP settings for all enabled languages
31   were detected.
32 ``OpenMP_VERSION``
33   Minimal version of the OpenMP standard detected among the requested languages,
34   or all enabled languages if no components were specified.
35
36 This module will set the following variables per language in your
37 project, where ``<lang>`` is one of C, CXX, or Fortran:
38
39 ``OpenMP_<lang>_FOUND``
40   Variable indicating if OpenMP support for ``<lang>`` was detected.
41 ``OpenMP_<lang>_FLAGS``
42   OpenMP compiler flags for ``<lang>``, separated by spaces.
43 ``OpenMP_<lang>_INCLUDE_DIRS``
44   Directories that must be added to the header search path for ``<lang>``
45   when using OpenMP.
46
47 For linking with OpenMP code written in ``<lang>``, the following
48 variables are provided:
49
50 ``OpenMP_<lang>_LIB_NAMES``
51   :ref:`;-list <CMake Language Lists>` of libraries for OpenMP programs for ``<lang>``.
52 ``OpenMP_<libname>_LIBRARY``
53   Location of the individual libraries needed for OpenMP support in ``<lang>``.
54 ``OpenMP_<lang>_LIBRARIES``
55   A list of libraries needed to link with OpenMP code written in ``<lang>``.
56
57 Additionally, the module provides :prop_tgt:`IMPORTED` targets:
58
59 ``OpenMP::OpenMP_<lang>``
60   Target for using OpenMP from ``<lang>``.
61
62 Specifically for Fortran, the module sets the following variables:
63
64 ``OpenMP_Fortran_HAVE_OMPLIB_HEADER``
65   Boolean indicating if OpenMP is accessible through ``omp_lib.h``.
66 ``OpenMP_Fortran_HAVE_OMPLIB_MODULE``
67   Boolean indicating if OpenMP is accessible through the ``omp_lib`` Fortran module.
68
69 The module will also try to provide the OpenMP version variables:
70
71 ``OpenMP_<lang>_SPEC_DATE``
72   .. versionadded:: 3.7
73
74   Date of the OpenMP specification implemented by the ``<lang>`` compiler.
75 ``OpenMP_<lang>_VERSION_MAJOR``
76   Major version of OpenMP implemented by the ``<lang>`` compiler.
77 ``OpenMP_<lang>_VERSION_MINOR``
78   Minor version of OpenMP implemented by the ``<lang>`` compiler.
79 ``OpenMP_<lang>_VERSION``
80   OpenMP version implemented by the ``<lang>`` compiler.
81
82 The specification date is formatted as given in the OpenMP standard:
83 ``yyyymm`` where ``yyyy`` and ``mm`` represents the year and month of
84 the OpenMP specification implemented by the ``<lang>`` compiler.
85
86 For some compilers, it may be necessary to add a header search path to find
87 the relevant OpenMP headers.  This location may be language-specific.  Where
88 this is needed, the module may attempt to find the location, but it can be
89 provided directly by setting the ``OpenMP_<lang>_INCLUDE_DIR`` cache variable.
90 Note that this variable is an _input_ control to the module.  Project code
91 should use the ``OpenMP_<lang>_INCLUDE_DIRS`` _output_ variable if it needs
92 to know what include directories are needed.
93 #]=======================================================================]
94
95 cmake_policy(PUSH)
96 cmake_policy(SET CMP0012 NEW) # if() recognizes numbers and booleans
97 cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced
98 cmake_policy(SET CMP0057 NEW) # if IN_LIST
99
100 function(_OPENMP_FLAG_CANDIDATES LANG)
101   if(NOT OpenMP_${LANG}_FLAG)
102     unset(OpenMP_FLAG_CANDIDATES)
103
104     set(OMP_FLAG_GNU "-fopenmp")
105     set(OMP_FLAG_LCC "-fopenmp")
106     set(OMP_FLAG_Clang "-fopenmp=libomp" "-fopenmp=libiomp5" "-fopenmp" "-Xclang -fopenmp")
107     set(OMP_FLAG_AppleClang "-Xclang -fopenmp")
108     set(OMP_FLAG_HP "+Oopenmp")
109     if(WIN32)
110       set(OMP_FLAG_Intel "-Qopenmp")
111     elseif(CMAKE_${LANG}_COMPILER_ID STREQUAL "Intel" AND
112            "${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS "15.0.0.20140528")
113       set(OMP_FLAG_Intel "-openmp")
114     else()
115       set(OMP_FLAG_Intel "-qopenmp")
116     endif()
117     if(CMAKE_${LANG}_COMPILER_ID STREQUAL "IntelLLVM" AND
118       "x${CMAKE_${LANG}_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
119       set(OMP_FLAG_IntelLLVM "-Qiopenmp")
120     else()
121       set(OMP_FLAG_IntelLLVM "-fiopenmp")
122     endif()
123     set(OMP_FLAG_MSVC "-openmp")
124     set(OMP_FLAG_PathScale "-openmp")
125     set(OMP_FLAG_NAG "-openmp")
126     set(OMP_FLAG_Absoft "-openmp")
127     set(OMP_FLAG_NVHPC "-mp")
128     set(OMP_FLAG_PGI "-mp")
129     set(OMP_FLAG_Flang "-fopenmp")
130     set(OMP_FLAG_SunPro "-xopenmp")
131     set(OMP_FLAG_XL "-qsmp=omp")
132     # Cray compiler activate OpenMP with -h omp, which is enabled by default.
133     set(OMP_FLAG_Cray " " "-h omp")
134     set(OMP_FLAG_Fujitsu "-Kopenmp" "-KOMP")
135     set(OMP_FLAG_FujitsuClang "-fopenmp" "-Kopenmp")
136
137     # If we know the correct flags, use those
138     if(DEFINED OMP_FLAG_${CMAKE_${LANG}_COMPILER_ID})
139       set(OpenMP_FLAG_CANDIDATES "${OMP_FLAG_${CMAKE_${LANG}_COMPILER_ID}}")
140     # Fall back to reasonable default tries otherwise
141     else()
142       set(OpenMP_FLAG_CANDIDATES "-openmp" "-fopenmp" "-mp" " ")
143     endif()
144     set(OpenMP_${LANG}_FLAG_CANDIDATES "${OpenMP_FLAG_CANDIDATES}" PARENT_SCOPE)
145   else()
146     set(OpenMP_${LANG}_FLAG_CANDIDATES "${OpenMP_${LANG}_FLAG}" PARENT_SCOPE)
147   endif()
148 endfunction()
149
150 # sample openmp source code to test
151 set(OpenMP_C_CXX_TEST_SOURCE
152 "
153 #include <omp.h>
154 int main(void) {
155 #ifdef _OPENMP
156   omp_get_max_threads();
157   return 0;
158 #elif defined(__HIP_DEVICE_COMPILE__)
159   return 0;
160 #else
161   breaks_on_purpose
162 #endif
163 }
164 ")
165
166 # in Fortran, an implementation may provide an omp_lib.h header
167 # or omp_lib module, or both (OpenMP standard, section 3.1)
168 # Furthmore !$ is the Fortran equivalent of #ifdef _OPENMP (OpenMP standard, 2.2.2)
169 # Without the conditional compilation, some compilers (e.g. PGI) might compile OpenMP code
170 # while not actually enabling OpenMP, building code sequentially
171 set(OpenMP_Fortran_TEST_SOURCE
172   "
173       program test
174       @OpenMP_Fortran_INCLUDE_LINE@
175   !$  integer :: n
176       n = omp_get_num_threads()
177       end program test
178   "
179 )
180
181 macro(_OPENMP_PREPARE_SOURCE LANG CONTENT_ID NAME_PREFIX FULLNAME_VAR CONTENT_VAR)
182   if("${LANG}" STREQUAL "C")
183     set(${FULLNAME_VAR} "${NAME_PREFIX}.c")
184     set(${CONTENT_VAR} "${OpenMP_C_CXX_${CONTENT_ID}}")
185   elseif("${LANG}" STREQUAL "CXX")
186     set(${FULLNAME_VAR} "${NAME_PREFIX}.cpp")
187     set(${CONTENT_VAR} "${OpenMP_C_CXX_${CONTENT_ID}}")
188   elseif("${LANG}" STREQUAL "Fortran")
189     set(${FULLNAME_VAR} "${NAME_PREFIX}.F90")
190     string(CONFIGURE "${OpenMP_Fortran_${CONTENT_ID}}" ${CONTENT_VAR} @ONLY)
191   endif()
192 endmacro()
193
194 include(${CMAKE_CURRENT_LIST_DIR}/CMakeParseImplicitLinkInfo.cmake)
195
196 function(_OPENMP_GET_FLAGS LANG FLAG_MODE OPENMP_FLAG_VAR OPENMP_LIB_NAMES_VAR)
197   _OPENMP_FLAG_CANDIDATES("${LANG}")
198   _OPENMP_PREPARE_SOURCE("${LANG}" TEST_SOURCE OpenMPTryFlag
199     _OPENMP_TEST_SRC_NAME _OPENMP_TEST_SRC_CONTENT)
200
201   unset(OpenMP_VERBOSE_COMPILE_OPTIONS)
202   separate_arguments(OpenMP_VERBOSE_OPTIONS NATIVE_COMMAND "${CMAKE_${LANG}_VERBOSE_FLAG}")
203   foreach(_VERBOSE_OPTION IN LISTS OpenMP_VERBOSE_OPTIONS)
204     if(NOT _VERBOSE_OPTION MATCHES "^-Wl,")
205       list(APPEND OpenMP_VERBOSE_COMPILE_OPTIONS ${_VERBOSE_OPTION})
206     endif()
207   endforeach()
208
209   foreach(OPENMP_FLAG IN LISTS OpenMP_${LANG}_FLAG_CANDIDATES)
210     set(OPENMP_FLAGS_TEST "${OPENMP_FLAG}")
211     if(OpenMP_VERBOSE_COMPILE_OPTIONS)
212       string(APPEND OPENMP_FLAGS_TEST " ${OpenMP_VERBOSE_COMPILE_OPTIONS}")
213     endif()
214     string(REGEX REPLACE "[-/=+]" "" OPENMP_PLAIN_FLAG "${OPENMP_FLAG}")
215     try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG}
216       SOURCE_FROM_VAR "${_OPENMP_TEST_SRC_NAME}" _OPENMP_TEST_SRC_CONTENT
217       CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}"
218       LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG}
219       OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT
220     )
221
222     if(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG})
223       set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG}" PARENT_SCOPE)
224
225       if(CMAKE_${LANG}_VERBOSE_FLAG)
226         unset(OpenMP_${LANG}_IMPLICIT_LIBRARIES)
227         unset(OpenMP_${LANG}_IMPLICIT_LINK_DIRS)
228         unset(OpenMP_${LANG}_IMPLICIT_FWK_DIRS)
229         unset(OpenMP_${LANG}_LOG_VAR)
230
231         file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
232         "Detecting ${LANG} OpenMP compiler ABI info compiled with the following output:\n${OpenMP_TRY_COMPILE_OUTPUT}\n\n")
233
234         cmake_parse_implicit_link_info("${OpenMP_TRY_COMPILE_OUTPUT}"
235           OpenMP_${LANG}_IMPLICIT_LIBRARIES
236           OpenMP_${LANG}_IMPLICIT_LINK_DIRS
237           OpenMP_${LANG}_IMPLICIT_FWK_DIRS
238           OpenMP_${LANG}_LOG_VAR
239           "${CMAKE_${LANG}_IMPLICIT_OBJECT_REGEX}"
240           LANGUAGE ${LANG}
241         )
242
243         file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
244         "Parsed ${LANG} OpenMP implicit link information from above output:\n${OpenMP_${LANG}_LOG_VAR}\n\n")
245
246         # For LCC we should additionally alanyze -print-search-dirs output
247         # to check for additional implicit_dirs.
248         # Note: This won't work if CMP0129 policy is set to OLD!
249         if("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "LCC")
250           execute_process(
251             COMMAND ${CMAKE_${LANG}_COMPILER} -print-search-dirs
252             OUTPUT_VARIABLE output_lines
253             COMMAND_ERROR_IS_FATAL ANY
254             ERROR_QUIET)
255           if("${output_lines}" MATCHES ".*\nlibraries:[ \t]+(.*:)\n.*")
256             string(REPLACE ":" ";" implicit_dirs_addon "${CMAKE_MATCH_1}")
257             list(PREPEND OpenMP_${LANG}_IMPLICIT_LINK_DIRS ${implicit_dirs_addon})
258             file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
259               "  Extended OpenMP library search paths: [${implicit_dirs}]\n")
260           endif()
261         endif()
262
263         unset(_OPENMP_LIB_NAMES)
264         foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_IMPLICIT_LIBRARIES)
265           get_filename_component(_OPENMP_IMPLICIT_LIB_DIR "${_OPENMP_IMPLICIT_LIB}" DIRECTORY)
266           get_filename_component(_OPENMP_IMPLICIT_LIB_NAME "${_OPENMP_IMPLICIT_LIB}" NAME)
267           get_filename_component(_OPENMP_IMPLICIT_LIB_PLAIN "${_OPENMP_IMPLICIT_LIB}" NAME_WE)
268           string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" _OPENMP_IMPLICIT_LIB_PLAIN_ESC "${_OPENMP_IMPLICIT_LIB_PLAIN}")
269           string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" _OPENMP_IMPLICIT_LIB_PATH_ESC "${_OPENMP_IMPLICIT_LIB}")
270           if(NOT ( "${_OPENMP_IMPLICIT_LIB}" IN_LIST CMAKE_${LANG}_IMPLICIT_LINK_LIBRARIES
271             OR "${CMAKE_${LANG}_STANDARD_LIBRARIES}" MATCHES "(^| )(-Wl,)?(-l)?(${_OPENMP_IMPLICIT_LIB_PLAIN_ESC}|${_OPENMP_IMPLICIT_LIB_PATH_ESC})( |$)"
272             OR "${CMAKE_${LANG}_LINK_EXECUTABLE}" MATCHES "(^| )(-Wl,)?(-l)?(${_OPENMP_IMPLICIT_LIB_PLAIN_ESC}|${_OPENMP_IMPLICIT_LIB_PATH_ESC})( |$)" ) )
273             if(_OPENMP_IMPLICIT_LIB_DIR)
274               set(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY "${_OPENMP_IMPLICIT_LIB}" CACHE FILEPATH
275                 "Path to the ${_OPENMP_IMPLICIT_LIB_PLAIN} library for OpenMP")
276             else()
277               find_library(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY
278                 NAMES "${_OPENMP_IMPLICIT_LIB_NAME}"
279                 DOC "Path to the ${_OPENMP_IMPLICIT_LIB_PLAIN} library for OpenMP"
280                 HINTS ${OpenMP_${LANG}_IMPLICIT_LINK_DIRS}
281                 CMAKE_FIND_ROOT_PATH_BOTH
282                 NO_PACKAGE_ROOT_PATH
283                 NO_CMAKE_PATH
284                 NO_CMAKE_ENVIRONMENT_PATH
285               )
286             endif()
287             mark_as_advanced(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY)
288             list(APPEND _OPENMP_LIB_NAMES ${_OPENMP_IMPLICIT_LIB_PLAIN})
289           endif()
290         endforeach()
291         set("${OPENMP_LIB_NAMES_VAR}" "${_OPENMP_LIB_NAMES}" PARENT_SCOPE)
292       else()
293         # We do not know how to extract implicit OpenMP libraries for this compiler.
294         # Assume that it handles them automatically, e.g. the Intel Compiler on
295         # Windows should put the dependency in its object files.
296         set("${OPENMP_LIB_NAMES_VAR}" "" PARENT_SCOPE)
297       endif()
298       break()
299     elseif(CMAKE_${LANG}_COMPILER_ID STREQUAL "AppleClang"
300       AND CMAKE_${LANG}_COMPILER_VERSION VERSION_GREATER_EQUAL "7.0")
301
302       # Check for separate OpenMP library on AppleClang 7+
303       find_library(OpenMP_libomp_LIBRARY
304         NAMES omp gomp iomp5
305         HINTS ${CMAKE_${LANG}_IMPLICIT_LINK_DIRECTORIES}
306       )
307       mark_as_advanced(OpenMP_libomp_LIBRARY)
308
309       if(OpenMP_libomp_LIBRARY)
310         # Try without specifying include directory first. We only want to
311         # explicitly add a search path if the header can't be found on the
312         # default header search path already.
313         try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG}
314           SOURCE_FROM_VAR "${_OPENMP_TEST_SRC_NAME}" _OPENMP_TEST_SRC_CONTENT
315           CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}"
316           LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG} ${OpenMP_libomp_LIBRARY}
317           OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT
318         )
319         if(NOT OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG})
320           find_path(OpenMP_${LANG}_INCLUDE_DIR omp.h)
321           mark_as_advanced(OpenMP_${LANG}_INCLUDE_DIR)
322           set(OpenMP_${LANG}_INCLUDE_DIR "${OpenMP_${LANG}_INCLUDE_DIR}" PARENT_SCOPE)
323           if(OpenMP_${LANG}_INCLUDE_DIR)
324             try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG}
325               SOURCE_FROM_VAR "${_OPENMP_TEST_SRC_NAME}" _OPENMP_TEST_SRC_CONTENT
326               CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}"
327                           "-DINCLUDE_DIRECTORIES:STRING=${OpenMP_${LANG}_INCLUDE_DIR}"
328               LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG} ${OpenMP_libomp_LIBRARY}
329               OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT
330             )
331           endif()
332         endif()
333         if(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG})
334           set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG}" PARENT_SCOPE)
335           set("${OPENMP_LIB_NAMES_VAR}" "libomp" PARENT_SCOPE)
336           break()
337         endif()
338       endif()
339     elseif(CMAKE_${LANG}_COMPILER_ID STREQUAL "Clang" AND WIN32)
340       # Check for separate OpenMP library for Clang on Windows
341       find_library(OpenMP_libomp_LIBRARY
342         NAMES libomp libgomp libiomp5
343         HINTS ${CMAKE_${LANG}_IMPLICIT_LINK_DIRECTORIES}
344       )
345       mark_as_advanced(OpenMP_libomp_LIBRARY)
346       if(OpenMP_libomp_LIBRARY)
347         try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG}
348           SOURCE_FROM_VAR "${_OPENMP_TEST_SRC_NAME}" _OPENMP_TEST_SRC_CONTENT
349           CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}"
350           LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG} ${OpenMP_libomp_LIBRARY}
351           OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT
352         )
353         if(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG})
354           set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG}" PARENT_SCOPE)
355           set("${OPENMP_LIB_NAMES_VAR}" "libomp" PARENT_SCOPE)
356           break()
357         endif()
358       endif()
359     else()
360       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
361         "Detecting ${LANG} OpenMP failed with the following output:\n${OpenMP_TRY_COMPILE_OUTPUT}\n\n")
362     endif()
363     set("${OPENMP_LIB_NAMES_VAR}" "NOTFOUND" PARENT_SCOPE)
364     set("${OPENMP_FLAG_VAR}" "NOTFOUND" PARENT_SCOPE)
365   endforeach()
366
367   unset(OpenMP_VERBOSE_COMPILE_OPTIONS)
368 endfunction()
369
370 set(OpenMP_C_CXX_CHECK_VERSION_SOURCE
371 "
372 #include <stdio.h>
373 #include <omp.h>
374 const char ompver_str[] = { 'I', 'N', 'F', 'O', ':', 'O', 'p', 'e', 'n', 'M',
375                             'P', '-', 'd', 'a', 't', 'e', '[',
376                             ('0' + ((_OPENMP/100000)%10)),
377                             ('0' + ((_OPENMP/10000)%10)),
378                             ('0' + ((_OPENMP/1000)%10)),
379                             ('0' + ((_OPENMP/100)%10)),
380                             ('0' + ((_OPENMP/10)%10)),
381                             ('0' + ((_OPENMP/1)%10)),
382                             ']', '\\0' };
383 int main(void)
384 {
385   puts(ompver_str);
386   return 0;
387 }
388 ")
389
390 set(OpenMP_Fortran_CHECK_VERSION_SOURCE
391 "
392       program omp_ver
393       @OpenMP_Fortran_INCLUDE_LINE@
394       integer, parameter :: zero = ichar('0')
395       integer, parameter :: ompv = openmp_version
396       character, dimension(24), parameter :: ompver_str =&
397       (/ 'I', 'N', 'F', 'O', ':', 'O', 'p', 'e', 'n', 'M', 'P', '-',&
398          'd', 'a', 't', 'e', '[',&
399          char(zero + mod(ompv/100000, 10)),&
400          char(zero + mod(ompv/10000, 10)),&
401          char(zero + mod(ompv/1000, 10)),&
402          char(zero + mod(ompv/100, 10)),&
403          char(zero + mod(ompv/10, 10)),&
404          char(zero + mod(ompv/1, 10)), ']' /)
405       print *, ompver_str
406       end program omp_ver
407 ")
408
409 function(_OPENMP_GET_SPEC_DATE LANG SPEC_DATE)
410   _OPENMP_PREPARE_SOURCE("${LANG}" CHECK_VERSION_SOURCE OpenMPCheckVersion
411     _OPENMP_TEST_SRC_NAME _OPENMP_TEST_SRC_CONTENT)
412
413   unset(_includeDirFlags)
414   if(OpenMP_${LANG}_INCLUDE_DIR)
415     set(_includeDirFlags "-DINCLUDE_DIRECTORIES:STRING=${OpenMP_${LANG}_INCLUDE_DIR}")
416   endif()
417
418   set(BIN_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindOpenMP/ompver_${LANG}.bin")
419   string(REGEX REPLACE "[-/=+]" "" OPENMP_PLAIN_FLAG "${OPENMP_FLAG}")
420   try_compile(OpenMP_SPECTEST_${LANG}_${OPENMP_PLAIN_FLAG}
421     SOURCE_FROM_VAR "${_OPENMP_TEST_SRC_NAME}" _OPENMP_TEST_SRC_CONTENT
422     CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OpenMP_${LANG}_FLAGS}" ${_includeDirFlags}
423     COPY_FILE "${BIN_FILE}"
424     OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT)
425
426   if(${OpenMP_SPECTEST_${LANG}_${OPENMP_PLAIN_FLAG}})
427     file(STRINGS ${BIN_FILE} specstr LIMIT_COUNT 1 REGEX "INFO:OpenMP-date")
428     set(regex_spec_date ".*INFO:OpenMP-date\\[0*([^]]*)\\].*")
429     if("${specstr}" MATCHES "${regex_spec_date}")
430       set(${SPEC_DATE} "${CMAKE_MATCH_1}" PARENT_SCOPE)
431     endif()
432   else()
433     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
434         "Detecting ${LANG} OpenMP version failed with the following output:\n${OpenMP_TRY_COMPILE_OUTPUT}\n\n")
435   endif()
436 endfunction()
437
438 macro(_OPENMP_SET_VERSION_BY_SPEC_DATE LANG)
439   set(OpenMP_SPEC_DATE_MAP
440     # Preview versions
441     "201611=5.0" # OpenMP 5.0 preview 1
442     # Combined versions, 2.5 onwards
443     "201811=5.0"
444     "201511=4.5"
445     "201307=4.0"
446     "201107=3.1"
447     "200805=3.0"
448     "200505=2.5"
449     # C/C++ version 2.0
450     "200203=2.0"
451     # Fortran version 2.0
452     "200011=2.0"
453     # Fortran version 1.1
454     "199911=1.1"
455     # C/C++ version 1.0 (there's no 1.1 for C/C++)
456     "199810=1.0"
457     # Fortran version 1.0
458     "199710=1.0"
459   )
460   if(MSVC)
461     list(APPEND OpenMP_SPEC_DATE_MAP "2019=2.0")
462   endif()
463
464   if(OpenMP_${LANG}_SPEC_DATE)
465     string(REGEX MATCHALL "${OpenMP_${LANG}_SPEC_DATE}=([0-9]+)\\.([0-9]+)" _version_match "${OpenMP_SPEC_DATE_MAP}")
466   else()
467     set(_version_match "")
468   endif()
469   if(NOT _version_match STREQUAL "")
470     set(OpenMP_${LANG}_VERSION_MAJOR ${CMAKE_MATCH_1})
471     set(OpenMP_${LANG}_VERSION_MINOR ${CMAKE_MATCH_2})
472     set(OpenMP_${LANG}_VERSION "${OpenMP_${LANG}_VERSION_MAJOR}.${OpenMP_${LANG}_VERSION_MINOR}")
473   else()
474     unset(OpenMP_${LANG}_VERSION_MAJOR)
475     unset(OpenMP_${LANG}_VERSION_MINOR)
476     unset(OpenMP_${LANG}_VERSION)
477   endif()
478   unset(_version_match)
479   unset(OpenMP_SPEC_DATE_MAP)
480 endmacro()
481
482 foreach(LANG IN ITEMS C CXX)
483   if(CMAKE_${LANG}_COMPILER_LOADED)
484     if(NOT DEFINED OpenMP_${LANG}_FLAGS OR "${OpenMP_${LANG}_FLAGS}" STREQUAL "NOTFOUND"
485       OR NOT DEFINED OpenMP_${LANG}_LIB_NAMES OR "${OpenMP_${LANG}_LIB_NAMES}" STREQUAL "NOTFOUND")
486       _OPENMP_GET_FLAGS("${LANG}" "${LANG}" OpenMP_${LANG}_FLAGS_WORK OpenMP_${LANG}_LIB_NAMES_WORK)
487       if(NOT DEFINED OpenMP_${LANG}_FLAGS OR "${OpenMP_${LANG}_FLAGS}" STREQUAL "NOTFOUND")
488         set(OpenMP_${LANG}_FLAGS "${OpenMP_${LANG}_FLAGS_WORK}"
489           CACHE STRING "${LANG} compiler flags for OpenMP parallelization" FORCE)
490       endif()
491       if(NOT DEFINED OpenMP_${LANG}_LIB_NAMES OR "${OpenMP_${LANG}_LIB_NAMES}" STREQUAL "NOTFOUND")
492         set(OpenMP_${LANG}_LIB_NAMES "${OpenMP_${LANG}_LIB_NAMES_WORK}"
493           CACHE STRING "${LANG} compiler libraries for OpenMP parallelization" FORCE)
494       endif()
495       mark_as_advanced(OpenMP_${LANG}_FLAGS OpenMP_${LANG}_LIB_NAMES)
496     endif()
497   endif()
498 endforeach()
499
500 if(CMAKE_Fortran_COMPILER_LOADED)
501   if(NOT DEFINED OpenMP_Fortran_FLAGS OR "${OpenMP_Fortran_FLAGS}" STREQUAL "NOTFOUND"
502     OR NOT DEFINED OpenMP_Fortran_LIB_NAMES OR "${OpenMP_Fortran_LIB_NAMES}" STREQUAL "NOTFOUND"
503     OR NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_MODULE)
504     set(OpenMP_Fortran_INCLUDE_LINE "use omp_lib\n      implicit none")
505     _OPENMP_GET_FLAGS("Fortran" "FortranHeader" OpenMP_Fortran_FLAGS_WORK OpenMP_Fortran_LIB_NAMES_WORK)
506     if(OpenMP_Fortran_FLAGS_WORK)
507       set(OpenMP_Fortran_HAVE_OMPLIB_MODULE TRUE CACHE BOOL INTERNAL "")
508     endif()
509
510     if(NOT DEFINED OpenMP_Fortran_FLAGS OR "${OpenMP_Fortran_FLAGS}" STREQUAL "NOTFOUND")
511       set(OpenMP_Fortran_FLAGS "${OpenMP_Fortran_FLAGS_WORK}"
512         CACHE STRING "Fortran compiler flags for OpenMP parallelization" FORCE)
513     endif()
514     if(NOT DEFINED OpenMP_Fortran_LIB_NAMES OR "${OpenMP_Fortran_LIB_NAMES}" STREQUAL "NOTFOUND")
515       set(OpenMP_Fortran_LIB_NAMES "${OpenMP_Fortran_LIB_NAMES_WORK}"
516         CACHE STRING "Fortran compiler libraries for OpenMP parallelization" FORCE)
517     endif()
518     mark_as_advanced(OpenMP_Fortran_FLAGS OpenMP_Fortran_LIB_NAMES)
519   endif()
520
521   if(NOT DEFINED OpenMP_Fortran_FLAGS OR "${OpenMP_Fortran_FLAGS}" STREQUAL "NOTFOUND"
522     OR NOT DEFINED OpenMP_Fortran_LIB_NAMES OR "${OpenMP_Fortran_LIB_NAMES}" STREQUAL "NOTFOUND"
523     OR NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_HEADER)
524     set(OpenMP_Fortran_INCLUDE_LINE "implicit none\n      include 'omp_lib.h'")
525     _OPENMP_GET_FLAGS("Fortran" "FortranModule" OpenMP_Fortran_FLAGS_WORK OpenMP_Fortran_LIB_NAMES_WORK)
526     if(OpenMP_Fortran_FLAGS_WORK)
527       set(OpenMP_Fortran_HAVE_OMPLIB_HEADER TRUE CACHE BOOL INTERNAL "")
528     endif()
529
530     if(NOT DEFINED OpenMP_Fortran_FLAGS OR "${OpenMP_Fortran_FLAGS}" STREQUAL "NOTFOUND")
531       set(OpenMP_Fortran_FLAGS "${OpenMP_Fortran_FLAGS_WORK}"
532         CACHE STRING "Fortran compiler flags for OpenMP parallelization" FORCE)
533     endif()
534     if(NOT DEFINED OpenMP_Fortran_LIB_NAMES OR "${OpenMP_Fortran_LIB_NAMES}" STREQUAL "NOTFOUND")
535       set(OpenMP_Fortran_LIB_NAMES "${OpenMP_Fortran_LIB_NAMES_WORK}"
536         CACHE STRING "Fortran compiler libraries for OpenMP parallelization" FORCE)
537     endif()
538   endif()
539
540   if(OpenMP_Fortran_HAVE_OMPLIB_MODULE)
541     set(OpenMP_Fortran_INCLUDE_LINE "use omp_lib\n      implicit none")
542   else()
543     set(OpenMP_Fortran_INCLUDE_LINE "implicit none\n      include 'omp_lib.h'")
544   endif()
545 endif()
546
547 if(NOT OpenMP_FIND_COMPONENTS)
548   set(OpenMP_FINDLIST C CXX Fortran)
549 else()
550   set(OpenMP_FINDLIST ${OpenMP_FIND_COMPONENTS})
551 endif()
552
553 unset(_OpenMP_MIN_VERSION)
554
555 include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
556
557 foreach(LANG IN LISTS OpenMP_FINDLIST)
558   if(CMAKE_${LANG}_COMPILER_LOADED)
559     if (NOT OpenMP_${LANG}_SPEC_DATE AND OpenMP_${LANG}_FLAGS)
560       _OPENMP_GET_SPEC_DATE("${LANG}" OpenMP_${LANG}_SPEC_DATE_INTERNAL)
561       set(OpenMP_${LANG}_SPEC_DATE "${OpenMP_${LANG}_SPEC_DATE_INTERNAL}" CACHE
562         INTERNAL "${LANG} compiler's OpenMP specification date")
563     endif()
564     _OPENMP_SET_VERSION_BY_SPEC_DATE("${LANG}")
565
566     set(OpenMP_${LANG}_FIND_QUIETLY ${OpenMP_FIND_QUIETLY})
567     set(OpenMP_${LANG}_FIND_REQUIRED ${OpenMP_FIND_REQUIRED})
568     set(OpenMP_${LANG}_FIND_VERSION ${OpenMP_FIND_VERSION})
569     set(OpenMP_${LANG}_FIND_VERSION_EXACT ${OpenMP_FIND_VERSION_EXACT})
570
571     set(_OPENMP_${LANG}_REQUIRED_VARS OpenMP_${LANG}_FLAGS)
572     if("${OpenMP_${LANG}_LIB_NAMES}" STREQUAL "NOTFOUND")
573       set(_OPENMP_${LANG}_REQUIRED_LIB_VARS OpenMP_${LANG}_LIB_NAMES)
574     else()
575       foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_LIB_NAMES)
576         list(APPEND _OPENMP_${LANG}_REQUIRED_LIB_VARS OpenMP_${_OPENMP_IMPLICIT_LIB}_LIBRARY)
577       endforeach()
578     endif()
579
580     find_package_handle_standard_args(OpenMP_${LANG}
581       NAME_MISMATCHED
582       REQUIRED_VARS OpenMP_${LANG}_FLAGS ${_OPENMP_${LANG}_REQUIRED_LIB_VARS}
583       VERSION_VAR OpenMP_${LANG}_VERSION
584     )
585
586     if(OpenMP_${LANG}_FOUND)
587       if(DEFINED OpenMP_${LANG}_VERSION)
588         if(NOT _OpenMP_MIN_VERSION OR _OpenMP_MIN_VERSION VERSION_GREATER OpenMP_${LANG}_VERSION)
589           set(_OpenMP_MIN_VERSION OpenMP_${LANG}_VERSION)
590         endif()
591       endif()
592       set(OpenMP_${LANG}_LIBRARIES "")
593       foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_LIB_NAMES)
594         list(APPEND OpenMP_${LANG}_LIBRARIES "${OpenMP_${_OPENMP_IMPLICIT_LIB}_LIBRARY}")
595       endforeach()
596       if(OpenMP_${LANG}_INCLUDE_DIR)
597         set(OpenMP_${LANG}_INCLUDE_DIRS ${OpenMP_${LANG}_INCLUDE_DIR})
598       else()
599         set(OpenMP_${LANG}_INCLUDE_DIRS "")
600       endif()
601
602       if(NOT TARGET OpenMP::OpenMP_${LANG})
603         add_library(OpenMP::OpenMP_${LANG} INTERFACE IMPORTED)
604       endif()
605       if(OpenMP_${LANG}_FLAGS)
606         separate_arguments(_OpenMP_${LANG}_OPTIONS NATIVE_COMMAND "${OpenMP_${LANG}_FLAGS}")
607         set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY
608           INTERFACE_COMPILE_OPTIONS "$<$<COMPILE_LANGUAGE:${LANG}>:${_OpenMP_${LANG}_OPTIONS}>")
609         if(CMAKE_${LANG}_COMPILER_ID STREQUAL "Fujitsu"
610           OR ${CMAKE_${LANG}_COMPILER_ID} STREQUAL "IntelLLVM")
611           set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY
612             INTERFACE_LINK_OPTIONS "${OpenMP_${LANG}_FLAGS}")
613         endif()
614         unset(_OpenMP_${LANG}_OPTIONS)
615       endif()
616       if(OpenMP_${LANG}_INCLUDE_DIRS)
617         set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY
618           INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${OpenMP_${LANG}_INCLUDE_DIRS}>")
619       endif()
620       if(OpenMP_${LANG}_LIBRARIES)
621         set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY
622           INTERFACE_LINK_LIBRARIES "${OpenMP_${LANG}_LIBRARIES}")
623       endif()
624     endif()
625   endif()
626 endforeach()
627
628 unset(_OpenMP_REQ_VARS)
629 foreach(LANG IN ITEMS C CXX Fortran)
630   if((NOT OpenMP_FIND_COMPONENTS AND CMAKE_${LANG}_COMPILER_LOADED) OR LANG IN_LIST OpenMP_FIND_COMPONENTS)
631     list(APPEND _OpenMP_REQ_VARS "OpenMP_${LANG}_FOUND")
632   endif()
633 endforeach()
634
635 find_package_handle_standard_args(OpenMP
636     REQUIRED_VARS ${_OpenMP_REQ_VARS}
637     VERSION_VAR ${_OpenMP_MIN_VERSION}
638     HANDLE_COMPONENTS)
639
640 set(OPENMP_FOUND ${OpenMP_FOUND})
641
642 if(CMAKE_Fortran_COMPILER_LOADED AND OpenMP_Fortran_FOUND)
643   if(NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_MODULE)
644     set(OpenMP_Fortran_HAVE_OMPLIB_MODULE FALSE CACHE BOOL INTERNAL "")
645   endif()
646   if(NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_HEADER)
647     set(OpenMP_Fortran_HAVE_OMPLIB_HEADER FALSE CACHE BOOL INTERNAL "")
648   endif()
649 endif()
650
651 if(NOT ( CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED OR CMAKE_Fortran_COMPILER_LOADED ))
652   message(SEND_ERROR "FindOpenMP requires the C, CXX or Fortran languages to be enabled")
653 endif()
654
655 unset(OpenMP_C_CXX_TEST_SOURCE)
656 unset(OpenMP_Fortran_TEST_SOURCE)
657 unset(OpenMP_C_CXX_CHECK_VERSION_SOURCE)
658 unset(OpenMP_Fortran_CHECK_VERSION_SOURCE)
659 unset(OpenMP_Fortran_INCLUDE_LINE)
660
661 cmake_policy(POP)