refactor: import check as a common function (#2526)

* feat: import check as a common function

* docs: add cmake to docs
This commit is contained in:
Henry Schreiner 2020-10-02 22:34:22 -04:00 committed by GitHub
parent ca4127ce07
commit 3488494a81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 230 additions and 70 deletions

View File

@ -85,6 +85,9 @@ See :ref:`upgrade-guide-2.6` for help upgrading to the new version.
``CMAKE_INTERPROCEDURAL_OPTIMIZATION``, ``set(CMAKE_CXX_VISIBILITY_PRESET ``CMAKE_INTERPROCEDURAL_OPTIMIZATION``, ``set(CMAKE_CXX_VISIBILITY_PRESET
hidden)``. hidden)``.
* Helper functions ``pybind11_strip``, ``pybind11_extension``,
``pybind11_find_import`` added, see :doc:`cmake/index`.
* Optional :ref:`find-python-mode` and :ref:`nopython-mode` with CMake. * Optional :ref:`find-python-mode` and :ref:`nopython-mode` with CMake.
`#2370 <https://github.com/pybind/pybind11/pull/2370>`_ `#2370 <https://github.com/pybind/pybind11/pull/2370>`_

9
docs/cmake/index.rst Normal file
View File

@ -0,0 +1,9 @@
CMake helpers
-------------
Pybind11 can be used with ``add_subdirectory(extern/pybind11)``, or from an
install with ``find_package(pybind11 CONFIG)``. The interface provided in
either case is functionally identical.
.. cmake-module:: ../../tools/pybind11Config.cmake.in

View File

@ -201,6 +201,8 @@ PyPI integration, can be found in the [cmake_example]_ repository.
.. versionchanged:: 2.6 .. versionchanged:: 2.6
CMake 3.4+ is required. CMake 3.4+ is required.
Further information can be found at :doc:`cmake/index`.
pybind11_add_module pybind11_add_module
------------------- -------------------

View File

@ -31,7 +31,7 @@ import subprocess
# Add any Sphinx extension module names here, as strings. They can be # Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones. # ones.
extensions = ['breathe', 'sphinxcontrib.rsvgconverter'] extensions = ['breathe', 'sphinxcontrib.rsvgconverter', 'sphinxcontrib.moderncmakedomain']
breathe_projects = {'pybind11': '.build/doxygenxml/'} breathe_projects = {'pybind11': '.build/doxygenxml/'}
breathe_default_project = 'pybind11' breathe_default_project = 'pybind11'

View File

@ -40,3 +40,4 @@
benchmark benchmark
limitations limitations
reference reference
cmake/index

View File

@ -4,3 +4,4 @@ recommonmark==0.6.0
sphinx==3.2.1 sphinx==3.2.1
sphinx_rtd_theme==0.5.0 sphinx_rtd_theme==0.5.0
sphinxcontrib-svg2pdfconverter==1.1.0 sphinxcontrib-svg2pdfconverter==1.1.0
sphinxcontrib-moderncmakedomain==3.13

View File

@ -347,24 +347,7 @@ foreach(target ${test_targets})
endforeach() endforeach()
# Make sure pytest is found or produce a warning # Make sure pytest is found or produce a warning
if(NOT PYBIND11_PYTEST_FOUND) pybind11_find_import(pytest VERSION 3.1)
execute_process(
COMMAND ${PYTHON_EXECUTABLE} -c "import pytest; print(pytest.__version__)"
RESULT_VARIABLE pytest_not_found
OUTPUT_VARIABLE pytest_version
ERROR_QUIET)
if(pytest_not_found)
message(WARNING "Running the tests requires pytest. Please install it manually"
" (try: ${PYTHON_EXECUTABLE} -m pip install pytest)")
elseif(pytest_version VERSION_LESS 3.1)
message(WARNING "Running the tests requires pytest >= 3.1. Found: ${pytest_version}"
"Please update it (try: ${PYTHON_EXECUTABLE} -m pip install -U pytest)")
else()
set(PYBIND11_PYTEST_FOUND
TRUE
CACHE INTERNAL "")
endif()
endif()
if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
# This is not used later in the build, so it's okay to regenerate each time. # This is not used later in the build, so it's okay to regenerate each time.

View File

@ -15,7 +15,7 @@ Adds the following targets::
Adds the following functions:: Adds the following functions::
pybind11_strip(target) - strip target after building on linux/macOS pybind11_strip(target) - strip target after building on linux/macOS
pybind11_find_import(module) - See if a module is installed.
#]======================================================] #]======================================================]
@ -196,6 +196,77 @@ else()
endif() endif()
# --------------------- pybind11_check_import -------------------------------
if(NOT _pybind11_nopython)
# Check to see if modules are importable. Use REQUIRED to force an error if
# one of the modules is not found. <package_name>_FOUND will be set if the
# package was found (underscores replace dashes if present). QUIET will hide
# the found message, and VERSION will require a minimum version. A successful
# find will cache the result.
function(pybind11_find_import PYPI_NAME)
# CMake variables need underscores (PyPI doesn't care)
string(REPLACE "-" "_" NORM_PYPI_NAME "${PYPI_NAME}")
# Return if found previously
if(${NORM_PYPI_NAME}_FOUND)
return()
endif()
set(options "REQUIRED;QUIET")
set(oneValueArgs "VERSION")
cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "" ${ARGN})
if(ARG_REQUIRED)
set(status_level FATAL_ERROR)
else()
set(status_level WARNING)
endif()
execute_process(
COMMAND
${${_Python}_EXECUTABLE} -c
"from pkg_resources import get_distribution; print(get_distribution('${PYPI_NAME}').version)"
RESULT_VARIABLE RESULT_PRESENT
OUTPUT_VARIABLE PKG_VERSION
ERROR_QUIET)
string(STRIP "${PKG_VERSION}" PKG_VERSION)
# If a result is present, this failed
if(RESULT_PRESENT)
set(${NORM_PYPI_NAME}_FOUND
${NORM_PYPI_NAME}-NOTFOUND
CACHE INTERNAL "")
# Always warn or error
message(
${status_level}
"Missing: ${PYPI_NAME} ${ARG_VERSION}\nTry: ${${_Python}_EXECUTABLE} -m pip install ${PYPI_NAME}"
)
else()
if(ARG_VERSION AND PKG_VERSION VERSION_LESS ARG_VERSION)
message(
${status_level}
"Version incorrect: ${PYPI_NAME} ${PKG_VERSION} found, ${ARG_VERSION} required - try upgrading"
)
else()
set(${NORM_PYPI_NAME}_FOUND
YES
CACHE INTERNAL "")
set(${NORM_PYPI_NAME}_VERSION
${PKG_VERSION}
CACHE INTERNAL "")
endif()
if(NOT ARG_QUIET)
message(STATUS "Found ${PYPI_NAME} ${PKG_VERSION}")
endif()
endif()
if(NOT ARG_VERSION OR (NOT PKG_VERSION VERSION_LESS ARG_VERSION))
# We have successfully found a good version, cache to avoid calling again.
endif()
endfunction()
endif()
# --------------------- LTO ------------------------------- # --------------------- LTO -------------------------------
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)

