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
100set(OpenMP_pthread_LIBRARY -lpthread)
101
102# If the compiler itself has support for OpenMP, then omp.h is hidden
103# away somewhere and it won't be found here; but if the support comes
104# from an external package, it needs to have the right -I and -L flags.
105find_file(_path_to_omp_h omp.h)
106if(NOT _path_to_omp_h)
107  find_file(_path_to_omp_h omp.h
108    HINTS $ENV{LOCALBASE}/include /usr/local/include)
109endif()
110if(_path_to_omp_h)
111  get_filename_component(OpenMP_INCLUDE_DIR ${_path_to_omp_h} DIRECTORY)
112else()
113  set(OpenMP_INCLUDE_DIR "omp_h-NOTFOUND")
114endif()
115
116find_library(_path_to_omp_lib omp)
117if(NOT _path_to_omp_lib)
118  find_library(_path_to_omp_lib omp
119    PATHS $ENV{LOCALBASE}/lib /usr/local/lib)
120endif()
121if(_path_to_omp_lib)
122  get_filename_component(OpenMP_LIB_DIR ${_path_to_omp_lib} DIRECTORY)
123else()
124  set(OpenMP_LIB_DIR "omp_lib-NOTFOUND")
125endif()
126
127function(_OPENMP_FLAG_CANDIDATES LANG)
128  if(NOT OpenMP_${LANG}_FLAG)
129    unset(OpenMP_FLAG_CANDIDATES)
130
131    set(OMP_FLAG_GNU "-fopenmp")
132    set(OMP_FLAG_Clang "-fopenmp=libomp" "-fopenmp=libiomp5" "-fopenmp" "-Xclang -fopenmp")
133    set(OMP_FLAG_AppleClang "-Xclang -fopenmp")
134    set(OMP_FLAG_HP "+Oopenmp")
135    if(WIN32)
136      set(OMP_FLAG_Intel "-Qopenmp")
137    elseif(CMAKE_${LANG}_COMPILER_ID STREQUAL "Intel" AND
138           "${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS "15.0.0.20140528")
139      set(OMP_FLAG_Intel "-openmp")
140    else()
141      set(OMP_FLAG_Intel "-qopenmp")
142    endif()
143    if(CMAKE_${LANG}_COMPILER_ID STREQUAL "IntelLLVM" AND
144      "x${CMAKE_${LANG}_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
145      set(OMP_FLAG_IntelLLVM "-Qiopenmp")
146    else()
147      set(OMP_FLAG_IntelLLVM "-fiopenmp")
148    endif()
149    set(OMP_FLAG_MSVC "-openmp")
150    set(OMP_FLAG_PathScale "-openmp")
151    set(OMP_FLAG_NAG "-openmp")
152    set(OMP_FLAG_Absoft "-openmp")
153    set(OMP_FLAG_NVHPC "-mp")
154    set(OMP_FLAG_PGI "-mp")
155    set(OMP_FLAG_Flang "-fopenmp")
156    set(OMP_FLAG_SunPro "-xopenmp")
157    set(OMP_FLAG_XL "-qsmp=omp")
158    # Cray compiler activate OpenMP with -h omp, which is enabled by default.
159    set(OMP_FLAG_Cray " " "-h omp")
160    set(OMP_FLAG_Fujitsu "-Kopenmp" "-KOMP")
161    set(OMP_FLAG_FujitsuClang "-fopenmp" "-Kopenmp")
162
163    # If we know the correct flags, use those
164    if(DEFINED OMP_FLAG_${CMAKE_${LANG}_COMPILER_ID})
165      set(OpenMP_FLAG_CANDIDATES "${OMP_FLAG_${CMAKE_${LANG}_COMPILER_ID}}")
166    # Fall back to reasonable default tries otherwise
167    else()
168      set(OpenMP_FLAG_CANDIDATES "-openmp" "-fopenmp" "-mp" " ")
169    endif()
170    set(OpenMP_${LANG}_FLAG_CANDIDATES "${OpenMP_FLAG_CANDIDATES}" PARENT_SCOPE)
171  else()
172    set(OpenMP_${LANG}_FLAG_CANDIDATES "${OpenMP_${LANG}_FLAG}" PARENT_SCOPE)
173  endif()
174endfunction()
175
176# sample openmp source code to test
177set(OpenMP_C_CXX_TEST_SOURCE
178"
179#include <omp.h>
180int main(void) {
181#ifdef _OPENMP
182  omp_get_max_threads();
183  return 0;
184#elif defined(__HIP_DEVICE_COMPILE__)
185  return 0;
186#else
187  breaks_on_purpose
188#endif
189}
190")
191
192# in Fortran, an implementation may provide an omp_lib.h header
193# or omp_lib module, or both (OpenMP standard, section 3.1)
194# Furthmore !$ is the Fortran equivalent of #ifdef _OPENMP (OpenMP standard, 2.2.2)
195# Without the conditional compilation, some compilers (e.g. PGI) might compile OpenMP code
196# while not actually enabling OpenMP, building code sequentially
197set(OpenMP_Fortran_TEST_SOURCE
198  "
199      program test
200      @OpenMP_Fortran_INCLUDE_LINE@
201  !$  integer :: n
202      n = omp_get_num_threads()
203      end program test
204  "
205)
206
207function(_OPENMP_WRITE_SOURCE_FILE LANG SRC_FILE_CONTENT_VAR SRC_FILE_NAME SRC_FILE_FULLPATH)
208  set(WORK_DIR ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindOpenMP)
209  if("${LANG}" STREQUAL "C")
210    set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.c")
211    file(WRITE "${SRC_FILE}" "${OpenMP_C_CXX_${SRC_FILE_CONTENT_VAR}}")
212  elseif("${LANG}" STREQUAL "CXX")
213    set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.cpp")
214    file(WRITE "${SRC_FILE}" "${OpenMP_C_CXX_${SRC_FILE_CONTENT_VAR}}")
215  elseif("${LANG}" STREQUAL "Fortran")
216    set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.f90")
217    file(WRITE "${SRC_FILE}_in" "${OpenMP_Fortran_${SRC_FILE_CONTENT_VAR}}")
218    configure_file("${SRC_FILE}_in" "${SRC_FILE}" @ONLY)
219  endif()
220  set(${SRC_FILE_FULLPATH} "${SRC_FILE}" PARENT_SCOPE)
221endfunction()
222
223include(${CMAKE_CURRENT_LIST_DIR}/CMakeParseImplicitLinkInfo.cmake)
224
225function(_OPENMP_GET_FLAGS LANG FLAG_MODE OPENMP_FLAG_VAR OPENMP_LIB_NAMES_VAR)
226  _OPENMP_FLAG_CANDIDATES("${LANG}")
227  _OPENMP_WRITE_SOURCE_FILE("${LANG}" "TEST_SOURCE" OpenMPTryFlag _OPENMP_TEST_SRC)
228
229  unset(OpenMP_VERBOSE_COMPILE_OPTIONS)
230  separate_arguments(OpenMP_VERBOSE_OPTIONS NATIVE_COMMAND "${CMAKE_${LANG}_VERBOSE_FLAG}")
231  foreach(_VERBOSE_OPTION IN LISTS OpenMP_VERBOSE_OPTIONS)
232    if(NOT _VERBOSE_OPTION MATCHES "^-Wl,")
233      list(APPEND OpenMP_VERBOSE_COMPILE_OPTIONS ${_VERBOSE_OPTION})
234    endif()
235  endforeach()
236
237  foreach(OPENMP_FLAG IN LISTS OpenMP_${LANG}_FLAG_CANDIDATES)
238    set(OPENMP_FLAGS_TEST "${OPENMP_FLAG}")
239    if(OpenMP_VERBOSE_COMPILE_OPTIONS)
240      string(APPEND OPENMP_FLAGS_TEST " ${OpenMP_VERBOSE_COMPILE_OPTIONS}")
241    endif()
242    set(_extra_flag "")
243    if(OpenMP_INCLUDE_DIR)
244      string(APPEND _extra_flag " -I${OpenMP_INCLUDE_DIR}")
245    endif()
246    if(OpenMP_LIB_DIR)
247      string(APPEND _extra_flag " -L${OpenMP_LIB_DIR}")
248    endif()
249    set(_need_extra FALSE)
250
251    string(REGEX REPLACE "[-/=+]" "" OPENMP_PLAIN_FLAG "${OPENMP_FLAG}")
252    try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC}
253      CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}"
254      LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG}
255      OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT
256    )
257
258    # Might need that -I -L after all..
259    if(NOT OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG})
260      unset(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG})
261      try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC}
262        CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST} ${_extra_flag}"
263        LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG}
264        OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT
265      )
266      set(_need_extra TRUE)
267    endif()
268
269    if(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG})
270      if(_need_extra)
271        set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG} ${_extra_flag}" PARENT_SCOPE)
272      else()
273        set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG}" PARENT_SCOPE)
274      endif()
275
276      if(CMAKE_${LANG}_VERBOSE_FLAG)
277        unset(OpenMP_${LANG}_IMPLICIT_LIBRARIES)
278        unset(OpenMP_${LANG}_IMPLICIT_LINK_DIRS)
279        unset(OpenMP_${LANG}_IMPLICIT_FWK_DIRS)
280        unset(OpenMP_${LANG}_LOG_VAR)
281
282        file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
283        "Detecting ${LANG} OpenMP compiler ABI info compiled with the following output:\n${OpenMP_TRY_COMPILE_OUTPUT}\n\n")
284
285        cmake_parse_implicit_link_info("${OpenMP_TRY_COMPILE_OUTPUT}"
286          OpenMP_${LANG}_IMPLICIT_LIBRARIES
287          OpenMP_${LANG}_IMPLICIT_LINK_DIRS
288          OpenMP_${LANG}_IMPLICIT_FWK_DIRS
289          OpenMP_${LANG}_LOG_VAR
290          "${CMAKE_${LANG}_IMPLICIT_OBJECT_REGEX}"
291        )
292
293        file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
294        "Parsed ${LANG} OpenMP implicit link information from above output:\n${OpenMP_${LANG}_LOG_VAR}\n\n")
295
296        unset(_OPENMP_LIB_NAMES)
297        foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_IMPLICIT_LIBRARIES)
298          get_filename_component(_OPENMP_IMPLICIT_LIB_DIR "${_OPENMP_IMPLICIT_LIB}" DIRECTORY)
299          get_filename_component(_OPENMP_IMPLICIT_LIB_NAME "${_OPENMP_IMPLICIT_LIB}" NAME)
300          get_filename_component(_OPENMP_IMPLICIT_LIB_PLAIN "${_OPENMP_IMPLICIT_LIB}" NAME_WE)
301          string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" _OPENMP_IMPLICIT_LIB_PLAIN_ESC "${_OPENMP_IMPLICIT_LIB_PLAIN}")
302          string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" _OPENMP_IMPLICIT_LIB_PATH_ESC "${_OPENMP_IMPLICIT_LIB}")
303          if(NOT ( "${_OPENMP_IMPLICIT_LIB}" IN_LIST CMAKE_${LANG}_IMPLICIT_LINK_LIBRARIES
304            OR "${CMAKE_${LANG}_STANDARD_LIBRARIES}" MATCHES "(^| )(-Wl,)?(-l)?(${_OPENMP_IMPLICIT_LIB_PLAIN_ESC}|${_OPENMP_IMPLICIT_LIB_PATH_ESC})( |$)"
305            OR "${CMAKE_${LANG}_LINK_EXECUTABLE}" MATCHES "(^| )(-Wl,)?(-l)?(${_OPENMP_IMPLICIT_LIB_PLAIN_ESC}|${_OPENMP_IMPLICIT_LIB_PATH_ESC})( |$)" ) )
306            if(_OPENMP_IMPLICIT_LIB_DIR)
307              set(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY "${_OPENMP_IMPLICIT_LIB}" CACHE FILEPATH
308                "Path to the ${_OPENMP_IMPLICIT_LIB_PLAIN} library for OpenMP")
309            else()
310              find_library(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY
311                NAMES "${_OPENMP_IMPLICIT_LIB_NAME}"
312                DOC "Path to the ${_OPENMP_IMPLICIT_LIB_PLAIN} library for OpenMP"
313                HINTS ${OpenMP_${LANG}_IMPLICIT_LINK_DIRS}
314                CMAKE_FIND_ROOT_PATH_BOTH
315                NO_DEFAULT_PATH
316              )
317            endif()
318            mark_as_advanced(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY)
319            list(APPEND _OPENMP_LIB_NAMES ${_OPENMP_IMPLICIT_LIB_PLAIN})
320          endif()
321        endforeach()
322        set("${OPENMP_LIB_NAMES_VAR}" "${_OPENMP_LIB_NAMES}" PARENT_SCOPE)
323      else()
324        # We do not know how to extract implicit OpenMP libraries for this compiler.
325        # Assume that it handles them automatically, e.g. the Intel Compiler on
326        # Windows should put the dependency in its object files.
327        set("${OPENMP_LIB_NAMES_VAR}" "" PARENT_SCOPE)
328      endif()
329      break()
330    elseif(CMAKE_${LANG}_COMPILER_ID STREQUAL "AppleClang"
331      AND CMAKE_${LANG}_COMPILER_VERSION VERSION_GREATER_EQUAL "7.0")
332
333      # Check for separate OpenMP library on AppleClang 7+
334      find_library(OpenMP_libomp_LIBRARY
335        NAMES omp gomp iomp5
336        HINTS ${CMAKE_${LANG}_IMPLICIT_LINK_DIRECTORIES}
337      )
338      mark_as_advanced(OpenMP_libomp_LIBRARY)
339
340      if(OpenMP_libomp_LIBRARY)
341        # Try without specifying include directory first. We only want to
342        # explicitly add a search path if the header can't be found on the
343        # default header search path already.
344        try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC}
345          CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}"
346          LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG} ${OpenMP_libomp_LIBRARY}
347          OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT
348        )
349        if(NOT OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG})
350          find_path(OpenMP_${LANG}_INCLUDE_DIR omp.h)
351          mark_as_advanced(OpenMP_${LANG}_INCLUDE_DIR)
352          set(OpenMP_${LANG}_INCLUDE_DIR "${OpenMP_${LANG}_INCLUDE_DIR}" PARENT_SCOPE)
353          if(OpenMP_${LANG}_INCLUDE_DIR)
354            try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC}
355              CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}"
356                          "-DINCLUDE_DIRECTORIES:STRING=${OpenMP_${LANG}_INCLUDE_DIR}"
357              LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG} ${OpenMP_libomp_LIBRARY}
358              OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT
359            )
360          endif()
361        endif()
362        if(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG})
363          set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG}" PARENT_SCOPE)
364          set("${OPENMP_LIB_NAMES_VAR}" "libomp" PARENT_SCOPE)
365          break()
366        endif()
367      endif()
368    elseif(CMAKE_${LANG}_COMPILER_ID STREQUAL "Clang" AND WIN32)
369      # Check for separate OpenMP library for Clang on Windows
370      find_library(OpenMP_libomp_LIBRARY
371        NAMES libomp libgomp libiomp5
372        HINTS ${CMAKE_${LANG}_IMPLICIT_LINK_DIRECTORIES}
373      )
374      mark_as_advanced(OpenMP_libomp_LIBRARY)
375      if(OpenMP_libomp_LIBRARY)
376        try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC}
377          CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}"
378          LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG} ${OpenMP_libomp_LIBRARY}
379          OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT
380        )
381        if(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG})
382          set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG}" PARENT_SCOPE)
383          set("${OPENMP_LIB_NAMES_VAR}" "libomp" PARENT_SCOPE)
384          break()
385        endif()
386      endif()
387    else()
388      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
389        "Detecting ${LANG} OpenMP failed with the following output:\n${OpenMP_TRY_COMPILE_OUTPUT}\n\n")
390    endif()
391    set("${OPENMP_LIB_NAMES_VAR}" "NOTFOUND" PARENT_SCOPE)
392    set("${OPENMP_FLAG_VAR}" "NOTFOUND" PARENT_SCOPE)
393  endforeach()
394
395  unset(OpenMP_VERBOSE_COMPILE_OPTIONS)
396endfunction()
397
398set(OpenMP_C_CXX_CHECK_VERSION_SOURCE
399"
400#include <stdio.h>
401#include <omp.h>
402const char ompver_str[] = { 'I', 'N', 'F', 'O', ':', 'O', 'p', 'e', 'n', 'M',
403                            'P', '-', 'd', 'a', 't', 'e', '[',
404                            ('0' + ((_OPENMP/100000)%10)),
405                            ('0' + ((_OPENMP/10000)%10)),
406                            ('0' + ((_OPENMP/1000)%10)),
407                            ('0' + ((_OPENMP/100)%10)),
408                            ('0' + ((_OPENMP/10)%10)),
409                            ('0' + ((_OPENMP/1)%10)),
410                            ']', '\\0' };
411int main(void)
412{
413  puts(ompver_str);
414  return 0;
415}
416")
417
418set(OpenMP_Fortran_CHECK_VERSION_SOURCE
419"
420      program omp_ver
421      @OpenMP_Fortran_INCLUDE_LINE@
422      integer, parameter :: zero = ichar('0')
423      integer, parameter :: ompv = openmp_version
424      character, dimension(24), parameter :: ompver_str =&
425      (/ 'I', 'N', 'F', 'O', ':', 'O', 'p', 'e', 'n', 'M', 'P', '-',&
426         'd', 'a', 't', 'e', '[',&
427         char(zero + mod(ompv/100000, 10)),&
428         char(zero + mod(ompv/10000, 10)),&
429         char(zero + mod(ompv/1000, 10)),&
430         char(zero + mod(ompv/100, 10)),&
431         char(zero + mod(ompv/10, 10)),&
432         char(zero + mod(ompv/1, 10)), ']' /)
433      print *, ompver_str
434      end program omp_ver
435")
436
437function(_OPENMP_GET_SPEC_DATE LANG SPEC_DATE)
438  _OPENMP_WRITE_SOURCE_FILE("${LANG}" "CHECK_VERSION_SOURCE" OpenMPCheckVersion _OPENMP_TEST_SRC)
439
440  unset(_includeDirFlags)
441  if(OpenMP_${LANG}_INCLUDE_DIR)
442    set(_includeDirFlags "-DINCLUDE_DIRECTORIES:STRING=${OpenMP_${LANG}_INCLUDE_DIR}")
443  endif()
444
445  set(BIN_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindOpenMP/ompver_${LANG}.bin")
446  string(REGEX REPLACE "[-/=+]" "" OPENMP_PLAIN_FLAG "${OPENMP_FLAG}")
447  try_compile(OpenMP_SPECTEST_${LANG}_${OPENMP_PLAIN_FLAG} "${CMAKE_BINARY_DIR}" "${_OPENMP_TEST_SRC}"
448              CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OpenMP_${LANG}_FLAGS}" ${_includeDirFlags}
449              COPY_FILE ${BIN_FILE}
450              OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT)
451
452  if(${OpenMP_SPECTEST_${LANG}_${OPENMP_PLAIN_FLAG}})
453    file(STRINGS ${BIN_FILE} specstr LIMIT_COUNT 1 REGEX "INFO:OpenMP-date")
454    set(regex_spec_date ".*INFO:OpenMP-date\\[0*([^]]*)\\].*")
455    if("${specstr}" MATCHES "${regex_spec_date}")
456      set(${SPEC_DATE} "${CMAKE_MATCH_1}" PARENT_SCOPE)
457    endif()
458  else()
459    file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
460        "Detecting ${LANG} OpenMP version failed with the following output:\n${OpenMP_TRY_COMPILE_OUTPUT}\n\n")
461  endif()
462endfunction()
463
464macro(_OPENMP_SET_VERSION_BY_SPEC_DATE LANG)
465  set(OpenMP_SPEC_DATE_MAP
466    # Preview versions
467    "201611=5.0" # OpenMP 5.0 preview 1
468    # Combined versions, 2.5 onwards
469    "201811=5.0"
470    "201511=4.5"
471    "201307=4.0"
472    "201107=3.1"
473    "200805=3.0"
474    "200505=2.5"
475    # C/C++ version 2.0
476    "200203=2.0"
477    # Fortran version 2.0
478    "200011=2.0"
479    # Fortran version 1.1
480    "199911=1.1"
481    # C/C++ version 1.0 (there's no 1.1 for C/C++)
482    "199810=1.0"
483    # Fortran version 1.0
484    "199710=1.0"
485  )
486  if(MSVC)
487    list(APPEND OpenMP_SPEC_DATE_MAP "2019=2.0")
488  endif()
489
490  if(OpenMP_${LANG}_SPEC_DATE)
491    string(REGEX MATCHALL "${OpenMP_${LANG}_SPEC_DATE}=([0-9]+)\\.([0-9]+)" _version_match "${OpenMP_SPEC_DATE_MAP}")
492  else()
493    set(_version_match "")
494  endif()
495  if(NOT _version_match STREQUAL "")
496    set(OpenMP_${LANG}_VERSION_MAJOR ${CMAKE_MATCH_1})
497    set(OpenMP_${LANG}_VERSION_MINOR ${CMAKE_MATCH_2})
498    set(OpenMP_${LANG}_VERSION "${OpenMP_${LANG}_VERSION_MAJOR}.${OpenMP_${LANG}_VERSION_MINOR}")
499  else()
500    unset(OpenMP_${LANG}_VERSION_MAJOR)
501    unset(OpenMP_${LANG}_VERSION_MINOR)
502    unset(OpenMP_${LANG}_VERSION)
503  endif()
504  unset(_version_match)
505  unset(OpenMP_SPEC_DATE_MAP)
506endmacro()
507
508foreach(LANG IN ITEMS C CXX)
509  if(CMAKE_${LANG}_COMPILER_LOADED)
510    if(NOT DEFINED OpenMP_${LANG}_FLAGS OR "${OpenMP_${LANG}_FLAGS}" STREQUAL "NOTFOUND"
511      OR NOT DEFINED OpenMP_${LANG}_LIB_NAMES OR "${OpenMP_${LANG}_LIB_NAMES}" STREQUAL "NOTFOUND")
512      _OPENMP_GET_FLAGS("${LANG}" "${LANG}" OpenMP_${LANG}_FLAGS_WORK OpenMP_${LANG}_LIB_NAMES_WORK)
513      set(OpenMP_${LANG}_FLAGS "${OpenMP_${LANG}_FLAGS_WORK}"
514        CACHE STRING "${LANG} compiler flags for OpenMP parallelization" FORCE)
515      set(OpenMP_${LANG}_LIB_NAMES "${OpenMP_${LANG}_LIB_NAMES_WORK}"
516        CACHE STRING "${LANG} compiler libraries for OpenMP parallelization" FORCE)
517      mark_as_advanced(OpenMP_${LANG}_FLAGS OpenMP_${LANG}_LIB_NAMES)
518    endif()
519  endif()
520endforeach()
521
522if(CMAKE_Fortran_COMPILER_LOADED)
523  if(NOT DEFINED OpenMP_Fortran_FLAGS OR "${OpenMP_Fortran_FLAGS}" STREQUAL "NOTFOUND"
524    OR NOT DEFINED OpenMP_Fortran_LIB_NAMES OR "${OpenMP_Fortran_LIB_NAMES}" STREQUAL "NOTFOUND"
525    OR NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_MODULE)
526    set(OpenMP_Fortran_INCLUDE_LINE "use omp_lib\n      implicit none")
527    _OPENMP_GET_FLAGS("Fortran" "FortranHeader" OpenMP_Fortran_FLAGS_WORK OpenMP_Fortran_LIB_NAMES_WORK)
528    if(OpenMP_Fortran_FLAGS_WORK)
529      set(OpenMP_Fortran_HAVE_OMPLIB_MODULE TRUE CACHE BOOL INTERNAL "")
530    endif()
531
532    set(OpenMP_Fortran_FLAGS "${OpenMP_Fortran_FLAGS_WORK}"
533      CACHE STRING "Fortran compiler flags for OpenMP parallelization")
534    set(OpenMP_Fortran_LIB_NAMES "${OpenMP_Fortran_LIB_NAMES_WORK}"
535      CACHE STRING "Fortran compiler libraries for OpenMP parallelization")
536    mark_as_advanced(OpenMP_Fortran_FLAGS OpenMP_Fortran_LIB_NAMES)
537  endif()
538
539  if(NOT DEFINED OpenMP_Fortran_FLAGS OR "${OpenMP_Fortran_FLAGS}" STREQUAL "NOTFOUND"
540    OR NOT DEFINED OpenMP_Fortran_LIB_NAMES OR "${OpenMP_Fortran_LIB_NAMES}" STREQUAL "NOTFOUND"
541    OR NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_HEADER)
542    set(OpenMP_Fortran_INCLUDE_LINE "implicit none\n      include 'omp_lib.h'")
543    _OPENMP_GET_FLAGS("Fortran" "FortranModule" OpenMP_Fortran_FLAGS_WORK OpenMP_Fortran_LIB_NAMES_WORK)
544    if(OpenMP_Fortran_FLAGS_WORK)
545      set(OpenMP_Fortran_HAVE_OMPLIB_HEADER TRUE CACHE BOOL INTERNAL "")
546    endif()
547
548    set(OpenMP_Fortran_FLAGS "${OpenMP_Fortran_FLAGS_WORK}"
549      CACHE STRING "Fortran compiler flags for OpenMP parallelization")
550
551    set(OpenMP_Fortran_LIB_NAMES "${OpenMP_Fortran_LIB_NAMES}"
552      CACHE STRING "Fortran compiler libraries for OpenMP parallelization")
553  endif()
554
555  if(OpenMP_Fortran_HAVE_OMPLIB_MODULE)
556    set(OpenMP_Fortran_INCLUDE_LINE "use omp_lib\n      implicit none")
557  else()
558    set(OpenMP_Fortran_INCLUDE_LINE "implicit none\n      include 'omp_lib.h'")
559  endif()
560endif()
561
562if(NOT OpenMP_FIND_COMPONENTS)
563  set(OpenMP_FINDLIST C CXX Fortran)
564else()
565  set(OpenMP_FINDLIST ${OpenMP_FIND_COMPONENTS})
566endif()
567
568unset(_OpenMP_MIN_VERSION)
569
570include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
571
572foreach(LANG IN LISTS OpenMP_FINDLIST)
573  if(CMAKE_${LANG}_COMPILER_LOADED)
574    if (NOT OpenMP_${LANG}_SPEC_DATE AND OpenMP_${LANG}_FLAGS)
575      _OPENMP_GET_SPEC_DATE("${LANG}" OpenMP_${LANG}_SPEC_DATE_INTERNAL)
576      set(OpenMP_${LANG}_SPEC_DATE "${OpenMP_${LANG}_SPEC_DATE_INTERNAL}" CACHE
577        INTERNAL "${LANG} compiler's OpenMP specification date")
578    endif()
579    _OPENMP_SET_VERSION_BY_SPEC_DATE("${LANG}")
580
581    set(OpenMP_${LANG}_FIND_QUIETLY ${OpenMP_FIND_QUIETLY})
582    set(OpenMP_${LANG}_FIND_REQUIRED ${OpenMP_FIND_REQUIRED})
583    set(OpenMP_${LANG}_FIND_VERSION ${OpenMP_FIND_VERSION})
584    set(OpenMP_${LANG}_FIND_VERSION_EXACT ${OpenMP_FIND_VERSION_EXACT})
585
586    set(_OPENMP_${LANG}_REQUIRED_VARS OpenMP_${LANG}_FLAGS)
587    if("${OpenMP_${LANG}_LIB_NAMES}" STREQUAL "NOTFOUND")
588      set(_OPENMP_${LANG}_REQUIRED_LIB_VARS OpenMP_${LANG}_LIB_NAMES)
589    else()
590      foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_LIB_NAMES)
591        list(APPEND _OPENMP_${LANG}_REQUIRED_LIB_VARS OpenMP_${_OPENMP_IMPLICIT_LIB}_LIBRARY)
592      endforeach()
593    endif()
594
595    find_package_handle_standard_args(OpenMP_${LANG}
596      NAME_MISMATCHED
597      REQUIRED_VARS OpenMP_${LANG}_FLAGS ${_OPENMP_${LANG}_REQUIRED_LIB_VARS}
598      VERSION_VAR OpenMP_${LANG}_VERSION
599    )
600
601    if(OpenMP_${LANG}_FOUND)
602      if(DEFINED OpenMP_${LANG}_VERSION)
603        if(NOT _OpenMP_MIN_VERSION OR _OpenMP_MIN_VERSION VERSION_GREATER OpenMP_${LANG}_VERSION)
604          set(_OpenMP_MIN_VERSION OpenMP_${LANG}_VERSION)
605        endif()
606      endif()
607      set(OpenMP_${LANG}_LIBRARIES "")
608      foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_LIB_NAMES)
609        list(APPEND OpenMP_${LANG}_LIBRARIES "${OpenMP_${_OPENMP_IMPLICIT_LIB}_LIBRARY}")
610      endforeach()
611      if(OpenMP_${LANG}_INCLUDE_DIR)
612        set(OpenMP_${LANG}_INCLUDE_DIRS ${OpenMP_${LANG}_INCLUDE_DIR})
613      else()
614        set(OpenMP_${LANG}_INCLUDE_DIRS "")
615      endif()
616
617      if(NOT TARGET OpenMP::OpenMP_${LANG})
618        add_library(OpenMP::OpenMP_${LANG} INTERFACE IMPORTED)
619      endif()
620      if(OpenMP_${LANG}_FLAGS)
621        # All the options except -L..
622        separate_arguments(_OpenMP_${LANG}_COMPILE_OPTIONS NATIVE_COMMAND "${OpenMP_${LANG}_FLAGS}")
623        list(FILTER _OpenMP_${LANG}_COMPILE_OPTIONS EXCLUDE REGEX "^-L/")
624        # All the options except -I..
625        separate_arguments(_OpenMP_${LANG}_LINK_OPTIONS NATIVE_COMMAND "${OpenMP_${LANG}_FLAGS}")
626        list(FILTER _OpenMP_${LANG}_LINK_OPTIONS EXCLUDE REGEX "^-I/")
627        set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY
628          INTERFACE_COMPILE_OPTIONS "$<$<COMPILE_LANGUAGE:${LANG}>:${_OpenMP_${LANG}_COMPILE_OPTIONS}>")
629        set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY
630          INTERFACE_LINK_OPTIONS "$<$<COMPILE_LANGUAGE:${LANG}>:${_OpenMP_${LANG}_LINK_OPTIONS}>")
631        if(CMAKE_${LANG}_COMPILER_ID STREQUAL "Fujitsu")
632          set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY
633            INTERFACE_LINK_OPTIONS "${OpenMP_${LANG}_FLAGS}")
634        endif()
635        unset(_OpenMP_${LANG}_OPTIONS)
636      endif()
637      if(OpenMP_${LANG}_INCLUDE_DIRS)
638        set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY
639          INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${OpenMP_${LANG}_INCLUDE_DIRS}>")
640      endif()
641      if(OpenMP_${LANG}_LIBRARIES)
642        set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY
643          INTERFACE_LINK_LIBRARIES "${OpenMP_${LANG}_LIBRARIES}")
644      endif()
645    endif()
646  endif()
647endforeach()
648
649unset(_OpenMP_REQ_VARS)
650foreach(LANG IN ITEMS C CXX Fortran)
651  if((NOT OpenMP_FIND_COMPONENTS AND CMAKE_${LANG}_COMPILER_LOADED) OR LANG IN_LIST OpenMP_FIND_COMPONENTS)
652    list(APPEND _OpenMP_REQ_VARS "OpenMP_${LANG}_FOUND")
653  endif()
654endforeach()
655
656find_package_handle_standard_args(OpenMP
657    REQUIRED_VARS ${_OpenMP_REQ_VARS}
658    VERSION_VAR ${_OpenMP_MIN_VERSION}
659    HANDLE_COMPONENTS)
660
661set(OPENMP_FOUND ${OpenMP_FOUND})
662
663if(CMAKE_Fortran_COMPILER_LOADED AND OpenMP_Fortran_FOUND)
664  if(NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_MODULE)
665    set(OpenMP_Fortran_HAVE_OMPLIB_MODULE FALSE CACHE BOOL INTERNAL "")
666  endif()
667  if(NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_HEADER)
668    set(OpenMP_Fortran_HAVE_OMPLIB_HEADER FALSE CACHE BOOL INTERNAL "")
669  endif()
670endif()
671
672if(NOT ( CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED OR CMAKE_Fortran_COMPILER_LOADED ))
673  message(SEND_ERROR "FindOpenMP requires the C, CXX or Fortran languages to be enabled")
674endif()
675
676unset(OpenMP_C_CXX_TEST_SOURCE)
677unset(OpenMP_Fortran_TEST_SOURCE)
678unset(OpenMP_C_CXX_CHECK_VERSION_SOURCE)
679unset(OpenMP_Fortran_CHECK_VERSION_SOURCE)
680unset(OpenMP_Fortran_INCLUDE_LINE)
681
682cmake_policy(POP)
683