| #[======================================================[.rst |
| |
| Adds the following targets:: |
| |
| pybind11::pybind11 - link to headers and pybind11 |
| pybind11::module - Adds module links |
| pybind11::embed - Adds embed links |
| pybind11::lto - Link time optimizations (manual selection) |
| pybind11::thin_lto - Link time optimizations (manual selection) |
| pybind11::python_link_helper - Adds link to Python libraries |
| pybind11::python2_no_register - Avoid warning/error with Python 2 + C++14/7 |
| pybind11::windows_extras - MSVC bigobj and mp for building multithreaded |
| pybind11::opt_size - avoid optimizations that increase code size |
| |
| Adds the following functions:: |
| |
| pybind11_strip(target) - strip target after building on linux/macOS |
| pybind11_find_import(module) - See if a module is installed. |
| |
| #]======================================================] |
| |
| # CMake 3.10 has an include_guard command, but we can't use that yet |
| # include_guard(global) (pre-CMake 3.10) |
| if(TARGET pybind11::lto) |
| return() |
| endif() |
| |
| # If we are in subdirectory mode, all IMPORTED targets must be GLOBAL. If we |
| # are in CONFIG mode, they should be "normal" targets instead. |
| # In CMake 3.11+ you can promote a target to global after you create it, |
| # which might be simpler than this check. |
| get_property( |
| is_config |
| TARGET pybind11::headers |
| PROPERTY IMPORTED) |
| if(NOT is_config) |
| set(optional_global GLOBAL) |
| endif() |
| |
| # If not run in Python mode, we still would like this to at least |
| # include pybind11's include directory: |
| set(pybind11_INCLUDE_DIRS |
| "${pybind11_INCLUDE_DIR}" |
| CACHE INTERNAL "Include directory for pybind11 (Python not requested)") |
| |
| # --------------------- Shared targets ---------------------------- |
| |
| # Build an interface library target: |
| add_library(pybind11::pybind11 IMPORTED INTERFACE ${optional_global}) |
| set_property( |
| TARGET pybind11::pybind11 |
| APPEND |
| PROPERTY INTERFACE_LINK_LIBRARIES pybind11::headers) |
| |
| # Build a module target: |
| add_library(pybind11::module IMPORTED INTERFACE ${optional_global}) |
| set_property( |
| TARGET pybind11::module |
| APPEND |
| PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11) |
| |
| # Build an embed library target: |
| add_library(pybind11::embed IMPORTED INTERFACE ${optional_global}) |
| set_property( |
| TARGET pybind11::embed |
| APPEND |
| PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11) |
| |
| # ----------------------- no register ---------------------- |
| |
| # Workaround for Python 2.7 and C++17 (C++14 as a warning) incompatibility |
| # This adds the flags -Wno-register and -Wno-deprecated-register if the compiler |
| # is Clang 3.9+ or AppleClang and the compile language is CXX, or /wd5033 for MSVC (all languages, |
| # since MSVC didn't recognize COMPILE_LANGUAGE until CMake 3.11+). |
| |
| add_library(pybind11::python2_no_register INTERFACE IMPORTED ${optional_global}) |
| set(clang_4plus |
| "$<AND:$<CXX_COMPILER_ID:Clang>,$<NOT:$<VERSION_LESS:$<CXX_COMPILER_VERSION>,3.9>>>") |
| set(no_register "$<OR:${clang_4plus},$<CXX_COMPILER_ID:AppleClang>>") |
| |
| if(MSVC AND CMAKE_VERSION VERSION_LESS 3.11) |
| set(cxx_no_register "${no_register}") |
| else() |
| set(cxx_no_register "$<AND:$<COMPILE_LANGUAGE:CXX>,${no_register}>") |
| endif() |
| |
| set(msvc "$<CXX_COMPILER_ID:MSVC>") |
| |
| set_property( |
| TARGET pybind11::python2_no_register |
| PROPERTY INTERFACE_COMPILE_OPTIONS |
| "$<${cxx_no_register}:-Wno-register;-Wno-deprecated-register>" "$<${msvc}:/wd5033>") |
| |
| # --------------------------- link helper --------------------------- |
| |
| add_library(pybind11::python_link_helper IMPORTED INTERFACE ${optional_global}) |
| |
| if(CMAKE_VERSION VERSION_LESS 3.13) |
| # In CMake 3.11+, you can set INTERFACE properties via the normal methods, and |
| # this would be simpler. |
| set_property( |
| TARGET pybind11::python_link_helper |
| APPEND |
| PROPERTY INTERFACE_LINK_LIBRARIES "$<$<PLATFORM_ID:Darwin>:-undefined dynamic_lookup>") |
| else() |
| # link_options was added in 3.13+ |
| # This is safer, because you are ensured the deduplication pass in CMake will not consider |
| # these separate and remove one but not the other. |
| set_property( |
| TARGET pybind11::python_link_helper |
| APPEND |
| PROPERTY INTERFACE_LINK_OPTIONS "$<$<PLATFORM_ID:Darwin>:LINKER:-undefined,dynamic_lookup>") |
| endif() |
| |
| # ------------------------ Windows extras ------------------------- |
| |
| add_library(pybind11::windows_extras IMPORTED INTERFACE ${optional_global}) |
| |
| if(MSVC) # That's also clang-cl |
| # /bigobj is needed for bigger binding projects due to the limit to 64k |
| # addressable sections |
| set_property( |
| TARGET pybind11::windows_extras |
| APPEND |
| PROPERTY INTERFACE_COMPILE_OPTIONS /bigobj) |
| |
| # /MP enables multithreaded builds (relevant when there are many files) for MSVC |
| if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # no Clang no Intel |
| if(CMAKE_VERSION VERSION_LESS 3.11) |
| set_property( |
| TARGET pybind11::windows_extras |
| APPEND |
| PROPERTY INTERFACE_COMPILE_OPTIONS $<$<NOT:$<CONFIG:Debug>>:/MP>) |
| else() |
| # Only set these options for C++ files. This is important so that, for |
| # instance, projects that include other types of source files like CUDA |
| # .cu files don't get these options propagated to nvcc since that would |
| # cause the build to fail. |
| set_property( |
| TARGET pybind11::windows_extras |
| APPEND |
| PROPERTY INTERFACE_COMPILE_OPTIONS |
| $<$<NOT:$<CONFIG:Debug>>:$<$<COMPILE_LANGUAGE:CXX>:/MP>>) |
| endif() |
| endif() |
| endif() |
| |
| # ----------------------- Optimize binary size -------------------------- |
| |
| add_library(pybind11::opt_size IMPORTED INTERFACE ${optional_global}) |
| |
| if(MSVC) |
| set(PYBIND11_OPT_SIZE /Os) |
| else() |
| set(PYBIND11_OPT_SIZE -Os) |
| endif() |
| |
| set_property( |
| TARGET pybind11::opt_size |
| APPEND |
| PROPERTY INTERFACE_COMPILE_OPTIONS $<$<CONFIG:Release>:${PYBIND11_OPT_SIZE}> |
| $<$<CONFIG:MinSizeRel>:${PYBIND11_OPT_SIZE}> |
| $<$<CONFIG:RelWithDebInfo>:${PYBIND11_OPT_SIZE}>) |
| |
| # ----------------------- Legacy option -------------------------- |
| |
| # Warn or error if old variable name used |
| if(PYBIND11_CPP_STANDARD) |
| string(REGEX MATCH [[..$]] VAL "${PYBIND11_CPP_STANDARD}") |
| if(CMAKE_CXX_STANDARD) |
| if(NOT CMAKE_CXX_STANDARD STREQUAL VAL) |
| message(WARNING "CMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} does not match " |
| "PYBIND11_CPP_STANDARD=${PYBIND11_CPP_STANDARD}, " |
| "please remove PYBIND11_CPP_STANDARD from your cache") |
| endif() |
| else() |
| set(supported_standards 11 14 17 20) |
| if("${VAL}" IN_LIST supported_standards) |
| message(WARNING "USE -DCMAKE_CXX_STANDARD=${VAL} instead of PYBIND11_CPP_STANDARD") |
| set(CMAKE_CXX_STANDARD |
| ${VAL} |
| CACHE STRING "From PYBIND11_CPP_STANDARD") |
| else() |
| message(FATAL_ERROR "PYBIND11_CPP_STANDARD should be replaced with CMAKE_CXX_STANDARD " |
| "(last two chars: ${VAL} not understood as a valid CXX std)") |
| endif() |
| endif() |
| endif() |
| |
| # --------------------- Python specifics ------------------------- |
| |
| # Check to see which Python mode we are in, new, old, or no python |
| if(PYBIND11_NOPYTHON) |
| set(_pybind11_nopython ON) |
| elseif( |
| PYBIND11_FINDPYTHON |
| OR Python_FOUND |
| OR Python2_FOUND |
| OR Python3_FOUND) |
| # New mode |
| include("${CMAKE_CURRENT_LIST_DIR}/pybind11NewTools.cmake") |
| |
| else() |
| |
| # Classic mode |
| include("${CMAKE_CURRENT_LIST_DIR}/pybind11Tools.cmake") |
| |
| endif() |
| |
| # --------------------- pybind11_find_import ------------------------------- |
| |
| if(NOT _pybind11_nopython) |
| # Check to see if modules are importable. Use REQUIRED to force an error if |
| # one of the modules is not found. <package_name>_FOUND will be set if the |
| # package was found (underscores replace dashes if present). QUIET will hide |
| # the found message, and VERSION will require a minimum version. A successful |
| # find will cache the result. |
| function(pybind11_find_import PYPI_NAME) |
| # CMake variables need underscores (PyPI doesn't care) |
| string(REPLACE "-" "_" NORM_PYPI_NAME "${PYPI_NAME}") |
| |
| # Return if found previously |
| if(${NORM_PYPI_NAME}_FOUND) |
| return() |
| endif() |
| |
| set(options "REQUIRED;QUIET") |
| set(oneValueArgs "VERSION") |
| cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "" ${ARGN}) |
| |
| if(ARG_REQUIRED) |
| set(status_level FATAL_ERROR) |
| else() |
| set(status_level WARNING) |
| endif() |
| |
| execute_process( |
| COMMAND |
| ${${_Python}_EXECUTABLE} -c |
| "from pkg_resources import get_distribution; print(get_distribution('${PYPI_NAME}').version)" |
| RESULT_VARIABLE RESULT_PRESENT |
| OUTPUT_VARIABLE PKG_VERSION |
| ERROR_QUIET) |
| |
| string(STRIP "${PKG_VERSION}" PKG_VERSION) |
| |
| # If a result is present, this failed |
| if(RESULT_PRESENT) |
| set(${NORM_PYPI_NAME}_FOUND |
| ${NORM_PYPI_NAME}-NOTFOUND |
| CACHE INTERNAL "") |
| # Always warn or error |
| message( |
| ${status_level} |
| "Missing: ${PYPI_NAME} ${ARG_VERSION}\nTry: ${${_Python}_EXECUTABLE} -m pip install ${PYPI_NAME}" |
| ) |
| else() |
| if(ARG_VERSION AND PKG_VERSION VERSION_LESS ARG_VERSION) |
| message( |
| ${status_level} |
| "Version incorrect: ${PYPI_NAME} ${PKG_VERSION} found, ${ARG_VERSION} required - try upgrading" |
| ) |
| else() |
| set(${NORM_PYPI_NAME}_FOUND |
| YES |
| CACHE INTERNAL "") |
| set(${NORM_PYPI_NAME}_VERSION |
| ${PKG_VERSION} |
| CACHE INTERNAL "") |
| endif() |
| if(NOT ARG_QUIET) |
| message(STATUS "Found ${PYPI_NAME} ${PKG_VERSION}") |
| endif() |
| endif() |
| if(NOT ARG_VERSION OR (NOT PKG_VERSION VERSION_LESS ARG_VERSION)) |
| # We have successfully found a good version, cache to avoid calling again. |
| endif() |
| endfunction() |
| endif() |
| |
| # --------------------- LTO ------------------------------- |
| |
| include(CheckCXXCompilerFlag) |
| |
| # Checks whether the given CXX/linker flags can compile and link a cxx file. |
| # cxxflags and linkerflags are lists of flags to use. The result variable is a |
| # unique variable name for each set of flags: the compilation result will be |
| # cached base on the result variable. If the flags work, sets them in |
| # cxxflags_out/linkerflags_out internal cache variables (in addition to |
| # ${result}). |
| function(_pybind11_return_if_cxx_and_linker_flags_work result cxxflags linkerflags cxxflags_out |
| linkerflags_out) |
| set(CMAKE_REQUIRED_LIBRARIES ${linkerflags}) |
| check_cxx_compiler_flag("${cxxflags}" ${result}) |
| if(${result}) |
| set(${cxxflags_out} |
| "${cxxflags}" |
| PARENT_SCOPE) |
| set(${linkerflags_out} |
| "${linkerflags}" |
| PARENT_SCOPE) |
| endif() |
| endfunction() |
| |
| function(_pybind11_generate_lto target prefer_thin_lto) |
| if(MINGW) |
| message(STATUS "${target} disabled (problems with undefined symbols for MinGW for now)") |
| return() |
| endif() |
| |
| if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") |
| set(cxx_append "") |
| set(linker_append "") |
| if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT APPLE) |
| # Clang Gold plugin does not support -Os; append -O3 to MinSizeRel builds to override it |
| set(linker_append ";$<$<CONFIG:MinSizeRel>:-O3>") |
| elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND NOT MINGW) |
| set(cxx_append ";-fno-fat-lto-objects") |
| endif() |
| |
| if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND prefer_thin_lto) |
| _pybind11_return_if_cxx_and_linker_flags_work( |
| HAS_FLTO_THIN "-flto=thin${cxx_append}" "-flto=thin${linker_append}" |
| PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) |
| endif() |
| |
| if(NOT HAS_FLTO_THIN) |
| _pybind11_return_if_cxx_and_linker_flags_work( |
| HAS_FLTO "-flto${cxx_append}" "-flto${linker_append}" PYBIND11_LTO_CXX_FLAGS |
| PYBIND11_LTO_LINKER_FLAGS) |
| endif() |
| elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel") |
| # Intel equivalent to LTO is called IPO |
| _pybind11_return_if_cxx_and_linker_flags_work(HAS_INTEL_IPO "-ipo" "-ipo" |
| PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) |
| elseif(MSVC) |
| # cmake only interprets libraries as linker flags when they start with a - (otherwise it |
| # converts /LTCG to \LTCG as if it was a Windows path). Luckily MSVC supports passing flags |
| # with - instead of /, even if it is a bit non-standard: |
| _pybind11_return_if_cxx_and_linker_flags_work(HAS_MSVC_GL_LTCG "/GL" "-LTCG" |
| PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) |
| endif() |
| |
| # Enable LTO flags if found, except for Debug builds |
| if(PYBIND11_LTO_CXX_FLAGS) |
| # CONFIG takes multiple values in CMake 3.19+, until then we have to use OR |
| set(is_debug "$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>") |
| set(not_debug "$<NOT:${is_debug}>") |
| set(cxx_lang "$<COMPILE_LANGUAGE:CXX>") |
| if(MSVC AND CMAKE_VERSION VERSION_LESS 3.11) |
| set(genex "${not_debug}") |
| else() |
| set(genex "$<AND:${not_debug},${cxx_lang}>") |
| endif() |
| set_property( |
| TARGET ${target} |
| APPEND |
| PROPERTY INTERFACE_COMPILE_OPTIONS "$<${genex}:${PYBIND11_LTO_CXX_FLAGS}>") |
| if(CMAKE_PROJECT_NAME STREQUAL "pybind11") |
| message(STATUS "${target} enabled") |
| endif() |
| else() |
| if(CMAKE_PROJECT_NAME STREQUAL "pybind11") |
| message(STATUS "${target} disabled (not supported by the compiler and/or linker)") |
| endif() |
| endif() |
| |
| if(PYBIND11_LTO_LINKER_FLAGS) |
| if(CMAKE_VERSION VERSION_LESS 3.11) |
| set_property( |
| TARGET ${target} |
| APPEND |
| PROPERTY INTERFACE_LINK_LIBRARIES "$<${not_debug}:${PYBIND11_LTO_LINKER_FLAGS}>") |
| else() |
| set_property( |
| TARGET ${target} |
| APPEND |
| PROPERTY INTERFACE_LINK_OPTIONS "$<${not_debug}:${PYBIND11_LTO_LINKER_FLAGS}>") |
| endif() |
| endif() |
| endfunction() |
| |
| add_library(pybind11::lto IMPORTED INTERFACE ${optional_global}) |
| _pybind11_generate_lto(pybind11::lto FALSE) |
| |
| add_library(pybind11::thin_lto IMPORTED INTERFACE ${optional_global}) |
| _pybind11_generate_lto(pybind11::thin_lto TRUE) |
| |
| # ---------------------- pybind11_strip ----------------------------- |
| |
| function(pybind11_strip target_name) |
| # Strip unnecessary sections of the binary on Linux/macOS |
| if(CMAKE_STRIP) |
| if(APPLE) |
| set(x_opt -x) |
| endif() |
| |
| add_custom_command( |
| TARGET ${target_name} |
| POST_BUILD |
| COMMAND ${CMAKE_STRIP} ${x_opt} $<TARGET_FILE:${target_name}>) |
| endif() |
| endfunction() |