From bbfef234fa665c99f9d63fecc6d73cd50fdac5f0 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Wed, 5 Aug 2020 23:26:45 -0400 Subject: [PATCH] feat: FindPython support --- .github/workflows/ci.yml | 11 +- .github/workflows/configure.yml | 2 +- CMakeLists.txt | 104 ++----- docs/compiling.rst | 140 ++++++--- tests/CMakeLists.txt | 7 + tests/test_cmake_build/CMakeLists.txt | 28 +- .../installed_function/CMakeLists.txt | 5 + .../installed_target/CMakeLists.txt | 9 +- .../subdirectory_target/CMakeLists.txt | 5 +- tests/test_embed/CMakeLists.txt | 2 +- tools/pybind11Common.cmake | 268 ++++++++++++++++++ tools/pybind11Config.cmake.in | 110 +++---- tools/pybind11NewTools.cmake | 160 +++++++++++ tools/pybind11Tools.cmake | 191 +++++-------- 14 files changed, 735 insertions(+), 307 deletions(-) create mode 100644 tools/pybind11Common.cmake create mode 100644 tools/pybind11NewTools.cmake diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5216e29ca4e..55e1ade9cdd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,10 +30,12 @@ jobs: python: 3.6 arch: x64 max-cxx-std: 17 + args: "-DPYBIND11_NEW_PYTHON=ON" - runs-on: macos-latest python: 3.7 arch: x64 max-cxx-std: 17 + args: "-DPYBIND11_NEW_PYTHON=ON" - runs-on: windows-2016 python: 3.7 arch: x86 @@ -42,6 +44,7 @@ jobs: python: 3.6 arch: x64 max-cxx-std: 17 + args: "-DPYBIND11_NEW_PYTHON=ON" - runs-on: windows-latest python: 3.7 arch: x64 @@ -86,6 +89,10 @@ jobs: python-version: ${{ matrix.python }} architecture: ${{ matrix.arch }} + - name: Update CMake + uses: jwlawson/actions-setup-cmake@v1.3 + + - name: Cache wheels if: startsWith(runner.os, 'macOS') uses: actions/cache@v2 @@ -108,7 +115,7 @@ jobs: -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=11 - -DPYTHON_EXECUTABLE=$(python -c "import sys; print(sys.executable)") + ${{ matrix.args }} - name: Build C++11 run: cmake --build build -j 2 @@ -130,7 +137,7 @@ jobs: -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=${{ matrix.max-cxx-std }} - -DPYTHON_EXECUTABLE=$(python -c "import sys; print(sys.executable)") + ${{ matrix.args }} - name: Build C++${{ matrix.max-cxx-std }} run: cmake --build build2 -j 2 diff --git a/.github/workflows/configure.yml b/.github/workflows/configure.yml index 934b2d73ba0..8ba27b48da4 100644 --- a/.github/workflows/configure.yml +++ b/.github/workflows/configure.yml @@ -26,7 +26,7 @@ jobs: # TODO: 3.8 - runs-on: windows-2016 arch: x86 - cmake: 3.11 + cmake: 3.8 - runs-on: windows-2016 arch: x86 diff --git a/CMakeLists.txt b/CMakeLists.txt index 3571e33e625..fb4f524eefd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,9 @@ cmake_dependent_option( "Install pybind11 headers in Python include directory instead of default installation prefix" OFF "PYBIND11_INSTALL" OFF) +cmake_dependent_option(PYBIND11_NEW_PYTHON "Force new findPython" OFF + "NOT CMAKE_VERSION VERSION_LESS 3.12" OFF) + # NB: when adding a header don't forget to also add it to setup.py set(PYBIND11_HEADERS include/pybind11/detail/class.h @@ -118,102 +121,36 @@ endif() string(REPLACE "include/" "${CMAKE_CURRENT_SOURCE_DIR}/include/" PYBIND11_HEADERS "${PYBIND11_HEADERS}") -# Classic mode - -include("${CMAKE_CURRENT_LIST_DIR}/tools/pybind11Tools.cmake") - # Cache variables so pybind11_add_module can be used in parent projects set(PYBIND11_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/include" CACHE INTERNAL "") -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_IS_DEBUG - "${PYTHON_IS_DEBUG}" - CACHE INTERNAL "") - -if(USE_PYTHON_INCLUDE_DIR) - file(RELATIVE_PATH CMAKE_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX} ${PYTHON_INCLUDE_DIRS}) -endif() # Note: when creating targets, you cannot use if statements at configure time - # you need generator expressions, because those will be placed in the target file. # You can also place ifs *in* the Config.in, but not here. -# Build an interface library target: -add_library(pybind11 INTERFACE) -add_library(pybind11::pybind11 ALIAS pybind11) # to match exported target +# This section builds targets, but does *not* touch Python -target_include_directories( - pybind11 ${pybind11_system} INTERFACE $ - $) -# Only add Python for build - must be added during the import for config since it has to be re-discovered. -target_include_directories(pybind11 SYSTEM INTERFACE $) - -if(CMAKE_VERSION VERSION_LESS 3.13) - target_compile_features(pybind11 INTERFACE cxx_inheriting_constructors cxx_user_literals - cxx_right_angle_brackets) -else() - # This was added in CMake 3.8, but we are keeping a consistent breaking - # point for the config file at 3.13. A config generated by CMake 3.13+ - # can only be read in 3.13+ due to the SHELL usage later, so this is safe to do. - target_compile_features(pybind11 INTERFACE cxx_std_11) -endif() +# Build the headers-only target (no Python included): +add_library(headers INTERFACE) +add_library(pybind11::headers ALIAS headers) # to match exported target -add_library(module INTERFACE) -add_library(pybind11::module ALIAS module) +target_include_directories( + headers ${pybind11_system} INTERFACE $ + $) -target_link_libraries(module INTERFACE pybind11::pybind11) +target_compile_features(headers INTERFACE cxx_inheriting_constructors cxx_user_literals + cxx_right_angle_brackets) -# See https://github.com/Kitware/CMake/blob/master/Modules/CMakePlatformId.h.in for platform IDs -# Note: CMake 3.15 allows $ -target_link_libraries( - module - INTERFACE - "$<$,$>:$>") +include("${CMAKE_CURRENT_SOURCE_DIR}/tools/pybind11Common.cmake") -if(CMAKE_VERSION VERSION_LESS 3.13) - target_link_libraries(module INTERFACE "$<$:-undefined dynamic_lookup>") -else() - # SHELL (3.12+) forces this to remain together, and 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. - target_link_options(module INTERFACE "$<$:SHELL:-undefined dynamic_lookup>") +if(USE_PYTHON_INCLUDE_DIR AND DEFINED Python_INCLUDE_DIRS) + file(RELATIVE_PATH CMAKE_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX} ${Python_INCLUDE_DIRS}) +elseif(USE_PYTHON_INCLUDE_DIR AND DEFINED PYTHON_INCLUDE_DIR) + file(RELATIVE_PATH CMAKE_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX} ${PYTHON_INCLUDE_DIRS}) endif() -# 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+). -set(clang_4plus - "$,$,3.9>>>") -set(no_register "$>") -set(cxx_no_register "$,${no_register}>") -set(msvc "$") -target_compile_options( - pybind11 INTERFACE "$<${cxx_no_register}:-Wno-register;-Wno-deprecated-register>" - "$<${msvc}:/wd5033>") - -add_library(embed INTERFACE) -add_library(pybind11::embed ALIAS embed) -target_link_libraries(embed INTERFACE pybind11::pybind11 $) - if(PYBIND11_INSTALL) install(DIRECTORY ${PYBIND11_INCLUDE_DIR}/pybind11 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) # GNUInstallDirs "DATADIR" wrong here; CMake search path wants "share". @@ -248,14 +185,17 @@ if(PYBIND11_INSTALL) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake - tools/FindPythonLibsNew.cmake tools/pybind11Tools.cmake + tools/FindPythonLibsNew.cmake + tools/pybind11Common.cmake + tools/pybind11Tools.cmake + tools/pybind11NewTools.cmake DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR}) if(NOT PYBIND11_EXPORT_NAME) set(PYBIND11_EXPORT_NAME "${PROJECT_NAME}Targets") endif() - install(TARGETS pybind11 module embed EXPORT "${PYBIND11_EXPORT_NAME}") + install(TARGETS headers EXPORT "${PYBIND11_EXPORT_NAME}") install( EXPORT "${PYBIND11_EXPORT_NAME}" diff --git a/docs/compiling.rst b/docs/compiling.rst index 07f93e7cc5a..77748b043e0 100644 --- a/docs/compiling.rst +++ b/docs/compiling.rst @@ -33,8 +33,8 @@ extension module can be created with just a few lines of code: .. code-block:: cmake - cmake_minimum_required(VERSION 3.7) - project(example) + cmake_minimum_required(VERSION 3.7...3.18) + project(example LANGUAGES CXX) add_subdirectory(pybind11) pybind11_add_module(example example.cpp) @@ -89,7 +89,9 @@ will result in code bloat and is generally not recommended. As stated above, LTO is enabled by default. Some newer compilers also support different flavors of LTO such as `ThinLTO`_. Setting ``THIN_LTO`` will cause the function to prefer this flavor if available. The function falls back to -regular LTO if ``-flto=thin`` is not available. +regular LTO if ``-flto=thin`` is not available. If +``CMAKE_INTERPROCEDURAL_OPTIMIZATION`` is set (either ON or OFF), then that +will be respected instead of the built-in flag search. .. _ThinLTO: http://clang.llvm.org/docs/ThinLTO.html @@ -113,9 +115,9 @@ the ``-D=`` flag. You can also manually set ``CXX_STANDARD`` on a target or use ``target_compile_features`` on your targets - anything that CMake supports. -The target Python version can be selected by setting ``PYBIND11_PYTHON_VERSION`` -or an exact Python installation can be specified with ``PYTHON_EXECUTABLE``. -For example: +Classic Python support: The target Python version can be selected by setting +``PYBIND11_PYTHON_VERSION`` or an exact Python installation can be specified +with ``PYTHON_EXECUTABLE``. For example: .. code-block:: bash @@ -127,6 +129,7 @@ For example: # This often is a good way to get the current Python, works in environments: cmake -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") .. + find_package vs. add_subdirectory --------------------------------- @@ -136,8 +139,8 @@ See the `Config file`_ docstring for details of relevant CMake variables. .. code-block:: cmake - cmake_minimum_required(VERSION 3.7) - project(example) + cmake_minimum_required(VERSION 3.7...3.18) + project(example LANGUAGES CXX) find_package(pybind11 REQUIRED) pybind11_add_module(example example.cpp) @@ -169,52 +172,109 @@ can refer to the same [cmake_example]_ repository for a full sample project .. _Config file: https://github.com/pybind/pybind11/blob/master/tools/pybind11Config.cmake.in -Advanced: interface library target ----------------------------------- +New: FindPython support +----------------------- + +CMake 3.12+ (3.15+ recommended) added a new module called FindPython that had a +highly improved search algorithm and modern targets and tools. If you use +FindPython, pybind11 will detect this and use the existing targets instead: + +.. code-block:: cmake + + cmake_minumum_required(VERSION 3.15...3.18) + project(example LANGUAGES CXX) + + find_package(Python COMPONENTS Interpreter Development REQUIRED) + find_package(pybind11 CONFIG REQUIRED) # or add_subdirectory + + pybind11_add_module(example example.cpp) + +You can also use the targets (as listed below) with FindPython. If you define +``PYBIND11_NEW_PYTHON``, pybind11 will perform the FindPython step for you +(mostly useful when building pybind11's own tests, or as a way to change search +algorithms from the CMake invocation, with ``-DPYBIND11_NEW_PYTHON=ON``. + +.. warning:: + + If you use FindPython2/FindPython3 instead of FindPython, use the + individual targets listed below, and avoid targets that directly include + Python parts. + +There are `many ways to hint or force a discovery +`_), setting +``Python_ROOT_DIR`` may be the most common one (though with virtualenv/venv +support, and Conda support, this tends to find the correct Python version more +often than the old system did). + +Advanced: interface library targets +----------------------------------- + +Pybind11 supports modern CMake usage patterns with a set of interface targets, +available in all modes. The targets provided are: + + ``pybind11::headers`` + Just the pybind11 headers and minimum compile requirements -When using a version of CMake greater than 3.0, pybind11 can additionally -be used as a special *interface library* . The target ``pybind11::module`` -is available with pybind11 headers, Python headers and libraries as needed, -and C++ compile features attached. This target is suitable for linking -to an independently constructed (through ``add_library``, not -``pybind11_add_module``) target in the consuming project. + ``pybind11::python2_no_register`` + Quiets the warning/error when mixing C++14 or higher and Python 2 + + ``pybind11::pybind11`` + Python headers + ``pybind11::headers`` + ``pybind11::python2_no_register`` (Python 2 only) + + ``pybind11::python_link_helper`` + Just the "linking" part of pybind11:module + + ``pybind11::module`` + Everything for extension modules - ``pybind11::pybind11`` + ``Python::Module`` (FindPython CMake 3.15+) or ``pybind11::python_link_helper`` + + ``pybind11::embed`` + Everything for embedding the Python interpreter - ``pybind11::pybind11`` + ``Python::Embed`` (FindPython) or Python libs + + ``pybind11::lto`` / ``pybind11::thin_lto`` + An alternative to `INTERPROCEDURAL_OPTIMIZATION` for adding link-time optimization. + + ``pybind11::windows_extras`` + Bigobj and mp for MSVC. + +Two helper functions are also provided: + + ``pybind11_strip(target)`` + Strips a target (uses ``CMAKE_STRIP`` after the target is built) + + ``pybind11_extension(target)`` + Sets the correct extension (with SOABI) for a target. + +You can use these targets to build complex applications. For example, the +``add_python_module`` function is identical to: .. code-block:: cmake cmake_minimum_required(VERSION 3.7) - project(example) + project(example LANGUAGES CXX) find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11) add_library(example MODULE main.cpp) - target_link_libraries(example PRIVATE pybind11::module) - set_target_properties(example PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}" - SUFFIX "${PYTHON_MODULE_EXTENSION}") -.. warning:: + target_link_libraries(example PRIVATE pybind11::module pybind11::lto pybind11::windows_extras) - Since pybind11 is a metatemplate library, it is crucial that certain - compiler flags are provided to ensure high quality code generation. In - contrast to the ``pybind11_add_module()`` command, the CMake interface - library only provides the *minimal* set of parameters to ensure that the - code using pybind11 compiles, but it does **not** pass these extra compiler - flags (i.e. this is up to you). + pybind11_extension(example) + pybind11_strip(example) - These include Link Time Optimization (``-flto`` on GCC/Clang/ICPC, ``/GL`` - and ``/LTCG`` on Visual Studio) and .OBJ files with many sections on Visual - Studio (``/bigobj``). The :ref:`FAQ ` contains an - explanation on why these are needed. + set_target_properties(example PROPERTIES CXX_VISIBILITY_PRESET "hidden" + CUDA_VISIBILITY_PRESET "hidden") - If you want to add these in yourself, you can use: +Instead of setting properties, you can set ``CMAKE_*`` variables to initialize these correctly. - .. code-block:: cmake - set(CMAKE_CXX_VISIBILITY_PRESET hidden) - set(CMAKE_VISIBILITY_INLINES_HIDDEN ON) - set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) # CMake 3.9+ required +.. warning:: - or set the corresponding property (without the ``CMAKE_``) on the targets - manually. + Since pybind11 is a metatemplate library, it is crucial that certain + compiler flags are provided to ensure high quality code generation. In + contrast to the ``pybind11_add_module()`` command, the CMake interface + provides a *composable* set of targets to ensure that you retain flexibility. + It can be expecially important to provide or set these properties; the + :ref:`FAQ ` contains an explanation on why these are needed. Embedding the Python interpreter -------------------------------- @@ -228,8 +288,8 @@ information about usage in C++, see :doc:`/advanced/embedding`. .. code-block:: cmake - cmake_minimum_required(VERSION 3.7) - project(example) + cmake_minimum_required(VERSION 3.7...3.18) + project(example LANGUAGES CXX) find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f19fa28c195..239841b95d3 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -16,6 +16,13 @@ else() cmake_policy(VERSION 3.18) endif() +# New Python support +if(DEFINED Python_EXECUTABLE) + set(PYTHON_EXECUTABLE "${Python_EXECUTABLE}") + set(PYTHON_VERSION "${Python_VERSION}") +endif() +message(STATUS "Python version for tests: ${PYTHON_VERSION}") + # There's no harm in including a project in a project project(pybind11_tests CXX) diff --git a/tests/test_cmake_build/CMakeLists.txt b/tests/test_cmake_build/CMakeLists.txt index 0be071f2fcf..6ce638adf8a 100644 --- a/tests/test_cmake_build/CMakeLists.txt +++ b/tests/test_cmake_build/CMakeLists.txt @@ -3,10 +3,23 @@ add_custom_target(test_cmake_build) function(pybind11_add_build_test name) cmake_parse_arguments(PARSE_ARGV 1 ARG "INSTALL" "" "") - set(build_options - "-DCMAKE_PREFIX_PATH=${pybind11_BINARY_DIR}/mock_install" - "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" - "-DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE}") + set(build_options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}") + + if(DEFINED PYBIND11_NEW_PYTHON) + list(APPEND build_options "-DPYBIND11_NEW_PYTHON=${PYBIND11_NEW_PYTHON}") + endif() + + if(DEFINED Python_ROOT_DIR) + list(APPEND build_options "-DPython_ROOT_DIR=${Python_ROOT_DIR}") + endif() + + if(DEFINED PYTHON_EXECUTABLE) + list(APPEND build_options "-DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE}") + endif() + + if(DEFINED Python_EXECUTABLE) + list(APPEND build_options "-DPython_EXECUTABLE=${Python_EXECUTABLE}") + endif() if(DEFINED CMAKE_CXX_STANDARD) list(APPEND build_options "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}") @@ -45,7 +58,9 @@ endfunction() pybind11_add_build_test(subdirectory_function) pybind11_add_build_test(subdirectory_target) -if(NOT ${PYTHON_MODULE_EXTENSION} MATCHES "pypy") +if("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy") + message(STATUS "Skipping embed test on PyPy") +else() pybind11_add_build_test(subdirectory_embed) endif() @@ -56,7 +71,8 @@ if(PYBIND11_INSTALL) pybind11_add_build_test(installed_function INSTALL) pybind11_add_build_test(installed_target INSTALL) - if(NOT ${PYTHON_MODULE_EXTENSION} MATCHES "pypy") + if(NOT ("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy" + )) pybind11_add_build_test(installed_embed INSTALL) endif() endif() diff --git a/tests/test_cmake_build/installed_function/CMakeLists.txt b/tests/test_cmake_build/installed_function/CMakeLists.txt index db8213c9830..dc513f2211a 100644 --- a/tests/test_cmake_build/installed_function/CMakeLists.txt +++ b/tests/test_cmake_build/installed_function/CMakeLists.txt @@ -1,4 +1,5 @@ cmake_minimum_required(VERSION 3.7) +project(test_installed_module CXX) # The `cmake_minimum_required(VERSION 3.7...3.18)` syntax does not work with # some versions of VS that have a patched CMake 3.11. This forces us to emulate @@ -18,6 +19,10 @@ message( pybind11_add_module(test_installed_function SHARED NO_EXTRAS ../main.cpp) set_target_properties(test_installed_function PROPERTIES OUTPUT_NAME test_cmake_build) +if(DEFINED Python_EXECUTABLE) + set(PYTHON_EXECUTABLE "${Python_EXECUTABLE}") +endif() + add_custom_target( check_installed_function ${CMAKE_COMMAND} diff --git a/tests/test_cmake_build/installed_target/CMakeLists.txt b/tests/test_cmake_build/installed_target/CMakeLists.txt index 1a124b9c274..a408dcf349a 100644 --- a/tests/test_cmake_build/installed_target/CMakeLists.txt +++ b/tests/test_cmake_build/installed_target/CMakeLists.txt @@ -19,14 +19,17 @@ add_library(test_installed_target MODULE ../main.cpp) target_link_libraries(test_installed_target PRIVATE pybind11::module) set_target_properties(test_installed_target PROPERTIES OUTPUT_NAME test_cmake_build) -# make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib -set_target_properties(test_installed_target PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}" - SUFFIX "${PYTHON_MODULE_EXTENSION}") +# Make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib +pybind11_extension(test_installed_target) # Do not treat includes from IMPORTED target as SYSTEM (Python headers in pybind11::module). # This may be needed to resolve header conflicts, e.g. between Python release and debug headers. set_target_properties(test_installed_target PROPERTIES NO_SYSTEM_FROM_IMPORTED ON) +if(DEFINED Python_EXECUTABLE) + set(PYTHON_EXECUTABLE "${Python_EXECUTABLE}") +endif() + add_custom_target( check_installed_target ${CMAKE_COMMAND} diff --git a/tests/test_cmake_build/subdirectory_target/CMakeLists.txt b/tests/test_cmake_build/subdirectory_target/CMakeLists.txt index 4f2312ee649..051a3d308ed 100644 --- a/tests/test_cmake_build/subdirectory_target/CMakeLists.txt +++ b/tests/test_cmake_build/subdirectory_target/CMakeLists.txt @@ -18,9 +18,8 @@ set_target_properties(test_subdirectory_target PROPERTIES OUTPUT_NAME test_cmake target_link_libraries(test_subdirectory_target PRIVATE pybind11::module) -# make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib -set_target_properties(test_subdirectory_target PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}" - SUFFIX "${PYTHON_MODULE_EXTENSION}") +# Make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib +pybind11_extension(test_subdirectory_target) add_custom_target( check_subdirectory_target diff --git a/tests/test_embed/CMakeLists.txt b/tests/test_embed/CMakeLists.txt index 25972701fc9..78c19132d0e 100644 --- a/tests/test_embed/CMakeLists.txt +++ b/tests/test_embed/CMakeLists.txt @@ -1,4 +1,4 @@ -if(${PYTHON_MODULE_EXTENSION} MATCHES "pypy") +if("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy") add_custom_target(cpptest) # Dummy target on PyPy. Embedding is not supported. set(_suppress_unused_variable_warning "${DOWNLOAD_CATCH}") return() diff --git a/tools/pybind11Common.cmake b/tools/pybind11Common.cmake new file mode 100644 index 00000000000..a5b7abc7303 --- /dev/null +++ b/tools/pybind11Common.cmake @@ -0,0 +1,268 @@ +#[======================================================[.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 + "$,$,3.9>>>") +set(no_register "$>") + +if(MSVC AND CMAKE_VERSION VERSION_LESS 3.11) + set(cxx_no_register "${no_register}") +else() + set(cxx_no_register "$,${no_register}>") +endif() + +set(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 "$<$:-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 "$<$: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 $<$>:/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 $<$>:$<$:/MP>>) + endif() +endif() +# --------------------- Python specifics ------------------------- + +# Check to see which Python mode we are in, new or old python +if(PYBIND11_NEW_PYTHON + OR Python_FOUND + OR Python3_FOUND + OR Python2_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 ";$<$:-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 "$>") + set(cxx_lang "$") + if(MSVC AND CMAKE_VERSION VERSION_LESS 3.11) + set(genex "${not_debug}") + else() + set(genex "$") + endif() + set_property( + TARGET ${target} + APPEND + PROPERTY INTERFACE_COMPILE_OPTIONS "$<${genex}:${PYBIND11_LTO_CXX_FLAGS}>") + if(NOT is_config) + message(STATUS "${target} enabled") + endif() + else() + if(NOT is_config) + 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} $) + endif() +endfunction() diff --git a/tools/pybind11Config.cmake.in b/tools/pybind11Config.cmake.in index c86e0dea250..94bd4fbf62a 100644 --- a/tools/pybind11Config.cmake.in +++ b/tools/pybind11Config.cmake.in @@ -28,6 +28,47 @@ interface library targets:: Python headers, libraries (as needed by platform), and the C++ standard 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_NEW_PYTHON`` 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:: Set PythonLibsNew variables to influence python detection and @@ -38,11 +79,11 @@ CMAKE_CXX_STANDARD to influence standard setting. :: # Create an extension module 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 add_executable(myexe main.cpp) - target_link_libraries(myexe pybind11::embed) + target_link_libraries(myexe PUBLIC pybind11::embed) Suggested usage:: @@ -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 CMAKE_DISABLE_FIND_PACKAGE_pybind11 - CMake variable, disables 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@ # Location of pybind11/pybind11.h @@ -72,50 +122,12 @@ set(pybind11_VERSION_TYPE "@pybind11_VERSION_TYPE@") check_required_components(pybind11) -include("${CMAKE_CURRENT_LIST_DIR}/pybind11Tools.cmake") - -#----------------------------------------------------------------------------- -# Don't include targets if this file is being picked up by another -# project which has already built this as a subproject -#----------------------------------------------------------------------------- -if(NOT TARGET pybind11::pybind11) - 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 - "$<$,$>:$>" - ) - - get_property( - _iid - TARGET pybind11::pybind11 - PROPERTY INTERFACE_INCLUDE_DIRECTORIES) - get_property( - _ill - TARGET pybind11::module - PROPERTY INTERFACE_LINK_LIBRARIES) - set(pybind11_INCLUDE_DIRS ${_iid}) - set(pybind11_LIBRARIES ${_ico} ${_ill}) - - 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 + return() endif() + +include("${CMAKE_CURRENT_LIST_DIR}/pybind11Targets.cmake") + +include("${CMAKE_CURRENT_LIST_DIR}/pybind11Common.cmake") diff --git a/tools/pybind11NewTools.cmake b/tools/pybind11NewTools.cmake new file mode 100644 index 00000000000..4845f1044e5 --- /dev/null +++ b/tools/pybind11NewTools.cmake @@ -0,0 +1,160 @@ +# tools/pybind11NewTools.cmake -- Build system for the pybind11 modules +# +# Copyright (c) 2020 Wenzel Jakob 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(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 + OR Python2_FOUND + OR Python3_FOUND) + + if(NOT DEFINED Python_FIND_IMPLEMENTATIONS) + set(Python_FIND_IMPLEMENTATIONS CPython PyPy) + endif() + + if(NOT DEFINED Python_ROOT_DIR AND DEFINED ENV{pythonLocation}) + set(Python_ROOT_DIR "$ENV{pythonLocation}") + endif() + + find_package(Python COMPONENTS Interpreter Development) + + # 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() + +# 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 $) +endif() + +if(DEFINED Python2_VERSION OR (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 (also Python2 and Python3, for which we do nothing) +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 2 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(COMMAND Python_add_library) + python_add_library(${target_name} ${type} WITH_SOABI ${ARG_UNPARSED_ARGUMENTS}) + elseif(COMMAND Python3_add_library) + python3_add_library(${target_name} ${type} WITH_SOABI ${ARG_UNPARSED_ARGUMENTS}) + elseif(COMMAND Python2_add_library) + python2_add_library(${target_name} ${type} WITH_SOABI ${ARG_UNPARSED_ARGUMENTS}) + 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 Python2_VERSION + OR Python_VERSION + AND Python_VERSION VERSION_LESS 3) + target_link_libraries(${target_name} PRIVATE pybind11::python2_no_register) + endif() + + # Currently Debug Python interps not supported for Python < 3.8 + + 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() diff --git a/tools/pybind11Tools.cmake b/tools/pybind11Tools.cmake index 703c08d02bd..3fb9865fd09 100644 --- a/tools/pybind11Tools.cmake +++ b/tools/pybind11Tools.cmake @@ -17,12 +17,19 @@ set(Python_ADDITIONAL_VERSIONS "3.9;3.8;3.7;3.6;3.5;3.4" CACHE INTERNAL "") +# Support for GitHub Actions-like activations +if(NOT DEFINED PYTHON_EXECUTABLE AND DEFINED ENV{pythonLocation}) + if(EXISTS "$ENV{pythonLocation}/bin/python") + set(PYTHON_EXECUTABLE "$ENV{pythonLocation}/bin/python") + elseif(EXISTS "$ENV{pythonLocation}/python") + set(PYTHON_EXECUTABLE "$ENV{pythonLocation}/python") + endif() +endif() + list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} MODULE REQUIRED) list(REMOVE_AT CMAKE_MODULE_PATH -1) -include(CheckCXXCompilerFlag) - # Warn or error if old variable name used if(PYBIND11_CPP_STANDARD) string(REGEX MATCH [[..$]] VAL "${PYBIND11_CPP_STANDARD}") @@ -46,84 +53,61 @@ if(PYBIND11_CPP_STANDARD) endif() endif() -# 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}" - CACHE INTERNAL "" FORCE) - set(${linkerflags_out} - "${linkerflags}" - CACHE INTERNAL "" FORCE) - endif() -endfunction() +# 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 "") -# Internal: find the appropriate link time optimization flags for this compiler -function(_pybind11_add_lto_flags target_name prefer_thin_lto) - if(NOT DEFINED PYBIND11_LTO_CXX_FLAGS) - set(PYBIND11_LTO_CXX_FLAGS - "" - CACHE INTERNAL "") - set(PYBIND11_LTO_LINKER_FLAGS - "" - CACHE INTERNAL "") - - 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 ";$<$:-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() +# Only add Python for build - must be added during the import for config since it has to be re-discovered. +set_property( + TARGET pybind11::pybind11 + APPEND + PROPERTY INTERFACE_INCLUDE_DIRECTORIES $) + +set_property( + TARGET pybind11::module + APPEND + PROPERTY + INTERFACE_LINK_LIBRARIES pybind11::python_link_helper + "$<$,$>:$>") + +if(PYTHON_VERSION VERSION_LESS 3) + set_property( + TARGET pybind11::pybind11 + APPEND + PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python2_no_register) +endif() - if(PYBIND11_LTO_CXX_FLAGS) - message(STATUS "LTO enabled") - else() - message(STATUS "LTO disabled (not supported by the compiler and/or linker)") - endif() - endif() +set_property( + TARGET pybind11::embed + APPEND + PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11 $) - # Enable LTO flags if found, except for Debug builds - if(PYBIND11_LTO_CXX_FLAGS) - set(not_debug "$>") - set(cxx_lang "$") - target_compile_options(${target_name} - PRIVATE "$<$:${PYBIND11_LTO_CXX_FLAGS}>") - endif() - if(PYBIND11_LTO_LINKER_FLAGS) - target_link_libraries(${target_name} PRIVATE "$<${not_debug}:${PYBIND11_LTO_LINKER_FLAGS}>") - endif() +function(pybind11_extension name) + # The prefix and extension are provided by FindPythonLibsNew.cmake + set_target_properties(${name} PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}" + SUFFIX "${PYTHON_MODULE_EXTENSION}") endfunction() # Build a Python extension module: @@ -166,67 +150,34 @@ function(pybind11_add_module target_name) 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}") + pybind11_extension(${target_name}) # -fvisibility=hidden is required to allow multiple modules compiled against # different pybind versions to work properly, and for some features (e.g. # py::module_local). We force it on everything inside the `pybind11` # namespace; also turning it on for a pybind module compilation here avoids # 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 CUDA_VISIBILITY_PRESET "hidden") + set_target_properties(${target_name} PROPERTIES CXX_VISIBILITY_PRESET "hidden" + CUDA_VISIBILITY_PRESET "hidden") if(ARG_NO_EXTRAS) return() endif() - if(CMAKE_VERSION VERSION_LESS 3.9 OR PYBIND11_CLASSIC_LTO) - _pybind11_add_lto_flags(${target_name} ${ARG_THIN_LTO}) - else() - include(CheckIPOSupported) - check_ipo_supported( - RESULT supported - OUTPUT error - LANGUAGES CXX) - if(supported) - set_property(TARGET ${target_name} PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) + if(NOT DEFINED CMAKE_INTERPROCEDURAL_OPTIMIZATION) + if(ARG_THIN_LTO) + target_link_libraries(${target_name} PRIVATE pybind11::thin_lto) else() - message(WARNING "IPO is not supported: ${output}") + 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 - if(CMAKE_STRIP) - if(APPLE) - add_custom_command( - TARGET ${target_name} - POST_BUILD - COMMAND ${CMAKE_STRIP} -x $) - else() - add_custom_command( - TARGET ${target_name} - POST_BUILD - COMMAND ${CMAKE_STRIP} $) - endif() - endif() + pybind11_strip(${target_name}) endif() 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 - target_compile_options(${target_name} PRIVATE /bigobj) - if(CMAKE_VERSION VERSION_LESS 3.11) - target_compile_options(${target_name} PRIVATE $<$>:/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 $<$>:$<$:/MP>>) - endif() + target_link_libraries(${target_name} PRIVATE pybind11::windows_extras) endif() + endfunction()