diff --git a/.gitignore b/.gitignore index 4df6229a..c444c17e 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,5 @@ MANIFEST /cmake/ .cache/ sosize-*.txt +pybind11Config*.cmake +pybind11Targets.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 99aba0cf..fc4d61f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -180,6 +180,7 @@ if (PYBIND11_TEST) endif() include(GNUInstallDirs) +include(CMakePackageConfigHelpers) # extract project version from source file(STRINGS "${PYBIND11_INCLUDE_DIR}/pybind11/common.h" pybind11_version_defines @@ -191,10 +192,40 @@ foreach(ver ${pybind11_version_defines}) endforeach() set(${PROJECT_NAME}_VERSION ${PYBIND11_VERSION_MAJOR}.${PYBIND11_VERSION_MINOR}.${PYBIND11_VERSION_PATCH}) +if(NOT (CMAKE_VERSION VERSION_LESS 3.0)) # CMake >= 3.0 + # Build an interface library target: + add_library(pybind11 INTERFACE) + target_include_directories(pybind11 INTERFACE $ + $) + if(APPLE) + target_link_libraries(pybind11 INTERFACE "-undefined dynamic_lookup") + endif() +endif() + if (PYBIND11_INSTALL) install(FILES ${PYBIND11_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/pybind11) # GNUInstallDirs "DATADIR" wrong here; CMake search path wants "share". set(PYBIND11_CMAKECONFIG_INSTALL_DIR "share/cmake/${PROJECT_NAME}" CACHE STRING "install path for pybind11Config.cmake") + configure_package_config_file(tools/${PROJECT_NAME}Config.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + INSTALL_DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR}) + write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake + VERSION ${${PROJECT_NAME}_VERSION} + COMPATIBILITY AnyNewerVersion) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake + tools/FindPythonLibsNew.cmake + tools/pybind11Tools.cmake + DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR}) + + if(NOT (CMAKE_VERSION VERSION_LESS 3.0)) + install(TARGETS pybind11 + EXPORT "${PROJECT_NAME}Targets") + install(EXPORT "${PROJECT_NAME}Targets" + NAMESPACE "${PROJECT_NAME}::" + DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR}) + message(STATUS "Exporting ${PROJECT_NAME}::pybind11 interface library target version ${${PROJECT_NAME}_VERSION}") + endif() endif() diff --git a/docs/compiling.rst b/docs/compiling.rst index 30cd83b7..642dfe01 100644 --- a/docs/compiling.rst +++ b/docs/compiling.rst @@ -51,3 +51,67 @@ A working sample project, including a way to invoke CMake from :file:`setup.py` PyPI integration, can be found in the [cmake_example]_ repository. .. [cmake_example] https://github.com/pybind/cmake_example + +For CMake-based projects that don't include the pybind11 +repository internally, an external installation can be detected +through `find_package(pybind11 ... CONFIG ...)`. See the `Config file +`_ +docstring for details of relevant CMake variables. + +Once detected, and after setting any variables to guide Python and C++ +standard detection, the aforementioned ``pybind11_add_module`` +wrapper to ``add_library`` can +be employed as described above (after ``include(pybind11Tools)``). This +procedure is available when using CMake >= 2.8.12. A +working example can be found at [test_installed_module]_ . + +.. code-block:: cmake + + cmake_minimum_required(VERSION 2.8.12) + project(example) + + find_package(pybind11 REQUIRED) + pybind11_add_module(example example.cpp) + +.. [test_installed_module] https://github.com/pybind/pybind11/blob/master/tests/test_installed_module/CMakeLists.txt + +When using a version of CMake greater than 3.0, pybind11 can +additionally be used as a special *interface library* following the call +to ``find_package``. CMake +variables to guide Python and C++ standard detection should be set +*before* ``find_package``. When ``find_package`` returns, the target +``pybind11::pybind11`` is available with pybind11 headers, Python headers +and libraries as needed, and C++ compile definitions attached. This +target is suitable for linking to an independently constructed (through +``add_library``, not ``pybind11_add_module``) target in the consuming +project. A working example can be found at [test_installed_target]_ . + +.. code-block:: cmake + + cmake_minimum_required(VERSION 3.0) + project(example) + + add_library(example MODULE main.cpp) + + find_package(pybind11 REQUIRED) + target_link_libraries(example PRIVATE pybind11::pybind11) + set_target_properties(example PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}" + SUFFIX "${PYTHON_MODULE_EXTENSION}") + +.. 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). + + These include Link Time Optimization (``-flto`` on GCC/Clang/ICPC, ``/GL`` + and ``/LTCG`` on Visual Studio). Default-hidden symbols on GCC/Clang/ICPC + (``-fvisibility=hidden``) and .OBJ files with many sections on Visual Studio + (``/bigobj``). The :ref:`FAQ ` contains an + explanation on why these are needed. + +.. [test_installed_target] https://github.com/pybind/pybind11/blob/master/tests/test_installed_target/CMakeLists.txt + diff --git a/docs/faq.rst b/docs/faq.rst index 7f9bd35b..34002b42 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -162,6 +162,8 @@ culprit is generally the generation of function signatures at compile time using C++14 template metaprogramming. +.. _`faq:symhidden`: + How can I create smaller binaries? ================================== diff --git a/tools/pybind11Config.cmake.in b/tools/pybind11Config.cmake.in new file mode 100644 index 00000000..23588c30 --- /dev/null +++ b/tools/pybind11Config.cmake.in @@ -0,0 +1,92 @@ +# pybind11Config.cmake +# -------------------- +# +# PYBIND11 cmake module. +# 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_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. +# CMAKE_MODULE_PATH - appends location of accompanying FindPythonLibsNew.cmake and +# pybind11Tools.cmake modules. +# +# +# Available components: None +# +# +# Exported targets:: +# +# If pybind11 is found, this module defines the following :prop_tgt:`IMPORTED` +# target. Python headers, libraries (as needed by platform), and C++ standard +# are attached to the target. Set PythonLibsNew variables to influence +# python detection and PYBIND11_CPP_STANDARD (-std=c++11 or -std=c++14) to +# influence standard setting. :: +# +# pybind11::pybind11 - the main pybind11 interface library (i.e., headers) +# +# find_package(pybind11 CONFIG REQUIRED) +# message(STATUS "Found pybind11: ${pybind11_INCLUDE_DIR} (found version ${pybind11_VERSION} & Py${PYTHON_VERSION_STRING})") +# add_library(mylib MODULE main.cpp) +# target_link_libraries(mylib pybind11::pybind11) +# +# Suggested usage:: +# +# find_package with version info is not recommended except for release versions. :: +# +# find_package(pybind11 CONFIG) +# 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 + +@PACKAGE_INIT@ + +set(PN pybind11) + +# location of pybind11/pybind11.h +set(${PN}_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_INCLUDEDIR@") + +set(${PN}_LIBRARY "") +set(${PN}_DEFINITIONS USING_${PN}) + +check_required_components(${PN}) + +# make detectable the FindPythonLibsNew.cmake module +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) + +include(pybind11Tools) + +if(NOT (CMAKE_VERSION VERSION_LESS 3.0)) +#----------------------------------------------------------------------------- +# 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 ${PN}::pybind11) + include("${CMAKE_CURRENT_LIST_DIR}/${PN}Targets.cmake") + + find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} MODULE REQUIRED) + set_property(TARGET ${PN}::pybind11 APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${PYTHON_INCLUDE_DIRS}) + if(WIN32 OR CYGWIN) + set_property(TARGET ${PN}::pybind11 APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${PYTHON_LIBRARIES}) + endif() + + select_cxx_standard() + set_property(TARGET ${PN}::pybind11 APPEND PROPERTY INTERFACE_COMPILE_OPTIONS "${PYBIND11_CPP_STANDARD}") + + get_property(_iid TARGET ${PN}::pybind11 PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + get_property(_ill TARGET ${PN}::pybind11 PROPERTY INTERFACE_LINK_LIBRARIES) + get_property(_ico TARGET ${PN}::pybind11 PROPERTY INTERFACE_COMPILE_OPTIONS) + set(${PN}_INCLUDE_DIRS ${_iid}) + set(${PN}_LIBRARIES ${_ico} ${_ill}) +endif() +endif()