From 1729aae96fe5da9b978fa6f448c6bb8f56da6b94 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Wed, 19 Aug 2020 12:26:26 -0400 Subject: [PATCH] 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 --- .github/workflows/ci.yml | 24 +- .github/workflows/configure.yml | 25 +- .gitignore | 2 +- CMakeLists.txt | 151 ++++----- docs/advanced/embedding.rst | 2 +- docs/changelog.rst | 33 ++ docs/compiling.rst | 159 +++++++--- docs/requirements.txt | 4 +- docs/upgrade.rst | 47 +++ tests/CMakeLists.txt | 44 ++- tests/test_cmake_build/CMakeLists.txt | 29 +- .../installed_embed/CMakeLists.txt | 4 +- .../installed_function/CMakeLists.txt | 15 +- .../installed_target/CMakeLists.txt | 19 +- .../subdirectory_embed/CMakeLists.txt | 4 +- .../subdirectory_function/CMakeLists.txt | 16 +- .../subdirectory_target/CMakeLists.txt | 19 +- tests/test_embed/CMakeLists.txt | 11 +- tools/FindCatch.cmake | 3 + tools/FindPythonLibsNew.cmake | 43 ++- tools/pybind11Common.cmake | 296 ++++++++++++++++++ tools/pybind11Config.cmake.in | 117 ++++--- tools/pybind11NewTools.cmake | 203 ++++++++++++ tools/pybind11Tools.cmake | 238 ++++++-------- 24 files changed, 1115 insertions(+), 393 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 30829631d5..4f9ebac9f7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,11 +31,13 @@ jobs: arch: x64 max-cxx-std: 17 dev: false + args: "-DPYBIND11_FINDPYTHON=ON" - runs-on: macos-latest python: 3.7 arch: x64 max-cxx-std: 17 dev: false + args: "-DPYBIND11_FINDPYTHON=ON" - runs-on: windows-2016 python: 3.7 arch: x86 @@ -46,6 +48,7 @@ jobs: arch: x64 max-cxx-std: 17 dev: false + args: "-DPYBIND11_FINDPYTHON=ON" - runs-on: windows-latest python: 3.7 arch: x64 @@ -89,7 +92,7 @@ jobs: dev: false - name: "🐍 ${{ matrix.python }} • ${{ matrix.runs-on }} • ${{ matrix.arch }}" + name: "🐍 ${{ matrix.python }} • ${{ matrix.runs-on }} • ${{ matrix.arch }} ${{ matrix.args }}" runs-on: ${{ matrix.runs-on }} continue-on-error: ${{ matrix.dev }} @@ -106,6 +109,9 @@ jobs: if: runner.os != 'macOS' run: echo "::set-env name=BOOST_ROOT::$BOOST_ROOT_1_72_0" + - name: Update CMake + uses: jwlawson/actions-setup-cmake@v1.3 + - name: Cache wheels if: runner.os == 'macOS' uses: actions/cache@v2 @@ -120,7 +126,7 @@ jobs: - name: Prepare env run: python -m pip install -r tests/requirements.txt - - name: Configure C++11 + - name: Configure C++11 ${{ matrix.args }} shell: bash run: > cmake -S . -B build @@ -128,7 +134,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 @@ -140,9 +146,9 @@ jobs: run: cmake --build build --target cpptest -j 2 - name: Interface test C++11 - run: cmake --build build --target test_cmake_build + run: cmake --build build --target test_cmake_build -v - - name: Configure C++${{ matrix.max-cxx-std }} + - name: Configure C++${{ matrix.max-cxx-std }} ${{ matrix.args }} shell: bash run: > cmake -S . -B build2 @@ -150,7 +156,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 @@ -350,14 +356,14 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Install requirements + - name: Install system requirements run: apk add doxygen python3-dev - name: Ensure pip run: python3 -m ensurepip - - name: Install python docs requirements - run: python3 -m pip install "sphinx<3" sphinx_rtd_theme breathe==4.13.1 pytest setuptools + - name: Install docs & setup requirements + run: python3 -m pip install -r docs/requirements.txt pytest setuptools - name: Build docs run: python3 -m sphinx -W -b html docs docs/.build diff --git a/.github/workflows/configure.yml b/.github/workflows/configure.yml index 934b2d73ba..d472f4b191 100644 --- a/.github/workflows/configure.yml +++ b/.github/workflows/configure.yml @@ -14,19 +14,22 @@ jobs: strategy: fail-fast: false matrix: - runs-on: [ubuntu-latest, macos-latest] + runs-on: [ubuntu-latest, macos-latest, windows-latest] arch: [x64] - cmake: [3.7, 3.18] + cmake: [3.18] include: - - runs-on: windows-latest + - runs-on: ubuntu-latest arch: x64 - cmake: 3.18 + cmake: 3.4 + + - runs-on: macos-latest + arch: x64 + cmake: 3.7 - # TODO: 3.8 - runs-on: windows-2016 arch: x86 - cmake: 3.11 + cmake: 3.8 - runs-on: windows-2016 arch: x86 @@ -63,3 +66,13 @@ jobs: -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DPYTHON_EXECUTABLE=$(python -c "import sys; print(sys.executable)") + + - name: Build + working-directory: build dir + if: github.event_name == 'workflow_dispatch' + run: cmake --build . --config Release + + - name: Test + working-directory: build dir + if: github.event_name == 'workflow_dispatch' + run: cmake --build . --config Release --target check diff --git a/.gitignore b/.gitignore index 54a1f92601..6d65838b50 100644 --- a/.gitignore +++ b/.gitignore @@ -32,7 +32,7 @@ MANIFEST .*.swp .DS_Store /dist -/build +/build* .cache/ sosize-*.txt pybind11Config*.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index f38a8f89b4..427975258a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,9 +5,9 @@ # All rights reserved. Use of this source code is governed by a # BSD-style license that can be found in the LICENSE file. -cmake_minimum_required(VERSION 3.7) +cmake_minimum_required(VERSION 3.4) -# The `cmake_minimum_required(VERSION 3.7...3.18)` syntax does not work with +# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with # some versions of VS that have a patched CMake 3.11. This forces us to emulate # the behavior using the following workaround: if(${CMAKE_VERSION} VERSION_LESS 3.18) @@ -41,11 +41,22 @@ include(GNUInstallDirs) include(CMakePackageConfigHelpers) include(CMakeDependentOption) -message(STATUS "pybind11 v${pybind11_VERSION} ${pybind11_VERSION_TYPE}") +if(NOT pybind11_FIND_QUIETLY) + message(STATUS "pybind11 v${pybind11_VERSION} ${pybind11_VERSION_TYPE}") +endif() # Check if pybind11 is being used directly or via add_subdirectory if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) set(PYBIND11_MASTER_PROJECT ON) + + if(OSX AND CMAKE_VERSION VERSION_LESS 3.7) + # Bug in macOS CMake < 3.7 is unable to download catch + message(WARNING "CMAKE 3.7+ needed on macOS to download catch, and newer HIGHLY recommended") + elseif(WINDOWS AND CMAKE_VERSION VERSION_LESS 3.8) + # Only tested with 3.8+ in CI. + message(WARNING "CMAKE 3.8+ tested on Windows, previous versions untested") + endif() + message(STATUS "CMake ${CMAKE_VERSION}") if(CMAKE_CXX_STANDARD) @@ -60,13 +71,16 @@ endif() # Options option(PYBIND11_INSTALL "Install pybind11 header files?" ${PYBIND11_MASTER_PROJECT}) option(PYBIND11_TEST "Build pybind11 test suite?" ${PYBIND11_MASTER_PROJECT}) -option(PYBIND11_CLASSIC_LTO "Use the classic LTO flag algorithm, even on CMake 3.9+" OFF) +option(PYBIND11_NOPYTHON "Disable search for Python" OFF) cmake_dependent_option( USE_PYTHON_INCLUDE_DIR "Install pybind11 headers in Python include directory instead of default installation prefix" OFF "PYBIND11_INSTALL" OFF) +cmake_dependent_option(PYBIND11_FINDPYTHON "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,101 +132,41 @@ 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 - -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() +# This section builds targets, but does *not* touch Python -add_library(module INTERFACE) -add_library(pybind11::module ALIAS module) +# Build the headers-only target (no Python included): +add_library(headers INTERFACE) +add_library(pybind11::headers ALIAS headers) # to match exported target -target_link_libraries(module INTERFACE pybind11::pybind11) +include("${CMAKE_CURRENT_SOURCE_DIR}/tools/pybind11Common.cmake") -# 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 - "$<$,$>:$>") +if(NOT PYBIND11_MASTER_PROJECT AND NOT pybind11_FIND_QUIETLY) + message(STATUS "Using pybind11: (version \"${pybind11_VERSION}\" ${pybind11_VERSION_TYPE})") +endif() -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>") +# Relative directory setting +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 $) +# Fill in headers target +target_include_directories( + headers ${pybind11_system} INTERFACE $ + $) + +target_compile_features(headers INTERFACE cxx_inheriting_constructors cxx_user_literals + cxx_right_angle_brackets) if(PYBIND11_INSTALL) install(DIRECTORY ${PYBIND11_INCLUDE_DIR}/pybind11 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) @@ -248,14 +202,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}" @@ -275,10 +232,28 @@ endif() # BUILD_TESTING takes priority, but only if this is the master project if(PYBIND11_MASTER_PROJECT AND DEFINED BUILD_TESTING) if(BUILD_TESTING) - add_subdirectory(tests) + if(_pybind11_nopython) + message(FATAL_ERROR "Cannot activate tests in NOPYTHON mode") + else() + add_subdirectory(tests) + endif() endif() else() if(PYBIND11_TEST) - add_subdirectory(tests) + if(_pybind11_nopython) + message(FATAL_ERROR "Cannot activate tests in NOPYTHON mode") + else() + add_subdirectory(tests) + endif() endif() endif() + +# Better symmetry with find_package(pybind11 CONFIG) mode. +if(NOT PYBIND11_MASTER_PROJECT) + set(pybind11_FOUND + TRUE + CACHE INTERNAL "true if pybind11 and all required components found on the system") + set(pybind11_INCLUDE_DIR + "${PYBIND11_INCLUDE_DIR}" + CACHE INTERNAL "Directory where pybind11 headers are located") +endif() diff --git a/docs/advanced/embedding.rst b/docs/advanced/embedding.rst index 3930316032..98a5c52190 100644 --- a/docs/advanced/embedding.rst +++ b/docs/advanced/embedding.rst @@ -18,7 +18,7 @@ information, see :doc:`/compiling`. .. code-block:: cmake - cmake_minimum_required(VERSION 3.0) + cmake_minimum_required(VERSION 3.4) project(example) find_package(pybind11 REQUIRED) # or `add_subdirectory(pybind11)` diff --git a/docs/changelog.rst b/docs/changelog.rst index 2def2b0719..fbb3667f27 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -6,6 +6,39 @@ Changelog Starting with version 1.8.0, pybind11 releases use a `semantic versioning `_ policy. +v2.6.0 (IN PROGRESS) +-------------------- + +See :ref:`upgrade-guide-2.6` for help upgrading to the new version. + +* Minimum CMake required increased to 3.4. + `#2338 `_ and + `#2370 `_ + + * Full integration with CMake’s C++ standard system replaces + ``PYBIND11_CPP_STANDARD``. + + * Generated config file is now portable to different Python/compiler/CMake + versions. + + * Virtual environments prioritized if ``PYTHON_EXECUTABLE`` is not set + (``venv``, ``virtualenv``, and ``conda``) (similar to the new FindPython + mode). + + * Other CMake features now natively supported, like + ``CMAKE_INTERPROCEDURAL_OPTIMIZATION``, ``set(CMAKE_CXX_VISIBILITY_PRESET + hidden)``. + +* Optional :ref:`find-python-mode` and :ref:`nopython-mode` with CMake. + `#2370 `_ + +* Uninstall target added. + `#2265 `_ and + `#2346 `_ + + + + v2.5.0 (Mar 31, 2020) ----------------------------------------------------- diff --git a/docs/compiling.rst b/docs/compiling.rst index 3935dda134..72b0c1eecf 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.4...3.18) + project(example LANGUAGES CXX) add_subdirectory(pybind11) pybind11_add_module(example example.cpp) @@ -50,6 +50,9 @@ PyPI integration, can be found in the [cmake_example]_ repository. .. [cmake_example] https://github.com/pybind/cmake_example +.. versionchanged:: 2.6 + CMake 3.4+ is required. + pybind11_add_module ------------------- @@ -89,7 +92,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 +118,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 +132,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 +142,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.4...3.18) + project(example LANGUAGES CXX) find_package(pybind11 REQUIRED) pybind11_add_module(example example.cpp) @@ -169,52 +175,131 @@ 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 ----------------------------------- -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. +.. _find-python-mode: + +FindPython mode +--------------- + +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_minimum_required(VERSION 3.7) - project(example) + 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) + + pybind11_add_module(example example.cpp) + +You can also use the targets (as listed below) with FindPython. If you define +``PYBIND11_FINDPYTHON``, 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_FINDPYTHON=ON``. + +.. warning:: + + If you use FindPython2 and FindPython3 to dual-target Python, use the + individual targets listed below, and avoid targets that directly include + Python parts. + +There are `many ways to hint or force a discovery of a specific Python +installation `_), +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). + +.. versionadded:: 2.6 + +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 + + ``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.4) + 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}") + + target_link_libraries(example PRIVATE pybind11::module pybind11::lto pybind11::windows_extras) + + pybind11_extension(example) + pybind11_strip(example) + + set_target_properties(example PROPERTIES CXX_VISIBILITY_PRESET "hidden" + CUDA_VISIBILITY_PRESET "hidden") + +Instead of setting properties, you can set ``CMAKE_*`` variables to initialize these correctly. .. warning:: 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). + 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. - 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. +.. versionadded:: 2.6 - If you want to add these in yourself, you can use: +.. _nopython-mode: - .. code-block:: cmake +Advanced: NOPYTHON mode +----------------------- - set(CMAKE_CXX_VISIBILITY_PRESET hidden) - set(CMAKE_VISIBILITY_INLINES_HIDDEN ON) - set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) # CMake 3.9+ required +If you want complete control, you can set ``PYBIND11_NOPYTHON`` to completely +disable Python integration (this also happens if you run ``FindPython2`` and +``FindPython3`` without running ``FindPython``). This gives you complete +freedom to integrate into an existing system (like `Scikit-Build's +`_ ``PythonExtensions``). +``pybind11_add_module`` and ``pybind11_extension`` will be unavailable, and the +targets will be missing any Python specific behavior. - or set the corresponding property (without the ``CMAKE_``) on the targets - manually. +.. versionadded:: 2.6 Embedding the Python interpreter -------------------------------- @@ -228,8 +313,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.4...3.18) + project(example LANGUAGES CXX) find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11) diff --git a/docs/requirements.txt b/docs/requirements.txt index 3818fe80ee..2eb7f2020a 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1 +1,3 @@ -breathe == 4.5.0 +breathe==4.13.1 +sphinx<3 +sphinx_rtd_theme diff --git a/docs/upgrade.rst b/docs/upgrade.rst index 3f5697391b..98285eb6e8 100644 --- a/docs/upgrade.rst +++ b/docs/upgrade.rst @@ -8,6 +8,53 @@ to a new version. But it goes into more detail. This includes things like deprecated APIs and their replacements, build system changes, general code modernization and other useful information. +.. _upgrade-guide-2.6: + +v2.6 +==== + +CMake support: +-------------- + +The minimum required version of CMake is now 3.4. Several details of the CMake +support have been deprecated; warnings will be shown if you need to change +something. The changes are: + +* ``PYBIND11_CPP_STANDARD=`` is deprecated, please use + ``CMAKE_CXX_STANDARD=`` instead, or any other valid CMake CXX or CUDA + standard selection method, like ``target_compile_features``. + +* If you do not request a standard, PyBind11 targets will compile with the + compiler default, but not less than C++11, instead of forcing C++14 always. + If you depend on the old behavior, please use ``set(CMAKE_CXX_STANDARD 14)`` + instead. + +* Direct ``pybind11::module`` usage should always be accompanied by at least + ``set(CMAKE_CXX_VISIBILITY_PRESET hidden)`` or similar - it used to try to + manually force this compiler flag (but not correctly on all compilers or with + CUDA). + +* ``pybind11_add_module``'s ``SYSTEM`` argument is deprecated and does nothing; + linking now behaves like other imported libraries consistently in both + config and submodule mode, and behaves like a ``SYSTEM`` library by + default. + +* If ``PYTHON_EXECUTABLE`` is not set, virtual environments (``venv``, + ``virtualenv``, and ``conda``) are prioritized over the standard search + (similar to the new FindPython mode). + +In addition, the following changes may be of interest: + +* ``CMAKE_INTERPROCEDURAL_OPTIMIZATION`` will be respected by + ``pybind11_add_module`` if set instead of linking to ``pybind11::lto`` or + ``pybind11::thin_lto``. + +* Using ``find_package(Python COMPONENTS Interpreter Development)`` before + pybind11 will cause pybind11 to use the new Python mechanisms instead of its + own custom search, based on a patched version of classic + FindPythonInterp/FindPythonLibs. In the future, this may become the default. + + v2.2 ==== diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9a97ec5bdc..895cfe75eb 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,9 +5,9 @@ # All rights reserved. Use of this source code is governed by a # BSD-style license that can be found in the LICENSE file. -cmake_minimum_required(VERSION 3.7) +cmake_minimum_required(VERSION 3.4) -# The `cmake_minimum_required(VERSION 3.7...3.18)` syntax does not work with +# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with # some versions of VS that have a patched CMake 3.11. This forces us to emulate # the behavior using the following workaround: if(${CMAKE_VERSION} VERSION_LESS 3.18) @@ -16,6 +16,12 @@ 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() + # There's no harm in including a project in a project project(pybind11_tests CXX) @@ -137,13 +143,9 @@ if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1) set(EIGEN3_INCLUDE_DIR ${eigen_SOURCE_DIR}) set(EIGEN3_FOUND TRUE) + else() find_package(Eigen3 3.2.7 QUIET CONFIG) - if(EIGEN3_FOUND) - if(EIGEN3_VERSION_STRING AND NOT EIGEN3_VERSION_STRING VERSION_LESS 3.3.1) - set(PYBIND11_EIGEN_VIA_TARGET TRUE) - endif() - endif() if(NOT EIGEN3_FOUND) # Couldn't load via target, so fall back to allowing module mode finding, which will pick up @@ -153,6 +155,12 @@ if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1) endif() if(EIGEN3_FOUND) + if(NOT TARGET Eigen3::Eigen) + add_library(Eigen3::Eigen IMPORTED INTERFACE) + set_property(TARGET Eigen3::Eigen PROPERTY INTERFACE_INCLUDE_DIRECTORIES + "${EIGEN3_INCLUDE_DIR}") + endif() + # Eigen 3.3.1+ cmake sets EIGEN3_VERSION_STRING (and hard codes the version when installed # rather than looking it up in the cmake script); older versions, and the # tools/FindEigen3.cmake, set EIGEN3_VERSION instead. @@ -169,6 +177,20 @@ endif() # Optional dependency for some tests (boost::variant is only supported with version >= 1.56) find_package(Boost 1.56) +if(Boost_FOUND) + if(NOT TARGET Boost::headers) + if(TARGET Boost::boost) + # Classic FindBoost + add_library(Boost::headers ALIAS Boost::boost) + else() + # Very old FindBoost, or newer Boost than CMake in older CMakes + add_library(Boost::headers IMPORTED INTERFACE) + set_property(TARGET Boost::headers PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${Boost_INCLUDE_DIRS}) + endif() + endif() +endif() + # Compile with compiler warnings turned on function(pybind11_enable_warnings target_name) if(MSVC) @@ -233,16 +255,12 @@ foreach(target ${test_targets}) endif() if(EIGEN3_FOUND) - if(PYBIND11_EIGEN_VIA_TARGET) - target_link_libraries(${target} PRIVATE Eigen3::Eigen) - else() - target_include_directories(${target} SYSTEM PRIVATE ${EIGEN3_INCLUDE_DIR}) - endif() + target_link_libraries(${target} PRIVATE Eigen3::Eigen) target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_EIGEN) endif() if(Boost_FOUND) - target_include_directories(${target} SYSTEM PRIVATE ${Boost_INCLUDE_DIRS}) + target_link_libraries(${target} PRIVATE Boost::headers) target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_BOOST) endif() diff --git a/tests/test_cmake_build/CMakeLists.txt b/tests/test_cmake_build/CMakeLists.txt index 0be071f2fc..0c0578ad3d 100644 --- a/tests/test_cmake_build/CMakeLists.txt +++ b/tests/test_cmake_build/CMakeLists.txt @@ -1,12 +1,24 @@ +# Built-in in CMake 3.5+ +include(CMakeParseArguments) + add_custom_target(test_cmake_build) function(pybind11_add_build_test name) - cmake_parse_arguments(PARSE_ARGV 1 ARG "INSTALL" "" "") + cmake_parse_arguments(ARG "INSTALL" "" "" ${ARGN}) + + set(build_options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}") + + if(PYBIND11_FINDPYTHON) + list(APPEND build_options "-DPYBIND11_FINDPYTHON=${PYBIND11_FINDPYTHON}") - set(build_options - "-DCMAKE_PREFIX_PATH=${pybind11_BINARY_DIR}/mock_install" - "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" - "-DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE}") + if(DEFINED Python_ROOT_DIR) + list(APPEND build_options "-DPython_ROOT_DIR=${Python_ROOT_DIR}") + endif() + + list(APPEND build_options "-DPython_EXECUTABLE=${Python_EXECUTABLE}") + else() + 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 +57,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 +70,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_embed/CMakeLists.txt b/tests/test_cmake_build/installed_embed/CMakeLists.txt index 6b773c7c55..64ae5c4bff 100644 --- a/tests/test_cmake_build/installed_embed/CMakeLists.txt +++ b/tests/test_cmake_build/installed_embed/CMakeLists.txt @@ -1,6 +1,6 @@ -cmake_minimum_required(VERSION 3.7) +cmake_minimum_required(VERSION 3.4) -# The `cmake_minimum_required(VERSION 3.7...3.18)` syntax does not work with +# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with # some versions of VS that have a patched CMake 3.11. This forces us to emulate # the behavior using the following workaround: if(${CMAKE_VERSION} VERSION_LESS 3.18) diff --git a/tests/test_cmake_build/installed_function/CMakeLists.txt b/tests/test_cmake_build/installed_function/CMakeLists.txt index db8213c983..1a502863c0 100644 --- a/tests/test_cmake_build/installed_function/CMakeLists.txt +++ b/tests/test_cmake_build/installed_function/CMakeLists.txt @@ -1,6 +1,7 @@ -cmake_minimum_required(VERSION 3.7) +cmake_minimum_required(VERSION 3.4) +project(test_installed_module CXX) -# The `cmake_minimum_required(VERSION 3.7...3.18)` syntax does not work with +# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with # some versions of VS that have a patched CMake 3.11. This forces us to emulate # the behavior using the following workaround: if(${CMAKE_VERSION} VERSION_LESS 3.18) @@ -18,12 +19,20 @@ 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}") +elseif(DEFINED PYTHON_EXECUTABLE) + set(_Python_EXECUTABLE "${PYTHON_EXECUTABLE}") +else() + message(FATAL_ERROR "No Python executable defined (should not be possible at this stage)") +endif() + add_custom_target( check_installed_function ${CMAKE_COMMAND} -E env PYTHONPATH=$ - ${PYTHON_EXECUTABLE} + ${_Python_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME}) diff --git a/tests/test_cmake_build/installed_target/CMakeLists.txt b/tests/test_cmake_build/installed_target/CMakeLists.txt index 1a124b9c27..b38eb77470 100644 --- a/tests/test_cmake_build/installed_target/CMakeLists.txt +++ b/tests/test_cmake_build/installed_target/CMakeLists.txt @@ -1,6 +1,6 @@ -cmake_minimum_required(VERSION 3.7) +cmake_minimum_required(VERSION 3.4) -# The `cmake_minimum_required(VERSION 3.7...3.18)` syntax does not work with +# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with # some versions of VS that have a patched CMake 3.11. This forces us to emulate # the behavior using the following workaround: if(${CMAKE_VERSION} VERSION_LESS 3.18) @@ -19,20 +19,27 @@ 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}") +elseif(DEFINED PYTHON_EXECUTABLE) + set(_Python_EXECUTABLE "${PYTHON_EXECUTABLE}") +else() + message(FATAL_ERROR "No Python executable defined (should not be possible at this stage)") +endif() + add_custom_target( check_installed_target ${CMAKE_COMMAND} -E env PYTHONPATH=$ - ${PYTHON_EXECUTABLE} + ${_Python_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME}) diff --git a/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt b/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt index 4571e87ff6..c7df0cf77c 100644 --- a/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt +++ b/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt @@ -1,6 +1,6 @@ -cmake_minimum_required(VERSION 3.7) +cmake_minimum_required(VERSION 3.4) -# The `cmake_minimum_required(VERSION 3.7...3.18)` syntax does not work with +# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with # some versions of VS that have a patched CMake 3.11. This forces us to emulate # the behavior using the following workaround: if(${CMAKE_VERSION} VERSION_LESS 3.18) diff --git a/tests/test_cmake_build/subdirectory_function/CMakeLists.txt b/tests/test_cmake_build/subdirectory_function/CMakeLists.txt index 697f881433..624c600f85 100644 --- a/tests/test_cmake_build/subdirectory_function/CMakeLists.txt +++ b/tests/test_cmake_build/subdirectory_function/CMakeLists.txt @@ -1,6 +1,6 @@ -cmake_minimum_required(VERSION 3.7) +cmake_minimum_required(VERSION 3.4) -# The `cmake_minimum_required(VERSION 3.7...3.18)` syntax does not work with +# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with # some versions of VS that have a patched CMake 3.11. This forces us to emulate # the behavior using the following workaround: if(${CMAKE_VERSION} VERSION_LESS 3.18) @@ -12,15 +12,23 @@ endif() project(test_subdirectory_function CXX) add_subdirectory("${PYBIND11_PROJECT_DIR}" pybind11) -pybind11_add_module(test_subdirectory_function THIN_LTO ../main.cpp) +pybind11_add_module(test_subdirectory_function ../main.cpp) set_target_properties(test_subdirectory_function PROPERTIES OUTPUT_NAME test_cmake_build) +if(DEFINED Python_EXECUTABLE) + set(_Python_EXECUTABLE "${Python_EXECUTABLE}") +elseif(DEFINED PYTHON_EXECUTABLE) + set(_Python_EXECUTABLE "${PYTHON_EXECUTABLE}") +else() + message(FATAL_ERROR "No Python executable defined (should not be possible at this stage)") +endif() + add_custom_target( check_subdirectory_function ${CMAKE_COMMAND} -E env PYTHONPATH=$ - ${PYTHON_EXECUTABLE} + ${_Python_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME}) diff --git a/tests/test_cmake_build/subdirectory_target/CMakeLists.txt b/tests/test_cmake_build/subdirectory_target/CMakeLists.txt index 4f2312ee64..2471941fb6 100644 --- a/tests/test_cmake_build/subdirectory_target/CMakeLists.txt +++ b/tests/test_cmake_build/subdirectory_target/CMakeLists.txt @@ -1,6 +1,6 @@ -cmake_minimum_required(VERSION 3.7) +cmake_minimum_required(VERSION 3.4) -# The `cmake_minimum_required(VERSION 3.7...3.18)` syntax does not work with +# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with # some versions of VS that have a patched CMake 3.11. This forces us to emulate # the behavior using the following workaround: if(${CMAKE_VERSION} VERSION_LESS 3.18) @@ -18,9 +18,16 @@ 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) + +if(DEFINED Python_EXECUTABLE) + set(_Python_EXECUTABLE "${Python_EXECUTABLE}") +elseif(DEFINED PYTHON_EXECUTABLE) + set(_Python_EXECUTABLE "${PYTHON_EXECUTABLE}") +else() + message(FATAL_ERROR "No Python executable defined (should not be possible at this stage)") +endif() add_custom_target( check_subdirectory_target @@ -28,6 +35,6 @@ add_custom_target( -E env PYTHONPATH=$ - ${PYTHON_EXECUTABLE} + ${_Python_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME}) diff --git a/tests/test_embed/CMakeLists.txt b/tests/test_embed/CMakeLists.txt index c358d33220..1495c77753 100644 --- a/tests/test_embed/CMakeLists.txt +++ b/tests/test_embed/CMakeLists.txt @@ -1,10 +1,11 @@ -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() endif() find_package(Catch 2.13.0) + if(CATCH_FOUND) message(STATUS "Building interpreter tests using Catch v${CATCH_VERSION}") else() @@ -13,14 +14,12 @@ else() return() endif() +find_package(Threads REQUIRED) + add_executable(test_embed catch.cpp test_interpreter.cpp) -target_include_directories(test_embed SYSTEM PRIVATE "${CATCH_INCLUDE_DIR}") pybind11_enable_warnings(test_embed) -target_link_libraries(test_embed PRIVATE pybind11::embed) - -find_package(Threads REQUIRED) -target_link_libraries(test_embed PUBLIC Threads::Threads) +target_link_libraries(test_embed PRIVATE pybind11::embed Catch2::Catch2 Threads::Threads) add_custom_target( cpptest diff --git a/tools/FindCatch.cmake b/tools/FindCatch.cmake index ade66c79e6..4d6bffcf68 100644 --- a/tools/FindCatch.cmake +++ b/tools/FindCatch.cmake @@ -64,4 +64,7 @@ if(NOT CATCH_VERSION OR CATCH_VERSION VERSION_LESS ${Catch_FIND_VERSION}) endif() endif() +add_library(Catch2::Catch2 IMPORTED INTERFACE) +set_property(TARGET Catch2::Catch2 PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CATCH_INCLUDE_DIR}") + set(CATCH_FOUND TRUE) diff --git a/tools/FindPythonLibsNew.cmake b/tools/FindPythonLibsNew.cmake index 822ec7718a..c1c72c763c 100644 --- a/tools/FindPythonLibsNew.cmake +++ b/tools/FindPythonLibsNew.cmake @@ -55,15 +55,46 @@ if(PYTHONLIBS_FOUND AND PYTHON_MODULE_EXTENSION) return() endif() +if(PythonLibsNew_FIND_QUIETLY) + set(_pythonlibs_quiet QUIET) +endif() + +if(PythonLibsNew_FIND_REQUIRED) + set(_pythonlibs_required REQUIRED) +endif() + +# Check to see if the `python` command is present and from a virtual +# environment, conda, or GHA activation - if it is, try to use that. + +if(NOT DEFINED PYTHON_EXECUTABLE) + if(DEFINED ENV{VIRTUAL_ENV}) + find_program( + PYTHON_EXECUTABLE python + PATHS "$ENV{VIRTUAL_ENV}" "$ENV{VIRTUAL_ENV}/bin" + NO_DEFAULT_PATH) + elseif(DEFINED ENV{CONDA_PREFIX}) + find_program( + PYTHON_EXECUTABLE python + PATHS "$ENV{CONDA_PREFIX}" "$ENV{CONDA_PREFIX}/bin" + NO_DEFAULT_PATH) + elseif(DEFINED ENV{pythonLocation}) + find_program( + PYTHON_EXECUTABLE python + PATHS "$ENV{pythonLocation}" "$ENV{pythonLocation}/bin" + NO_DEFAULT_PATH) + endif() + if(NOT PYTHON_EXECUTABLE) + unset(PYTHON_EXECUTABLE) + endif() +endif() + # Use the Python interpreter to find the libs. if(NOT PythonLibsNew_FIND_VERSION) set(PythonLibsNew_FIND_VERSION "") endif() -if(PythonLibsNew_FIND_REQUIRED) - find_package(PythonInterp ${PythonLibsNew_FIND_VERSION} REQUIRED) -else() - find_package(PythonInterp ${PythonLibsNew_FIND_VERSION}) -endif() + +find_package(PythonInterp ${PythonLibsNew_FIND_VERSION} ${_pythonlibs_required} + ${_pythonlibs_quiet}) if(NOT PYTHONINTERP_FOUND) set(PYTHONLIBS_FOUND FALSE) @@ -71,7 +102,7 @@ if(NOT PYTHONINTERP_FOUND) return() endif() -# According to http://stackoverflow.com/questions/646518/python-how-to-detect-debug-interpreter +# According to https://stackoverflow.com/questions/646518/python-how-to-detect-debug-interpreter # testing whether sys has the gettotalrefcount function is a reliable, cross-platform # way to detect a CPython debug interpreter. # diff --git a/tools/pybind11Common.cmake b/tools/pybind11Common.cmake new file mode 100644 index 0000000000..f05845179f --- /dev/null +++ b/tools/pybind11Common.cmake @@ -0,0 +1,296 @@ +#[======================================================[.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() + +# ----------------------- 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 ";$<$:-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(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} $) + endif() +endfunction() diff --git a/tools/pybind11Config.cmake.in b/tools/pybind11Config.cmake.in index c86e0dea25..4f0500a5f4 100644 --- a/tools/pybind11Config.cmake.in +++ b/tools/pybind11Config.cmake.in @@ -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_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_DIR - Directory where pybind11 headers are located. pybind11_DEFINITIONS - Definitions necessary to use pybind11, namely USING_pybind11. @@ -28,21 +29,61 @@ 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_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:: Set PythonLibsNew variables to influence python detection and CMAKE_CXX_STANDARD to influence standard setting. :: find_package(pybind11 CONFIG REQUIRED) - message(STATUS "Found pybind11 v${pybind11_VERSION} ${pybind11_VERSION_TYPE}: ${pybind11_INCLUDE_DIRS}") # 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,19 @@ 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 - "$<$,$>:$>" - ) +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") - 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") +include("${CMAKE_CURRENT_LIST_DIR}/pybind11Common.cmake") + +if(NOT pybind11_FIND_QUIETLY) + message( + STATUS + "Found pybind11: ${pybind11_INCLUDE_DIR} (found version \"${pybind11_VERSION}\" ${pybind11_VERSION_TYPE})" + ) endif() diff --git a/tools/pybind11NewTools.cmake b/tools/pybind11NewTools.cmake new file mode 100644 index 0000000000..2e7a9310f1 --- /dev/null +++ b/tools/pybind11NewTools.cmake @@ -0,0 +1,203 @@ +# 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(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 $) +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() diff --git a/tools/pybind11Tools.cmake b/tools/pybind11Tools.cmake index 6e666957d9..29885ae998 100644 --- a/tools/pybind11Tools.cmake +++ b/tools/pybind11Tools.cmake @@ -5,6 +5,13 @@ # All rights reserved. Use of this source code is governed by a # 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 if(NOT PYBIND11_PYTHON_VERSION) set(PYBIND11_PYTHON_VERSION @@ -18,112 +25,91 @@ set(Python_ADDITIONAL_VERSIONS CACHE INTERNAL "") 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) -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_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") +if(PYBIND11_MASTER_PROJECT) + if(PYTHON_MODULE_EXTENSION MATCHES "pypy") + if(NOT DEFINED PYPY_VERSION) + execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c + [=[import sys; print(".".join(map(str, sys.pypy_version_info[:3])))]=] + OUTPUT_VARIABLE pypy_version) + set(PYPY_VERSION + ${pypy_version} + CACHE INTERNAL "") endif() + message(STATUS "PYPY ${PYPY_VERSION} (Py ${PYTHON_VERSION})") 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() + message(STATUS "PYTHON ${PYTHON_VERSION}") 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() +# 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 $) + +# 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() -# 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() +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: @@ -132,7 +118,7 @@ endfunction() # function(pybind11_add_module target_name) 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) message(FATAL_ERROR "Can't be both MODULE and SHARED") @@ -159,74 +145,34 @@ function(pybind11_add_module target_name) ) endif() - # 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) - 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()