Update the cmake build configuration for AppleClang compiler (#15820)

Summary:
This pr try to merge the https://github.com/pytorch/pytorch/pull/11563 again and fix the linking error in https://github.com/pytorch/pytorch/pull/14837.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/15820

Differential Revision: D13942024

Pulled By: ezyang

fbshipit-source-id: dc6d1e9c4b0f177914f3745665244272a03ce33c
This commit is contained in:
JerryShih
2019-02-04 08:50:35 -08:00
committed by Facebook Github Bot
parent dc528fd734
commit 73db487a8e
12 changed files with 848 additions and 97 deletions

View File

@ -184,7 +184,7 @@ setup_ci_environment: &setup_ci_environment
eval $(aws ecr get-login --region us-east-1 --no-include-email)
macos_brew_update: &macos_brew_update
name: Brew update and install moreutils and expect
name: Brew update and install moreutils, expect and libomp
no_output_timeout: "1h"
command: |
set -ex
@ -198,6 +198,7 @@ macos_brew_update: &macos_brew_update
brew install moreutils
brew link parallel --overwrite
brew install expect
brew install libomp
##############################################################################
@ -246,7 +247,7 @@ pytorch_linux_test_defaults: &pytorch_linux_test_defaults
<<: *setup_ci_environment
- run:
name: Test
no_output_timeout: "1h"
no_output_timeout: "90m"
command: |
set -e
export COMMIT_DOCKER_IMAGE=${DOCKER_IMAGE}-${CIRCLE_SHA1}

View File

@ -14,9 +14,23 @@ clang --version
# symbolize=1: Gives us much better errors when things go wrong
export ASAN_OPTIONS=detect_leaks=0:symbolize=1
# FIXME: Remove the hardcoded "-pthread" option.
# With asan build, the cmake thread CMAKE_HAVE_LIBC_CREATE[1] checking will
# succeed because "pthread_create" is in libasan.so. However, libasan doesn't
# have the full pthread implementation. Other advanced pthread functions doesn't
# exist in libasan.so[2]. If we need some pthread advanced functions, we still
# need to link the pthread library.
# This issue is already fixed in cmake 3.13[3]. If we use the newer cmake, we
# could remove this hardcoded option.
#
# [1] https://github.com/Kitware/CMake/blob/8cabaaf054a16ea9c8332ce8e9291bd026b38c62/Modules/FindThreads.cmake#L135
# [2] https://wiki.gentoo.org/wiki/AddressSanitizer/Problems
# [3] https://github.com/Kitware/CMake/commit/e9a1ddc594de6e6251bf06d732775dae2cabe4c8
#
# TODO: Make the ASAN flags a more unified env var
CC="clang" CXX="clang++" LDSHARED="clang --shared" \
CFLAGS="-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -shared-libasan" \
CFLAGS="-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -shared-libasan -pthread" \
CXX_FLAGS="-pthread" \
NO_CUDA=1 USE_MKLDNN=0 \
python setup.py install

View File

@ -50,6 +50,14 @@ if [ -z "${IN_CIRCLECI}" ]; then
7z x ${IMAGE_COMMIT_TAG}.7z -o"${PYTORCH_ENV_DIR}/miniconda3/lib/python3.6/site-packages"
fi
# Test that OpenMP is enabled
pushd test
if [[ ! $(python -c "import torch; print(int(torch.backends.openmp.is_available()))") == "1" ]]; then
echo "Build should have OpenMP enabled, but torch.backends.openmp.is_available() is False"
exit 1
fi
popd
test_python_all() {
echo "Ninja version: $(ninja --version)"
python test/run_test.py --verbose

View File

@ -2,6 +2,11 @@ cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
#cmake_policy(SET CMP0022 NEW)
#cmake_policy(SET CMP0023 NEW)
# Use compiler ID "AppleClang" instead of "Clang" for XCode.
# Not setting this sometimes makes XCode C compiler gets detected as "Clang",
# even when the C++ one is detected as "AppleClang".
cmake_policy(SET CMP0025 NEW)
# ---[ Project and semantic versioning.
project(Caffe2 CXX C)
@ -125,7 +130,7 @@ option(USE_NUMPY "Use NumPy" ON)
option(USE_OBSERVERS "Use observers module." OFF)
option(USE_OPENCL "Use OpenCL" OFF)
option(USE_OPENCV "Use OpenCV" ON)
option(USE_OPENMP "Use OpenMP for parallel code" OFF)
option(USE_OPENMP "Use OpenMP for parallel code" ON)
option(USE_PROF "Use profiling" OFF)
option(USE_QNNPACK "Use QNNPACK (quantized 8-bit operators)" ON)
option(USE_REDIS "Use Redis" OFF)

View File

@ -224,6 +224,13 @@ if(NOT BUILD_ATEN_ONLY)
endif()
endif()
if (USE_OPENMP AND OPENMP_FOUND)
message(STATUS "Caffe2 is compiling with OpenMP. \n"
"OpenMP CXX_FLAGS: ${OpenMP_CXX_FLAGS}. \n"
"OpenMP libraries: ${OpenMP_CXX_LIBRARIES}.")
target_link_libraries(caffe2 PRIVATE ${OpenMP_CXX_LIBRARIES})
endif()
target_link_libraries(caffe2 PUBLIC c10)
target_link_libraries(caffe2 PUBLIC ${Caffe2_PUBLIC_DEPENDENCY_LIBS})
target_link_libraries(caffe2 PRIVATE ${Caffe2_DEPENDENCY_LIBS})

View File

@ -107,6 +107,10 @@ elseif(BLAS STREQUAL "MKL")
endif()
include(${CMAKE_CURRENT_LIST_DIR}/public/mkl.cmake)
if(MKL_FOUND)
message(STATUS "MKL libraries: ${MKL_LIBRARIES}")
message(STATUS "MKL include directory: ${MKL_INCLUDE_DIR}")
message(STATUS "MKL OpenMP type: ${MKL_OPENMP_TYPE}")
message(STATUS "MKL OpenMP library: ${MKL_OPENMP_LIBRARY}")
include_directories(SYSTEM ${MKL_INCLUDE_DIR})
list(APPEND Caffe2_PUBLIC_DEPENDENCY_LIBS caffe2::mkl)
set(CAFFE2_USE_MKL ON)
@ -670,12 +674,45 @@ endif()
# ---[ OpenMP
if(USE_OPENMP)
find_package(OpenMP)
# OpenMP support?
SET(WITH_OPENMP ON CACHE BOOL "OpenMP support if available?")
# macOS + GCC
IF (APPLE AND CMAKE_COMPILER_IS_GNUCC)
EXEC_PROGRAM (uname ARGS -v OUTPUT_VARIABLE DARWIN_VERSION)
STRING (REGEX MATCH "[0-9]+" DARWIN_VERSION ${DARWIN_VERSION})
MESSAGE (STATUS "macOS Darwin version: ${DARWIN_VERSION}")
IF (DARWIN_VERSION GREATER 9)
SET(APPLE_OPENMP_SUCKS 1)
ENDIF (DARWIN_VERSION GREATER 9)
EXECUTE_PROCESS (COMMAND ${CMAKE_C_COMPILER} -dumpversion
OUTPUT_VARIABLE GCC_VERSION)
IF (APPLE_OPENMP_SUCKS AND GCC_VERSION VERSION_LESS 4.6.2)
MESSAGE(WARNING "Disabling OpenMP (unstable with this version of GCC). "
"Install GCC >= 4.6.2 or change your OS to enable OpenMP.")
add_compile_options(-Wno-unknown-pragmas)
SET(WITH_OPENMP OFF CACHE BOOL "OpenMP support if available?" FORCE)
ENDIF()
ENDIF()
IF (WITH_OPENMP AND NOT CHECKED_OPENMP)
FIND_PACKAGE(OpenMP QUIET)
SET(CHECKED_OPENMP ON CACHE BOOL "already checked for OpenMP")
# OPENMP_FOUND is not cached in FindOpenMP.cmake (all other variables are cached)
# see https://github.com/Kitware/CMake/blob/master/Modules/FindOpenMP.cmake
SET(OPENMP_FOUND ${OPENMP_FOUND} CACHE BOOL "OpenMP Support found")
ENDIF()
if(OPENMP_FOUND)
message(STATUS "Adding " ${OpenMP_CXX_FLAGS})
message(STATUS "Adding OpenMP CXX_FLAGS: " ${OpenMP_CXX_FLAGS})
IF("${OpenMP_CXX_LIBRARIES}" STREQUAL "")
message(STATUS "No OpenMP library needs to be linked against")
ELSE()
message(STATUS "Will link against OpenMP libraries: ${OpenMP_CXX_LIBRARIES}")
ENDIF()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
else()
message(WARNING "Not compiling with OpenMP. Suppress this warning with -DUSE_OPENMP=OFF")
caffe2_update_option(USE_OPENMP OFF)
@ -1096,43 +1133,6 @@ if (NOT BUILD_ATEN_MOBILE)
STRING(REGEX REPLACE "[-/]DNDEBUG" "" CMAKE_CXX_FLAGS_RELEASE "" ${CMAKE_CXX_FLAGS_RELEASE})
ENDIF()
# OpenMP support?
SET(WITH_OPENMP ON CACHE BOOL "OpenMP support if available?")
# macOS + GCC
IF (APPLE AND CMAKE_COMPILER_IS_GNUCC)
EXEC_PROGRAM (uname ARGS -v OUTPUT_VARIABLE DARWIN_VERSION)
STRING (REGEX MATCH "[0-9]+" DARWIN_VERSION ${DARWIN_VERSION})
MESSAGE (STATUS "macOS Darwin version: ${DARWIN_VERSION}")
IF (DARWIN_VERSION GREATER 9)
SET(APPLE_OPENMP_SUCKS 1)
ENDIF (DARWIN_VERSION GREATER 9)
EXECUTE_PROCESS (COMMAND ${CMAKE_C_COMPILER} -dumpversion
OUTPUT_VARIABLE GCC_VERSION)
IF (APPLE_OPENMP_SUCKS AND GCC_VERSION VERSION_LESS 4.6.2)
MESSAGE(WARNING "Disabling OpenMP (unstable with this version of GCC). "
"Install GCC >= 4.6.2 or change your OS to enable OpenMP.")
add_compile_options(-Wno-unknown-pragmas)
SET(WITH_OPENMP OFF CACHE BOOL "OpenMP support if available?" FORCE)
ENDIF()
ENDIF()
IF (WITH_OPENMP AND NOT CHECKED_OPENMP)
FIND_PACKAGE(OpenMP)
SET(CHECKED_OPENMP ON CACHE BOOL "already checked for OpenMP")
# OPENMP_FOUND is not cached in FindOpenMP.cmake (all other variables are cached)
# see https://github.com/Kitware/CMake/blob/master/Modules/FindOpenMP.cmake
SET(OPENMP_FOUND ${OPENMP_FOUND} CACHE BOOL "OpenMP Support found")
ENDIF()
IF (OPENMP_FOUND)
MESSAGE(STATUS "Compiling with OpenMP support")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
ENDIF()
SET(CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE OFF)
FIND_PACKAGE(MAGMA)

View File

@ -5,6 +5,8 @@
# MKL_VERSION - best guess of the found mkl version
# MKL_INCLUDE_DIR - path to include dir.
# MKL_LIBRARIES - list of libraries for base mkl
# MKL_OPENMP_TYPE - OpenMP flavor that the found mkl uses: GNU or Intel
# MKL_OPENMP_LIBRARY - path to the OpenMP library the found mkl uses
# MKL_LAPACK_LIBRARIES - list of libraries to add for lapack
# MKL_SCALAPACK_LIBRARIES - list of libraries to add for scalapack
# MKL_SOLVER_LIBRARIES - list of libraries to add for the solvers
@ -16,6 +18,8 @@ IF (NOT MKL_FOUND)
SET(MKL_VERSION)
SET(MKL_INCLUDE_DIR)
SET(MKL_LIBRARIES)
SET(MKL_OPENMP_TYPE)
SET(MKL_OPENMP_LIBRARY)
SET(MKL_LAPACK_LIBRARIES)
SET(MKL_SCALAPACK_LIBRARIES)
SET(MKL_SOLVER_LIBRARIES)
@ -103,7 +107,7 @@ IF (EXISTS ${INTEL_MKL_DIR})
ENDIF()
# Try linking multiple libs
MACRO(CHECK_ALL_LIBRARIES LIBRARIES _name _list _flags)
MACRO(CHECK_ALL_LIBRARIES LIBRARIES OPENMP_TYPE OPENMP_LIBRARY _name _list _flags)
# This macro checks for the existence of the combination of libraries given by _list.
# If the combination is found, this macro checks whether we can link against that library
# combination using the name of a routine given by _name using the linker
@ -116,30 +120,60 @@ MACRO(CHECK_ALL_LIBRARIES LIBRARIES _name _list _flags)
# start checking
SET(_libraries_work TRUE)
SET(${LIBRARIES})
SET(${OPENMP_TYPE})
SET(${OPENMP_LIBRARY})
SET(_combined_name)
SET(_openmp_type)
SET(_openmp_library)
SET(_paths)
set(__list)
foreach(_elem ${_list})
if(__list)
set(__list "${__list} - ${_elem}")
else(__list)
set(__list "${_elem}")
endif(__list)
endforeach(_elem)
IF (NOT MKL_FIND_QUIETLY)
message(STATUS "Checking for [${__list}]")
set(_str_list)
foreach(_elem ${_list})
if(_str_list)
set(_str_list "${_str_list} - ${_elem}")
else()
set(_str_list "${_elem}")
endif()
endforeach(_elem)
message(STATUS "Checking for [${_str_list}]")
ENDIF ()
FOREACH(_library ${_list})
SET(_combined_name ${_combined_name}_${_library})
UNSET(${_prefix}_${_library}_LIBRARY)
IF(_libraries_work)
IF(${_library} STREQUAL "gomp")
FIND_PACKAGE(OpenMP)
IF(${_library} MATCHES "omp")
IF(_openmp_type)
MESSAGE(FATAL_ERROR "More than one OpenMP libraries appear in the MKL test: ${_list}")
ELSEIF(${_library} MATCHES "gomp")
SET(_openmp_type "GNU")
# Use FindOpenMP to find gomp
FIND_PACKAGE(OpenMP QUIET)
IF(OPENMP_FOUND)
SET(${_prefix}_${_library}_LIBRARY ${OpenMP_C_FLAGS})
# Test that none of the found library names contains "iomp" (Intel
# OpenMP). This doesn't necessarily mean that we have gomp... but it
# is probably good enough since on gcc we should already have
# OpenMP_CXX_FLAGS="-fopenmp" and OpenMP_CXX_LIB_NAMES="".
SET(_found_gomp true)
FOREACH(_lib_name ${OpenMP_CXX_LIB_NAMES})
IF (_found_gomp AND "${_lib_name}" MATCHES "iomp")
SET(_found_gomp false)
ENDIF()
ENDFOREACH()
IF(_found_gomp)
SET(${_prefix}_${_library}_LIBRARY ${OpenMP_CXX_FLAGS})
SET(_openmp_library "${${_prefix}_${_library}_LIBRARY}")
ENDIF()
ENDIF(OPENMP_FOUND)
ELSE(${_library} STREQUAL "gomp")
ELSEIF(${_library} MATCHES "iomp")
SET(_openmp_type "Intel")
FIND_LIBRARY(${_prefix}_${_library}_LIBRARY NAMES ${_library})
ENDIF(${_library} STREQUAL "gomp")
SET(_openmp_library "${${_prefix}_${_library}_LIBRARY}")
ELSE()
MESSAGE(FATAL_ERROR "Unknown OpenMP flavor: ${_library}")
ENDIF()
ELSE(${_library} MATCHES "omp")
FIND_LIBRARY(${_prefix}_${_library}_LIBRARY NAMES ${_library})
ENDIF(${_library} MATCHES "omp")
MARK_AS_ADVANCED(${_prefix}_${_library}_LIBRARY)
SET(${LIBRARIES} ${${LIBRARIES}} ${${_prefix}_${_library}_LIBRARY})
SET(_libraries_work ${${_prefix}_${_library}_LIBRARY})
@ -163,6 +197,10 @@ MACRO(CHECK_ALL_LIBRARIES LIBRARIES _name _list _flags)
ENDIF(_libraries_work)
# Fin
IF(_libraries_work)
SET(${OPENMP_TYPE} ${_openmp_type})
MARK_AS_ADVANCED(${OPENMP_TYPE})
SET(${OPENMP_LIBRARY} ${_openmp_library})
MARK_AS_ADVANCED(${OPENMP_LIBRARY})
ELSE (_libraries_work)
SET(${LIBRARIES})
MARK_AS_ADVANCED(${LIBRARIES})
@ -187,40 +225,44 @@ ENDIF(UNIX AND NOT APPLE)
IF (NOT MKL_LIBRARIES)
SET(MKL_VERSION 1011)
ENDIF (NOT MKL_LIBRARIES)
FOREACH(mklrtl ${mklrtls} "")
# First: search for parallelized ones with intel thread lib
IF (NOT INTEL_MKL_SEQUENTIAL)
FOREACH(mklrtl ${mklrtls} "")
FOREACH(mkliface ${mklifaces})
FOREACH(mkl64 ${mkl64s} "")
FOREACH(mklthread ${mklthreads})
IF (NOT MKL_LIBRARIES AND NOT INTEL_MKL_SEQUENTIAL)
CHECK_ALL_LIBRARIES(MKL_LIBRARIES cblas_sgemm
IF (NOT MKL_LIBRARIES)
CHECK_ALL_LIBRARIES(MKL_LIBRARIES MKL_OPENMP_TYPE MKL_OPENMP_LIBRARY cblas_sgemm
"mkl_${mkliface}${mkl64};${mklthread};mkl_core;${mklrtl};${mkl_pthread};${mkl_m};${mkl_dl}" "")
ENDIF (NOT MKL_LIBRARIES AND NOT INTEL_MKL_SEQUENTIAL)
ENDIF (NOT MKL_LIBRARIES)
ENDFOREACH(mklthread)
ENDFOREACH(mkl64)
ENDFOREACH(mkliface)
ENDFOREACH(mklrtl)
FOREACH(mklrtl ${mklrtls} "")
FOREACH(mkliface ${mklifaces})
ENDFOREACH(mklrtl)
ENDIF (NOT INTEL_MKL_SEQUENTIAL)
# Second: search for sequential ones
FOREACH(mkliface ${mklifaces})
FOREACH(mkl64 ${mkl64s} "")
IF (NOT MKL_LIBRARIES)
CHECK_ALL_LIBRARIES(MKL_LIBRARIES cblas_sgemm
CHECK_ALL_LIBRARIES(MKL_LIBRARIES MKL_OPENMP_TYPE MKL_OPENMP_LIBRARY cblas_sgemm
"mkl_${mkliface}${mkl64};mkl_sequential;mkl_core;${mkl_m};${mkl_dl}" "")
IF (MKL_LIBRARIES)
SET(mklseq "_sequential")
ENDIF (MKL_LIBRARIES)
ENDIF (NOT MKL_LIBRARIES)
ENDFOREACH(mkl64)
ENDFOREACH(mkliface)
ENDFOREACH(mklrtl)
ENDFOREACH(mkliface)
# First: search for parallelized ones with native pthread lib
FOREACH(mklrtl ${mklrtls} "")
FOREACH(mkliface ${mklifaces})
FOREACH(mkl64 ${mkl64s} "")
FOREACH(mklthread ${mklthreads})
IF (NOT MKL_LIBRARIES)
CHECK_ALL_LIBRARIES(MKL_LIBRARIES cblas_sgemm
CHECK_ALL_LIBRARIES(MKL_LIBRARIES MKL_OPENMP_TYPE MKL_OPENMP_LIBRARY cblas_sgemm
"mkl_${mkliface}${mkl64};${mklthread};mkl_core;${mklrtl};pthread;${mkl_m};${mkl_dl}" "")
ENDIF (NOT MKL_LIBRARIES)
ENDFOREACH(mklthread)
ENDFOREACH(mkl64)
ENDFOREACH(mkliface)
ENDFOREACH(mklrtl)
@ -228,7 +270,7 @@ ENDFOREACH(mklrtl)
# Check for older versions
IF (NOT MKL_LIBRARIES)
SET(MKL_VERSION 900)
CHECK_ALL_LIBRARIES(MKL_LIBRARIES cblas_sgemm
CHECK_ALL_LIBRARIES(MKL_LIBRARIES MKL_OPENMP_TYPE MKL_OPENMP_LIBRARY cblas_sgemm
"mkl;guide;pthread;m" "")
ENDIF (NOT MKL_LIBRARIES)

View File

@ -0,0 +1,635 @@
# 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
function(_OPENMP_FLAG_CANDIDATES LANG)
if(NOT OpenMP_${LANG}_FLAG)
unset(OpenMP_FLAG_CANDIDATES)
set(OMP_FLAG_GNU "-fopenmp")
set(OMP_FLAG_Clang "-fopenmp=libomp" "-fopenmp=libiomp5" "-fopenmp")
# 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")
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")
set(OMP_FLAG_MSVC "-openmp")
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 found (if any). 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` choses
# to avoid conflicts.
#
# Crucially, we only do so for non-GNU compilers. For GNU ones,
# `FindMKL.cmake` calls `FindOpenMP.cmake` when trying to find `gomp` and
# thus will cause infinite recursion if this is not taken care of. Moreover,
# for them, since the compiler provices the OpenMP library, it is most
# likely that only one viable gomp library can be found in search path by
# `FindOpenMP.cmake`, so the chance of having conflicts is slow.
#
# TODO: refactor to solve this weird dependency where
# - for non-GNU, FindOpenMP.cmake replies on FindMKL.cmake to finish first, but
# - for GNU, FindMKL.cmake replies on FindOpenMP.cmake to finish first.
if(NOT "${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "GNU")
find_package(MKL QUIET)
if(MKL_FOUND AND (NOT "${MKL_OPENMP_LIBRARY}" STREQUAL ""))
# 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")
else()
find_library(OpenMP_libomp_LIBRARY
NAMES omp gomp iomp5
HINTS ${CMAKE_${LANG}_IMPLICIT_LINK_DIRECTORIES}
DOC "libomp location for OpenMP"
)
endif()
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()
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)
cmake_policy(POP)

34
cmake/Modules/README.md Normal file
View File

@ -0,0 +1,34 @@
This folder contains various custom cmake modules for finding libraries and packages. Details about some of them are listed below.
### [`FindOpenMP.cmake`](./FindOpenMP.cmake)
This is modified from [the file included in CMake 3.13 release](https://github.com/Kitware/CMake/blob/05a2ca7f87b9ae73f373e9967fde1ee5210e33af/Modules/FindOpenMP.cmake), with the following changes:
+ Replace `VERSION_GREATER_EQUAL` with `NOT ... VERSION_LESS` as `VERSION_GREATER_EQUAL` is not supported in CMake 3.5 (our min supported version).
+ Update the `separate_arguments` commands to not use `NATIVE_COMMAND` which is not supported in CMake 3.5 (our min supported version).
+ Make it respect the `QUIET` flag so that, when it is set, `try_compile` failures are not reported.
+ For `AppleClang` compilers, use `-Xpreprocessor` instead of `-Xclang` as the later is not documented.
+ For `AppleClang` compilers, an extra flag option is tried, which is `-Xpreprocessor -openmp -I${DIR_OF_omp_h}`, where `${DIR_OF_omp_h}` is a obtained using `find_path` on `omp.h` with `brew`'s default include directory as a hint. Without this, the compiler will complain about missing headers as they are not natively included in Apple's LLVM.
+ For non-GNU compilers, whenever we try a candidate OpenMP flag, first try it with directly linking MKL's `libomp` if it has one. Otherwise, we may end up linking two `libomp`s and end up with this nasty error:
```
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/
```
See NOTE [ Linking both MKL and OpenMP ] for details.

View File

@ -7,6 +7,7 @@ function (caffe2_print_configuration_summary)
message(STATUS " CMake command : ${CMAKE_COMMAND}")
message(STATUS " System : ${CMAKE_SYSTEM_NAME}")
message(STATUS " C++ compiler : ${CMAKE_CXX_COMPILER}")
message(STATUS " C++ compiler id : ${CMAKE_CXX_COMPILER_ID}")
message(STATUS " C++ compiler version : ${CMAKE_CXX_COMPILER_VERSION}")
message(STATUS " BLAS : ${BLAS}")
message(STATUS " CXX flags : ${CMAKE_CXX_FLAGS}")

View File

@ -2,6 +2,10 @@ file(GLOB Detectron_CPU_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/*.cc)
file(GLOB Detectron_GPU_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/*.cu)
if (BUILD_CAFFE2_OPS)
if (USE_OPENMP AND OPENMP_FOUND)
Set(OpenMP_link ${OpenMP_CXX_LIBRARIES})
endif()
# Note(ilijar): Since Detectron ops currently have no
# CPU implementation, we only build GPU ops for now.
if (USE_CUDA)
@ -10,14 +14,14 @@ if (BUILD_CAFFE2_OPS)
${Detectron_CPU_SRCS}
${Detectron_GPU_SRCS})
target_link_libraries(caffe2_detectron_ops_gpu caffe2_gpu)
target_link_libraries(caffe2_detectron_ops_gpu caffe2_gpu ${OpenMP_link})
install(TARGETS caffe2_detectron_ops_gpu DESTINATION lib)
if (MSVC)
install(FILES $<TARGET_PDB_FILE:caffe2_detectron_ops_gpu> DESTINATION lib OPTIONAL)
endif()
elseif(NOT IOS_PLATFORM)
add_library(caffe2_detectron_ops SHARED ${Detectron_CPU_SRCS})
target_link_libraries(caffe2_detectron_ops caffe2)
target_link_libraries(caffe2_detectron_ops caffe2 ${OpenMP_link})
install(TARGETS caffe2_detectron_ops DESTINATION lib)
if (MSVC)
install(FILES $<TARGET_PDB_FILE:caffe2_detectron_ops> DESTINATION lib OPTIONAL)

View File

@ -314,13 +314,13 @@ endif()
target_link_libraries(torch caffe2_library)
find_package(OpenMP)
find_package(OpenMP QUIET)
if(OPENMP_FOUND)
if (VERBOSE)
message(STATUS "Compiling with OpenMP")
endif()
target_compile_options(torch INTERFACE -fopenmp)
target_link_libraries(torch -fopenmp)
message(STATUS "pytorch is compiling with OpenMP. \n"
"OpenMP CXX_FLAGS: ${OpenMP_CXX_FLAGS}. \n"
"OpenMP libraries: ${OpenMP_CXX_LIBRARIES}.")
target_compile_options(torch INTERFACE ${OpenMP_CXX_FLAGS})
target_link_libraries(torch ${OpenMP_CXX_LIBRARIES})
endif()
if (NOT NO_API)