Add CMake target for embedding the Python interpreter

All targets provided by pybind11:

* pybind11::module - the existing target for creating extension modules
* pybind11::embed - new target for embedding the interpreter
* pybind11::pybind11 - common "base" target (headers only)
This commit is contained in:
Dean Moldovan 2017-03-23 13:32:54 +01:00
parent 46dbee7d42
commit 7f5c85c861
6 changed files with 91 additions and 15 deletions

View File

@ -84,18 +84,25 @@ endif()
if(NOT (CMAKE_VERSION VERSION_LESS 3.0)) # CMake >= 3.0 if(NOT (CMAKE_VERSION VERSION_LESS 3.0)) # CMake >= 3.0
# Build an interface library target: # Build an interface library target:
add_library(module INTERFACE) add_library(pybind11 INTERFACE)
target_include_directories(module INTERFACE $<BUILD_INTERFACE:${PYBIND11_INCLUDE_DIR}> add_library(pybind11::pybind11 ALIAS pybind11) # to match exported target
target_include_directories(pybind11 INTERFACE $<BUILD_INTERFACE:${PYBIND11_INCLUDE_DIR}>
$<BUILD_INTERFACE:${PYTHON_INCLUDE_DIRS}> $<BUILD_INTERFACE:${PYTHON_INCLUDE_DIRS}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>) $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
target_compile_options(pybind11 INTERFACE $<BUILD_INTERFACE:${PYBIND11_CPP_STANDARD}>)
add_library(module INTERFACE)
add_library(pybind11::module ALIAS module)
target_link_libraries(module INTERFACE pybind11::pybind11)
if(WIN32 OR CYGWIN) if(WIN32 OR CYGWIN)
target_link_libraries(module INTERFACE $<BUILD_INTERFACE:${PYTHON_LIBRARIES}>) target_link_libraries(module INTERFACE $<BUILD_INTERFACE:${PYTHON_LIBRARIES}>)
elseif(APPLE) elseif(APPLE)
target_link_libraries(module INTERFACE "-undefined dynamic_lookup") target_link_libraries(module INTERFACE "-undefined dynamic_lookup")
endif() endif()
target_compile_options(module INTERFACE $<BUILD_INTERFACE:${PYBIND11_CPP_STANDARD}>)
add_library(pybind11::module ALIAS module) # to match exported target add_library(embed INTERFACE)
add_library(pybind11::embed ALIAS embed)
target_link_libraries(embed INTERFACE pybind11::pybind11 $<BUILD_INTERFACE:${PYTHON_LIBRARIES}>)
endif() endif()
if (PYBIND11_INSTALL) if (PYBIND11_INSTALL)
@ -122,7 +129,7 @@ if (PYBIND11_INSTALL)
DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR}) DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
if(NOT (CMAKE_VERSION VERSION_LESS 3.0)) if(NOT (CMAKE_VERSION VERSION_LESS 3.0))
install(TARGETS module install(TARGETS pybind11 module embed
EXPORT "${PROJECT_NAME}Targets") EXPORT "${PROJECT_NAME}Targets")
install(EXPORT "${PROJECT_NAME}Targets" install(EXPORT "${PROJECT_NAME}Targets"
NAMESPACE "${PROJECT_NAME}::" NAMESPACE "${PROJECT_NAME}::"

View File

@ -233,6 +233,9 @@ if(NOT CMAKE_VERSION VERSION_LESS 3.1)
pybind11_add_build_test(subdirectory_function) pybind11_add_build_test(subdirectory_function)
pybind11_add_build_test(subdirectory_target) pybind11_add_build_test(subdirectory_target)
if(NOT ${PYTHON_MODULE_EXTENSION} MATCHES "pypy")
pybind11_add_build_test(subdirectory_embed)
endif()
if(PYBIND11_INSTALL) if(PYBIND11_INSTALL)
add_custom_target(mock_install ${CMAKE_COMMAND} add_custom_target(mock_install ${CMAKE_COMMAND}
@ -242,6 +245,9 @@ if(NOT CMAKE_VERSION VERSION_LESS 3.1)
pybind11_add_build_test(installed_function INSTALL) pybind11_add_build_test(installed_function INSTALL)
pybind11_add_build_test(installed_target INSTALL) pybind11_add_build_test(installed_target INSTALL)
if(NOT ${PYTHON_MODULE_EXTENSION} MATCHES "pypy")
pybind11_add_build_test(installed_embed INSTALL)
endif()
endif() endif()
endif() endif()

View File

@ -0,0 +1,30 @@
#include <pybind11/pybind11.h>
#include <pybind11/eval.h>
namespace py = pybind11;
PyObject *make_module() {
py::module m("test_cmake_build");
m.def("add", [](int i, int j) { return i + j; });
return m.ptr();
}
int main(int argc, char *argv[]) {
if (argc != 2)
throw std::runtime_error("Expected test.py file as the first argument");
auto test_py_file = argv[1];
PyImport_AppendInittab("test_cmake_build", &make_module);
Py_Initialize();
{
auto m = py::module::import("test_cmake_build");
if (m.attr("add")(1, 2).cast<int>() != 3)
throw std::runtime_error("embed.cpp failed");
auto globals = py::module::import("__main__").attr("__dict__");
py::module::import("sys").attr("argv") = py::make_tuple("test.py", "embed.cpp");
py::eval_file(test_py_file, globals);
}
Py_Finalize();
}

View File

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.0)
project(test_installed_embed CXX)
set(CMAKE_MODULE_PATH "")
find_package(pybind11 CONFIG REQUIRED)
message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}")
add_executable(test_cmake_build ../embed.cpp)
target_link_libraries(test_cmake_build PRIVATE pybind11::embed)
# Do not treat includes from IMPORTED target as SYSTEM (Python headers in pybind11::embed).
# This may be needed to resolve header conflicts, e.g. between Python release and debug headers.
set_target_properties(test_cmake_build PROPERTIES NO_SYSTEM_FROM_IMPORTED ON)
add_custom_target(check $<TARGET_FILE:test_cmake_build> ${PROJECT_SOURCE_DIR}/../test.py)

View File

@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.0)
project(test_subdirectory_embed CXX)
add_subdirectory(${PYBIND11_PROJECT_DIR} pybind11)
add_executable(test_cmake_build ../embed.cpp)
target_link_libraries(test_cmake_build PRIVATE pybind11::embed)
add_custom_target(check $<TARGET_FILE:test_cmake_build> ${PROJECT_SOURCE_DIR}/../test.py)

View File

@ -21,18 +21,27 @@
# 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 :prop_tgt:`IMPORTED`
# target. Python headers, libraries (as needed by platform), and C++ standard # interface library targets::
#
# pybind11::module - for extension modules
# pybind11::embed - for embedding the Python interpreter
#
# Python headers, libraries (as needed by platform), and the C++ standard
# are attached to the target. Set PythonLibsNew variables to influence # are attached to the target. Set PythonLibsNew variables to influence
# python detection and PYBIND11_CPP_STANDARD (-std=c++11 or -std=c++14) to # python detection and PYBIND11_CPP_STANDARD (-std=c++11 or -std=c++14) to
# influence standard setting. :: # influence standard setting. ::
# #
# pybind11::module - the main pybind11 interface library for extension modules (i.e., headers)
#
# find_package(pybind11 CONFIG REQUIRED) # find_package(pybind11 CONFIG REQUIRED)
# message(STATUS "Found pybind11: ${pybind11_INCLUDE_DIR} (found version ${pybind11_VERSION} & Py${PYTHON_VERSION_STRING})") # message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}")
#
# # Create an extension module
# add_library(mylib MODULE main.cpp) # add_library(mylib MODULE main.cpp)
# target_link_libraries(mylib pybind11::module) # target_link_libraries(mylib pybind11::module)
# #
# # Or embed the Python interpreter into an executable
# add_executable(myexe main.cpp)
# target_link_libraries(myexe pybind11::embed)
#
# Suggested usage:: # Suggested usage::
# #
# find_package with version info is not recommended except for release versions. :: # find_package with version info is not recommended except for release versions. ::
@ -71,21 +80,21 @@ if(NOT (CMAKE_VERSION VERSION_LESS 3.0))
# Don't include targets if this file is being picked up by another # Don't include targets if this file is being picked up by another
# project which has already built this as a subproject # project which has already built this as a subproject
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
if(NOT TARGET ${PN}::module) if(NOT TARGET ${PN}::pybind11)
include("${CMAKE_CURRENT_LIST_DIR}/${PN}Targets.cmake") include("${CMAKE_CURRENT_LIST_DIR}/${PN}Targets.cmake")
find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} MODULE REQUIRED) find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} MODULE REQUIRED)
set_property(TARGET ${PN}::module APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${PYTHON_INCLUDE_DIRS}) set_property(TARGET ${PN}::pybind11 APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${PYTHON_INCLUDE_DIRS})
set_property(TARGET ${PN}::embed APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${PYTHON_LIBRARIES})
if(WIN32 OR CYGWIN) if(WIN32 OR CYGWIN)
set_property(TARGET ${PN}::module APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${PYTHON_LIBRARIES}) set_property(TARGET ${PN}::module APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${PYTHON_LIBRARIES})
endif() endif()
select_cxx_standard() select_cxx_standard()
set_property(TARGET ${PN}::module APPEND PROPERTY INTERFACE_COMPILE_OPTIONS "${PYBIND11_CPP_STANDARD}") set_property(TARGET ${PN}::pybind11 APPEND PROPERTY INTERFACE_COMPILE_OPTIONS "${PYBIND11_CPP_STANDARD}")
get_property(_iid TARGET ${PN}::module PROPERTY INTERFACE_INCLUDE_DIRECTORIES) get_property(_iid TARGET ${PN}::pybind11 PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
get_property(_ill TARGET ${PN}::module PROPERTY INTERFACE_LINK_LIBRARIES) get_property(_ill TARGET ${PN}::module PROPERTY INTERFACE_LINK_LIBRARIES)
get_property(_ico TARGET ${PN}::module PROPERTY INTERFACE_COMPILE_OPTIONS)
set(${PN}_INCLUDE_DIRS ${_iid}) set(${PN}_INCLUDE_DIRS ${_iid})
set(${PN}_LIBRARIES ${_ico} ${_ill}) set(${PN}_LIBRARIES ${_ico} ${_ill})
endif() endif()