mirror of
https://github.com/pytorch/pytorch.git
synced 2026-10-28 18:56:51 +08:00
Fixes #193784. Also fixes #176091, the SDPA symptom of the same defect. On MSVC x64 `torch_cpu` imports two OpenMP runtimes at once. `-openmp:experimental` compiles `#pragma omp parallel` into `_vcomp_*` calls and links VCOMP140 by itself, while this module's library search finds the `libomp.lib` shipped with Visual Studio and adds it to the link line. The two runtimes share no state, so inside a vcomp team every worker asks libomp and is told `omp_get_num_threads() == 1` and `omp_get_thread_num() == 0`. `ParallelOpenMP.h` then hands every worker the whole range and `at::get_thread_num()` returns 0 on all of them, so each one runs the entire chunk and any non-idempotent kernel body silently accumulates N times. The fix skips both library searches when the compiler id is MSVC - the generic one and the `OpenMP_PREFIX` one. There is nothing for them to find: cl.exe links the runtime matching its `-openmp` flag on its own, so naming a library is redundant at best, and naming libomp is the defect. The prefix search needs the guard too because `HINTS` adds to the default search paths rather than replacing them, so any non-empty `OMP_PREFIX` - even one pointing at a directory that does not exist - still finds the Visual Studio `libomp.lib`. The compiler id is checked rather than `MSVC`, because `Platform/Windows-Clang.cmake` sets `MSVC` for clang-cl too, and clang-cl emits `__kmpc_*` calls that do need libomp. For the same reason the MSVC ARM64 special case is removed: it was guarded on bare `MSVC`, so on clang-cl ARM64 it linked vcomp for a compiler that needs libomp, and on cl.exe ARM64 the new check already covers it. ### Rebuilding The fix is invisible to an in-place reconfigure. `OpenMP_<LANG>_FLAGS`, `OpenMP_<LANG>_LIB_NAMES` and `OpenMP_libomp_LIBRARY` are cache entries. This module skips detection while the first two are cached, and even when detection reruns, both guarded searches start with `NOT OpenMP_libomp_LIBRARY`, so a cached libomp path is reused. An existing build directory therefore keeps linking libomp. Delete the build directory, or clear the entries first: ``` cmake -U "OpenMP_*" <build-dir> ``` ### History I first sent this extending the ARM64 branch to find vcomp explicitly. @frost-intel pointed out that linking vcomp explicitly is redundant and that `MSVC` is too broad a guard. #196730 by @taras-janea implemented that suggestion and also removes the ARM64 block, which is adopted here with co-authorship. @ezyang's review of #196730 caught the unguarded `OpenMP_PREFIX` search. ### Test Plan Windows 11, MSVC 14.44.35207, CPU-only, no MKL. **The module in isolation, each configure in a fresh directory.** A minimal project that runs `find_package(OpenMP)` under the real MSVC environment and prints what the module selects: | case | `OpenMP_CXX_LIB_NAMES` | |---|---| | main | `libomp` | | this PR | empty | | previous revision of this PR, `OMP_PREFIX=C:\nonexistent` | `libomp` | | this PR, `OMP_PREFIX=C:\nonexistent` | empty | | configured with main, then reconfigured in place with this PR | `libomp` (stale cache) | | same directory, reconfigured with `-U "OpenMP_*"` | empty | **Full build, 8 intra-op threads.** Integer addition is exactly associative, so a wrong integer sum cannot come from reassociation: ``` python -c "import torch; y = torch.ones(40_000_000, dtype=torch.int64); print(sorted({y.sum().item() for _ in range(8)}))" ``` ``` before: [600000000, 640000000] # 15x and 16x the true 40000000 after: [40000000] ``` ``` python test/test_transformers.py TestSDPACpuOnlyCPU TestSDPAFailureModesCPU ``` ``` before: FAILED (failures=3108, skipped=58) after: OK (skipped=58) # 3203 tests ``` ``` dumpbin -imports build/bin/torch_cpu.dll ``` ``` before: VCOMP140.DLL and libomp140.x86_64.dll after: VCOMP140.DLL only, zero __kmpc_* imports ``` Where these full-build numbers came from: the first revision of this change (generic-search guard only), on main as of `7744b78e00e`, in an existing build directory with the `OpenMP_*` cache entries cleared before reconfiguring - the `cmake -U "OpenMP_*"` equivalent, not a deleted build directory. The later revisions only remove the ARM64 block and guard the `OMP_PREFIX` search. On x64 without `OMP_PREFIX` they select the same libraries, as the fresh-directory table above shows, so the link line is unchanged and rebuilding did not relink `torch_cpu.dll`. `cmake/public/mkldnn.cmake:20-30` relies on `caffe2::openmp` to give binaries that pull dnnl objects their OpenMP runtime, because oneDNN adds no link dependency of its own. With an empty MSVC library list `caffe2::openmp` carries no library, so those binaries could fail to resolve `omp_*`. All 125 executables under `build/bin` - the C++ tests plus `protoc` and two benchmarks - were deleted and linked fresh, with no unresolved externals. `test_jit` is the only one that links dnnl directly (`test/cpp/jit/CMakeLists.txt:129`). It links, loads and runs: 563 of 590 pass, and none of the 26 failures involves OpenMP - 14 are test backends this Windows build does not register, 9 are `pinv`/`tensorinv` in a build without LAPACK, 2 cannot read a model archive, and 1 matches an error message. The change touches no compiler flag, so nothing recompiles; the full `pip install -e . -v --no-build-isolation` takes about fifteen minutes. MSVC ARM64 is covered by CI rather than by me: `windows-arm64-binary-wheel` built the previous revision of this PR (`e27f297`), which already dropped the ARM64 block, with `USE_MKL` off, `BLAS=apl` and `-openmp:experimental`, and it linked. That was the real risk of removing the block - no vcomp on the link line and unresolved `_vcomp_*` symbols - so the autolink holds on ARM64 too. It shows the link, not runtime behaviour. clang-cl is untested, for lack of the toolchain; the reasoning is above. Developed with AI assistance (Claude), which also ran the measurements on my Windows machine; I reviewed the change and the results. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Pull Request resolved: https://github.com/pytorch/pytorch/pull/193792 Approved by: https://github.com/zklaus, https://github.com/atalman Co-authored-by: Taras <taras@janeasystems.com>
723 lines
30 KiB
CMake
723 lines
30 KiB
CMake
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
# file Copyright.txt or https://cmake.org/licensing for details.
|
|
|
|
#.rst:
|
|
# FindOpenMP
|
|
# ----------
|
|
#
|
|
# Finds OpenMP support
|
|
#
|
|
# This module can be used to detect OpenMP support in a compiler. If
|
|
# the compiler supports OpenMP, the flags required to compile with
|
|
# OpenMP support are returned in variables for the different languages.
|
|
# The variables may be empty if the compiler does not need a special
|
|
# flag to support OpenMP.
|
|
#
|
|
# Variables
|
|
# ^^^^^^^^^
|
|
#
|
|
# The module exposes the components ``C``, ``CXX``, and ``Fortran``.
|
|
# Each of these controls the various languages to search OpenMP support for.
|
|
#
|
|
# Depending on the enabled components the following variables will be set:
|
|
#
|
|
# ``OpenMP_FOUND``
|
|
# Variable indicating that OpenMP flags for all requested languages have been found.
|
|
# If no components are specified, this is true if OpenMP settings for all enabled languages
|
|
# were detected.
|
|
# ``OpenMP_VERSION``
|
|
# Minimal version of the OpenMP standard detected among the requested languages,
|
|
# or all enabled languages if no components were specified.
|
|
#
|
|
# This module will set the following variables per language in your
|
|
# project, where ``<lang>`` is one of C, CXX, or Fortran:
|
|
#
|
|
# ``OpenMP_<lang>_FOUND``
|
|
# Variable indicating if OpenMP support for ``<lang>`` was detected.
|
|
# ``OpenMP_<lang>_FLAGS``
|
|
# OpenMP compiler flags for ``<lang>``, separated by spaces.
|
|
#
|
|
# For linking with OpenMP code written in ``<lang>``, the following
|
|
# variables are provided:
|
|
#
|
|
# ``OpenMP_<lang>_LIB_NAMES``
|
|
# :ref:`;-list <CMake Language Lists>` of libraries for OpenMP programs for ``<lang>``.
|
|
# ``OpenMP_<libname>_LIBRARY``
|
|
# Location of the individual libraries needed for OpenMP support in ``<lang>``.
|
|
# ``OpenMP_<lang>_LIBRARIES``
|
|
# A list of libraries needed to link with OpenMP code written in ``<lang>``.
|
|
#
|
|
# Additionally, the module provides :prop_tgt:`IMPORTED` targets:
|
|
#
|
|
# ``OpenMP::OpenMP_<lang>``
|
|
# Target for using OpenMP from ``<lang>``.
|
|
#
|
|
# Specifically for Fortran, the module sets the following variables:
|
|
#
|
|
# ``OpenMP_Fortran_HAVE_OMPLIB_HEADER``
|
|
# Boolean indicating if OpenMP is accessible through ``omp_lib.h``.
|
|
# ``OpenMP_Fortran_HAVE_OMPLIB_MODULE``
|
|
# Boolean indicating if OpenMP is accessible through the ``omp_lib`` Fortran module.
|
|
#
|
|
# The module will also try to provide the OpenMP version variables:
|
|
#
|
|
# ``OpenMP_<lang>_SPEC_DATE``
|
|
# Date of the OpenMP specification implemented by the ``<lang>`` compiler.
|
|
# ``OpenMP_<lang>_VERSION_MAJOR``
|
|
# Major version of OpenMP implemented by the ``<lang>`` compiler.
|
|
# ``OpenMP_<lang>_VERSION_MINOR``
|
|
# Minor version of OpenMP implemented by the ``<lang>`` compiler.
|
|
# ``OpenMP_<lang>_VERSION``
|
|
# OpenMP version implemented by the ``<lang>`` compiler.
|
|
#
|
|
# The specification date is formatted as given in the OpenMP standard:
|
|
# ``yyyymm`` where ``yyyy`` and ``mm`` represents the year and month of
|
|
# the OpenMP specification implemented by the ``<lang>`` compiler.
|
|
|
|
cmake_policy(PUSH)
|
|
cmake_policy(SET CMP0012 NEW) # if() recognizes numbers and booleans
|
|
cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced
|
|
cmake_policy(SET CMP0057 NEW) # if IN_LIST
|
|
|
|
|
|
if(NOT "$ENV{OMP_PREFIX}" STREQUAL "")
|
|
set(OpenMP_PREFIX "$ENV{OMP_PREFIX}")
|
|
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" AND EXISTS /opt/homebrew/opt/libomp)
|
|
set(OpenMP_PREFIX "/opt/homebrew/opt/libomp")
|
|
endif()
|
|
|
|
function(_OPENMP_FLAG_CANDIDATES LANG)
|
|
if(NOT OpenMP_${LANG}_FLAG)
|
|
unset(OpenMP_FLAG_CANDIDATES)
|
|
|
|
set(OMP_FLAG_GNU "-fopenmp")
|
|
if(CMAKE_${LANG}_COMPILER_ID STREQUAL "Clang" AND CMAKE_${LANG}_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
|
# clang-cl specific flags
|
|
set(OMP_FLAG_Clang "-Xclang -fopenmp=libomp" "-Xclang -fopenmp=libiomp5" "-Xclang -fopenmp")
|
|
else()
|
|
# regular clang flags
|
|
set(OMP_FLAG_Clang "-fopenmp=libomp" "-fopenmp=libiomp5" "-fopenmp")
|
|
endif()
|
|
|
|
if(WIN32)
|
|
# Prefer Intel OpenMP header which can be provided by CMAKE_INCLUDE_PATH.
|
|
# Note that CMAKE_INCLUDE_PATH is searched before CMAKE_SYSTEM_INCLUDE_PATH (MSVC path in this case)
|
|
find_path(__header_dir "omp.h")
|
|
else()
|
|
# AppleClang may need a header file, search for omp.h with hints to brew
|
|
# default include dir
|
|
find_path(__header_dir "omp.h" HINTS "/usr/local/include" "${OpenMP_PREFIX}/include")
|
|
endif()
|
|
set(OMP_FLAG_AppleClang "-Xpreprocessor -fopenmp" "-Xpreprocessor -fopenmp -I${__header_dir}")
|
|
|
|
set(OMP_FLAG_HP "+Oopenmp")
|
|
if(WIN32)
|
|
set(OMP_FLAG_Intel "-Qopenmp")
|
|
elseif(CMAKE_${LANG}_COMPILER_ID STREQUAL "Intel" AND
|
|
"${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS "15.0.0.20140528")
|
|
set(OMP_FLAG_Intel "-openmp")
|
|
else()
|
|
set(OMP_FLAG_Intel "-qopenmp")
|
|
endif()
|
|
set(OMP_FLAG_MIPSpro "-mp")
|
|
if(__header_dir MATCHES ".*Microsoft Visual Studio.*")
|
|
# MSVC header. No need to pass it as additional include.
|
|
set(OMP_FLAG_MSVC "-openmp:experimental" "-openmp")
|
|
else()
|
|
set(OMP_FLAG_MSVC "-openmp:experimental -I${__header_dir}" "-openmp -I${__header_dir}")
|
|
endif()
|
|
set(OMP_FLAG_PathScale "-openmp")
|
|
set(OMP_FLAG_NAG "-openmp")
|
|
set(OMP_FLAG_Absoft "-openmp")
|
|
set(OMP_FLAG_PGI "-mp")
|
|
set(OMP_FLAG_Flang "-fopenmp")
|
|
set(OMP_FLAG_SunPro "-xopenmp")
|
|
set(OMP_FLAG_XL "-qsmp=omp")
|
|
# Cray compiler activate OpenMP with -h omp, which is enabled by default.
|
|
set(OMP_FLAG_Cray " " "-h omp")
|
|
|
|
# If we know the correct flags, use those
|
|
if(DEFINED OMP_FLAG_${CMAKE_${LANG}_COMPILER_ID})
|
|
set(OpenMP_FLAG_CANDIDATES "${OMP_FLAG_${CMAKE_${LANG}_COMPILER_ID}}")
|
|
# Fall back to reasonable default tries otherwise
|
|
else()
|
|
set(OpenMP_FLAG_CANDIDATES "-openmp" "-fopenmp" "-mp" " ")
|
|
endif()
|
|
set(OpenMP_${LANG}_FLAG_CANDIDATES "${OpenMP_FLAG_CANDIDATES}" PARENT_SCOPE)
|
|
else()
|
|
set(OpenMP_${LANG}_FLAG_CANDIDATES "${OpenMP_${LANG}_FLAG}" PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
# sample openmp source code to test
|
|
set(OpenMP_C_CXX_TEST_SOURCE
|
|
"
|
|
#include <omp.h>
|
|
int main(void) {
|
|
#ifdef _OPENMP
|
|
omp_get_max_threads();
|
|
return 0;
|
|
#else
|
|
breaks_on_purpose
|
|
#endif
|
|
}
|
|
")
|
|
|
|
# in Fortran, an implementation may provide an omp_lib.h header
|
|
# or omp_lib module, or both (OpenMP standard, section 3.1)
|
|
# Furthmore !$ is the Fortran equivalent of #ifdef _OPENMP (OpenMP standard, 2.2.2)
|
|
# Without the conditional compilation, some compilers (e.g. PGI) might compile OpenMP code
|
|
# while not actually enabling OpenMP, building code sequentially
|
|
set(OpenMP_Fortran_TEST_SOURCE
|
|
"
|
|
program test
|
|
@OpenMP_Fortran_INCLUDE_LINE@
|
|
!$ integer :: n
|
|
n = omp_get_num_threads()
|
|
end program test
|
|
"
|
|
)
|
|
|
|
function(_OPENMP_WRITE_SOURCE_FILE LANG SRC_FILE_CONTENT_VAR SRC_FILE_NAME SRC_FILE_FULLPATH)
|
|
set(WORK_DIR ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindOpenMP)
|
|
if("${LANG}" STREQUAL "C")
|
|
set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.c")
|
|
file(WRITE "${SRC_FILE}" "${OpenMP_C_CXX_${SRC_FILE_CONTENT_VAR}}")
|
|
elseif("${LANG}" STREQUAL "CXX")
|
|
set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.cpp")
|
|
file(WRITE "${SRC_FILE}" "${OpenMP_C_CXX_${SRC_FILE_CONTENT_VAR}}")
|
|
elseif("${LANG}" STREQUAL "Fortran")
|
|
set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.f90")
|
|
file(WRITE "${SRC_FILE}_in" "${OpenMP_Fortran_${SRC_FILE_CONTENT_VAR}}")
|
|
configure_file("${SRC_FILE}_in" "${SRC_FILE}" @ONLY)
|
|
endif()
|
|
set(${SRC_FILE_FULLPATH} "${SRC_FILE}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
include(CMakeParseImplicitLinkInfo)
|
|
|
|
function(_OPENMP_GET_FLAGS LANG FLAG_MODE OPENMP_FLAG_VAR OPENMP_LIB_NAMES_VAR)
|
|
_OPENMP_FLAG_CANDIDATES("${LANG}")
|
|
_OPENMP_WRITE_SOURCE_FILE("${LANG}" "TEST_SOURCE" OpenMPTryFlag _OPENMP_TEST_SRC)
|
|
|
|
unset(OpenMP_VERBOSE_COMPILE_OPTIONS)
|
|
if(UNIX)
|
|
separate_arguments(OpenMP_VERBOSE_OPTIONS UNIX_COMMAND "${CMAKE_${LANG}_VERBOSE_FLAG}")
|
|
else()
|
|
separate_arguments(OpenMP_VERBOSE_OPTIONS WINDOWS_COMMAND "${CMAKE_${LANG}_VERBOSE_FLAG}")
|
|
endif()
|
|
foreach(_VERBOSE_OPTION IN LISTS OpenMP_VERBOSE_OPTIONS)
|
|
if(NOT _VERBOSE_OPTION MATCHES "^-Wl,")
|
|
list(APPEND OpenMP_VERBOSE_COMPILE_OPTIONS ${_VERBOSE_OPTION})
|
|
endif()
|
|
endforeach()
|
|
|
|
foreach(OPENMP_FLAG IN LISTS OpenMP_${LANG}_FLAG_CANDIDATES)
|
|
set(OPENMP_FLAGS_TEST "${OPENMP_FLAG}")
|
|
if(OpenMP_VERBOSE_COMPILE_OPTIONS)
|
|
string(APPEND OPENMP_FLAGS_TEST " ${OpenMP_VERBOSE_COMPILE_OPTIONS}")
|
|
endif()
|
|
string(REGEX REPLACE "[-/=+]" "" OPENMP_PLAIN_FLAG "${OPENMP_FLAG}")
|
|
|
|
# NOTE [ Linking both MKL and OpenMP ]
|
|
#
|
|
# It is crucial not to link two `libomp` libraries together, even when they
|
|
# are both Intel or GNU. Otherwise, you will end up with this nasty error,
|
|
# and may get incorrect results.
|
|
#
|
|
# OMP: Error #15: Initializing libomp.dylib, but found libiomp5.dylib
|
|
# already initialized.
|
|
#
|
|
# OMP: Hint This means that multiple copies of the OpenMP runtime have
|
|
# been linked into the program. That is dangerous, since it can degrade
|
|
# performance or cause incorrect results. The best thing to do is to
|
|
# ensure that only a single OpenMP runtime is linked into the process,
|
|
# e.g. by avoiding static linking of the OpenMP runtime in any library. As
|
|
# an unsafe, unsupported, undocumented workaround you can set the
|
|
# environment variable KMP_DUPLICATE_LIB_OK=TRUE to allow the program to
|
|
# continue to execute, but that may cause crashes or silently produce
|
|
# incorrect results. For more information, please see
|
|
# http://openmp.llvm.org/
|
|
#
|
|
# So here, before we test each flag combination, we first try directly
|
|
# linking against any `libomp` MKL has linked to (if any and when MKL is
|
|
# specified). This allows us to do sensible things in tricky (yet common)
|
|
# conditions like:
|
|
# - using `clang` (so no native GNU OpenMP), and
|
|
# - having `brew` `libomp` installed at `/usr/local/`, and
|
|
# - having `conda` `mkl` installed at `$HOME/conda/`, with includes a copy
|
|
# of `libiomp5`.
|
|
# Rather than blindly picking one, we pick what ever `FindMKL.cmake` chooses
|
|
# to avoid conflicts.
|
|
#
|
|
# `FindMKL.cmake` calls `FindOpenMP.cmake` when trying to find `gomp` and
|
|
# thus will cause infinite recursion if this is not taken care of. Therefore,
|
|
# we record an internal flag to detect repeatedly inclusion.
|
|
|
|
if(NOT MKL_OPENMP_LIBRARY AND NOT IN_FIND_OMP AND BLAS STREQUAL "MKL")
|
|
set(IN_FIND_OMP ON CACHE BOOL "" FORCE)
|
|
find_package(MKL QUIET)
|
|
unset(IN_FIND_OMP CACHE)
|
|
endif()
|
|
|
|
if(MKL_OPENMP_LIBRARY)
|
|
# If we already link OpenMP via MKL, use that. Otherwise at run-time
|
|
# OpenMP will complain about being initialized twice (OMP: Error #15),
|
|
# can may cause incorrect behavior.
|
|
set(OpenMP_libomp_LIBRARY "${MKL_OPENMP_LIBRARY}" CACHE STRING "libomp location for OpenMP")
|
|
endif()
|
|
|
|
# Check if we are using OpenBLAS which is linked against libgomp
|
|
# we may end up with multiple omp runtimes linked
|
|
# against libtorch_cpu.so
|
|
if(OpenBLAS_LIB AND OPENBLAS_USES_LIBGOMP)
|
|
find_library(OpenMP_libomp_LIBRARY
|
|
NAMES gomp
|
|
HINTS ${CMAKE_${LANG}_IMPLICIT_LINK_DIRECTORIES}
|
|
DOC "libomp location for OpenMP"
|
|
)
|
|
mark_as_advanced(OpenMP_libomp_LIBRARY)
|
|
endif()
|
|
|
|
# For Clang, ask the compiler where it keeps libomp.so before falling back
|
|
# to the generic search. This avoids picking up GCC's libgomp (which lacks
|
|
# the __kmpc_* ABI) when libomp lives in a non-standard location (e.g.
|
|
# inside a ROCm venv SDK directory not in CMAKE_IMPLICIT_LINK_DIRECTORIES).
|
|
if (NOT OpenMP_libomp_LIBRARY AND CMAKE_${LANG}_COMPILER_ID MATCHES "Clang")
|
|
execute_process(
|
|
COMMAND "${CMAKE_${LANG}_COMPILER}" -print-file-name=libomp.so
|
|
OUTPUT_VARIABLE _omp_clang_lib
|
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
ERROR_QUIET
|
|
)
|
|
if(_omp_clang_lib AND NOT _omp_clang_lib STREQUAL "libomp.so")
|
|
set(OpenMP_libomp_LIBRARY "${_omp_clang_lib}" CACHE STRING "libomp location for OpenMP")
|
|
mark_as_advanced(OpenMP_libomp_LIBRARY)
|
|
endif()
|
|
unset(_omp_clang_lib)
|
|
endif()
|
|
|
|
# cl.exe links the OpenMP runtime matching its -openmp flag by itself (vcomp
|
|
# for -openmp[:experimental]), so on MSVC this search must not add one. It
|
|
# would find the libomp.lib shipped with Visual Studio, and with two runtimes
|
|
# in one process omp_get_thread_num() returns 0 on every vcomp worker, so
|
|
# at::parallel_for runs the whole range on each thread (#193784). The compiler
|
|
# id is checked rather than MSVC because clang-cl sets MSVC too but emits
|
|
# __kmpc_* calls and does need libomp.
|
|
if ((NOT OpenMP_libomp_LIBRARY) AND (NOT CMAKE_${LANG}_COMPILER_ID STREQUAL "MSVC"))
|
|
find_library(OpenMP_libomp_LIBRARY
|
|
NAMES omp gomp iomp5
|
|
HINTS ${CMAKE_${LANG}_IMPLICIT_LINK_DIRECTORIES}
|
|
DOC "libomp location for OpenMP"
|
|
)
|
|
mark_as_advanced(OpenMP_libomp_LIBRARY)
|
|
endif()
|
|
|
|
# Use OpenMP_PREFIX if defined. Skipped on MSVC for the same reason as above:
|
|
# setting a prefix must not bring libomp in next to vcomp.
|
|
if ((NOT OpenMP_libomp_LIBRARY) AND (NOT "${OpenMP_PREFIX}" STREQUAL "") AND (NOT CMAKE_${LANG}_COMPILER_ID STREQUAL "MSVC"))
|
|
find_library(OpenMP_libomp_LIBRARY
|
|
NAMES omp gomp iomp5
|
|
HINTS "${OpenMP_PREFIX}/lib"
|
|
DOC "libomp location for OpenMP"
|
|
)
|
|
mark_as_advanced(OpenMP_libomp_LIBRARY)
|
|
endif()
|
|
|
|
if(OpenMP_libomp_LIBRARY MATCHES "iomp5")
|
|
set(OpenMP_libiomp5_LIBRARY "${MKL_OPENMP_LIBRARY}" CACHE STRING "libiomp5 location for OpenMP")
|
|
if("-fopenmp=libiomp5" IN_LIST OpenMP_${LANG}_FLAG_CANDIDATES)
|
|
get_filename_component(iomp5_dir "${OpenMP_libomp_LIBRARY}" DIRECTORY)
|
|
set(OPENMP_FLAGS_TEST "-fopenmp=libiomp5 -L${iomp5_dir}")
|
|
endif()
|
|
endif()
|
|
|
|
if(OpenMP_libomp_LIBRARY)
|
|
message(STATUS "Check OMP with lib ${OpenMP_libomp_LIBRARY} and flags ${OPENMP_FLAGS_TEST}")
|
|
try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC}
|
|
CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}"
|
|
LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG} ${OpenMP_libomp_LIBRARY}
|
|
OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT
|
|
)
|
|
if(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG})
|
|
set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG}" PARENT_SCOPE)
|
|
if(OpenMP_libomp_LIBRARY MATCHES "iomp5")
|
|
set("${OPENMP_LIB_NAMES_VAR}" "libiomp5" PARENT_SCOPE)
|
|
else()
|
|
set("${OPENMP_LIB_NAMES_VAR}" "libomp" PARENT_SCOPE)
|
|
endif()
|
|
break()
|
|
else()
|
|
message(WARNING "Detecting ${LANG} OpenMP compiler ABI info compiled with the following output:\n${OpenMP_TRY_COMPILE_OUTPUT}")
|
|
endif()
|
|
endif()
|
|
|
|
try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC}
|
|
CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}"
|
|
LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG}
|
|
OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT
|
|
)
|
|
|
|
if(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG})
|
|
set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG}" PARENT_SCOPE)
|
|
|
|
if(CMAKE_${LANG}_VERBOSE_FLAG)
|
|
unset(OpenMP_${LANG}_IMPLICIT_LIBRARIES)
|
|
unset(OpenMP_${LANG}_IMPLICIT_LINK_DIRS)
|
|
unset(OpenMP_${LANG}_IMPLICIT_FWK_DIRS)
|
|
unset(OpenMP_${LANG}_LOG_VAR)
|
|
|
|
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
|
|
"Detecting ${LANG} OpenMP compiler ABI info compiled with the following output:\n${OpenMP_TRY_COMPILE_OUTPUT}\n\n")
|
|
|
|
cmake_parse_implicit_link_info("${OpenMP_TRY_COMPILE_OUTPUT}"
|
|
OpenMP_${LANG}_IMPLICIT_LIBRARIES
|
|
OpenMP_${LANG}_IMPLICIT_LINK_DIRS
|
|
OpenMP_${LANG}_IMPLICIT_FWK_DIRS
|
|
OpenMP_${LANG}_LOG_VAR
|
|
"${CMAKE_${LANG}_IMPLICIT_OBJECT_REGEX}"
|
|
)
|
|
|
|
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
|
|
"Parsed ${LANG} OpenMP implicit link information from above output:\n${OpenMP_${LANG}_LOG_VAR}\n\n")
|
|
|
|
unset(_OPENMP_LIB_NAMES)
|
|
foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_IMPLICIT_LIBRARIES)
|
|
get_filename_component(_OPENMP_IMPLICIT_LIB_DIR "${_OPENMP_IMPLICIT_LIB}" DIRECTORY)
|
|
get_filename_component(_OPENMP_IMPLICIT_LIB_NAME "${_OPENMP_IMPLICIT_LIB}" NAME)
|
|
get_filename_component(_OPENMP_IMPLICIT_LIB_PLAIN "${_OPENMP_IMPLICIT_LIB}" NAME_WE)
|
|
string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" _OPENMP_IMPLICIT_LIB_PLAIN_ESC "${_OPENMP_IMPLICIT_LIB_PLAIN}")
|
|
string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" _OPENMP_IMPLICIT_LIB_PATH_ESC "${_OPENMP_IMPLICIT_LIB}")
|
|
if(NOT ( "${_OPENMP_IMPLICIT_LIB}" IN_LIST CMAKE_${LANG}_IMPLICIT_LINK_LIBRARIES
|
|
OR "${CMAKE_${LANG}_STANDARD_LIBRARIES}" MATCHES "(^| )(-Wl,)?(-l)?(${_OPENMP_IMPLICIT_LIB_PLAIN_ESC}|${_OPENMP_IMPLICIT_LIB_PATH_ESC})( |$)"
|
|
OR "${CMAKE_${LANG}_LINK_EXECUTABLE}" MATCHES "(^| )(-Wl,)?(-l)?(${_OPENMP_IMPLICIT_LIB_PLAIN_ESC}|${_OPENMP_IMPLICIT_LIB_PATH_ESC})( |$)" ) )
|
|
if(_OPENMP_IMPLICIT_LIB_DIR)
|
|
set(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY "${_OPENMP_IMPLICIT_LIB}" CACHE FILEPATH
|
|
"Path to the ${_OPENMP_IMPLICIT_LIB_PLAIN} library for OpenMP")
|
|
else()
|
|
find_library(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY
|
|
NAMES "${_OPENMP_IMPLICIT_LIB_NAME}"
|
|
DOC "Path to the ${_OPENMP_IMPLICIT_LIB_PLAIN} library for OpenMP"
|
|
HINTS ${OpenMP_${LANG}_IMPLICIT_LINK_DIRS}
|
|
CMAKE_FIND_ROOT_PATH_BOTH
|
|
NO_DEFAULT_PATH
|
|
)
|
|
endif()
|
|
mark_as_advanced(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY)
|
|
list(APPEND _OPENMP_LIB_NAMES ${_OPENMP_IMPLICIT_LIB_PLAIN})
|
|
endif()
|
|
endforeach()
|
|
set("${OPENMP_LIB_NAMES_VAR}" "${_OPENMP_LIB_NAMES}" PARENT_SCOPE)
|
|
else()
|
|
# We do not know how to extract implicit OpenMP libraries for this compiler.
|
|
# Assume that it handles them automatically, e.g. the Intel Compiler on
|
|
# Windows should put the dependency in its object files.
|
|
set("${OPENMP_LIB_NAMES_VAR}" "" PARENT_SCOPE)
|
|
endif()
|
|
break()
|
|
elseif((CMAKE_${LANG}_COMPILER_ID STREQUAL "AppleClang") AND
|
|
(NOT CMAKE_${LANG}_COMPILER_VERSION VERSION_LESS "7.0"))
|
|
|
|
# LLVM 3.7 supports OpenMP 3.1, and continues to add more features to
|
|
# support newer OpenMP standards in new versions.
|
|
# http://releases.llvm.org/3.7.0/tools/clang/docs/ReleaseNotes.html#openmp-support
|
|
#
|
|
# Apple Clang 7.0 is the first version based on LLVM 3.7 or later.
|
|
# https://en.wikipedia.org/wiki/Xcode#Latest_versions
|
|
#
|
|
# Check for separate OpenMP library on AppleClang 7+
|
|
find_library(OpenMP_libomp_LIBRARY
|
|
NAMES omp gomp iomp5
|
|
HINTS ${CMAKE_${LANG}_IMPLICIT_LINK_DIRECTORIES}
|
|
DOC "libomp location for OpenMP"
|
|
)
|
|
mark_as_advanced(OpenMP_libomp_LIBRARY)
|
|
|
|
if(OpenMP_libomp_LIBRARY)
|
|
try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC}
|
|
CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}"
|
|
LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG} ${OpenMP_libomp_LIBRARY}
|
|
OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT
|
|
)
|
|
if(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG})
|
|
set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG}" PARENT_SCOPE)
|
|
set("${OPENMP_LIB_NAMES_VAR}" "libomp" PARENT_SCOPE)
|
|
break()
|
|
endif()
|
|
endif()
|
|
else()
|
|
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
|
|
"Detecting ${LANG} OpenMP failed with the following output:\n${OpenMP_TRY_COMPILE_OUTPUT}\n\n")
|
|
endif()
|
|
if (NOT ${OpenMP_${LANG}_FIND_QUIETLY})
|
|
message(STATUS "OpenMP try_compile log:\n${OpenMP_TRY_COMPILE_OUTPUT}\n\n")
|
|
endif()
|
|
set("${OPENMP_LIB_NAMES_VAR}" "NOTFOUND" PARENT_SCOPE)
|
|
set("${OPENMP_FLAG_VAR}" "NOTFOUND" PARENT_SCOPE)
|
|
endforeach()
|
|
|
|
unset(OpenMP_VERBOSE_COMPILE_OPTIONS)
|
|
endfunction()
|
|
|
|
set(OpenMP_C_CXX_CHECK_VERSION_SOURCE
|
|
"
|
|
#include <stdio.h>
|
|
#include <omp.h>
|
|
const char ompver_str[] = { 'I', 'N', 'F', 'O', ':', 'O', 'p', 'e', 'n', 'M',
|
|
'P', '-', 'd', 'a', 't', 'e', '[',
|
|
('0' + ((_OPENMP/100000)%10)),
|
|
('0' + ((_OPENMP/10000)%10)),
|
|
('0' + ((_OPENMP/1000)%10)),
|
|
('0' + ((_OPENMP/100)%10)),
|
|
('0' + ((_OPENMP/10)%10)),
|
|
('0' + ((_OPENMP/1)%10)),
|
|
']', '\\0' };
|
|
int main(void)
|
|
{
|
|
puts(ompver_str);
|
|
return 0;
|
|
}
|
|
")
|
|
|
|
set(OpenMP_Fortran_CHECK_VERSION_SOURCE
|
|
"
|
|
program omp_ver
|
|
@OpenMP_Fortran_INCLUDE_LINE@
|
|
integer, parameter :: zero = ichar('0')
|
|
integer, parameter :: ompv = openmp_version
|
|
character, dimension(24), parameter :: ompver_str =&
|
|
(/ 'I', 'N', 'F', 'O', ':', 'O', 'p', 'e', 'n', 'M', 'P', '-',&
|
|
'd', 'a', 't', 'e', '[',&
|
|
char(zero + mod(ompv/100000, 10)),&
|
|
char(zero + mod(ompv/10000, 10)),&
|
|
char(zero + mod(ompv/1000, 10)),&
|
|
char(zero + mod(ompv/100, 10)),&
|
|
char(zero + mod(ompv/10, 10)),&
|
|
char(zero + mod(ompv/1, 10)), ']' /)
|
|
print *, ompver_str
|
|
end program omp_ver
|
|
")
|
|
|
|
function(_OPENMP_GET_SPEC_DATE LANG SPEC_DATE)
|
|
_OPENMP_WRITE_SOURCE_FILE("${LANG}" "CHECK_VERSION_SOURCE" OpenMPCheckVersion _OPENMP_TEST_SRC)
|
|
|
|
set(BIN_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindOpenMP/ompver_${LANG}.bin")
|
|
string(REGEX REPLACE "[-/=+]" "" OPENMP_PLAIN_FLAG "${OPENMP_FLAG}")
|
|
try_compile(OpenMP_SPECTEST_${LANG}_${OPENMP_PLAIN_FLAG} "${CMAKE_BINARY_DIR}" "${_OPENMP_TEST_SRC}"
|
|
CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OpenMP_${LANG}_FLAGS}"
|
|
COPY_FILE ${BIN_FILE}
|
|
OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT)
|
|
|
|
if(${OpenMP_SPECTEST_${LANG}_${OPENMP_PLAIN_FLAG}})
|
|
file(STRINGS ${BIN_FILE} specstr LIMIT_COUNT 1 REGEX "INFO:OpenMP-date")
|
|
set(regex_spec_date ".*INFO:OpenMP-date\\[0*([^]]*)\\].*")
|
|
if("${specstr}" MATCHES "${regex_spec_date}")
|
|
set(${SPEC_DATE} "${CMAKE_MATCH_1}" PARENT_SCOPE)
|
|
endif()
|
|
else()
|
|
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
|
|
"Detecting ${LANG} OpenMP version failed with the following output:\n${OpenMP_TRY_COMPILE_OUTPUT}\n\n")
|
|
endif()
|
|
endfunction()
|
|
|
|
macro(_OPENMP_SET_VERSION_BY_SPEC_DATE LANG)
|
|
set(OpenMP_SPEC_DATE_MAP
|
|
# Preview versions
|
|
"201611=5.0" # OpenMP 5.0 preview 1
|
|
# Combined versions, 2.5 onwards
|
|
"201511=4.5"
|
|
"201307=4.0"
|
|
"201107=3.1"
|
|
"200805=3.0"
|
|
"200505=2.5"
|
|
# C/C++ version 2.0
|
|
"200203=2.0"
|
|
# Fortran version 2.0
|
|
"200011=2.0"
|
|
# Fortran version 1.1
|
|
"199911=1.1"
|
|
# C/C++ version 1.0 (there's no 1.1 for C/C++)
|
|
"199810=1.0"
|
|
# Fortran version 1.0
|
|
"199710=1.0"
|
|
)
|
|
|
|
if(OpenMP_${LANG}_SPEC_DATE)
|
|
string(REGEX MATCHALL "${OpenMP_${LANG}_SPEC_DATE}=([0-9]+)\\.([0-9]+)" _version_match "${OpenMP_SPEC_DATE_MAP}")
|
|
else()
|
|
set(_version_match "")
|
|
endif()
|
|
if(NOT _version_match STREQUAL "")
|
|
set(OpenMP_${LANG}_VERSION_MAJOR ${CMAKE_MATCH_1})
|
|
set(OpenMP_${LANG}_VERSION_MINOR ${CMAKE_MATCH_2})
|
|
set(OpenMP_${LANG}_VERSION "${OpenMP_${LANG}_VERSION_MAJOR}.${OpenMP_${LANG}_VERSION_MINOR}")
|
|
else()
|
|
unset(OpenMP_${LANG}_VERSION_MAJOR)
|
|
unset(OpenMP_${LANG}_VERSION_MINOR)
|
|
unset(OpenMP_${LANG}_VERSION)
|
|
endif()
|
|
unset(_version_match)
|
|
unset(OpenMP_SPEC_DATE_MAP)
|
|
endmacro()
|
|
|
|
foreach(LANG IN ITEMS C CXX)
|
|
if(CMAKE_${LANG}_COMPILER_LOADED)
|
|
if(NOT DEFINED OpenMP_${LANG}_FLAGS OR "${OpenMP_${LANG}_FLAGS}" STREQUAL "NOTFOUND"
|
|
OR NOT DEFINED OpenMP_${LANG}_LIB_NAMES OR "${OpenMP_${LANG}_LIB_NAMES}" STREQUAL "NOTFOUND")
|
|
_OPENMP_GET_FLAGS("${LANG}" "${LANG}" OpenMP_${LANG}_FLAGS_WORK OpenMP_${LANG}_LIB_NAMES_WORK)
|
|
endif()
|
|
|
|
set(OpenMP_${LANG}_FLAGS "${OpenMP_${LANG}_FLAGS_WORK}"
|
|
CACHE STRING "${LANG} compiler flags for OpenMP parallelization")
|
|
set(OpenMP_${LANG}_LIB_NAMES "${OpenMP_${LANG}_LIB_NAMES_WORK}"
|
|
CACHE STRING "${LANG} compiler libraries for OpenMP parallelization")
|
|
mark_as_advanced(OpenMP_${LANG}_FLAGS OpenMP_${LANG}_LIB_NAMES)
|
|
endif()
|
|
endforeach()
|
|
|
|
if(CMAKE_Fortran_COMPILER_LOADED)
|
|
if(NOT DEFINED OpenMP_Fortran_FLAGS OR "${OpenMP_Fortran_FLAGS}" STREQUAL "NOTFOUND"
|
|
OR NOT DEFINED OpenMP_Fortran_LIB_NAMES OR "${OpenMP_Fortran_LIB_NAMES}" STREQUAL "NOTFOUND"
|
|
OR NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_MODULE)
|
|
set(OpenMP_Fortran_INCLUDE_LINE "use omp_lib\n implicit none")
|
|
_OPENMP_GET_FLAGS("Fortran" "FortranHeader" OpenMP_Fortran_FLAGS_WORK OpenMP_Fortran_LIB_NAMES_WORK)
|
|
if(OpenMP_Fortran_FLAGS_WORK)
|
|
set(OpenMP_Fortran_HAVE_OMPLIB_MODULE TRUE CACHE BOOL INTERNAL "")
|
|
endif()
|
|
|
|
set(OpenMP_Fortran_FLAGS "${OpenMP_Fortran_FLAGS_WORK}"
|
|
CACHE STRING "Fortran compiler flags for OpenMP parallelization")
|
|
set(OpenMP_Fortran_LIB_NAMES "${OpenMP_Fortran_LIB_NAMES_WORK}"
|
|
CACHE STRING "Fortran compiler libraries for OpenMP parallelization")
|
|
mark_as_advanced(OpenMP_Fortran_FLAGS OpenMP_Fortran_LIB_NAMES)
|
|
endif()
|
|
|
|
if(NOT DEFINED OpenMP_Fortran_FLAGS OR "${OpenMP_Fortran_FLAGS}" STREQUAL "NOTFOUND"
|
|
OR NOT DEFINED OpenMP_Fortran_LIB_NAMES OR "${OpenMP_Fortran_LIB_NAMES}" STREQUAL "NOTFOUND"
|
|
OR NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_HEADER)
|
|
set(OpenMP_Fortran_INCLUDE_LINE "implicit none\n include 'omp_lib.h'")
|
|
_OPENMP_GET_FLAGS("Fortran" "FortranModule" OpenMP_Fortran_FLAGS_WORK OpenMP_Fortran_LIB_NAMES_WORK)
|
|
if(OpenMP_Fortran_FLAGS_WORK)
|
|
set(OpenMP_Fortran_HAVE_OMPLIB_HEADER TRUE CACHE BOOL INTERNAL "")
|
|
endif()
|
|
|
|
set(OpenMP_Fortran_FLAGS "${OpenMP_Fortran_FLAGS_WORK}"
|
|
CACHE STRING "Fortran compiler flags for OpenMP parallelization")
|
|
|
|
set(OpenMP_Fortran_LIB_NAMES "${OpenMP_Fortran_LIB_NAMES}"
|
|
CACHE STRING "Fortran compiler libraries for OpenMP parallelization")
|
|
endif()
|
|
|
|
if(OpenMP_Fortran_HAVE_OMPLIB_MODULE)
|
|
set(OpenMP_Fortran_INCLUDE_LINE "use omp_lib\n implicit none")
|
|
else()
|
|
set(OpenMP_Fortran_INCLUDE_LINE "implicit none\n include 'omp_lib.h'")
|
|
endif()
|
|
endif()
|
|
|
|
if(NOT OpenMP_FIND_COMPONENTS)
|
|
set(OpenMP_FINDLIST C CXX Fortran)
|
|
else()
|
|
set(OpenMP_FINDLIST ${OpenMP_FIND_COMPONENTS})
|
|
endif()
|
|
|
|
unset(_OpenMP_MIN_VERSION)
|
|
|
|
include(FindPackageHandleStandardArgs)
|
|
|
|
foreach(LANG IN LISTS OpenMP_FINDLIST)
|
|
if(CMAKE_${LANG}_COMPILER_LOADED)
|
|
if (NOT OpenMP_${LANG}_SPEC_DATE AND OpenMP_${LANG}_FLAGS)
|
|
_OPENMP_GET_SPEC_DATE("${LANG}" OpenMP_${LANG}_SPEC_DATE_INTERNAL)
|
|
set(OpenMP_${LANG}_SPEC_DATE "${OpenMP_${LANG}_SPEC_DATE_INTERNAL}" CACHE
|
|
INTERNAL "${LANG} compiler's OpenMP specification date")
|
|
_OPENMP_SET_VERSION_BY_SPEC_DATE("${LANG}")
|
|
endif()
|
|
|
|
set(OpenMP_${LANG}_FIND_QUIETLY ${OpenMP_FIND_QUIETLY})
|
|
set(OpenMP_${LANG}_FIND_REQUIRED ${OpenMP_FIND_REQUIRED})
|
|
set(OpenMP_${LANG}_FIND_VERSION ${OpenMP_FIND_VERSION})
|
|
set(OpenMP_${LANG}_FIND_VERSION_EXACT ${OpenMP_FIND_VERSION_EXACT})
|
|
|
|
set(_OPENMP_${LANG}_REQUIRED_VARS OpenMP_${LANG}_FLAGS)
|
|
if("${OpenMP_${LANG}_LIB_NAMES}" STREQUAL "NOTFOUND")
|
|
set(_OPENMP_${LANG}_REQUIRED_LIB_VARS OpenMP_${LANG}_LIB_NAMES)
|
|
else()
|
|
foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_LIB_NAMES)
|
|
list(APPEND _OPENMP_${LANG}_REQUIRED_LIB_VARS OpenMP_${_OPENMP_IMPLICIT_LIB}_LIBRARY)
|
|
endforeach()
|
|
endif()
|
|
|
|
find_package_handle_standard_args(OpenMP_${LANG}
|
|
REQUIRED_VARS OpenMP_${LANG}_FLAGS ${_OPENMP_${LANG}_REQUIRED_LIB_VARS}
|
|
VERSION_VAR OpenMP_${LANG}_VERSION
|
|
)
|
|
|
|
if(OpenMP_${LANG}_FOUND)
|
|
if(DEFINED OpenMP_${LANG}_VERSION)
|
|
if(NOT _OpenMP_MIN_VERSION OR _OpenMP_MIN_VERSION VERSION_GREATER OpenMP_${LANG}_VERSION)
|
|
set(_OpenMP_MIN_VERSION OpenMP_${LANG}_VERSION)
|
|
endif()
|
|
endif()
|
|
set(OpenMP_${LANG}_LIBRARIES "")
|
|
foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_LIB_NAMES)
|
|
list(APPEND OpenMP_${LANG}_LIBRARIES "${OpenMP_${_OPENMP_IMPLICIT_LIB}_LIBRARY}")
|
|
endforeach()
|
|
|
|
if(NOT TARGET OpenMP::OpenMP_${LANG})
|
|
add_library(OpenMP::OpenMP_${LANG} INTERFACE IMPORTED)
|
|
endif()
|
|
if(OpenMP_${LANG}_FLAGS)
|
|
if(UNIX)
|
|
separate_arguments(_OpenMP_${LANG}_OPTIONS UNIX_COMMAND "${OpenMP_${LANG}_FLAGS}")
|
|
else()
|
|
separate_arguments(_OpenMP_${LANG}_OPTIONS WINDOWS_COMMAND "${OpenMP_${LANG}_FLAGS}")
|
|
endif()
|
|
set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY
|
|
INTERFACE_COMPILE_OPTIONS "$<$<COMPILE_LANGUAGE:${LANG}>:${_OpenMP_${LANG}_OPTIONS}>")
|
|
unset(_OpenMP_${LANG}_OPTIONS)
|
|
endif()
|
|
if(OpenMP_${LANG}_LIBRARIES)
|
|
set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY
|
|
INTERFACE_LINK_LIBRARIES "${OpenMP_${LANG}_LIBRARIES}")
|
|
endif()
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
|
|
unset(_OpenMP_REQ_VARS)
|
|
foreach(LANG IN ITEMS C CXX Fortran)
|
|
if((NOT OpenMP_FIND_COMPONENTS AND CMAKE_${LANG}_COMPILER_LOADED) OR LANG IN_LIST OpenMP_FIND_COMPONENTS)
|
|
list(APPEND _OpenMP_REQ_VARS "OpenMP_${LANG}_FOUND")
|
|
endif()
|
|
endforeach()
|
|
|
|
find_package_handle_standard_args(OpenMP
|
|
REQUIRED_VARS ${_OpenMP_REQ_VARS}
|
|
VERSION_VAR ${_OpenMP_MIN_VERSION}
|
|
HANDLE_COMPONENTS)
|
|
|
|
set(OPENMP_FOUND ${OpenMP_FOUND})
|
|
|
|
if(CMAKE_Fortran_COMPILER_LOADED AND OpenMP_Fortran_FOUND)
|
|
if(NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_MODULE)
|
|
set(OpenMP_Fortran_HAVE_OMPLIB_MODULE FALSE CACHE BOOL INTERNAL "")
|
|
endif()
|
|
if(NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_HEADER)
|
|
set(OpenMP_Fortran_HAVE_OMPLIB_HEADER FALSE CACHE BOOL INTERNAL "")
|
|
endif()
|
|
endif()
|
|
|
|
if(NOT ( CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED OR CMAKE_Fortran_COMPILER_LOADED ))
|
|
message(SEND_ERROR "FindOpenMP requires the C, CXX or Fortran languages to be enabled")
|
|
endif()
|
|
|
|
unset(OpenMP_C_CXX_TEST_SOURCE)
|
|
unset(OpenMP_Fortran_TEST_SOURCE)
|
|
unset(OpenMP_C_CXX_CHECK_VERSION_SOURCE)
|
|
unset(OpenMP_Fortran_CHECK_VERSION_SOURCE)
|
|
unset(OpenMP_Fortran_INCLUDE_LINE)
|
|
unset(OpenMP_PREFIX)
|
|
|
|
cmake_policy(POP)
|