483 lines
16 KiB
CMake
483 lines
16 KiB
CMake
## Copyright 2009-2021 Intel Corporation
|
|
## SPDX-License-Identifier: Apache-2.0
|
|
|
|
#===============================================================================
|
|
# This script will attempt to find TBB and set up a TBB target.
|
|
#
|
|
# The user may specify a version and lists of required and optional components:
|
|
#
|
|
# find_package(TBB 2017.0 EXACT REQUIRED
|
|
# tbb tbbmalloc
|
|
# OPTIONAL_COMPONENTS tbbmalloc_proxy
|
|
# QUIET)
|
|
#
|
|
# If this target exists already, the script will attempt to re-use it, but fail
|
|
# if version or components do not match the user-specified requirements.
|
|
#
|
|
# If all the required component targets (e.g. TBB::tbb) exist, the script will
|
|
# attempt to create a target TBB and link existing component targets to it.
|
|
# It will fail if the component target version does not match the user-specified
|
|
# requirements.
|
|
#
|
|
# The user may specify the following variables to help the search process:
|
|
# - TBB_ROOT
|
|
# - TBB_INCLUDE_DIR
|
|
#
|
|
# After the script has run successfully, there is a target TBB, as well as
|
|
# component targets TBB::<COMPONENT>, e.g. TBB::tbbmalloc.
|
|
#
|
|
# The targets will attempt to link to release versions of TBB in release mode,
|
|
# and debug versions in debug mode.
|
|
#
|
|
# In addition to the targets, the script defines:
|
|
#
|
|
# TBB_FOUND
|
|
# TBB_INCLUDE_DIRS
|
|
#
|
|
#===============================================================================
|
|
|
|
# We use INTERFACE libraries, which are only supported in 3.x
|
|
cmake_minimum_required(VERSION 3.5)
|
|
|
|
# These two are used to automatically find the root and include directories.
|
|
set(_TBB_INCLUDE_SUBDIR "include")
|
|
set(_TBB_HEADER "tbb/tbb.h")
|
|
|
|
# Initialize cache variable; but use existing non-cache variable as the default,
|
|
# and fall back to the environment variable.
|
|
if (NOT TBB_ROOT)
|
|
set(TBB_ROOT "$ENV{TBB_ROOT}")
|
|
endif()
|
|
|
|
set(TBB_ROOT "${TBB_ROOT}" CACHE PATH "The root path of TBB.")
|
|
|
|
#===============================================================================
|
|
# Error messages that respect the user's wishes about peace and quiet.
|
|
#===============================================================================
|
|
|
|
function(rk_tbb_status)
|
|
if (NOT TBB_FIND_QUIETLY)
|
|
message(STATUS "${ARGV}")
|
|
endif()
|
|
endfunction()
|
|
|
|
function(rk_tbb_warning)
|
|
if (NOT TBB_FIND_QUIETLY)
|
|
message(WARNING "${ARGV}")
|
|
endif()
|
|
endfunction()
|
|
|
|
macro(rk_tbb_error)
|
|
if (TBB_FIND_REQUIRED)
|
|
message(FATAL_ERROR "${ARGV}")
|
|
else()
|
|
rk_tbb_warning("${ARGV}")
|
|
endif()
|
|
return()
|
|
endmacro()
|
|
|
|
#===============================================================================
|
|
# Extract a list of required and optional components.
|
|
#===============================================================================
|
|
|
|
macro(rk_tbb_list_components)
|
|
# cmake provides the TBB_FIND_COMPONENTS and
|
|
# TBB_FIND_REQUIRED_<C> variables based on the invocation
|
|
# of find_package.
|
|
if (TBB_FIND_COMPONENTS STREQUAL "")
|
|
set(_REQUIRED_COMPONENTS "tbb")
|
|
set(_OPTIONAL_COMPONENTS "tbbmalloc"
|
|
"tbbmalloc_proxy"
|
|
"tbbbind"
|
|
"tbbpreview")
|
|
else()
|
|
set(_REQUIRED_COMPONENTS "")
|
|
set(_OPTIONAL_COMPONENTS "")
|
|
foreach (C IN LISTS TBB_FIND_COMPONENTS)
|
|
if (${TBB_FIND_REQUIRED_${C}})
|
|
list(APPEND _REQUIRED_COMPONENTS ${C})
|
|
else()
|
|
list(APPEND _OPTIONAL_COMPONENTS ${C})
|
|
endif()
|
|
endforeach()
|
|
endif()
|
|
|
|
rk_tbb_status("Looking for TBB components ${_REQUIRED_COMPONENTS}"
|
|
" (${_OPTIONAL_COMPONENTS})")
|
|
endmacro()
|
|
|
|
#===============================================================================
|
|
# List components that are available, and check if any REQUIRED components
|
|
# are missing.
|
|
#===============================================================================
|
|
|
|
macro(rk_tbb_check_components)
|
|
set(_TBB_MISSING_COMPONENTS "")
|
|
set(_TBB_AVAILABLE_COMPONENTS "")
|
|
|
|
foreach (C IN LISTS _REQUIRED_COMPONENTS)
|
|
if (TARGET TBB::${C})
|
|
list(APPEND _TBB_AVAILABLE_COMPONENTS ${C})
|
|
else()
|
|
list(APPEND _TBB_MISSING_COMPONENTS ${C})
|
|
endif()
|
|
endforeach()
|
|
|
|
foreach (C IN LISTS _OPTIONAL_COMPONENTS)
|
|
if (TARGET TBB::${C})
|
|
list(APPEND _TBB_AVAILABLE_COMPONENTS ${C})
|
|
endif()
|
|
endforeach()
|
|
endmacro()
|
|
|
|
#===============================================================================
|
|
# Check the version of the TBB root we found.
|
|
#===============================================================================
|
|
|
|
macro(rk_tbb_check_version)
|
|
# Extract the version we found in our root.
|
|
if(EXISTS "${TBB_INCLUDE_DIR}/oneapi/tbb/version.h")
|
|
set(_TBB_VERSION_HEADER "oneapi/tbb/version.h")
|
|
elseif(EXISTS "${TBB_INCLUDE_DIR}/tbb/tbb_stddef.h")
|
|
set(_TBB_VERSION_HEADER "tbb/tbb_stddef.h")
|
|
elseif(EXISTS "${TBB_INCLUDE_DIR}/tbb/version.h")
|
|
set(_TBB_VERSION_HEADER "tbb/version.h")
|
|
else()
|
|
rk_tbb_error("Missing TBB version information. Could not find"
|
|
"tbb/tbb_stddef.h or tbb/version.h in ${TBB_INCLUDE_DIR}")
|
|
endif()
|
|
file(READ "${TBB_INCLUDE_DIR}/${_TBB_VERSION_HEADER}" VERSION_HEADER_CONTENT)
|
|
string(REGEX MATCH "#define TBB_VERSION_MAJOR ([0-9]+)" DUMMY "${VERSION_HEADER_CONTENT}")
|
|
set(TBB_VERSION_MAJOR ${CMAKE_MATCH_1})
|
|
string(REGEX MATCH "#define TBB_VERSION_MINOR ([0-9]+)" DUMMY "${VERSION_HEADER_CONTENT}")
|
|
set(TBB_VERSION_MINOR ${CMAKE_MATCH_1})
|
|
set(TBB_VERSION "${TBB_VERSION_MAJOR}.${TBB_VERSION_MINOR}")
|
|
set(TBB_VERSION_STRING "${TBB_VERSION}")
|
|
|
|
# If the user provided information about required versions, check them!
|
|
if (TBB_FIND_VERSION)
|
|
if (${TBB_FIND_VERSION_EXACT} AND NOT
|
|
TBB_VERSION VERSION_EQUAL ${TBB_FIND_VERSION})
|
|
rk_tbb_error("Requested exact TBB version ${TBB_FIND_VERSION},"
|
|
" but found ${TBB_VERSION}")
|
|
elseif(TBB_VERSION VERSION_LESS ${TBB_FIND_VERSION})
|
|
rk_tbb_error("Requested minimum TBB version ${TBB_FIND_VERSION},"
|
|
" but found ${TBB_VERSION}")
|
|
endif()
|
|
endif()
|
|
|
|
rk_tbb_status("Found TBB version ${TBB_VERSION} at ${TBB_ROOT}")
|
|
endmacro()
|
|
|
|
#===============================================================================
|
|
# Reuse existing targets.
|
|
# NOTE: This must be a macro, as we rely on return() to exit this script.
|
|
#===============================================================================
|
|
|
|
macro(rk_tbb_reuse_existing_target_components)
|
|
rk_tbb_check_components()
|
|
|
|
if (_TBB_MISSING_COMPONENTS STREQUAL "")
|
|
rk_tbb_status("Found existing TBB component targets: ${_TBB_AVAILABLE_COMPONENTS}")
|
|
|
|
# Get TBB_INCLUDE_DIR if not already set to check for the version of the
|
|
# existing component targets (making the assumption that they all have
|
|
# the same version)
|
|
if (NOT TBB_INCLUDE_DIR)
|
|
list(GET _TBB_AVAILABLE_COMPONENTS 0 first_target)
|
|
get_target_property(TBB_INCLUDE_DIR TBB::${first_target} INTERFACE_INCLUDE_DIRECTORIES)
|
|
foreach(TGT IN LISTS _TBB_AVAILABLE_COMPONENTS)
|
|
get_target_property(_TGT_INCLUDE_DIR TBB::${TGT} INTERFACE_INCLUDE_DIRECTORIES)
|
|
if (NOT _TGT_INCLUDE_DIR STREQUAL "${TBB_INCLUDE_DIR}")
|
|
rk_tbb_error("Existing TBB component targets have inconsistent include directories.")
|
|
endif()
|
|
endforeach()
|
|
endif()
|
|
|
|
find_path(TBB_INCLUDE_DIR
|
|
NAMES "${_TBB_HEADER}"
|
|
PATHS "${TBB_INCLUDE_DIRS}")
|
|
|
|
# Extract TBB_ROOT from the include path so that rk_tbb_check_version
|
|
# prints the correct tbb location
|
|
string(REPLACE "/${_TBB_INCLUDE_SUBDIR}" "" TBB_ROOT "${TBB_INCLUDE_DIR}")
|
|
rk_tbb_check_version()
|
|
|
|
# Add target TBB and link all available components
|
|
if (NOT TARGET TBB)
|
|
add_library(TBB INTERFACE)
|
|
foreach(C IN LISTS _TBB_AVAILABLE_COMPONENTS)
|
|
target_link_libraries(TBB INTERFACE TBB::${C})
|
|
endforeach()
|
|
endif()
|
|
set(TBB_FOUND TRUE)
|
|
set(TBB_INCLUDE_DIRS "${TBB_INCLUDE_DIR}")
|
|
return()
|
|
elseif ((TARGET TBB) OR (NOT _TBB_AVAILABLE_COMPONENTS STREQUAL ""))
|
|
rk_tbb_error("Ignoring existing TBB targets because required components are missing: ${_TBB_MISSING_COMPONENTS}")
|
|
endif()
|
|
endmacro()
|
|
|
|
|
|
#===============================================================================
|
|
# Find the root directory if a manual override is not specified.
|
|
# Sets TBB_ROOT in the parent scope, but does not check for failure.
|
|
#===============================================================================
|
|
|
|
function(rk_tbb_find_root)
|
|
if (NOT TBB_ROOT OR TBB_ROOT STREQUAL "")
|
|
set(TBB_HINTS "")
|
|
set(TBB_PATHS "")
|
|
|
|
if (WIN32)
|
|
# workaround for parentheses in variable name / CMP0053
|
|
set(PROGRAMFILESx86 "PROGRAMFILES(x86)")
|
|
set(PROGRAMFILES32 "$ENV{${PROGRAMFILESx86}}")
|
|
if(NOT PROGRAMFILES32)
|
|
set(PROGRAMFILES32 "$ENV{PROGRAMFILES}")
|
|
endif()
|
|
if(NOT PROGRAMFILES32)
|
|
set(PROGRAMFILES32 "C:/Program Files (x86)")
|
|
endif()
|
|
set(TBB_PATHS
|
|
"${PROJECT_SOURCE_DIR}/../tbb"
|
|
"${PROGRAMFILES32}/IntelSWTools/compilers_and_libraries/windows/tbb"
|
|
"${PROGRAMFILES32}/Intel/Composer XE/tbb"
|
|
"${PROGRAMFILES32}/Intel/compilers_and_libraries/windows/tbb")
|
|
else()
|
|
set(TBB_HINTS "/usr/local")
|
|
set(TBB_PATHS
|
|
"${PROJECT_SOURCE_DIR}/tbb"
|
|
"/opt/intel/composerxe/tbb"
|
|
"/opt/intel/compilers_and_libraries/tbb"
|
|
"/opt/intel/compilers_and_libraries/linux/tbb"
|
|
"/opt/intel/tbb")
|
|
endif()
|
|
|
|
set(TBB_ROOT "TBB_ROOT-NOTFOUND")
|
|
find_path(TBB_ROOT
|
|
NAMES "${_TBB_INCLUDE_SUBDIR}/${_TBB_HEADER}"
|
|
HINTS ${TBB_HINTS}
|
|
PATHS ${TBB_PATHS}
|
|
NO_PACKAGE_ROOT_PATH)
|
|
endif()
|
|
endfunction()
|
|
|
|
#===============================================================================
|
|
# Find the include directory if a manual override is not specified.
|
|
# Assumes TBB_ROOT to be set.
|
|
#===============================================================================
|
|
|
|
function(rk_tbb_find_include_directory)
|
|
find_path(TBB_INCLUDE_DIR
|
|
NAMES "${_TBB_HEADER}"
|
|
HINTS "${TBB_ROOT}/${_TBB_INCLUDE_SUBDIR}"
|
|
NO_PACKAGE_ROOT_PATH)
|
|
endfunction()
|
|
|
|
#===============================================================================
|
|
# Find a specific library and create a target for it.
|
|
#===============================================================================
|
|
|
|
function(rk_tbb_find_library COMPONENT_NAME BUILD_CONFIG)
|
|
set(LIB_VAR "${COMPONENT_NAME}_LIBRARY_${BUILD_CONFIG}")
|
|
set(BIN_DIR_VAR "${COMPONENT_NAME}_BIN_DIR_${BUILD_CONFIG}")
|
|
set(DLL_VAR "${COMPONENT_NAME}_DLL_${BUILD_CONFIG}")
|
|
if (BUILD_CONFIG STREQUAL "DEBUG")
|
|
set(LIB_NAME "${COMPONENT_NAME}_debug")
|
|
else()
|
|
set(LIB_NAME "${COMPONENT_NAME}")
|
|
endif()
|
|
|
|
unset(LIB_PATHS)
|
|
|
|
if (WIN32)
|
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
|
set(TBB_ARCH intel64)
|
|
else()
|
|
set(TBB_ARCH ia32)
|
|
endif()
|
|
|
|
if(MSVC10)
|
|
set(TBB_VCVER vc10)
|
|
elseif(MSVC11)
|
|
set(TBB_VCVER vc11)
|
|
elseif(MSVC12)
|
|
set(TBB_VCVER vc12)
|
|
else()
|
|
set(TBB_VCVER vc14)
|
|
endif()
|
|
|
|
set(LIB_PATHS
|
|
${TBB_ROOT}/lib/${TBB_ARCH}/${TBB_VCVER}
|
|
${TBB_ROOT}/lib
|
|
)
|
|
|
|
# On window, also search the DLL so that the client may install it.
|
|
set(DLL_NAME "${LIB_NAME}.dll")
|
|
|
|
# lib name with version suffix to handle oneTBB tbb12.dll
|
|
set(LIB_NAME_VERSION "")
|
|
if (${COMPONENT_NAME} STREQUAL "tbb")
|
|
if (BUILD_CONFIG STREQUAL "DEBUG")
|
|
set(LIB_NAME_VERSION "tbb12_debug")
|
|
else()
|
|
set(LIB_NAME_VERSION "tbb12")
|
|
endif()
|
|
endif()
|
|
set(DLL_NAME_VERSION "${LIB_NAME_VERSION}.dll")
|
|
|
|
find_file(BIN_FILE
|
|
NAMES ${DLL_NAME} ${DLL_NAME_VERSION}
|
|
PATHS
|
|
"${TBB_ROOT}/bin/${TBB_ARCH}/${TBB_VCVER}"
|
|
"${TBB_ROOT}/bin"
|
|
"${TBB_ROOT}/redist/${TBB_ARCH}/${TBB_VCVER}"
|
|
"${TBB_ROOT}/../redist/${TBB_ARCH}/tbb/${TBB_VCVER}"
|
|
"${TBB_ROOT}/../redist/${TBB_ARCH}_win/tbb/${TBB_VCVER}"
|
|
NO_DEFAULT_PATH)
|
|
get_filename_component(${BIN_DIR_VAR} ${BIN_FILE} DIRECTORY)
|
|
set(${DLL_VAR} "${BIN_FILE}" CACHE PATH "${COMPONENT_NAME} ${BUILD_CONFIG} dll path")
|
|
elseif(APPLE)
|
|
set(LIB_PATHS ${TBB_ROOT}/lib)
|
|
else()
|
|
file(GLOB LIB_PATHS PATHS ${TBB_ROOT}/lib/intel64/gcc*)
|
|
list(REVERSE LIB_PATHS)
|
|
list(APPEND LIB_PATHS
|
|
${TBB_ROOT}/lib
|
|
${TBB_ROOT}/lib/x86_64-linux-gnu
|
|
${TBB_ROOT}/lib64
|
|
${TBB_ROOT}/libx86_64-linux-gnu)
|
|
endif()
|
|
|
|
# We prefer finding the versioned file on Unix so that the library path
|
|
# variable will not point to a symlink. This makes installing TBB as a
|
|
# dependency easier.
|
|
if (UNIX)
|
|
set(LIB_NAME lib${LIB_NAME}.so.2 ${LIB_NAME})
|
|
endif()
|
|
|
|
find_library(${LIB_VAR}
|
|
NAMES ${LIB_NAME}
|
|
PATHS ${LIB_PATHS}
|
|
NO_DEFAULT_PATH)
|
|
|
|
# Hide this variable if we found something, otherwise display it for
|
|
# easy override.
|
|
if(${LIB_VAR})
|
|
mark_as_advanced(${LIB_VAR})
|
|
endif()
|
|
if(${BIN_DIR_VAR})
|
|
mark_as_advanced(${BIN_DIR_VAR})
|
|
endif()
|
|
if(${DLL_VAR})
|
|
mark_as_advanced(${DLL_VAR})
|
|
endif()
|
|
endfunction()
|
|
|
|
#===============================================================================
|
|
# Find the given component.
|
|
# This macro attempts to find both release and debug versions, and falls back
|
|
# appropriately if only one can be found.
|
|
# On success, it creates a target ${TARGET}::${COMPONENT_NAME} and links
|
|
# it to the overall ${TARGET}.
|
|
#
|
|
# For more information on the variables set here, see
|
|
# https://cmake.org/cmake/help/v3.17/manual/cmake-developer.7.html#a-sample-find-module
|
|
#===============================================================================
|
|
|
|
function(rk_tbb_find_and_link_component COMPONENT_NAME)
|
|
set(COMPONENT_TARGET "TBB::${COMPONENT_NAME}")
|
|
|
|
rk_tbb_find_library("${COMPONENT_NAME}" RELEASE)
|
|
rk_tbb_find_library("${COMPONENT_NAME}" DEBUG)
|
|
|
|
if (${COMPONENT_NAME}_LIBRARY_RELEASE OR ${COMPONENT_NAME}_LIBRARY_DEBUG)
|
|
# Note: We *must* use SHARED here rather than UNKNOWN as our
|
|
# IMPORTED_NO_SONAME trick a few lines down does not work with
|
|
# UNKNOWN.
|
|
add_library(${COMPONENT_TARGET} SHARED IMPORTED)
|
|
|
|
if (${COMPONENT_NAME}_LIBRARY_RELEASE)
|
|
set_property(TARGET ${COMPONENT_TARGET} APPEND PROPERTY
|
|
IMPORTED_CONFIGURATIONS RELEASE)
|
|
if(WIN32)
|
|
set_target_properties(${COMPONENT_TARGET} PROPERTIES
|
|
IMPORTED_LOCATION_RELEASE "${${COMPONENT_NAME}_DLL_RELEASE}")
|
|
set_target_properties(${COMPONENT_TARGET} PROPERTIES
|
|
IMPORTED_IMPLIB_RELEASE "${${COMPONENT_NAME}_LIBRARY_RELEASE}")
|
|
else()
|
|
set_target_properties(${COMPONENT_TARGET} PROPERTIES
|
|
IMPORTED_LOCATION_RELEASE "${${COMPONENT_NAME}_LIBRARY_RELEASE}")
|
|
endif()
|
|
endif()
|
|
|
|
if (${COMPONENT_NAME}_LIBRARY_DEBUG)
|
|
set_property(TARGET ${COMPONENT_TARGET} APPEND PROPERTY
|
|
IMPORTED_CONFIGURATIONS DEBUG)
|
|
if(WIN32)
|
|
set_target_properties(${COMPONENT_TARGET} PROPERTIES
|
|
IMPORTED_LOCATION_DEBUG "${${COMPONENT_NAME}_DLL_DEBUG}")
|
|
set_target_properties(${COMPONENT_TARGET} PROPERTIES
|
|
IMPORTED_IMPLIB_DEBUG "${${COMPONENT_NAME}_LIBRARY_DEBUG}")
|
|
else()
|
|
set_target_properties(${COMPONENT_TARGET} PROPERTIES
|
|
IMPORTED_LOCATION_DEBUG "${${COMPONENT_NAME}_LIBRARY_DEBUG}")
|
|
endif()
|
|
endif()
|
|
|
|
set_target_properties(${COMPONENT_TARGET} PROPERTIES
|
|
INTERFACE_INCLUDE_DIRECTORIES "${TBB_INCLUDE_DIR}"
|
|
INTERFACE_COMPILE_DEFINITIONS "__TBB_NO_IMPLICIT_LINKAGE=1"
|
|
)
|
|
|
|
|
|
if(NOT WIN32)
|
|
# Note: IMPORTED_NO_SONAME must be set or cmake will attempt
|
|
# to link to the full path of libtbb.so. Instead, we
|
|
# rely on the linker to find libtbb.so.2.
|
|
set_target_properties(${COMPONENT_TARGET} PROPERTIES
|
|
IMPORTED_NO_SONAME TRUE
|
|
)
|
|
endif()
|
|
|
|
target_link_libraries(TBB INTERFACE ${COMPONENT_TARGET})
|
|
endif()
|
|
endfunction()
|
|
|
|
#===============================================================================
|
|
|
|
# Note: The order of these is important.
|
|
# Some of these macros create variables that are used in later calls.
|
|
rk_tbb_list_components()
|
|
rk_tbb_reuse_existing_target_components()
|
|
|
|
rk_tbb_find_root()
|
|
if (NOT EXISTS "${TBB_ROOT}")
|
|
rk_tbb_error("Unable to find root directory ${TBB_ROOT}")
|
|
endif()
|
|
mark_as_advanced(TBB_ROOT) # Hide, we found something.
|
|
|
|
rk_tbb_find_include_directory()
|
|
if (NOT EXISTS "${TBB_INCLUDE_DIR}")
|
|
rk_tbb_error("Unable to find include directory ${TBB_INCLUDE_DIR}")
|
|
endif()
|
|
mark_as_advanced(TBB_INCLUDE_DIR) # Hide, we found something.
|
|
|
|
rk_tbb_check_version()
|
|
|
|
add_library(TBB INTERFACE)
|
|
|
|
foreach(C IN LISTS _REQUIRED_COMPONENTS _OPTIONAL_COMPONENTS)
|
|
rk_tbb_find_and_link_component(${C})
|
|
endforeach()
|
|
|
|
rk_tbb_check_components()
|
|
if (_TBB_MISSING_COMPONENTS)
|
|
rk_tbb_error("Cannot find required components: "
|
|
"${_TBB_MISSING_COMPONENTS}")
|
|
endif()
|
|
|
|
set(TBB_FOUND TRUE)
|
|
set(TBB_INCLUDE_DIRS "${TBB_INCLUDE_DIR}")
|