Files
UnrealEngine/Engine/Source/ThirdParty/Intel/Embree/embree-4.3.3/common/cmake/FindTBB.cmake
2025-05-18 13:04:45 +08:00

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}")