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