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