View File

@ -1,57 +1,80 @@
#[=============================================================================[.rst #[=============================================================================[.rst:
pybind11Config.cmake pybind11Config.cmake
-------------------- ####################
PYBIND11 cmake module. Exported variables
This module sets the following variables in your project:: ==================
pybind11_FOUND - true if pybind11 and all required components found on the system This module sets the following variables in your project:
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.
pybind11_LIBRARIES - compile flags and python libraries (as needed) to link against.
pybind11_LIBRARY - empty.
``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.
``pybind11_LIBRARIES``
Compile flags and python libraries (as needed) to link against.
``pybind11_LIBRARY``
Empty.
Available components: None Available components: None
Exported targets:: Exported targets
================
If pybind11 is found, this module defines the following :prop_tgt:`IMPORTED` If pybind11 is found, this module defines the following ``IMPORTED``
interface library targets:: interface library targets:
pybind11::module - for extension modules ``pybind11::module``
pybind11::embed - for embedding the Python interpreter for extension modules.
``pybind11::embed``
for embedding the Python interpreter.
Python headers, libraries (as needed by platform), and the C++ standard Python headers, libraries (as needed by platform), and the C++ standard
are attached to the target. are attached to the target.
Advanced targets are also supplied - these are primary for users building Advanced targets are also supplied - these are primary for users building
complex applications, and they are available in all modes:: complex applications, and they are available in all modes:
pybind11::headers - Just the pybind11 headers and minimum compile requirements ``pybind11::headers``
pybind11::pybind11 - Python headers too Just the pybind11 headers and minimum compile requirements.
pybind11::python_link_helper - Just the "linking" part of pybind11:module, for CMake < 3.15 ``pybind11::pybind11``
pybind11::python2_no_register - Quiets the warning/error when mixing C++14+ and Python 2, also included in pybind11::module Python headers too.
pybind11::thin_lto - An alternative to INTERPROCEDURAL_OPTIMIZATION ``pybind11::python_link_helper``
pybind11::lto - An alternative to INTERPROCEDURAL_OPTIMIZATION (also avoids thin LTO on clang) Just the "linking" part of ``pybind11:module``, for CMake < 3.15.
pybind11::windows_extras - Adds bigobj and mp for MSVC ``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:: Modes
=====
There are two modes provided; classic, which is built on the old Python 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 discovery packages in CMake, or the new FindPython mode, which uses FindPython
from 3.12+ forward (3.15+ _highly_ recommended). from 3.12+ forward (3.15+ _highly_ recommended).
New FindPython mode:: New FindPython mode
^^^^^^^^^^^^^^^^^^^
To activate this mode, either call ``find_package(Python COMPONENTS Interpreter Development)`` 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, 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:: you can either use the basic targets, or use the FindPython tools:
.. code-block:: cmake
find_package(Python COMPONENTS Interpreter Development) find_package(Python COMPONENTS Interpreter Development)
find_package(pybind11 CONFIG) find_package(pybind11 CONFIG)
@ -70,10 +93,13 @@ you can either use the basic targets, or use the FindPython tools::
If you build targets yourself, you may be interested in stripping the output 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. for reduced size; this is the one other feature that the helper function gives you.
Classic mode:: Classic mode
^^^^^^^^^^^^
Set PythonLibsNew variables to influence python detection and Set PythonLibsNew variables to influence python detection and
CMAKE_CXX_STANDARD to influence standard setting. :: CMAKE_CXX_STANDARD to influence standard setting.
.. code-block:: cmake
find_package(pybind11 CONFIG REQUIRED) find_package(pybind11 CONFIG REQUIRED)
@ -85,31 +111,92 @@ CMAKE_CXX_STANDARD to influence standard setting. ::
add_executable(myexe main.cpp) add_executable(myexe main.cpp)
target_link_libraries(myexe PUBLIC pybind11::embed) target_link_libraries(myexe PUBLIC pybind11::embed)
Suggested usage::
find_package with version info is not recommended except for release versions. :: Hints
=====
The following variables can be set to guide the search for this package:
``pybind11_DIR``
CMake variable, set to directory containing this Config file.
``CMAKE_PREFIX_PATH``
CMake variable, set to root directory of 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.
Commands
========
pybind11_add_module
^^^^^^^^^^^^^^^^^^^
This module defines the following commands to assist with creating Python modules:
.. code-block:: cmake
pybind11_add_module(<target>
[STATIC|SHARED|MODULE]
[THIN_LTO] [OPT_SIZE] [NO_EXTRAS] [WITHOUT_SOBAI]
<files>...
)
Add a module and setup all helpers. You can select the type of the library; the
default is ``MODULE``. There are several options:
``OPT_SIZE``
Optimize for size, even if the ``CMAKE_BUILD_TYPE`` is not ``RelSize``.
``THIN_LTO``
Use thin TLO instead of regular if there's a choice (pybind11's selection
is disabled if ``CMAKE_INTERPROCEDURAL_OPTIMIZATIONS`` is set).
``WITHOUT_SOABI``
Disable the SOABI component (``PYBIND11_NEWPYTHON`` mode only).
``NO_EXTRAS``
Disable all extras, exit immediately after making the module.
pybind11_strip
^^^^^^^^^^^^^^
.. code-block:: cmake
pybind11_strip(<target>)
Strip a target after building it (linux/macOS), called by ``pybind11_add_module``.
pybind11_extension
^^^^^^^^^^^^^^^^^^
.. code-block:: cmake
pybind11_extension(<target>)
Sets the Python extension name correctly for Python on your platform, called by
``pybind11_add_module``.
pybind11_find_import(module)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: cmake
pybind11_find_import(<module> [VERSION <number>] [REQUIRED] [QUIET])
See if a module is installed. Use the registered name (the one on PyPI). You
can specify a ``VERSION``, and you can specify ``REQUIRED`` or ``QUIET``. Only available if
``NOPYTHON`` mode is not active. Sets ``module_VERSION`` and ``module_FOUND``. Caches the
result once a valid install is found.
Suggested usage
===============
Using ``find_package`` with version info is not recommended except for release versions.
.. code-block:: cmake
find_package(pybind11 CONFIG) find_package(pybind11 CONFIG)
find_package(pybind11 2.0 EXACT CONFIG REQUIRED) find_package(pybind11 2.0 EXACT CONFIG REQUIRED)
The following variables can be set to guide the search for this package::
pybind11_DIR - CMake variable, set to directory containing this Config file
CMAKE_PREFIX_PATH - CMake variable, set to root directory of 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@ @PACKAGE_INIT@

View File

@ -189,3 +189,6 @@ function(pybind11_add_module target_name)
target_link_libraries(${target_name} PRIVATE pybind11::opt_size) target_link_libraries(${target_name} PRIVATE pybind11::opt_size)
endif() endif()
endfunction() endfunction()
# Provide general way to call common Python commands in "common" file.
set(_Python PYTHON)