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 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# Variables 17# ^^^^^^^^^ 18# 19# The module exposes the components ``C``, ``CXX``, and ``Fortran``. 20# Each of these controls the various languages to search OpenMP support for. 21# 22# Depending on the enabled components the following variables will be set: 23# 24# ``OpenMP_FOUND`` 25# Variable indicating that OpenMP flags for all requested languages have been found. 26# If no components are specified, this is true if OpenMP settings for all enabled languages 27# were detected. 28# ``OpenMP_VERSION`` 29# Minimal version of the OpenMP standard detected among the requested languages, 30# or all enabled languages if no components were specified. 31# 32# This module will set the following variables per language in your 33# project, where ``<lang>`` is one of C, CXX, or Fortran: 34# 35# ``OpenMP_<lang>_FOUND`` 36# Variable indicating if OpenMP support for ``<lang>`` was detected. 37# ``OpenMP_<lang>_FLAGS`` 38# OpenMP compiler flags for ``<lang>``, separated by spaces. 39# 40# For linking with OpenMP code written in ``<lang>``, the following 41# variables are provided: 42# 43# ``OpenMP_<lang>_LIB_NAMES`` 44# :ref:`;-list <CMake Language Lists>` of libraries for OpenMP programs for ``<lang>``. 45# ``OpenMP_<libname>_LIBRARY`` 46# Location of the individual libraries needed for OpenMP support in ``<lang>``. 47# ``OpenMP_<lang>_LIBRARIES`` 48# A list of libraries needed to link with OpenMP code written in ``<lang>``. 49# 50# Additionally, the module provides :prop_tgt:`IMPORTED` targets: 51# 52# ``OpenMP::OpenMP_<lang>`` 53# Target for using OpenMP from ``<lang>``. 54# 55# Specifically for Fortran, the module sets the following variables: 56# 57# ``OpenMP_Fortran_HAVE_OMPLIB_HEADER`` 58# Boolean indicating if OpenMP is accessible through ``omp_lib.h``. 59# ``OpenMP_Fortran_HAVE_OMPLIB_MODULE`` 60# Boolean indicating if OpenMP is accessible through the ``omp_lib`` Fortran module. 61# 62# The module will also try to provide the OpenMP version variables: 63# 64# ``OpenMP_<lang>_SPEC_DATE`` 65# Date of the OpenMP specification implemented by the ``<lang>`` compiler. 66# ``OpenMP_<lang>_VERSION_MAJOR`` 67# Major version of OpenMP implemented by the ``<lang>`` compiler. 68# ``OpenMP_<lang>_VERSION_MINOR`` 69# Minor version of OpenMP implemented by the ``<lang>`` compiler. 70# ``OpenMP_<lang>_VERSION`` 71# OpenMP version implemented by the ``<lang>`` compiler. 72# 73# The specification date is formatted as given in the OpenMP standard: 74# ``yyyymm`` where ``yyyy`` and ``mm`` represents the year and month of 75# the OpenMP specification implemented by the ``<lang>`` compiler. 76 77cmake_policy(PUSH) 78cmake_policy(SET CMP0012 NEW) # if() recognizes numbers and booleans 79cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced 80cmake_policy(SET CMP0057 NEW) # if IN_LIST 81 82function(_OPENMP_FLAG_CANDIDATES LANG) 83 if(NOT OpenMP_${LANG}_FLAG) 84 unset(OpenMP_FLAG_CANDIDATES) 85 86 set(OMP_FLAG_GNU "-fopenmp") 87 set(OMP_FLAG_Clang "-fopenmp=libomp" "-fopenmp=libiomp5" "-fopenmp") 88 89 if(WIN32) 90 # Prefer Intel OpenMP header which can be provided by CMAKE_INCLUDE_PATH. 91 # Note that CMAKE_INCLUDE_PATH is searched before CMAKE_SYSTEM_INCLUDE_PATH (MSVC path in this case) 92 find_path(__header_dir "omp.h") 93 else() 94 # AppleClang may need a header file, search for omp.h with hints to brew 95 # default include dir 96 find_path(__header_dir "omp.h" HINTS "/usr/local/include") 97 endif() 98 set(OMP_FLAG_AppleClang "-Xpreprocessor -fopenmp" "-Xpreprocessor -fopenmp -I${__header_dir}") 99 100 set(OMP_FLAG_HP "+Oopenmp") 101 if(WIN32) 102 set(OMP_FLAG_Intel "-Qopenmp") 103 elseif(CMAKE_${LANG}_COMPILER_ID STREQUAL "Intel" AND 104 "${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS "15.0.0.20140528") 105 set(OMP_FLAG_Intel "-openmp") 106 else() 107 set(OMP_FLAG_Intel "-qopenmp") 108 endif() 109 set(OMP_FLAG_MIPSpro "-mp") 110 if(__header_dir MATCHES ".*Microsoft Visual Studio.*") 111 # MSVC header. No need to pass it as additional include. 112 set(OMP_FLAG_MSVC "-openmp:experimental" "-openmp") 113 else() 114 set(OMP_FLAG_MSVC "-openmp:experimental -I${__header_dir}" "-openmp -I${__header_dir}") 115 endif() 116 set(OMP_FLAG_PathScale "-openmp") 117 set(OMP_FLAG_NAG "-openmp") 118 set(OMP_FLAG_Absoft "-openmp") 119 set(OMP_FLAG_PGI "-mp") 120 set(OMP_FLAG_Flang "-fopenmp") 121 set(OMP_FLAG_SunPro "-xopenmp") 122 set(OMP_FLAG_XL "-qsmp=omp") 123 # Cray compiler activate OpenMP with -h omp, which is enabled by default. 124 set(OMP_FLAG_Cray " " "-h omp") 125 126 # If we know the correct flags, use those 127 if(DEFINED OMP_FLAG_${CMAKE_${LANG}_COMPILER_ID}) 128 set(OpenMP_FLAG_CANDIDATES "${OMP_FLAG_${CMAKE_${LANG}_COMPILER_ID}}") 129 # Fall back to reasonable default tries otherwise 130 else() 131 set(OpenMP_FLAG_CANDIDATES "-openmp" "-fopenmp" "-mp" " ") 132 endif() 133 set(OpenMP_${LANG}_FLAG_CANDIDATES "${OpenMP_FLAG_CANDIDATES}" PARENT_SCOPE) 134 else() 135 set(OpenMP_${LANG}_FLAG_CANDIDATES "${OpenMP_${LANG}_FLAG}" PARENT_SCOPE) 136 endif() 137endfunction() 138 139# sample openmp source code to test 140set(OpenMP_C_CXX_TEST_SOURCE 141" 142#include <omp.h> 143int main(void) { 144#ifdef _OPENMP 145 omp_get_max_threads(); 146 return 0; 147#else 148 breaks_on_purpose 149#endif 150} 151") 152 153# in Fortran, an implementation may provide an omp_lib.h header 154# or omp_lib module, or both (OpenMP standard, section 3.1) 155# Furthmore !$ is the Fortran equivalent of #ifdef _OPENMP (OpenMP standard, 2.2.2) 156# Without the conditional compilation, some compilers (e.g. PGI) might compile OpenMP code 157# while not actually enabling OpenMP, building code sequentially 158set(OpenMP_Fortran_TEST_SOURCE 159 " 160 program test 161 @OpenMP_Fortran_INCLUDE_LINE@ 162 !$ integer :: n 163 n = omp_get_num_threads() 164 end program test 165 " 166) 167 168function(_OPENMP_WRITE_SOURCE_FILE LANG SRC_FILE_CONTENT_VAR SRC_FILE_NAME SRC_FILE_FULLPATH) 169 set(WORK_DIR ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindOpenMP) 170 if("${LANG}" STREQUAL "C") 171 set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.c") 172 file(WRITE "${SRC_FILE}" "${OpenMP_C_CXX_${SRC_FILE_CONTENT_VAR}}") 173 elseif("${LANG}" STREQUAL "CXX") 174 set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.cpp") 175 file(WRITE "${SRC_FILE}" "${OpenMP_C_CXX_${SRC_FILE_CONTENT_VAR}}") 176 elseif("${LANG}" STREQUAL "Fortran") 177 set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.f90") 178 file(WRITE "${SRC_FILE}_in" "${OpenMP_Fortran_${SRC_FILE_CONTENT_VAR}}") 179 configure_file("${SRC_FILE}_in" "${SRC_FILE}" @ONLY) 180 endif() 181 set(${SRC_FILE_FULLPATH} "${SRC_FILE}" PARENT_SCOPE) 182endfunction() 183 184include(CMakeParseImplicitLinkInfo) 185 186function(_OPENMP_GET_FLAGS LANG FLAG_MODE OPENMP_FLAG_VAR OPENMP_LIB_NAMES_VAR) 187 _OPENMP_FLAG_CANDIDATES("${LANG}") 188 _OPENMP_WRITE_SOURCE_FILE("${LANG}" "TEST_SOURCE" OpenMPTryFlag _OPENMP_TEST_SRC) 189 190 unset(OpenMP_VERBOSE_COMPILE_OPTIONS) 191 if(UNIX) 192 separate_arguments(OpenMP_VERBOSE_OPTIONS UNIX_COMMAND "${CMAKE_${LANG}_VERBOSE_FLAG}") 193 else() 194 separate_arguments(OpenMP_VERBOSE_OPTIONS WINDOWS_COMMAND "${CMAKE_${LANG}_VERBOSE_FLAG}") 195 endif() 196 foreach(_VERBOSE_OPTION IN LISTS OpenMP_VERBOSE_OPTIONS) 197 if(NOT _VERBOSE_OPTION MATCHES "^-Wl,") 198 list(APPEND OpenMP_VERBOSE_COMPILE_OPTIONS ${_VERBOSE_OPTION}) 199 endif() 200 endforeach() 201 202 foreach(OPENMP_FLAG IN LISTS OpenMP_${LANG}_FLAG_CANDIDATES) 203 set(OPENMP_FLAGS_TEST "${OPENMP_FLAG}") 204 if(OpenMP_VERBOSE_COMPILE_OPTIONS) 205 string(APPEND OPENMP_FLAGS_TEST " ${OpenMP_VERBOSE_COMPILE_OPTIONS}") 206 endif() 207 string(REGEX REPLACE "[-/=+]" "" OPENMP_PLAIN_FLAG "${OPENMP_FLAG}") 208 209 # NOTE [ Linking both MKL and OpenMP ] 210 # 211 # It is crucial not to link two `libomp` libraries together, even when they 212 # are both Intel or GNU. Otherwise, you will end up with this nasty error, 213 # and may get incorrect results. 214 # 215 # OMP: Error #15: Initializing libomp.dylib, but found libiomp5.dylib 216 # already initialized. 217 # 218 # OMP: Hint This means that multiple copies of the OpenMP runtime have 219 # been linked into the program. That is dangerous, since it can degrade 220 # performance or cause incorrect results. The best thing to do is to 221 # ensure that only a single OpenMP runtime is linked into the process, 222 # e.g. by avoiding static linking of the OpenMP runtime in any library. As 223 # an unsafe, unsupported, undocumented workaround you can set the 224 # environment variable KMP_DUPLICATE_LIB_OK=TRUE to allow the program to 225 # continue to execute, but that may cause crashes or silently produce 226 # incorrect results. For more information, please see 227 # http://openmp.llvm.org/ 228 # 229 # So here, before we test each flag combination, we first try directly 230 # linking against any `libomp` MKL has linked to (if any and when MKL is 231 # specified). This allows us to do sensible things in tricky (yet common) 232 # conditions like: 233 # - using `clang` (so no native GNU OpenMP), and 234 # - having `brew` `libomp` installed at `/usr/local/`, and 235 # - having `conda` `mkl` installed at `$HOME/conda/`, with includes a copy 236 # of `libiomp5`. 237 # Rather than blindly picking one, we pick what ever `FindMKL.cmake` chooses 238 # to avoid conflicts. 239 # 240 # `FindMKL.cmake` calls `FindOpenMP.cmake` when trying to find `gomp` and 241 # thus will cause infinite recursion if this is not taken care of. Therefore, 242 # we record an internal flag to detect repeatedly inclusion. 243 244 if(NOT MKL_OPENMP_LIBRARY AND NOT IN_FIND_OMP AND BLAS STREQUAL "MKL") 245 set(IN_FIND_OMP ON CACHE BOOL "" FORCE) 246 find_package(MKL QUIET) 247 unset(IN_FIND_OMP CACHE) 248 endif() 249 250 if(MKL_OPENMP_LIBRARY) 251 # If we already link OpenMP via MKL, use that. Otherwise at run-time 252 # OpenMP will complain about being initialized twice (OMP: Error #15), 253 # can may cause incorrect behavior. 254 set(OpenMP_libomp_LIBRARY "${MKL_OPENMP_LIBRARY}" CACHE STRING "libomp location for OpenMP") 255 endif() 256 257 if (NOT OpenMP_libomp_LIBRARY) 258 find_library(OpenMP_libomp_LIBRARY 259 NAMES omp gomp iomp5 260 HINTS ${CMAKE_${LANG}_IMPLICIT_LINK_DIRECTORIES} 261 DOC "libomp location for OpenMP" 262 ) 263 mark_as_advanced(OpenMP_libomp_LIBRARY) 264 endif() 265 266 if(OpenMP_libomp_LIBRARY MATCHES "iomp5") 267 set(OpenMP_libiomp5_LIBRARY "${MKL_OPENMP_LIBRARY}" CACHE STRING "libiomp5 location for OpenMP") 268 if("-fopenmp=libiomp5" IN_LIST OpenMP_${LANG}_FLAG_CANDIDATES) 269 get_filename_component(iomp5_dir "${OpenMP_libomp_LIBRARY}" DIRECTORY) 270 set(OPENMP_FLAGS_TEST "-fopenmp=libiomp5 -L${iomp5_dir}") 271 endif() 272 endif() 273 274 if(OpenMP_libomp_LIBRARY) 275 message(STATUS "Check OMP with lib ${OpenMP_libomp_LIBRARY} and flags ${OPENMP_FLAGS_TEST}") 276 try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC} 277 CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}" 278 LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG} ${OpenMP_libomp_LIBRARY} 279 OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT 280 ) 281 if(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG}) 282 set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG}" PARENT_SCOPE) 283 if(OpenMP_libomp_LIBRARY MATCHES "iomp5") 284 set("${OPENMP_LIB_NAMES_VAR}" "libiomp5" PARENT_SCOPE) 285 else() 286 set("${OPENMP_LIB_NAMES_VAR}" "libomp" PARENT_SCOPE) 287 endif() 288 break() 289 else() 290 message(WARNING "Detecting ${LANG} OpenMP compiler ABI info compiled with the following output:\n${OpenMP_TRY_COMPILE_OUTPUT}") 291 endif() 292 endif() 293 294 try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC} 295 CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}" 296 LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG} 297 OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT 298 ) 299 300 if(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG}) 301 set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG}" PARENT_SCOPE) 302 303 if(CMAKE_${LANG}_VERBOSE_FLAG) 304 unset(OpenMP_${LANG}_IMPLICIT_LIBRARIES) 305 unset(OpenMP_${LANG}_IMPLICIT_LINK_DIRS) 306 unset(OpenMP_${LANG}_IMPLICIT_FWK_DIRS) 307 unset(OpenMP_${LANG}_LOG_VAR) 308 309 file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log 310 "Detecting ${LANG} OpenMP compiler ABI info compiled with the following output:\n${OpenMP_TRY_COMPILE_OUTPUT}\n\n") 311 312 cmake_parse_implicit_link_info("${OpenMP_TRY_COMPILE_OUTPUT}" 313 OpenMP_${LANG}_IMPLICIT_LIBRARIES 314 OpenMP_${LANG}_IMPLICIT_LINK_DIRS 315 OpenMP_${LANG}_IMPLICIT_FWK_DIRS 316 OpenMP_${LANG}_LOG_VAR 317 "${CMAKE_${LANG}_IMPLICIT_OBJECT_REGEX}" 318 ) 319 320 file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log 321 "Parsed ${LANG} OpenMP implicit link information from above output:\n${OpenMP_${LANG}_LOG_VAR}\n\n") 322 323 unset(_OPENMP_LIB_NAMES) 324 foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_IMPLICIT_LIBRARIES) 325 get_filename_component(_OPENMP_IMPLICIT_LIB_DIR "${_OPENMP_IMPLICIT_LIB}" DIRECTORY) 326 get_filename_component(_OPENMP_IMPLICIT_LIB_NAME "${_OPENMP_IMPLICIT_LIB}" NAME) 327 get_filename_component(_OPENMP_IMPLICIT_LIB_PLAIN "${_OPENMP_IMPLICIT_LIB}" NAME_WE) 328 string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" _OPENMP_IMPLICIT_LIB_PLAIN_ESC "${_OPENMP_IMPLICIT_LIB_PLAIN}") 329 string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" _OPENMP_IMPLICIT_LIB_PATH_ESC "${_OPENMP_IMPLICIT_LIB}") 330 if(NOT ( "${_OPENMP_IMPLICIT_LIB}" IN_LIST CMAKE_${LANG}_IMPLICIT_LINK_LIBRARIES 331 OR "${CMAKE_${LANG}_STANDARD_LIBRARIES}" MATCHES "(^| )(-Wl,)?(-l)?(${_OPENMP_IMPLICIT_LIB_PLAIN_ESC}|${_OPENMP_IMPLICIT_LIB_PATH_ESC})( |$)" 332 OR "${CMAKE_${LANG}_LINK_EXECUTABLE}" MATCHES "(^| )(-Wl,)?(-l)?(${_OPENMP_IMPLICIT_LIB_PLAIN_ESC}|${_OPENMP_IMPLICIT_LIB_PATH_ESC})( |$)" ) ) 333 if(_OPENMP_IMPLICIT_LIB_DIR) 334 set(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY "${_OPENMP_IMPLICIT_LIB}" CACHE FILEPATH 335 "Path to the ${_OPENMP_IMPLICIT_LIB_PLAIN} library for OpenMP") 336 else() 337 find_library(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY 338 NAMES "${_OPENMP_IMPLICIT_LIB_NAME}" 339 DOC "Path to the ${_OPENMP_IMPLICIT_LIB_PLAIN} library for OpenMP" 340 HINTS ${OpenMP_${LANG}_IMPLICIT_LINK_DIRS} 341 CMAKE_FIND_ROOT_PATH_BOTH 342 NO_DEFAULT_PATH 343 ) 344 endif() 345 mark_as_advanced(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY) 346 list(APPEND _OPENMP_LIB_NAMES ${_OPENMP_IMPLICIT_LIB_PLAIN}) 347 endif() 348 endforeach() 349 set("${OPENMP_LIB_NAMES_VAR}" "${_OPENMP_LIB_NAMES}" PARENT_SCOPE) 350 else() 351 # We do not know how to extract implicit OpenMP libraries for this compiler. 352 # Assume that it handles them automatically, e.g. the Intel Compiler on 353 # Windows should put the dependency in its object files. 354 set("${OPENMP_LIB_NAMES_VAR}" "" PARENT_SCOPE) 355 endif() 356 break() 357 elseif((CMAKE_${LANG}_COMPILER_ID STREQUAL "AppleClang") AND 358 (NOT CMAKE_${LANG}_COMPILER_VERSION VERSION_LESS "7.0")) 359 360 # LLVM 3.7 supports OpenMP 3.1, and continues to add more features to 361 # support newer OpenMP standards in new versions. 362 # http://releases.llvm.org/3.7.0/tools/clang/docs/ReleaseNotes.html#openmp-support 363 # 364 # Apple Clang 7.0 is the first version based on LLVM 3.7 or later. 365 # https://en.wikipedia.org/wiki/Xcode#Latest_versions 366 # 367 # Check for separate OpenMP library on AppleClang 7+ 368 find_library(OpenMP_libomp_LIBRARY 369 NAMES omp gomp iomp5 370 HINTS ${CMAKE_${LANG}_IMPLICIT_LINK_DIRECTORIES} 371 DOC "libomp location for OpenMP" 372 ) 373 mark_as_advanced(OpenMP_libomp_LIBRARY) 374 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 if (NOT ${OpenMP_${LANG}_FIND_QUIETLY}) 392 message(STATUS "OpenMP try_compile log:\n${OpenMP_TRY_COMPILE_OUTPUT}\n\n") 393 endif() 394 set("${OPENMP_LIB_NAMES_VAR}" "NOTFOUND" PARENT_SCOPE) 395 set("${OPENMP_FLAG_VAR}" "NOTFOUND" PARENT_SCOPE) 396 endforeach() 397 398 unset(OpenMP_VERBOSE_COMPILE_OPTIONS) 399endfunction() 400 401set(OpenMP_C_CXX_CHECK_VERSION_SOURCE 402" 403#include <stdio.h> 404#include <omp.h> 405const char ompver_str[] = { 'I', 'N', 'F', 'O', ':', 'O', 'p', 'e', 'n', 'M', 406 'P', '-', 'd', 'a', 't', 'e', '[', 407 ('0' + ((_OPENMP/100000)%10)), 408 ('0' + ((_OPENMP/10000)%10)), 409 ('0' + ((_OPENMP/1000)%10)), 410 ('0' + ((_OPENMP/100)%10)), 411 ('0' + ((_OPENMP/10)%10)), 412 ('0' + ((_OPENMP/1)%10)), 413 ']', '\\0' }; 414int main(void) 415{ 416 puts(ompver_str); 417 return 0; 418} 419") 420 421set(OpenMP_Fortran_CHECK_VERSION_SOURCE 422" 423 program omp_ver 424 @OpenMP_Fortran_INCLUDE_LINE@ 425 integer, parameter :: zero = ichar('0') 426 integer, parameter :: ompv = openmp_version 427 character, dimension(24), parameter :: ompver_str =& 428 (/ 'I', 'N', 'F', 'O', ':', 'O', 'p', 'e', 'n', 'M', 'P', '-',& 429 'd', 'a', 't', 'e', '[',& 430 char(zero + mod(ompv/100000, 10)),& 431 char(zero + mod(ompv/10000, 10)),& 432 char(zero + mod(ompv/1000, 10)),& 433 char(zero + mod(ompv/100, 10)),& 434 char(zero + mod(ompv/10, 10)),& 435 char(zero + mod(ompv/1, 10)), ']' /) 436 print *, ompver_str 437 end program omp_ver 438") 439 440function(_OPENMP_GET_SPEC_DATE LANG SPEC_DATE) 441 _OPENMP_WRITE_SOURCE_FILE("${LANG}" "CHECK_VERSION_SOURCE" OpenMPCheckVersion _OPENMP_TEST_SRC) 442 443 set(BIN_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindOpenMP/ompver_${LANG}.bin") 444 string(REGEX REPLACE "[-/=+]" "" OPENMP_PLAIN_FLAG "${OPENMP_FLAG}") 445 try_compile(OpenMP_SPECTEST_${LANG}_${OPENMP_PLAIN_FLAG} "${CMAKE_BINARY_DIR}" "${_OPENMP_TEST_SRC}" 446 CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OpenMP_${LANG}_FLAGS}" 447 COPY_FILE ${BIN_FILE} 448 OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT) 449 450 if(${OpenMP_SPECTEST_${LANG}_${OPENMP_PLAIN_FLAG}}) 451 file(STRINGS ${BIN_FILE} specstr LIMIT_COUNT 1 REGEX "INFO:OpenMP-date") 452 set(regex_spec_date ".*INFO:OpenMP-date\\[0*([^]]*)\\].*") 453 if("${specstr}" MATCHES "${regex_spec_date}") 454 set(${SPEC_DATE} "${CMAKE_MATCH_1}" PARENT_SCOPE) 455 endif() 456 else() 457 file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log 458 "Detecting ${LANG} OpenMP version failed with the following output:\n${OpenMP_TRY_COMPILE_OUTPUT}\n\n") 459 endif() 460endfunction() 461 462macro(_OPENMP_SET_VERSION_BY_SPEC_DATE LANG) 463 set(OpenMP_SPEC_DATE_MAP 464 # Preview versions 465 "201611=5.0" # OpenMP 5.0 preview 1 466 # Combined versions, 2.5 onwards 467 "201511=4.5" 468 "201307=4.0" 469 "201107=3.1" 470 "200805=3.0" 471 "200505=2.5" 472 # C/C++ version 2.0 473 "200203=2.0" 474 # Fortran version 2.0 475 "200011=2.0" 476 # Fortran version 1.1 477 "199911=1.1" 478 # C/C++ version 1.0 (there's no 1.1 for C/C++) 479 "199810=1.0" 480 # Fortran version 1.0 481 "199710=1.0" 482 ) 483 484 if(OpenMP_${LANG}_SPEC_DATE) 485 string(REGEX MATCHALL "${OpenMP_${LANG}_SPEC_DATE}=([0-9]+)\\.([0-9]+)" _version_match "${OpenMP_SPEC_DATE_MAP}") 486 else() 487 set(_version_match "") 488 endif() 489 if(NOT _version_match STREQUAL "") 490 set(OpenMP_${LANG}_VERSION_MAJOR ${CMAKE_MATCH_1}) 491 set(OpenMP_${LANG}_VERSION_MINOR ${CMAKE_MATCH_2}) 492 set(OpenMP_${LANG}_VERSION "${OpenMP_${LANG}_VERSION_MAJOR}.${OpenMP_${LANG}_VERSION_MINOR}") 493 else() 494 unset(OpenMP_${LANG}_VERSION_MAJOR) 495 unset(OpenMP_${LANG}_VERSION_MINOR) 496 unset(OpenMP_${LANG}_VERSION) 497 endif() 498 unset(_version_match) 499 unset(OpenMP_SPEC_DATE_MAP) 500endmacro() 501 502foreach(LANG IN ITEMS C CXX) 503 if(CMAKE_${LANG}_COMPILER_LOADED) 504 if(NOT DEFINED OpenMP_${LANG}_FLAGS OR "${OpenMP_${LANG}_FLAGS}" STREQUAL "NOTFOUND" 505 OR NOT DEFINED OpenMP_${LANG}_LIB_NAMES OR "${OpenMP_${LANG}_LIB_NAMES}" STREQUAL "NOTFOUND") 506 _OPENMP_GET_FLAGS("${LANG}" "${LANG}" OpenMP_${LANG}_FLAGS_WORK OpenMP_${LANG}_LIB_NAMES_WORK) 507 endif() 508 509 set(OpenMP_${LANG}_FLAGS "${OpenMP_${LANG}_FLAGS_WORK}" 510 CACHE STRING "${LANG} compiler flags for OpenMP parallelization") 511 set(OpenMP_${LANG}_LIB_NAMES "${OpenMP_${LANG}_LIB_NAMES_WORK}" 512 CACHE STRING "${LANG} compiler libraries for OpenMP parallelization") 513 mark_as_advanced(OpenMP_${LANG}_FLAGS OpenMP_${LANG}_LIB_NAMES) 514 endif() 515endforeach() 516 517if(CMAKE_Fortran_COMPILER_LOADED) 518 if(NOT DEFINED OpenMP_Fortran_FLAGS OR "${OpenMP_Fortran_FLAGS}" STREQUAL "NOTFOUND" 519 OR NOT DEFINED OpenMP_Fortran_LIB_NAMES OR "${OpenMP_Fortran_LIB_NAMES}" STREQUAL "NOTFOUND" 520 OR NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_MODULE) 521 set(OpenMP_Fortran_INCLUDE_LINE "use omp_lib\n implicit none") 522 _OPENMP_GET_FLAGS("Fortran" "FortranHeader" OpenMP_Fortran_FLAGS_WORK OpenMP_Fortran_LIB_NAMES_WORK) 523 if(OpenMP_Fortran_FLAGS_WORK) 524 set(OpenMP_Fortran_HAVE_OMPLIB_MODULE TRUE CACHE BOOL INTERNAL "") 525 endif() 526 527 set(OpenMP_Fortran_FLAGS "${OpenMP_Fortran_FLAGS_WORK}" 528 CACHE STRING "Fortran compiler flags for OpenMP parallelization") 529 set(OpenMP_Fortran_LIB_NAMES "${OpenMP_Fortran_LIB_NAMES_WORK}" 530 CACHE STRING "Fortran compiler libraries for OpenMP parallelization") 531 mark_as_advanced(OpenMP_Fortran_FLAGS OpenMP_Fortran_LIB_NAMES) 532 endif() 533 534 if(NOT DEFINED OpenMP_Fortran_FLAGS OR "${OpenMP_Fortran_FLAGS}" STREQUAL "NOTFOUND" 535 OR NOT DEFINED OpenMP_Fortran_LIB_NAMES OR "${OpenMP_Fortran_LIB_NAMES}" STREQUAL "NOTFOUND" 536 OR NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_HEADER) 537 set(OpenMP_Fortran_INCLUDE_LINE "implicit none\n include 'omp_lib.h'") 538 _OPENMP_GET_FLAGS("Fortran" "FortranModule" OpenMP_Fortran_FLAGS_WORK OpenMP_Fortran_LIB_NAMES_WORK) 539 if(OpenMP_Fortran_FLAGS_WORK) 540 set(OpenMP_Fortran_HAVE_OMPLIB_HEADER TRUE CACHE BOOL INTERNAL "") 541 endif() 542 543 set(OpenMP_Fortran_FLAGS "${OpenMP_Fortran_FLAGS_WORK}" 544 CACHE STRING "Fortran compiler flags for OpenMP parallelization") 545 546 set(OpenMP_Fortran_LIB_NAMES "${OpenMP_Fortran_LIB_NAMES}" 547 CACHE STRING "Fortran compiler libraries for OpenMP parallelization") 548 endif() 549 550 if(OpenMP_Fortran_HAVE_OMPLIB_MODULE) 551 set(OpenMP_Fortran_INCLUDE_LINE "use omp_lib\n implicit none") 552 else() 553 set(OpenMP_Fortran_INCLUDE_LINE "implicit none\n include 'omp_lib.h'") 554 endif() 555endif() 556 557if(NOT OpenMP_FIND_COMPONENTS) 558 set(OpenMP_FINDLIST C CXX Fortran) 559else() 560 set(OpenMP_FINDLIST ${OpenMP_FIND_COMPONENTS}) 561endif() 562 563unset(_OpenMP_MIN_VERSION) 564 565include(FindPackageHandleStandardArgs) 566 567foreach(LANG IN LISTS OpenMP_FINDLIST) 568 if(CMAKE_${LANG}_COMPILER_LOADED) 569 if (NOT OpenMP_${LANG}_SPEC_DATE AND OpenMP_${LANG}_FLAGS) 570 _OPENMP_GET_SPEC_DATE("${LANG}" OpenMP_${LANG}_SPEC_DATE_INTERNAL) 571 set(OpenMP_${LANG}_SPEC_DATE "${OpenMP_${LANG}_SPEC_DATE_INTERNAL}" CACHE 572 INTERNAL "${LANG} compiler's OpenMP specification date") 573 _OPENMP_SET_VERSION_BY_SPEC_DATE("${LANG}") 574 endif() 575 576 set(OpenMP_${LANG}_FIND_QUIETLY ${OpenMP_FIND_QUIETLY}) 577 set(OpenMP_${LANG}_FIND_REQUIRED ${OpenMP_FIND_REQUIRED}) 578 set(OpenMP_${LANG}_FIND_VERSION ${OpenMP_FIND_VERSION}) 579 set(OpenMP_${LANG}_FIND_VERSION_EXACT ${OpenMP_FIND_VERSION_EXACT}) 580 581 set(_OPENMP_${LANG}_REQUIRED_VARS OpenMP_${LANG}_FLAGS) 582 if("${OpenMP_${LANG}_LIB_NAMES}" STREQUAL "NOTFOUND") 583 set(_OPENMP_${LANG}_REQUIRED_LIB_VARS OpenMP_${LANG}_LIB_NAMES) 584 else() 585 foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_LIB_NAMES) 586 list(APPEND _OPENMP_${LANG}_REQUIRED_LIB_VARS OpenMP_${_OPENMP_IMPLICIT_LIB}_LIBRARY) 587 endforeach() 588 endif() 589 590 find_package_handle_standard_args(OpenMP_${LANG} 591 REQUIRED_VARS OpenMP_${LANG}_FLAGS ${_OPENMP_${LANG}_REQUIRED_LIB_VARS} 592 VERSION_VAR OpenMP_${LANG}_VERSION 593 ) 594 595 if(OpenMP_${LANG}_FOUND) 596 if(DEFINED OpenMP_${LANG}_VERSION) 597 if(NOT _OpenMP_MIN_VERSION OR _OpenMP_MIN_VERSION VERSION_GREATER OpenMP_${LANG}_VERSION) 598 set(_OpenMP_MIN_VERSION OpenMP_${LANG}_VERSION) 599 endif() 600 endif() 601 set(OpenMP_${LANG}_LIBRARIES "") 602 foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_LIB_NAMES) 603 list(APPEND OpenMP_${LANG}_LIBRARIES "${OpenMP_${_OPENMP_IMPLICIT_LIB}_LIBRARY}") 604 endforeach() 605 606 if(NOT TARGET OpenMP::OpenMP_${LANG}) 607 add_library(OpenMP::OpenMP_${LANG} INTERFACE IMPORTED) 608 endif() 609 if(OpenMP_${LANG}_FLAGS) 610 if(UNIX) 611 separate_arguments(_OpenMP_${LANG}_OPTIONS UNIX_COMMAND "${OpenMP_${LANG}_FLAGS}") 612 else() 613 separate_arguments(_OpenMP_${LANG}_OPTIONS WINDOWS_COMMAND "${OpenMP_${LANG}_FLAGS}") 614 endif() 615 set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY 616 INTERFACE_COMPILE_OPTIONS "$<$<COMPILE_LANGUAGE:${LANG}>:${_OpenMP_${LANG}_OPTIONS}>") 617 unset(_OpenMP_${LANG}_OPTIONS) 618 endif() 619 if(OpenMP_${LANG}_LIBRARIES) 620 set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY 621 INTERFACE_LINK_LIBRARIES "${OpenMP_${LANG}_LIBRARIES}") 622 endif() 623 endif() 624 endif() 625endforeach() 626 627unset(_OpenMP_REQ_VARS) 628foreach(LANG IN ITEMS C CXX Fortran) 629 if((NOT OpenMP_FIND_COMPONENTS AND CMAKE_${LANG}_COMPILER_LOADED) OR LANG IN_LIST OpenMP_FIND_COMPONENTS) 630 list(APPEND _OpenMP_REQ_VARS "OpenMP_${LANG}_FOUND") 631 endif() 632endforeach() 633 634find_package_handle_standard_args(OpenMP 635 REQUIRED_VARS ${_OpenMP_REQ_VARS} 636 VERSION_VAR ${_OpenMP_MIN_VERSION} 637 HANDLE_COMPONENTS) 638 639set(OPENMP_FOUND ${OpenMP_FOUND}) 640 641if(CMAKE_Fortran_COMPILER_LOADED AND OpenMP_Fortran_FOUND) 642 if(NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_MODULE) 643 set(OpenMP_Fortran_HAVE_OMPLIB_MODULE FALSE CACHE BOOL INTERNAL "") 644 endif() 645 if(NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_HEADER) 646 set(OpenMP_Fortran_HAVE_OMPLIB_HEADER FALSE CACHE BOOL INTERNAL "") 647 endif() 648endif() 649 650if(NOT ( CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED OR CMAKE_Fortran_COMPILER_LOADED )) 651 message(SEND_ERROR "FindOpenMP requires the C, CXX or Fortran languages to be enabled") 652endif() 653 654unset(OpenMP_C_CXX_TEST_SOURCE) 655unset(OpenMP_Fortran_TEST_SOURCE) 656unset(OpenMP_C_CXX_CHECK_VERSION_SOURCE) 657unset(OpenMP_Fortran_CHECK_VERSION_SOURCE) 658unset(OpenMP_Fortran_INCLUDE_LINE) 659 660cmake_policy(POP) 661