Unverified Commit 1729aae9 authored by Henry Schreiner's avatar Henry Schreiner Committed by GitHub
Browse files

feat: new FindPython support (#2370)

* feat: FindPython support

* refactor: rename to PYBIND11_FINDPYTHON

* docs: Caps fixes

* feat: NOPYTHON mode

* test: check simple call

* docs: add changelog/upgrade guide

* feat: Support Python3 and Python2

* refactor: Use targets in tests

* fix: support CMake 3.4+

* feat: classic search also finds virtual environments

* docs: some updates from @wjakob's review

* fix: wrong name for QUIET mode variable, reported by @skoslowski

* refactor: cleaner output messaging

* fix: support debug Python's in FindPython mode too

* fixup! refactor: cleaner output messaging

* fix: missing pybind11_FOUND and pybind11_INCLUDE_DIR restored to subdir mode

* fix: nicer reporting of Python / PyPy

* fix: out-of-order variable fix

* docs: minor last-minute cleanup
parent 69821d9e
#[======================================================[.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
Adds the following functions::
pybind11_strip(target) - strip target after building on linux/macOS
#]======================================================]
# CMake 3.10 has an include_guard command, but we can't use that yet
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()
# --------------------- 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)
# /MP enables multithreaded builds (relevant when there are many files), /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)
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()
# ----------------------- 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_PYTHON_VERSION")
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()
# --------------------- 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(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")
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)
set(not_debug "$<NOT:$<CONFIG: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/Mac OS
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()
...@@ -8,6 +8,7 @@ This module sets the following variables in your project:: ...@@ -8,6 +8,7 @@ This module sets the following variables in your project::
pybind11_FOUND - true if pybind11 and all required components found on the system pybind11_FOUND - true if pybind11 and all required components found on the system
pybind11_VERSION - pybind11 version in format Major.Minor.Release pybind11_VERSION - pybind11 version in format Major.Minor.Release
pybind11_VERSION_TYPE - pybind11 version type (dev, release)
pybind11_INCLUDE_DIRS - Directories where pybind11 and python headers are located. pybind11_INCLUDE_DIRS - Directories where pybind11 and python headers are located.
pybind11_INCLUDE_DIR - Directory where pybind11 headers are located. pybind11_INCLUDE_DIR - Directory where pybind11 headers are located.
pybind11_DEFINITIONS - Definitions necessary to use pybind11, namely USING_pybind11. pybind11_DEFINITIONS - Definitions necessary to use pybind11, namely USING_pybind11.
...@@ -28,21 +29,61 @@ interface library targets:: ...@@ -28,21 +29,61 @@ interface library targets::
Python headers, libraries (as needed by platform), and the C++ standard Python headers, libraries (as needed by platform), and the C++ standard
are attached to the target. are attached to the target.
Advanced targets are also supplied - these are primary for users building
complex applications, and they are available in all modes::
pybind11::headers - Just the pybind11 headers and minimum compile requirements
pybind11::pybind11 - Python headers too
pybind11::python_link_helper - Just the "linking" part of pybind11:module, for CMake < 3.15
pybind11::python2_no_register - Quiets the warning/error when mixing C++14+ and Python 2, also included in pybind11::module
pybind11::thin_lto - An alternative to INTERPROCEDURAL_OPTIMIZATION
pybind11::lto - An alternative to INTERPROCEDURAL_OPTIMIZATION (also avoids thin LTO on clang)
pybind11::windows_extras - Adds bigobj and mp for MSVC
Modes::
There are two modes provided; classic, which is built on the old Python
discovery packages in CMake, or the new FindPython mode, which uses FindPython
from 3.12+ forward (3.15+ _highly_ recommended).
New FindPython mode::
To activate this mode, either call ``find_package(Python COMPONENTS Interpreter Development)``
before finding this package, or set the ``PYBIND11_FINDPYTHON`` variable to ON. In this mode,
you can either use the basic targets, or use the FindPython tools::
find_package(Python COMPONENTS Interpreter Development)
find_package(pybind11 CONFIG)
# pybind11 method:
pybind11_add_module(MyModule1 src1.cpp)
# Python method:
Python_add_library(MyModule2 src2.cpp)
target_link_libraries(MyModule2 pybind11::headers)
set_target_properties(MyModule2 PROPERTIES
INTERPROCEDURAL_OPTIMIZATION ON
CXX__VISIBILITY_PRESET ON
VISIBLITY_INLINES_HIDDEN ON)
If you build targets yourself, you may be interested in stripping the output
for reduced size; this is the one other feature that the helper function gives you.
Classic mode:: Classic mode::
Set PythonLibsNew variables to influence python detection and Set PythonLibsNew variables to influence python detection and
CMAKE_CXX_STANDARD to influence standard setting. :: CMAKE_CXX_STANDARD to influence standard setting. ::
find_package(pybind11 CONFIG REQUIRED) find_package(pybind11 CONFIG REQUIRED)
message(STATUS "Found pybind11 v${pybind11_VERSION} ${pybind11_VERSION_TYPE}: ${pybind11_INCLUDE_DIRS}")
# Create an extension module # Create an extension module
add_library(mylib MODULE main.cpp) add_library(mylib MODULE main.cpp)
target_link_libraries(mylib pybind11::module) target_link_libraries(mylib PUBLIC pybind11::module)
# Or embed the Python interpreter into an executable # Or embed the Python interpreter into an executable
add_executable(myexe main.cpp) add_executable(myexe main.cpp)
target_link_libraries(myexe pybind11::embed) target_link_libraries(myexe PUBLIC pybind11::embed)
Suggested usage:: Suggested usage::
...@@ -59,8 +100,17 @@ The following variables can be set to guide the search for this package:: ...@@ -59,8 +100,17 @@ The following variables can be set to guide the search for this package::
PATH - environment variable, set to bin directory of this package PATH - environment variable, set to bin directory of this package
CMAKE_DISABLE_FIND_PACKAGE_pybind11 - CMake variable, disables CMAKE_DISABLE_FIND_PACKAGE_pybind11 - CMake variable, disables
find_package(pybind11) when not REQUIRED, perhaps to force internal build find_package(pybind11) when not REQUIRED, perhaps to force internal build
#]=============================================================================]
Helper functions::
pybind11_add_module(...) - Add a library and setup all helpers
pybind11_strip(target) - Strip a target after building it (linux/macOS)
pybind11_extension(target) - Injects the Python extension name
See ``pybind11Tools.cmake`` or ``pybind11NewTools.cmake`` for details on
``pybind11_add_module``.
#]=============================================================================]
@PACKAGE_INIT@ @PACKAGE_INIT@
# Location of pybind11/pybind11.h # Location of pybind11/pybind11.h
...@@ -72,50 +122,19 @@ set(pybind11_VERSION_TYPE "@pybind11_VERSION_TYPE@") ...@@ -72,50 +122,19 @@ set(pybind11_VERSION_TYPE "@pybind11_VERSION_TYPE@")
check_required_components(pybind11) check_required_components(pybind11)
include("${CMAKE_CURRENT_LIST_DIR}/pybind11Tools.cmake") if(TARGET pybind11::python_link_helper)
# This has already been setup elsewhere, such as with a previous call or
#----------------------------------------------------------------------------- # add_subdirectory
# Don't include targets if this file is being picked up by another return()
# project which has already built this as a subproject endif()
#-----------------------------------------------------------------------------
if(NOT TARGET pybind11::pybind11) include("${CMAKE_CURRENT_LIST_DIR}/pybind11Targets.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/pybind11Targets.cmake")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} MODULE REQUIRED)
list(REMOVE_AT CMAKE_MODULE_PATH -1)
set_property(
TARGET pybind11::pybind11
APPEND
PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${PYTHON_INCLUDE_DIRS})
set_property(
TARGET pybind11::pybind11
APPEND
PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES ${PYTHON_INCLUDE_DIRS})
set_property(
TARGET pybind11::embed
APPEND
PROPERTY INTERFACE_LINK_LIBRARIES ${PYTHON_LIBRARIES})
set_property(
TARGET pybind11::module
APPEND
PROPERTY
INTERFACE_LINK_LIBRARIES
"$<$<OR:$<PLATFORM_ID:Windows>,$<PLATFORM_ID:Cygwin>>:$<BUILD_INTERFACE:${PYTHON_LIBRARIES}>>"
)
get_property( include("${CMAKE_CURRENT_LIST_DIR}/pybind11Common.cmake")
_iid
TARGET pybind11::pybind11 if(NOT pybind11_FIND_QUIETLY)
PROPERTY INTERFACE_INCLUDE_DIRECTORIES) message(
get_property( STATUS
_ill "Found pybind11: ${pybind11_INCLUDE_DIR} (found version \"${pybind11_VERSION}\" ${pybind11_VERSION_TYPE})"
TARGET pybind11::module )
PROPERTY INTERFACE_LINK_LIBRARIES)
set(pybind11_INCLUDE_DIRS ${_iid})
set(pybind11_LIBRARIES ${_ico} ${_ill})
include("${CMAKE_CURRENT_LIST_DIR}/pybind11Tools.cmake")
endif() endif()
# tools/pybind11NewTools.cmake -- Build system for the pybind11 modules
#
# Copyright (c) 2020 Wenzel Jakob <wenzel@inf.ethz.ch> and Henry Schreiner
#
# All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
get_property(
is_config
TARGET pybind11::headers
PROPERTY IMPORTED)
if(pybind11_FIND_QUIETLY)
set(_pybind11_quiet QUIET)
endif()
if(CMAKE_VERSION VERSION_LESS 3.12)
message(FATAL_ERROR "You cannot use the new FindPython module with CMake < 3.12")
endif()
if(NOT Python_FOUND
AND NOT Python3_FOUND
AND NOT Python2_FOUND)
if(NOT DEFINED Python_FIND_IMPLEMENTATIONS)
set(Python_FIND_IMPLEMENTATIONS CPython PyPy)
endif()
# GitHub Actions like activation
if(NOT DEFINED Python_ROOT_DIR AND DEFINED ENV{pythonLocation})
set(Python_ROOT_DIR "$ENV{pythonLocation}")
endif()
find_package(Python REQUIRED COMPONENTS Interpreter Development ${_pybind11_quiet})
# If we are in submodule mode, export the Python targets to global targets.
# If this behavior is not desired, FindPython _before_ pybind11.
if(NOT is_config)
set_property(TARGET Python::Python PROPERTY IMPORTED_GLOBAL TRUE)
set_property(TARGET Python::Interpreter PROPERTY IMPORTED_GLOBAL TRUE)
if(TARGET Python::Module)
set_property(TARGET Python::Module PROPERTY IMPORTED_GLOBAL TRUE)
endif()
endif()
endif()
if(Python_FOUND)
set(_Python
Python
CACHE INTERNAL "" FORCE)
elseif(Python3_FOUND AND NOT Python2_FOUND)
set(_Python
Python3
CACHE INTERNAL "" FORCE)
elseif(Python2_FOUND AND NOT Python3_FOUND)
set(_Python
Python2
CACHE INTERNAL "" FORCE)
else()
message(AUTHOR_WARNING "Python2 and Python3 both present, pybind11 in "
"PYBIND11_NOPYTHON mode (manually activate to silence warning)")
set(_pybind11_nopython ON)
return()
endif()
if(PYBIND11_MASTER_PROJECT)
if(${_Python}_INTERPRETER_ID MATCHES "PyPy")
message(STATUS "PyPy ${${_Python}_PyPy_VERSION} (Py ${${_Python}_VERSION})")
else()
message(STATUS "${_Python} ${${_Python}_VERSION}")
endif()
endif()
# Debug check - see https://stackoverflow.com/questions/646518/python-how-to-detect-debug-Interpreter
execute_process(COMMAND ${_Python}::Python -c "import sys; print(hasattr(sys, 'gettotalrefcount'))"
OUTPUT_VARIABLE PYTHON_IS_DEBUG)
# Python debug libraries expose slightly different objects before 3.8
# https://docs.python.org/3.6/c-api/intro.html#debugging-builds
# https://stackoverflow.com/questions/39161202/how-to-work-around-missing-pymodule-create2-in-amd64-win-python35-d-lib
if(PYTHON_IS_DEBUG)
set_property(
TARGET pybind::pybind11
APPEND
PROPERTY INTERFACE_COMPILE_DEFINITIONS Py_DEBUG)
endif()
# Check on every access - since Python2 and Python3 could have been used - do nothing in that case.
if(DEFINED ${_Python}_INCLUDE_DIRS)
set_property(
TARGET pybind11::pybind11
APPEND
PROPERTY INTERFACE_INCLUDE_DIRECTORIES $<BUILD_INTERFACE:${${_Python}_INCLUDE_DIRS}>)
endif()
if(DEFINED ${_Python}_VERSION AND ${_Python}_VERSION VERSION_LESS 3)
set_property(
TARGET pybind11::pybind11
APPEND
PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python2_no_register)
endif()
# In CMake 3.18+, you can find these separately, so include an if
if(TARGET ${_Python}::${_Python})
set_property(
TARGET pybind11::embed
APPEND
PROPERTY INTERFACE_LINK_LIBRARIES ${_Python}::${_Python})
endif()
# CMake 3.15+ has this
if(TARGET ${_Python}::Module)
set_property(
TARGET pybind11::module
APPEND
PROPERTY INTERFACE_LINK_LIBRARIES ${_Python}::Module)
else()
set_property(
TARGET pybind11::module
APPEND
PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python_link_helper)
endif()
function(pybind11_add_module target_name)
cmake_parse_arguments(PARSE_ARGV 1 ARG "STATIC;SHARED;MODULE;THIN_LTO;NO_EXTRAS" "" "")
if(ARG_ADD_LIBRARY_STATIC)
set(type STATIC)
elseif(ARG_ADD_LIBRARY_SHARED)
set(type SHARED)
else()
set(type MODULE)
endif()
if("${_Python}" STREQUAL "Python")
python_add_library(${target_name} ${type} WITH_SOABI ${ARG_UNPARSED_ARGUMENTS})
elseif("${_Python}" STREQUAL "Python3")
python3_add_library(${target_name} ${type} WITH_SOABI ${ARG_UNPARSED_ARGUMENTS})
elseif("${_Python}" STREQUAL "Python2")
python2_add_library(${target_name} ${type} WITH_SOABI ${ARG_UNPARSED_ARGUMENTS})
else()
message(FATAL_ERROR "Cannot detect FindPython version: ${_Python}")
endif()
target_link_libraries(${target_name} PRIVATE pybind11::headers)
if(type STREQUAL "MODULE")
target_link_libraries(${target_name} PRIVATE pybind11::module)
else()
target_link_libraries(${target_name} PRIVATE pybind11::embed)
endif()
if(MSVC)
target_link_libraries(${target_name} PRIVATE pybind11::windows_extras)
endif()
if(DEFINED ${_Python}_VERSION AND ${_Python}_VERSION VERSION_LESS 3)
target_link_libraries(${target_name} PRIVATE pybind11::python2_no_register)
endif()
set_target_properties(${target_name} PROPERTIES CXX_VISIBILITY_PRESET "hidden"
CUDA_VISIBILITY_PRESET "hidden")
if(ARG_NO_EXTRAS)
return()
endif()
if(NOT DEFINED CMAKE_INTERPROCEDURAL_OPTIMIZATION)
if(ARG_THIN_LTO)
target_link_libraries(${target_name} PRIVATE pybind11::thin_lto)
else()
target_link_libraries(${target_name} PRIVATE pybind11::lto)
endif()
endif()
if(NOT MSVC AND NOT ${CMAKE_BUILD_TYPE} MATCHES Debug|RelWithDebInfo)
# Strip unnecessary sections of the binary on Linux/Mac OS
pybind11_strip(${target_name})
endif()
if(MSVC)
target_link_libraries(${target_name} PRIVATE pybind11::windows_extras)
endif()
endfunction()
function(pybind11_extension name)
set_property(TARGET ${name} PROPERTY PREFIX "")
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set_property(TARGET ${name} PROPERTY SUFFIX ".pyd")
endif()
if(${_Python}_SOABI)
get_property(
suffix
TARGET ${name}
PROPERTY SUFFIX)
if(NOT suffix)
set(suffix "${CMAKE_SHARED_MODULE_SUFFIX}")
endif()
set_property(TARGET ${name} PROPERTY SUFFIX ".${${_Python}_SOABI}${suffix}")
endif()
endfunction()
...@@ -5,6 +5,13 @@ ...@@ -5,6 +5,13 @@
# All rights reserved. Use of this source code is governed by a # All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file. # BSD-style license that can be found in the LICENSE file.
# Built-in in CMake 3.5+
include(CMakeParseArguments)
if(pybind11_FIND_QUIETLY)
set(_pybind11_quiet QUIET)
endif()
# Add a CMake parameter for choosing a desired Python version # Add a CMake parameter for choosing a desired Python version
if(NOT PYBIND11_PYTHON_VERSION) if(NOT PYBIND11_PYTHON_VERSION)
set(PYBIND11_PYTHON_VERSION set(PYBIND11_PYTHON_VERSION
...@@ -18,112 +25,91 @@ set(Python_ADDITIONAL_VERSIONS ...@@ -18,112 +25,91 @@ set(Python_ADDITIONAL_VERSIONS
CACHE INTERNAL "") CACHE INTERNAL "")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} MODULE REQUIRED) find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} MODULE REQUIRED ${_pybind11_quiet})
list(REMOVE_AT CMAKE_MODULE_PATH -1) list(REMOVE_AT CMAKE_MODULE_PATH -1)
include(CheckCXXCompilerFlag) # Cache variables so pybind11_add_module can be used in parent projects
set(PYTHON_INCLUDE_DIRS
${PYTHON_INCLUDE_DIRS}
CACHE INTERNAL "")
set(PYTHON_LIBRARIES
${PYTHON_LIBRARIES}
CACHE INTERNAL "")
set(PYTHON_MODULE_PREFIX
${PYTHON_MODULE_PREFIX}
CACHE INTERNAL "")
set(PYTHON_MODULE_EXTENSION
${PYTHON_MODULE_EXTENSION}
CACHE INTERNAL "")
set(PYTHON_VERSION_MAJOR
${PYTHON_VERSION_MAJOR}
CACHE INTERNAL "")
set(PYTHON_VERSION_MINOR
${PYTHON_VERSION_MINOR}
CACHE INTERNAL "")
set(PYTHON_VERSION
${PYTHON_VERSION}
CACHE INTERNAL "")
set(PYTHON_IS_DEBUG
"${PYTHON_IS_DEBUG}"
CACHE INTERNAL "")
# Warn or error if old variable name used if(PYBIND11_MASTER_PROJECT)
if(PYBIND11_CPP_STANDARD) if(PYTHON_MODULE_EXTENSION MATCHES "pypy")
string(REGEX MATCH [[..$]] VAL "${PYBIND11_CPP_STANDARD}") if(NOT DEFINED PYPY_VERSION)
if(CMAKE_CXX_STANDARD) execute_process(
if(NOT CMAKE_CXX_STANDARD STREQUAL VAL) COMMAND ${PYTHON_EXECUTABLE} -c
message(WARNING "CMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} does not match " [=[import sys; print(".".join(map(str, sys.pypy_version_info[:3])))]=]
"PYBIND11_CPP_STANDARD=${PYBIND11_CPP_STANDARD}, " OUTPUT_VARIABLE pypy_version)
"please remove PYBIND11_CPP_STANDARD from your cache") set(PYPY_VERSION
${pypy_version}
CACHE INTERNAL "")
endif() endif()
message(STATUS "PYPY ${PYPY_VERSION} (Py ${PYTHON_VERSION})")
else() else()
set(supported_standards 11 14 17 20) message(STATUS "PYTHON ${PYTHON_VERSION}")
if("${VAL}" IN_LIST supported_standards)
message(WARNING "USE -DCMAKE_CXX_STANDARD=${VAL} instead of PYBIND11_PYTHON_VERSION")
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()
endif() endif()
# Checks whether the given CXX/linker flags can compile and link a cxx file. cxxflags and # Only add Python for build - must be added during the import for config since it has to be re-discovered.
# linkerflags are lists of flags to use. The result variable is a unique variable name for each set set_property(
# of flags: the compilation result will be cached base on the result variable. If the flags work, TARGET pybind11::pybind11
# sets them in cxxflags_out/linkerflags_out internal cache variables (in addition to ${result}). APPEND
function(_pybind11_return_if_cxx_and_linker_flags_work result cxxflags linkerflags cxxflags_out PROPERTY INTERFACE_INCLUDE_DIRECTORIES $<BUILD_INTERFACE:${PYTHON_INCLUDE_DIRS}>)
linkerflags_out)
set(CMAKE_REQUIRED_LIBRARIES ${linkerflags}) # Python debug libraries expose slightly different objects before 3.8
check_cxx_compiler_flag("${cxxflags}" ${result}) # https://docs.python.org/3.6/c-api/intro.html#debugging-builds
if(${result}) # https://stackoverflow.com/questions/39161202/how-to-work-around-missing-pymodule-create2-in-amd64-win-python35-d-lib
set(${cxxflags_out} if(PYTHON_IS_DEBUG)
"${cxxflags}" set_property(
CACHE INTERNAL "" FORCE) TARGET pybind::pybind11
set(${linkerflags_out} APPEND
"${linkerflags}" PROPERTY INTERFACE_COMPILE_DEFINITIONS Py_DEBUG)
CACHE INTERNAL "" FORCE) endif()
endif()
endfunction()
# Internal: find the appropriate link time optimization flags for this compiler set_property(
function(_pybind11_add_lto_flags target_name prefer_thin_lto) TARGET pybind11::module
if(NOT DEFINED PYBIND11_LTO_CXX_FLAGS) APPEND
set(PYBIND11_LTO_CXX_FLAGS PROPERTY
"" INTERFACE_LINK_LIBRARIES pybind11::python_link_helper
CACHE INTERNAL "") "$<$<OR:$<PLATFORM_ID:Windows>,$<PLATFORM_ID:Cygwin>>:$<BUILD_INTERFACE:${PYTHON_LIBRARIES}>>")
set(PYBIND11_LTO_LINKER_FLAGS
"" if(PYTHON_VERSION VERSION_LESS 3)
CACHE INTERNAL "") set_property(
TARGET pybind11::pybind11
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") APPEND
set(cxx_append "") PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python2_no_register)
set(linker_append "") endif()
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")
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()
if(PYBIND11_LTO_CXX_FLAGS) set_property(
message(STATUS "LTO enabled") TARGET pybind11::embed
else() APPEND
message(STATUS "LTO disabled (not supported by the compiler and/or linker)") PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11 $<BUILD_INTERFACE:${PYTHON_LIBRARIES}>)
endif()
endif()
# Enable LTO flags if found, except for Debug builds function(pybind11_extension name)
if(PYBIND11_LTO_CXX_FLAGS) # The prefix and extension are provided by FindPythonLibsNew.cmake
set(not_debug "$<NOT:$<CONFIG:Debug>>") set_target_properties(${name} PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}"
set(cxx_lang "$<COMPILE_LANGUAGE:CXX>") SUFFIX "${PYTHON_MODULE_EXTENSION}")
target_compile_options(${target_name}
PRIVATE "$<$<AND:${not_debug},${cxx_lang}>:${PYBIND11_LTO_CXX_FLAGS}>")
endif()
if(PYBIND11_LTO_LINKER_FLAGS)
target_link_libraries(${target_name} PRIVATE "$<${not_debug}:${PYBIND11_LTO_LINKER_FLAGS}>")
endif()
endfunction() endfunction()
# Build a Python extension module: # Build a Python extension module:
...@@ -132,7 +118,7 @@ endfunction() ...@@ -132,7 +118,7 @@ endfunction()
# #
function(pybind11_add_module target_name) function(pybind11_add_module target_name)
set(options MODULE SHARED EXCLUDE_FROM_ALL NO_EXTRAS SYSTEM THIN_LTO) set(options MODULE SHARED EXCLUDE_FROM_ALL NO_EXTRAS SYSTEM THIN_LTO)
cmake_parse_arguments(PARSE_ARGV 1 ARG "${options}" "" "") cmake_parse_arguments(ARG "${options}" "" "" ${ARGN})
if(ARG_MODULE AND ARG_SHARED) if(ARG_MODULE AND ARG_SHARED)
message(FATAL_ERROR "Can't be both MODULE and SHARED") message(FATAL_ERROR "Can't be both MODULE and SHARED")
...@@ -159,74 +145,34 @@ function(pybind11_add_module target_name) ...@@ -159,74 +145,34 @@ function(pybind11_add_module target_name)
) )
endif() endif()
# Python debug libraries expose slightly different objects before 3.8 pybind11_extension(${target_name})
# https://docs.python.org/3.6/c-api/intro.html#debugging-builds
# https://stackoverflow.com/questions/39161202/how-to-work-around-missing-pymodule-create2-in-amd64-win-python35-d-lib
if(PYTHON_IS_DEBUG)
target_compile_definitions(${target_name} PRIVATE Py_DEBUG)
endif()
# The prefix and extension are provided by FindPythonLibsNew.cmake
set_target_properties(${target_name} PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}")
set_target_properties(${target_name} PROPERTIES SUFFIX "${PYTHON_MODULE_EXTENSION}")
# -fvisibility=hidden is required to allow multiple modules compiled against # -fvisibility=hidden is required to allow multiple modules compiled against
# different pybind versions to work properly, and for some features (e.g. # different pybind versions to work properly, and for some features (e.g.
# py::module_local). We force it on everything inside the `pybind11` # py::module_local). We force it on everything inside the `pybind11`
# namespace; also turning it on for a pybind module compilation here avoids # namespace; also turning it on for a pybind module compilation here avoids
# potential warnings or issues from having mixed hidden/non-hidden types. # potential warnings or issues from having mixed hidden/non-hidden types.
set_target_properties(${target_name} PROPERTIES CXX_VISIBILITY_PRESET "hidden") set_target_properties(${target_name} PROPERTIES CXX_VISIBILITY_PRESET "hidden"
set_target_properties(${target_name} PROPERTIES CUDA_VISIBILITY_PRESET "hidden") CUDA_VISIBILITY_PRESET "hidden")
if(ARG_NO_EXTRAS) if(ARG_NO_EXTRAS)
return() return()
endif() endif()
if(CMAKE_VERSION VERSION_LESS 3.9 OR PYBIND11_CLASSIC_LTO) if(NOT DEFINED CMAKE_INTERPROCEDURAL_OPTIMIZATION)
_pybind11_add_lto_flags(${target_name} ${ARG_THIN_LTO}) if(ARG_THIN_LTO)
else() target_link_libraries(${target_name} PRIVATE pybind11::thin_lto)
include(CheckIPOSupported)
check_ipo_supported(
RESULT supported
OUTPUT error
LANGUAGES CXX)
if(supported)
set_property(TARGET ${target_name} PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
else() else()
message(WARNING "IPO is not supported: ${output}") target_link_libraries(${target_name} PRIVATE pybind11::lto)
endif() endif()
endif() endif()
if(NOT MSVC AND NOT ${CMAKE_BUILD_TYPE} MATCHES Debug|RelWithDebInfo) if(NOT MSVC AND NOT ${CMAKE_BUILD_TYPE} MATCHES Debug|RelWithDebInfo)
# Strip unnecessary sections of the binary on Linux/Mac OS pybind11_strip(${target_name})
if(CMAKE_STRIP)
if(APPLE)
add_custom_command(
TARGET ${target_name}
POST_BUILD
COMMAND ${CMAKE_STRIP} -x $<TARGET_FILE:${target_name}>)
else()
add_custom_command(
TARGET ${target_name}
POST_BUILD
COMMAND ${CMAKE_STRIP} $<TARGET_FILE:${target_name}>)
endif()
endif()
endif() endif()
if(MSVC) if(MSVC)
# /MP enables multithreaded builds (relevant when there are many files), /bigobj is target_link_libraries(${target_name} PRIVATE pybind11::windows_extras)
# needed for bigger binding projects due to the limit to 64k addressable sections
target_compile_options(${target_name} PRIVATE /bigobj)
if(CMAKE_VERSION VERSION_LESS 3.11)
target_compile_options(${target_name} PRIVATE $<$<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.
target_compile_options(${target_name}
PRIVATE $<$<NOT:$<CONFIG:Debug>>:$<$<COMPILE_LANGUAGE:CXX>:/MP>>)
endif()
endif() endif()
endfunction() endfunction()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment