Merge branch 'master' into cygwin

This commit is contained in:
Boris Schäling 2016-05-29 16:51:48 +02:00
commit 3f3ea26215
14 changed files with 478 additions and 394 deletions

View File

@ -9,6 +9,7 @@ addons:
sources: sources:
- ubuntu-toolchain-r-test - ubuntu-toolchain-r-test
- deadsnakes - deadsnakes
- kubuntu-backports # cmake 2.8.12
packages: packages:
- g++-4.8 - g++-4.8
- g++-4.8-multilib - g++-4.8-multilib
@ -17,6 +18,7 @@ addons:
- python3.5-dev - python3.5-dev
- python3.5-venv - python3.5-venv
- python3.5-dev:i386 - python3.5-dev:i386
- cmake
matrix: matrix:
include: include:
- os: linux - os: linux

View File

@ -5,96 +5,149 @@
# All rights reserved. Use of this source code is governed by a # All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file. # BSD-style license that can be found in the LICENSE file.
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 2.8.12)
project(pybind11) project(pybind11)
option(PYBIND11_INSTALL "Install pybind11 header files?" ON) # Check if pybind11 is being used directly or via add_subdirectory
set(PYBIND11_MASTER_PROJECT OFF)
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(PYBIND11_MASTER_PROJECT ON)
endif()
option(PYBIND11_INSTALL "Install pybind11 header files?" ${PYBIND11_MASTER_PROJECT})
option(PYBIND11_TEST "Build pybind11 test suite?" ${PYBIND11_MASTER_PROJECT})
# Add a CMake parameter for choosing a desired Python version # Add a CMake parameter for choosing a desired Python version
set(PYBIND11_PYTHON_VERSION "" CACHE STRING "Python version to use for compiling the example application") set(PYBIND11_PYTHON_VERSION "" CACHE STRING "Python version to use for compiling the example application")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/tools")
set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6 3.7)
find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} REQUIRED)
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)
# Set a default build configuration if none is specified. 'MinSizeRel' produces the smallest binaries if(NOT MSVC AND NOT PYBIND11_CPP_STANDARD)
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) check_cxx_compiler_flag("-std=c++14" HAS_CPP14_FLAG)
message(STATUS "Setting build type to 'MinSizeRel' as none was specified.") check_cxx_compiler_flag("-std=c++11" HAS_CPP11_FLAG)
set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "Choose the type of build." FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
"MinSizeRel" "RelWithDebInfo")
endif()
string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE)
set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6 3.7)
if (NOT ${PYBIND11_PYTHON_VERSION} STREQUAL "")
find_package(PythonLibs ${PYBIND11_PYTHON_VERSION} EXACT)
if (NOT PYTHONLIBS_FOUND)
find_package(PythonLibs ${PYBIND11_PYTHON_VERSION} REQUIRED)
endif()
else()
find_package(PythonLibs REQUIRED)
endif()
# The above sometimes returns version numbers like "3.4.3+"; the "+" must be removed for the next line to work
string(REPLACE "+" "" PYTHONLIBS_VERSION_STRING "+${PYTHONLIBS_VERSION_STRING}")
find_package(PythonInterp ${PYTHONLIBS_VERSION_STRING} EXACT REQUIRED)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Intel")
CHECK_CXX_COMPILER_FLAG("-std=c++14" HAS_CPP14_FLAG)
CHECK_CXX_COMPILER_FLAG("-std=c++11" HAS_CPP11_FLAG)
if (HAS_CPP14_FLAG) if (HAS_CPP14_FLAG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") set(PYBIND11_CPP_STANDARD -std=c++14)
elseif (HAS_CPP11_FLAG) elseif (HAS_CPP11_FLAG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set(PYBIND11_CPP_STANDARD -std=c++11)
else() else()
message(FATAL_ERROR "Unsupported compiler -- pybind11 requires C++11 support!") message(FATAL_ERROR "Unsupported compiler -- pybind11 requires C++11 support!")
endif() endif()
set(PYBIND11_CPP_STANDARD ${PYBIND11_CPP_STANDARD} CACHE STRING
"C++ standard flag, e.g. -std=c++11 or -std=c++14. Defaults to latest available.")
endif()
# 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 "")
# Build a Python extension module:
# pybind11_add_module(<name> source1 [source2 ...])
#
function(pybind11_add_module target_name)
add_library(${target_name} MODULE ${ARGN})
target_include_directories(${target_name} PUBLIC ${PYBIND11_INCLUDE_DIR} ${PYTHON_INCLUDE_DIRS})
# 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}")
if(WIN32)
# Link against the Python shared library on Windows
target_link_libraries(${target_name} PRIVATE ${PYTHON_LIBRARIES})
elseif(APPLE)
# It's quite common to have multiple copies of the same Python version
# installed on one's system. E.g.: one copy from the OS and another copy
# that's statically linked into an application like Blender or Maya.
# If we link our plugin library against the OS Python here and import it
# into Blender or Maya later on, this will cause segfaults when multiple
# conflicting Python instances are active at the same time (even when they
# are of the same version).
# Windows is not affected by this issue since it handles DLL imports
# differently. The solution for Linux and Mac OS is simple: we just don't
# link against the Python library. The resulting shared library will have
# missing symbols, but that's perfectly fine -- they will be resolved at
# import time.
target_link_libraries(${target_name} PRIVATE "-undefined dynamic_lookup")
endif()
if(NOT MSVC)
# Make sure C++11/14 are enabled
target_compile_options(${target_name} PUBLIC ${PYBIND11_CPP_STANDARD})
# Enable link time optimization and set the default symbol # Enable link time optimization and set the default symbol
# visibility to hidden (very important to obtain small binaries) # visibility to hidden (very important to obtain small binaries)
string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE)
if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG)
# Default symbol visibility # Check for Link Time Optimization support (GCC/Clang)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden") check_cxx_compiler_flag("-flto" HAS_LTO_FLAG)
# Check for Link Time Optimization support
# (GCC/Clang)
CHECK_CXX_COMPILER_FLAG("-flto" HAS_LTO_FLAG)
if(HAS_LTO_FLAG AND NOT CYGWIN) if(HAS_LTO_FLAG AND NOT CYGWIN)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto") target_compile_options(${target_name} PRIVATE -flto)
endif() endif()
# Intel equivalent to LTO is called IPO # Intel equivalent to LTO is called IPO
if(CMAKE_CXX_COMPILER_ID MATCHES "Intel") if(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
CHECK_CXX_COMPILER_FLAG("-ipo" HAS_IPO_FLAG) check_cxx_compiler_flag("-ipo" HAS_IPO_FLAG)
if(HAS_IPO_FLAG) if(HAS_IPO_FLAG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ipo") target_compile_options(${target_name} PRIVATE -ipo)
endif()
endif()
# Default symbol visibility
target_compile_options(${target_name} PRIVATE "-fvisibility=hidden")
# 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} -u -r $<TARGET_FILE:${target_name}>)
else()
add_custom_command(TARGET ${target_name} POST_BUILD
COMMAND ${CMAKE_STRIP} $<TARGET_FILE:${target_name}>)
endif() endif()
endif() endif()
endif() endif()
elseif(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 /MP /bigobj)
# Enforce link time code generation on MSVC, except in debug mode
target_compile_options(${target_name} PRIVATE $<$<NOT:$<CONFIG:Debug>>:/GL>)
# Fancy generator expressions don't work with linker flags, for reasons unknown
set_property(TARGET ${target_name} APPEND_STRING PROPERTY LINK_FLAGS_RELEASE /LTCG)
set_property(TARGET ${target_name} APPEND_STRING PROPERTY LINK_FLAGS_MINSIZEREL /LTCG)
set_property(TARGET ${target_name} APPEND_STRING PROPERTY LINK_FLAGS_RELWITHDEBINFO /LTCG)
endif() endif()
endfunction()
# Compile with compiler warnings turned on # Compile with compiler warnings turned on
function(pybind11_enable_warnings target_name)
if(MSVC) if(MSVC)
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]") target_compile_options(${target_name} PRIVATE /W4)
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
else() else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") target_compile_options(${target_name} PRIVATE -Wall -Wextra -Wconversion)
endif() endif()
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") endfunction()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wconversion")
if (PYBIND11_TEST)
enable_testing()
add_subdirectory(example)
endif() endif()
if (PYBIND11_INSTALL)
# Check if Eigen is available
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/tools")
find_package(Eigen3 QUIET)
# Include path for pybind11 header files
include_directories(include)
# Include path for Python header files
include_directories(${PYTHON_INCLUDE_DIR})
set(PYBIND11_HEADERS set(PYBIND11_HEADERS
include/pybind11/attr.h include/pybind11/attr.h
include/pybind11/cast.h include/pybind11/cast.h
@ -112,133 +165,5 @@ set(PYBIND11_HEADERS
include/pybind11/typeid.h include/pybind11/typeid.h
) )
set(PYBIND11_EXAMPLES
example/example1.cpp
example/example2.cpp
example/example3.cpp
example/example4.cpp
example/example5.cpp
example/example6.cpp
example/example7.cpp
example/example8.cpp
example/example9.cpp
example/example10.cpp
example/example11.cpp
example/example12.cpp
example/example13.cpp
example/example14.cpp
example/example15.cpp
example/example16.cpp
example/example17.cpp
example/issues.cpp
)
if (EIGEN3_FOUND)
include_directories(${EIGEN3_INCLUDE_DIR})
list(APPEND PYBIND11_EXAMPLES example/eigen.cpp)
add_definitions(-DPYBIND11_TEST_EIGEN)
message(STATUS "Building Eigen testcase")
else()
message(STATUS "NOT Building Eigen testcase")
endif()
# Create the binding library
add_library(example SHARED
${PYBIND11_HEADERS}
example/example.cpp
${PYBIND11_EXAMPLES}
)
# Link against the Python shared library
target_link_libraries(example ${PYTHON_LIBRARY})
# Don't add a 'lib' prefix to the shared library
set_target_properties(example PROPERTIES PREFIX "")
# Always write the output file directly into the 'example' directory (even on MSVC)
set(CompilerFlags
LIBRARY_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY_RELEASE LIBRARY_OUTPUT_DIRECTORY_DEBUG
LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO
RUNTIME_OUTPUT_DIRECTORY RUNTIME_OUTPUT_DIRECTORY_RELEASE RUNTIME_OUTPUT_DIRECTORY_DEBUG
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO)
foreach(CompilerFlag ${CompilerFlags})
set_target_properties(example PROPERTIES ${CompilerFlag} ${PROJECT_SOURCE_DIR}/example)
endforeach()
if (WIN32)
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 example APPEND PROPERTY COMPILE_OPTIONS /MP /bigobj)
# Enforce size-based optimization and link time code generation on MSVC
# (~30% smaller binaries in experiments); do nothing in debug mode.
set_property(TARGET example APPEND PROPERTY COMPILE_OPTIONS
"$<$<CONFIG:Release>:/Os>" "$<$<CONFIG:Release>:/GL>"
"$<$<CONFIG:MinSizeRel>:/Os>" "$<$<CONFIG:MinSizeRel>:/GL>"
"$<$<CONFIG:RelWithDebInfo>:/Os>" "$<$<CONFIG:RelWithDebInfo>:/GL>"
)
set_property(TARGET example APPEND_STRING PROPERTY LINK_FLAGS_RELEASE "/LTCG ")
set_property(TARGET example APPEND_STRING PROPERTY LINK_FLAGS_MINSIZEREL "/LTCG ")
set_property(TARGET example APPEND_STRING PROPERTY LINK_FLAGS_RELWITHDEBINFO "/LTCG ")
endif()
# .PYD file extension on Windows
set_target_properties(example PROPERTIES SUFFIX ".pyd")
elseif (UNIX)
# It's quite common to have multiple copies of the same Python version
# installed on one's system. E.g.: one copy from the OS and another copy
# that's statically linked into an application like Blender or Maya.
# If we link our plugin library against the OS Python here and import it
# into Blender or Maya later on, this will cause segfaults when multiple
# conflicting Python instances are active at the same time (even when they
# are of the same version).
# Windows is not affected by this issue since it handles DLL imports
# differently. The solution for Linux and Mac OS is simple: we just don't
# link against the Python library. The resulting shared library will have
# missing symbols, but that's perfectly fine -- they will be resolved at
# import time.
# .DLL file extension on Cygwin, .SO file extension on Linux/Mac OS
if (CYGWIN)
set(SUFFIX ".dll")
else()
set(SUFFIX ".so")
endif()
set_target_properties(example PROPERTIES SUFFIX ${SUFFIX})
# Optimize for a small binary size
if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG)
set_target_properties(example PROPERTIES COMPILE_FLAGS "-Os")
endif()
# Strip unnecessary sections of the binary on Linux/Mac OS
if(APPLE)
set_target_properties(example PROPERTIES MACOSX_RPATH ".")
set_target_properties(example PROPERTIES LINK_FLAGS "-undefined dynamic_lookup ")
if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG)
add_custom_command(TARGET example POST_BUILD COMMAND strip -u -r ${PROJECT_SOURCE_DIR}/example/example${SUFFIX})
endif()
else()
if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG)
add_custom_command(TARGET example POST_BUILD COMMAND strip ${PROJECT_SOURCE_DIR}/example/example${SUFFIX})
endif()
endif()
endif()
enable_testing()
set(RUN_TEST ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example/run_test.py)
if (MSVC OR CMAKE_CXX_COMPILER_ID MATCHES "Intel")
set(RUN_TEST ${RUN_TEST} --relaxed)
endif()
foreach(VALUE ${PYBIND11_EXAMPLES})
string(REGEX REPLACE "^example/(.+).cpp$" "\\1" EXAMPLE_NAME "${VALUE}")
add_test(NAME ${EXAMPLE_NAME} COMMAND ${RUN_TEST} ${EXAMPLE_NAME})
endforeach()
if (PYBIND11_INSTALL)
install(FILES ${PYBIND11_HEADERS} DESTINATION include/pybind11) install(FILES ${PYBIND11_HEADERS} DESTINATION include/pybind11)
endif() endif()

View File

@ -90,6 +90,7 @@ In addition to the core functionality, pybind11 provides some extra goodies:
2. GCC (any non-ancient version with C++11 support) 2. GCC (any non-ancient version with C++11 support)
3. Microsoft Visual Studio 2015 or newer 3. Microsoft Visual Studio 2015 or newer
4. Intel C++ compiler v15 or newer 4. Intel C++ compiler v15 or newer
5. Cygwin
## About ## About
@ -101,8 +102,10 @@ Axel Huebl,
@hulucc, @hulucc,
Sergey Lyskov Sergey Lyskov
Johan Mabille, Johan Mabille,
Tomasz Miąsko, and Tomasz Miąsko,
Ben Pritchard. Dean Moldovan,
Ben Pritchard, and
Boris Schäling.
### License ### License

View File

@ -26,146 +26,28 @@ Building with cppimport
Building with CMake Building with CMake
=================== ===================
For C++ codebases that already have an existing CMake-based build system, the For C++ codebases that have an existing CMake-based build system, a Python
following snippet should be a good starting point to create bindings across extension module can be created with just a few lines of code:
platforms. It assumes that the code is located in a file named
:file:`example.cpp`, and that the pybind11 repository is located in a
subdirectory named :file:`pybind11`.
.. code-block:: cmake .. code-block:: cmake
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 2.8.12)
project(example) project(example)
# Add a CMake parameter for choosing a desired Python version add_subdirectory(pybind11)
set(EXAMPLE_PYTHON_VERSION "" CACHE STRING pybind11_add_module(example example.cpp)
"Python version to use for compiling the example library")
include(CheckCXXCompilerFlag) This assumes that the pybind11 repository is located in a subdirectory named
:file:`pybind11` and that the code is located in a file named :file:`example.cpp`.
The CMake command ``add_subdirectory`` will import a function with the signature
``pybind11_add_module(<name> source1 [source2 ...])``. It will take care of all
the details needed to build a Python extension module on any platform.
# Set a default build configuration if none is specified. The target Python version can be selected by setting the ``PYBIND11_PYTHON_VERSION``
# 'MinSizeRel' produces the smallest binaries variable before adding the pybind11 subdirectory. Alternatively, an exact Python
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) installation can be specified by setting ``PYTHON_EXECUTABLE``.
message(STATUS "Setting build type to 'MinSizeRel' as none was specified.")
set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "Choose the type of build." FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
"MinSizeRel" "RelWithDebInfo")
endif()
string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE)
# Try to autodetect Python (can be overridden manually if needed) A working sample project, including a way to invoke CMake from :file:`setup.py` for
set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6 3.7) PyPI integration, can be found in the [cmake_example]_ repository.
if (NOT ${EXAMPLE_PYTHON_VERSION} STREQUAL "")
find_package(PythonLibs ${EXAMPLE_PYTHON_VERSION} EXACT)
if (NOT PYTHONLIBS_FOUND)
find_package(PythonLibs ${EXAMPLE_PYTHON_VERSION} REQUIRED)
endif()
else()
find_package(PythonLibs REQUIRED)
endif()
# The above sometimes returns version numbers like "3.4.3+"; .. [cmake_example] https://github.com/dean0x7d/pybind11_cmake_example
# the "+" must be removed for the next lines to work
string(REPLACE "+" "" PYTHONLIBS_VERSION_STRING "+${PYTHONLIBS_VERSION_STRING}")
# Uncomment the following line if you will also require a matching Python interpreter
# find_package(PythonInterp ${PYTHONLIBS_VERSION_STRING} EXACT REQUIRED)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
CHECK_CXX_COMPILER_FLAG("-std=c++14" HAS_CPP14_FLAG)
CHECK_CXX_COMPILER_FLAG("-std=c++11" HAS_CPP11_FLAG)
if (HAS_CPP14_FLAG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
elseif (HAS_CPP11_FLAG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
else()
message(FATAL_ERROR "Unsupported compiler -- at least C++11 support is needed!")
endif()
# Enable link time optimization and set the default symbol
# visibility to hidden (very important to obtain small binaries)
if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG)
# Default symbol visibility
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
# Check for Link Time Optimization support
CHECK_CXX_COMPILER_FLAG("-flto" HAS_LTO_FLAG)
if (HAS_LTO_FLAG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto")
endif()
endif()
endif()
# Include path for Python header files
include_directories(${PYTHON_INCLUDE_DIR})
# Include path for pybind11 header files -- this may need to be
# changed depending on your setup
include_directories(${PROJECT_SOURCE_DIR}/pybind11/include)
# Create the binding library
add_library(example SHARED
example.cpp
# ... extra files go here ...
)
# Don't add a 'lib' prefix to the shared library
set_target_properties(example PROPERTIES PREFIX "")
if (WIN32)
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 example APPEND PROPERTY COMPILE_OPTIONS /MP /bigobj)
# Enforce size-based optimization and link time code generation on MSVC
# (~30% smaller binaries in experiments); do nothing in debug mode.
set_property(TARGET example APPEND PROPERTY COMPILE_OPTIONS
"$<$<CONFIG:Release>:/Os>" "$<$<CONFIG:Release>:/GL>"
"$<$<CONFIG:MinSizeRel>:/Os>" "$<$<CONFIG:MinSizeRel>:/GL>"
"$<$<CONFIG:RelWithDebInfo>:/Os>" "$<$<CONFIG:RelWithDebInfo>:/GL>"
)
set_property(TARGET example APPEND_STRING PROPERTY LINK_FLAGS_RELEASE "/LTCG ")
set_property(TARGET example APPEND_STRING PROPERTY LINK_FLAGS_MINSIZEREL "/LTCG ")
set_property(TARGET example APPEND_STRING PROPERTY LINK_FLAGS_RELWITHDEBINFO "/LTCG ")
endif()
# .PYD file extension on Windows
set_target_properties(example PROPERTIES SUFFIX ".pyd")
# Link against the Python shared library
target_link_libraries(example ${PYTHON_LIBRARY})
elseif (UNIX)
# It's quite common to have multiple copies of the same Python version
# installed on one's system. E.g.: one copy from the OS and another copy
# that's statically linked into an application like Blender or Maya.
# If we link our plugin library against the OS Python here and import it
# into Blender or Maya later on, this will cause segfaults when multiple
# conflicting Python instances are active at the same time (even when they
# are of the same version).
# Windows is not affected by this issue since it handles DLL imports
# differently. The solution for Linux and Mac OS is simple: we just don't
# link against the Python library. The resulting shared library will have
# missing symbols, but that's perfectly fine -- they will be resolved at
# import time.
# .SO file extension on Linux/Mac OS
set_target_properties(example PROPERTIES SUFFIX ".so")
# Strip unnecessary sections of the binary on Linux/Mac OS
if(APPLE)
set_target_properties(example PROPERTIES MACOSX_RPATH ".")
set_target_properties(example PROPERTIES LINK_FLAGS "-undefined dynamic_lookup ")
if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG)
add_custom_command(TARGET example POST_BUILD
COMMAND strip -u -r ${PROJECT_BINARY_DIR}/example.so)
endif()
else()
if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG)
add_custom_command(TARGET example POST_BUILD
COMMAND strip ${PROJECT_BINARY_DIR}/example.so)
endif()
endif()
endif()

68
example/CMakeLists.txt Normal file
View File

@ -0,0 +1,68 @@
# Set a default build configuration if none is specified. 'MinSizeRel' produces the smallest binaries
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to 'MinSizeRel' as none was specified.")
set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "Choose the type of build." FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
"MinSizeRel" "RelWithDebInfo")
endif()
set(PYBIND11_EXAMPLES
example1.cpp
example2.cpp
example3.cpp
example4.cpp
example5.cpp
example6.cpp
example7.cpp
example8.cpp
example9.cpp
example10.cpp
example11.cpp
example12.cpp
example13.cpp
example14.cpp
example15.cpp
example16.cpp
example17.cpp
issues.cpp
)
# Check if Eigen is available
find_package(Eigen3 QUIET)
if(EIGEN3_FOUND)
list(APPEND PYBIND11_EXAMPLES eigen.cpp)
message(STATUS "Building Eigen testcase")
else()
message(STATUS "NOT Building Eigen testcase")
endif()
# Create the binding library
pybind11_add_module(example example.cpp ${PYBIND11_EXAMPLES})
pybind11_enable_warnings(example)
if(EIGEN3_FOUND)
target_include_directories(example PRIVATE ${EIGEN3_INCLUDE_DIR})
target_compile_definitions(example PRIVATE -DPYBIND11_TEST_EIGEN)
endif()
# Always write the output file directly into the 'example' directory (even on MSVC)
set(CompilerFlags
LIBRARY_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY_RELEASE LIBRARY_OUTPUT_DIRECTORY_DEBUG
LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO
RUNTIME_OUTPUT_DIRECTORY RUNTIME_OUTPUT_DIRECTORY_RELEASE RUNTIME_OUTPUT_DIRECTORY_DEBUG
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO)
foreach(CompilerFlag ${CompilerFlags})
set_target_properties(example PROPERTIES ${CompilerFlag} ${PROJECT_SOURCE_DIR}/example)
endforeach()
set(RUN_TEST ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/run_test.py)
if(MSVC OR CMAKE_CXX_COMPILER_ID MATCHES "Intel")
set(RUN_TEST ${RUN_TEST} --relaxed)
endif()
foreach(VALUE ${PYBIND11_EXAMPLES})
string(REGEX REPLACE "^(.+).cpp$" "\\1" EXAMPLE_NAME "${VALUE}")
add_test(NAME ${EXAMPLE_NAME} COMMAND ${RUN_TEST} ${EXAMPLE_NAME})
endforeach()

View File

@ -133,22 +133,22 @@ void init_ex6(py::module &m) {
.def("__reversed__", [](const Sequence &s) -> Sequence { return s.reversed(); }) .def("__reversed__", [](const Sequence &s) -> Sequence { return s.reversed(); })
/// Slicing protocol (optional) /// Slicing protocol (optional)
.def("__getitem__", [](const Sequence &s, py::slice slice) -> Sequence* { .def("__getitem__", [](const Sequence &s, py::slice slice) -> Sequence* {
py::ssize_t start, stop, step, slicelength; size_t start, stop, step, slicelength;
if (!slice.compute(s.size(), &start, &stop, &step, &slicelength)) if (!slice.compute(s.size(), &start, &stop, &step, &slicelength))
throw py::error_already_set(); throw py::error_already_set();
Sequence *seq = new Sequence(slicelength); Sequence *seq = new Sequence(slicelength);
for (int i=0; i<slicelength; ++i) { for (size_t i=0; i<slicelength; ++i) {
(*seq)[i] = s[start]; start += step; (*seq)[i] = s[start]; start += step;
} }
return seq; return seq;
}) })
.def("__setitem__", [](Sequence &s, py::slice slice, const Sequence &value) { .def("__setitem__", [](Sequence &s, py::slice slice, const Sequence &value) {
py::ssize_t start, stop, step, slicelength; size_t start, stop, step, slicelength;
if (!slice.compute(s.size(), &start, &stop, &step, &slicelength)) if (!slice.compute(s.size(), &start, &stop, &step, &slicelength))
throw py::error_already_set(); throw py::error_already_set();
if ((size_t) slicelength != value.size()) if (slicelength != value.size())
throw std::runtime_error("Left and right hand size of slice assignment have different sizes!"); throw std::runtime_error("Left and right hand size of slice assignment have different sizes!");
for (int i=0; i<slicelength; ++i) { for (size_t i=0; i<slicelength; ++i) {
s[start] = value[i]; start += step; s[start] = value[i]; start += step;
} }
}) })

View File

@ -471,13 +471,13 @@ public:
ssize_t length; ssize_t length;
int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(load_src.ptr(), &buffer, &length); int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(load_src.ptr(), &buffer, &length);
if (err == -1) { PyErr_Clear(); return false; } // TypeError if (err == -1) { PyErr_Clear(); return false; } // TypeError
value = std::string(buffer, length); value = std::string(buffer, (size_t) length);
success = true; success = true;
return true; return true;
} }
static handle cast(const std::string &src, return_value_policy /* policy */, handle /* parent */) { static handle cast(const std::string &src, return_value_policy /* policy */, handle /* parent */) {
return PyUnicode_FromStringAndSize(src.c_str(), src.length()); return PyUnicode_FromStringAndSize(src.c_str(), (ssize_t) src.length());
} }
PYBIND11_TYPE_CASTER(std::string, _(PYBIND11_STRING_NAME)); PYBIND11_TYPE_CASTER(std::string, _(PYBIND11_STRING_NAME));
@ -520,17 +520,17 @@ public:
if (temp) { if (temp) {
int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), (char **) &buffer, &length); int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), (char **) &buffer, &length);
if (err == -1) { buffer = nullptr; } // TypeError if (err == -1) { buffer = nullptr; } // TypeError
length = length / sizeof(wchar_t) - 1; ++buffer; // Skip BOM length = length / (ssize_t) sizeof(wchar_t) - 1; ++buffer; // Skip BOM
} }
#endif #endif
if (!buffer) { PyErr_Clear(); return false; } if (!buffer) { PyErr_Clear(); return false; }
value = std::wstring(buffer, length); value = std::wstring(buffer, (size_t) length);
success = true; success = true;
return true; return true;
} }
static handle cast(const std::wstring &src, return_value_policy /* policy */, handle /* parent */) { static handle cast(const std::wstring &src, return_value_policy /* policy */, handle /* parent */) {
return PyUnicode_FromWideChar(src.c_str(), src.length()); return PyUnicode_FromWideChar(src.c_str(), (ssize_t) src.length());
} }
PYBIND11_TYPE_CASTER(std::wstring, _(PYBIND11_STRING_NAME)); PYBIND11_TYPE_CASTER(std::wstring, _(PYBIND11_STRING_NAME));
@ -570,7 +570,7 @@ public:
static handle cast(const wchar_t *src, return_value_policy /* policy */, handle /* parent */) { static handle cast(const wchar_t *src, return_value_policy /* policy */, handle /* parent */) {
if (src == nullptr) return handle(Py_None).inc_ref(); if (src == nullptr) return handle(Py_None).inc_ref();
return PyUnicode_FromWideChar(src, wcslen(src)); return PyUnicode_FromWideChar(src, (ssize_t) wcslen(src));
} }
static handle cast(wchar_t src, return_value_policy /* policy */, handle /* parent */) { static handle cast(wchar_t src, return_value_policy /* policy */, handle /* parent */) {

View File

@ -197,22 +197,23 @@ struct buffer_info {
size_t itemsize; // Size of individual items in bytes size_t itemsize; // Size of individual items in bytes
size_t size; // Total number of entries size_t size; // Total number of entries
std::string format; // For homogeneous buffers, this should be set to format_descriptor<T>::value std::string format; // For homogeneous buffers, this should be set to format_descriptor<T>::value
int ndim; // Number of dimensions size_t ndim; // Number of dimensions
std::vector<size_t> shape; // Shape of the tensor (1 entry per dimension) std::vector<size_t> shape; // Shape of the tensor (1 entry per dimension)
std::vector<size_t> strides; // Number of entries between adjacent entries (for each per dimension) std::vector<size_t> strides; // Number of entries between adjacent entries (for each per dimension)
buffer_info() : ptr(nullptr), view(nullptr) {} buffer_info() : ptr(nullptr), view(nullptr) {}
buffer_info(void *ptr, size_t itemsize, const std::string &format, int ndim, buffer_info(void *ptr, size_t itemsize, const std::string &format, size_t ndim,
const std::vector<size_t> &shape, const std::vector<size_t> &strides) const std::vector<size_t> &shape, const std::vector<size_t> &strides)
: ptr(ptr), itemsize(itemsize), size(1), format(format), : ptr(ptr), itemsize(itemsize), size(1), format(format),
ndim(ndim), shape(shape), strides(strides) { ndim(ndim), shape(shape), strides(strides) {
for (int i=0; i<ndim; ++i) size *= shape[i]; for (size_t i = 0; i < ndim; ++i)
size *= shape[i];
} }
buffer_info(Py_buffer *view) buffer_info(Py_buffer *view)
: ptr(view->buf), itemsize(view->itemsize), size(1), format(view->format), : ptr(view->buf), itemsize((size_t) view->itemsize), size(1), format(view->format),
ndim(view->ndim), shape(view->ndim), strides(view->ndim), view(view) { ndim((size_t) view->ndim), shape((size_t) view->ndim), strides((size_t) view->ndim), view(view) {
for (int i = 0; i < view->ndim; ++i) { for (size_t i = 0; i < (size_t) view->ndim; ++i) {
shape[i] = (size_t) view->shape[i]; shape[i] = (size_t) view->shape[i];
strides[i] = (size_t) view->strides[i]; strides[i] = (size_t) view->strides[i];
size *= shape[i]; size *= shape[i];

View File

@ -10,9 +10,19 @@
#pragma once #pragma once
#include "numpy.h" #include "numpy.h"
#if defined(__GNUG__) || defined(__clang__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wconversion"
#endif
#include <Eigen/Core> #include <Eigen/Core>
#include <Eigen/SparseCore> #include <Eigen/SparseCore>
#if defined(__GNUG__) || defined(__clang__)
# pragma GCC diagnostic pop
#endif
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma warning(push) #pragma warning(push)
#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant #pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
@ -63,7 +73,7 @@ struct type_caster<Type, typename std::enable_if<is_eigen_dense<Type>::value>::t
auto strides = Strides(info.strides[0] / sizeof(Scalar), 0); auto strides = Strides(info.strides[0] / sizeof(Scalar), 0);
value = Eigen::Map<Type, 0, Strides>( value = Eigen::Map<Type, 0, Strides>(
(Scalar *) info.ptr, info.shape[0], 1, strides); (Scalar *) info.ptr, typename Strides::Index(info.shape[0]), 1, strides);
} else if (info.ndim == 2) { } else if (info.ndim == 2) {
typedef Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic> Strides; typedef Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic> Strides;
@ -76,7 +86,9 @@ struct type_caster<Type, typename std::enable_if<is_eigen_dense<Type>::value>::t
info.strides[rowMajor ? 1 : 0] / sizeof(Scalar)); info.strides[rowMajor ? 1 : 0] / sizeof(Scalar));
value = Eigen::Map<Type, 0, Strides>( value = Eigen::Map<Type, 0, Strides>(
(Scalar *) info.ptr, info.shape[0], info.shape[1], strides); (Scalar *) info.ptr,
typename Strides::Index(info.shape[0]),
typename Strides::Index(info.shape[1]), strides);
} else { } else {
return false; return false;
} }
@ -117,8 +129,8 @@ struct type_caster<Type, typename std::enable_if<is_eigen_dense<Type>::value>::t
{ (size_t) src.rows(), { (size_t) src.rows(),
(size_t) src.cols() }, (size_t) src.cols() },
/* Strides (in bytes) for each index */ /* Strides (in bytes) for each index */
{ sizeof(Scalar) * (rowMajor ? src.cols() : 1), { sizeof(Scalar) * (rowMajor ? (size_t) src.cols() : 1),
sizeof(Scalar) * (rowMajor ? 1 : src.rows()) } sizeof(Scalar) * (rowMajor ? 1 : (size_t) src.rows()) }
)).release(); )).release();
} }
} }

View File

@ -109,7 +109,7 @@ public:
if (descr == nullptr) if (descr == nullptr)
pybind11_fail("NumPy: unsupported buffer format '" + info.format + "'!"); pybind11_fail("NumPy: unsupported buffer format '" + info.format + "'!");
object tmp(api.PyArray_NewFromDescr_( object tmp(api.PyArray_NewFromDescr_(
api.PyArray_Type_, descr, info.ndim, (Py_intptr_t *) &info.shape[0], api.PyArray_Type_, descr, (int) info.ndim, (Py_intptr_t *) &info.shape[0],
(Py_intptr_t *) &info.strides[0], info.ptr, 0, nullptr), false); (Py_intptr_t *) &info.strides[0], info.ptr, 0, nullptr), false);
if (info.ptr && tmp) if (info.ptr && tmp)
tmp = object(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */), false); tmp = object(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */), false);
@ -261,7 +261,7 @@ private:
while (buffer_shape_iter != buffer.shape.rend()) { while (buffer_shape_iter != buffer.shape.rend()) {
if (*shape_iter == *buffer_shape_iter) if (*shape_iter == *buffer_shape_iter)
*strides_iter = static_cast<int>(*buffer_strides_iter); *strides_iter = static_cast<size_t>(*buffer_strides_iter);
else else
*strides_iter = 0; *strides_iter = 0;
@ -286,12 +286,12 @@ private:
}; };
template <size_t N> template <size_t N>
bool broadcast(const std::array<buffer_info, N>& buffers, int& ndim, std::vector<size_t>& shape) { bool broadcast(const std::array<buffer_info, N>& buffers, size_t& ndim, std::vector<size_t>& shape) {
ndim = std::accumulate(buffers.begin(), buffers.end(), 0, [](int res, const buffer_info& buf) { ndim = std::accumulate(buffers.begin(), buffers.end(), size_t(0), [](size_t res, const buffer_info& buf) {
return std::max(res, buf.ndim); return std::max(res, buf.ndim);
}); });
shape = std::vector<size_t>(static_cast<size_t>(ndim), 1); shape = std::vector<size_t>(ndim, 1);
bool trivial_broadcast = true; bool trivial_broadcast = true;
for (size_t i = 0; i < N; ++i) { for (size_t i = 0; i < N; ++i) {
auto res_iter = shape.rbegin(); auto res_iter = shape.rbegin();
@ -329,7 +329,7 @@ struct vectorize_helper {
std::array<buffer_info, N> buffers {{ args.request()... }}; std::array<buffer_info, N> buffers {{ args.request()... }};
/* Determine dimensions parameters of output array */ /* Determine dimensions parameters of output array */
int ndim = 0; size_t ndim = 0;
std::vector<size_t> shape(0); std::vector<size_t> shape(0);
bool trivial_broadcast = broadcast(buffers, ndim, shape); bool trivial_broadcast = broadcast(buffers, ndim, shape);
@ -337,7 +337,7 @@ struct vectorize_helper {
std::vector<size_t> strides(ndim); std::vector<size_t> strides(ndim);
if (ndim > 0) { if (ndim > 0) {
strides[ndim-1] = sizeof(Return); strides[ndim-1] = sizeof(Return);
for (int i = ndim - 1; i > 0; --i) { for (size_t i = ndim - 1; i > 0; --i) {
strides[i - 1] = strides[i] * shape[i]; strides[i - 1] = strides[i] * shape[i];
size *= shape[i]; size *= shape[i];
} }

View File

@ -336,8 +336,8 @@ protected:
*it = overloads; *it = overloads;
/* Need to know how many arguments + keyword arguments there are to pick the right overload */ /* Need to know how many arguments + keyword arguments there are to pick the right overload */
size_t nargs = PyTuple_GET_SIZE(args), size_t nargs = (size_t) PyTuple_GET_SIZE(args),
nkwargs = kwargs ? PyDict_Size(kwargs) : 0; nkwargs = kwargs ? (size_t) PyDict_Size(kwargs) : 0;
handle parent = nargs > 0 ? PyTuple_GET_ITEM(args, 0) : nullptr, handle parent = nargs > 0 ? PyTuple_GET_ITEM(args, 0) : nullptr,
result = PYBIND11_TRY_NEXT_OVERLOAD; result = PYBIND11_TRY_NEXT_OVERLOAD;
@ -547,7 +547,7 @@ protected:
: std::string(rec->name)); : std::string(rec->name));
/* Basic type attributes */ /* Basic type attributes */
type->ht_type.tp_name = strdup(full_name.c_str()); type->ht_type.tp_name = strdup(full_name.c_str());
type->ht_type.tp_basicsize = rec->instance_size; type->ht_type.tp_basicsize = (ssize_t) rec->instance_size;
type->ht_type.tp_base = (PyTypeObject *) rec->base_handle.ptr(); type->ht_type.tp_base = (PyTypeObject *) rec->base_handle.ptr();
rec->base_handle.inc_ref(); rec->base_handle.inc_ref();
@ -702,14 +702,14 @@ protected:
view->ndim = 1; view->ndim = 1;
view->internal = info; view->internal = info;
view->buf = info->ptr; view->buf = info->ptr;
view->itemsize = info->itemsize; view->itemsize = (ssize_t) info->itemsize;
view->len = view->itemsize; view->len = view->itemsize;
for (auto s : info->shape) for (auto s : info->shape)
view->len *= s; view->len *= s;
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
view->format = const_cast<char *>(info->format.c_str()); view->format = const_cast<char *>(info->format.c_str());
if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) { if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
view->ndim = info->ndim; view->ndim = (int) info->ndim;
view->strides = (ssize_t *) &info->strides[0]; view->strides = (ssize_t *) &info->strides[0];
view->shape = (ssize_t *) &info->shape[0]; view->shape = (ssize_t *) &info->shape[0];
} }

View File

@ -336,7 +336,7 @@ public:
PYBIND11_OBJECT_DEFAULT(str, object, detail::PyUnicode_Check_Permissive) PYBIND11_OBJECT_DEFAULT(str, object, detail::PyUnicode_Check_Permissive)
str(const std::string &s) str(const std::string &s)
: object(PyUnicode_FromStringAndSize(s.c_str(), s.length()), false) { : object(PyUnicode_FromStringAndSize(s.c_str(), (ssize_t) s.length()), false) {
if (!m_ptr) pybind11_fail("Could not allocate string object!"); if (!m_ptr) pybind11_fail("Could not allocate string object!");
} }
@ -352,7 +352,7 @@ public:
int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length); int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length);
if (err == -1) if (err == -1)
pybind11_fail("Unable to extract string contents! (invalid type)"); pybind11_fail("Unable to extract string contents! (invalid type)");
return std::string(buffer, length); return std::string(buffer, (size_t) length);
} }
}; };
@ -370,7 +370,7 @@ public:
PYBIND11_OBJECT_DEFAULT(bytes, object, PYBIND11_BYTES_CHECK) PYBIND11_OBJECT_DEFAULT(bytes, object, PYBIND11_BYTES_CHECK)
bytes(const std::string &s) bytes(const std::string &s)
: object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(s.data(), s.size()), false) { : object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(s.data(), (ssize_t) s.size()), false) {
if (!m_ptr) pybind11_fail("Could not allocate bytes object!"); if (!m_ptr) pybind11_fail("Could not allocate bytes object!");
} }
@ -380,7 +380,7 @@ public:
int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length); int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length);
if (err == -1) if (err == -1)
pybind11_fail("Unable to extract bytes contents!"); pybind11_fail("Unable to extract bytes contents!");
return std::string(buffer, length); return std::string(buffer, (size_t) length);
} }
}; };
@ -463,9 +463,12 @@ public:
m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr()); m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr());
if (!m_ptr) pybind11_fail("Could not allocate slice object!"); if (!m_ptr) pybind11_fail("Could not allocate slice object!");
} }
bool compute(ssize_t length, ssize_t *start, ssize_t *stop, ssize_t *step, ssize_t *slicelength) const { bool compute(size_t length, size_t *start, size_t *stop, size_t *step,
return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr, length, size_t *slicelength) const {
start, stop, step, slicelength) == 0; return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr,
(ssize_t) length, (ssize_t *) start,
(ssize_t *) stop, (ssize_t *) step,
(ssize_t *) slicelength) == 0;
} }
}; };

View File

@ -135,6 +135,7 @@ template <typename T, typename Allocator = std::allocator<T>, typename holder_ty
pybind11::class_<std::vector<T, Allocator>, holder_type> bind_vector(pybind11::module &m, std::string const &name, Args&&... args) { pybind11::class_<std::vector<T, Allocator>, holder_type> bind_vector(pybind11::module &m, std::string const &name, Args&&... args) {
using Vector = std::vector<T, Allocator>; using Vector = std::vector<T, Allocator>;
using SizeType = typename Vector::size_type; using SizeType = typename Vector::size_type;
using DiffType = typename Vector::difference_type;
using Class_ = pybind11::class_<Vector, holder_type>; using Class_ = pybind11::class_<Vector, holder_type>;
Class_ cl(m, name.c_str(), std::forward<Args>(args)...); Class_ cl(m, name.c_str(), std::forward<Args>(args)...);
@ -176,7 +177,7 @@ pybind11::class_<std::vector<T, Allocator>, holder_type> bind_vector(pybind11::m
cl.def("insert", cl.def("insert",
[](Vector &v, SizeType i, const T &x) { [](Vector &v, SizeType i, const T &x) {
v.insert(v.begin() + i, x); v.insert(v.begin() + (DiffType) i, x);
}, },
arg("i") , arg("x"), arg("i") , arg("x"),
"Insert an item at a given position." "Insert an item at a given position."
@ -198,7 +199,7 @@ pybind11::class_<std::vector<T, Allocator>, holder_type> bind_vector(pybind11::m
if (i >= v.size()) if (i >= v.size())
throw pybind11::index_error(); throw pybind11::index_error();
T t = v[i]; T t = v[i];
v.erase(v.begin() + i); v.erase(v.begin() + (DiffType) i);
return t; return t;
}, },
arg("i"), arg("i"),
@ -232,7 +233,7 @@ pybind11::class_<std::vector<T, Allocator>, holder_type> bind_vector(pybind11::m
[](Vector &v, SizeType i) { [](Vector &v, SizeType i) {
if (i >= v.size()) if (i >= v.size())
throw pybind11::index_error(); throw pybind11::index_error();
v.erase(v.begin() + i); v.erase(v.begin() + typename Vector::difference_type(i));
}, },
"Delete list elements using a slice object" "Delete list elements using a slice object"
); );
@ -249,7 +250,7 @@ pybind11::class_<std::vector<T, Allocator>, holder_type> bind_vector(pybind11::m
/// Slicing protocol /// Slicing protocol
cl.def("__getitem__", cl.def("__getitem__",
[](const Vector &v, slice slice) -> Vector * { [](const Vector &v, slice slice) -> Vector * {
ssize_t start, stop, step, slicelength; size_t start, stop, step, slicelength;
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
throw pybind11::error_already_set(); throw pybind11::error_already_set();
@ -257,7 +258,7 @@ pybind11::class_<std::vector<T, Allocator>, holder_type> bind_vector(pybind11::m
Vector *seq = new Vector(); Vector *seq = new Vector();
seq->reserve((size_t) slicelength); seq->reserve((size_t) slicelength);
for (int i=0; i<slicelength; ++i) { for (size_t i=0; i<slicelength; ++i) {
seq->push_back(v[start]); seq->push_back(v[start]);
start += step; start += step;
} }
@ -269,14 +270,14 @@ pybind11::class_<std::vector<T, Allocator>, holder_type> bind_vector(pybind11::m
cl.def("__setitem__", cl.def("__setitem__",
[](Vector &v, slice slice, const Vector &value) { [](Vector &v, slice slice, const Vector &value) {
ssize_t start, stop, step, slicelength; size_t start, stop, step, slicelength;
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
throw pybind11::error_already_set(); throw pybind11::error_already_set();
if ((size_t) slicelength != value.size()) if (slicelength != value.size())
throw std::runtime_error("Left and right hand size of slice assignment have different sizes!"); throw std::runtime_error("Left and right hand size of slice assignment have different sizes!");
for (int i=0; i<slicelength; ++i) { for (size_t i=0; i<slicelength; ++i) {
v[start] = value[i]; v[start] = value[i];
start += step; start += step;
} }
@ -286,16 +287,16 @@ pybind11::class_<std::vector<T, Allocator>, holder_type> bind_vector(pybind11::m
cl.def("__delitem__", cl.def("__delitem__",
[](Vector &v, slice slice) { [](Vector &v, slice slice) {
ssize_t start, stop, step, slicelength; size_t start, stop, step, slicelength;
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
throw pybind11::error_already_set(); throw pybind11::error_already_set();
if (step == 1 && false) { if (step == 1 && false) {
v.erase(v.begin() + start, v.begin() + start + slicelength); v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength));
} else { } else {
for (ssize_t i = 0; i < slicelength; ++i) { for (size_t i = 0; i < slicelength; ++i) {
v.erase(v.begin() + start); v.erase(v.begin() + DiffType(start));
start += step - 1; start += step - 1;
} }
} }

View File

@ -0,0 +1,187 @@
# - Find python libraries
# This module finds the libraries corresponding to the Python interpeter
# FindPythonInterp provides.
# This code sets the following variables:
#
# PYTHONLIBS_FOUND - have the Python libs been found
# PYTHON_PREFIX - path to the Python installation
# PYTHON_LIBRARIES - path to the python library
# PYTHON_INCLUDE_DIRS - path to where Python.h is found
# PYTHON_SITE_PACKAGES - path to installation site-packages
# PYTHON_IS_DEBUG - whether the Python interpreter is a debug build
#
# PYTHON_INCLUDE_PATH - path to where Python.h is found (deprecated)
#
# A function PYTHON_ADD_MODULE(<name> src1 src2 ... srcN) is defined
# to build modules for python.
#
# Thanks to talljimbo for the patch adding the 'LDVERSION' config
# variable usage.
#=============================================================================
# Copyright 2001-2009 Kitware, Inc.
# Copyright 2012 Continuum Analytics, Inc.
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# * Neither the names of Kitware, Inc., the Insight Software Consortium,
# nor the names of their contributors may be used to endorse or promote
# products derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#=============================================================================
# Use the Python interpreter to find the libs.
if(PythonLibsNew_FIND_REQUIRED)
find_package(PythonInterp ${PythonLibsNew_FIND_VERSION} REQUIRED)
else()
find_package(PythonInterp ${PythonLibsNew_FIND_VERSION})
endif()
if(NOT PYTHONINTERP_FOUND)
set(PYTHONLIBS_FOUND FALSE)
return()
endif()
# According to http://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.
#
# The library suffix is from the config var LDVERSION sometimes, otherwise
# VERSION. VERSION will typically be like "2.7" on unix, and "27" on windows.
execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c"
"from distutils import sysconfig as s;import sys;import struct;
print('.'.join(str(v) for v in sys.version_info));
print(sys.prefix);
print(s.get_python_inc(plat_specific=True));
print(s.get_python_lib(plat_specific=True));
print(s.get_config_var('SO'));
print(hasattr(sys, 'gettotalrefcount')+0);
print(struct.calcsize('@P'));
print(s.get_config_var('LDVERSION') or s.get_config_var('VERSION'));
"
RESULT_VARIABLE _PYTHON_SUCCESS
OUTPUT_VARIABLE _PYTHON_VALUES
ERROR_VARIABLE _PYTHON_ERROR_VALUE
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT _PYTHON_SUCCESS MATCHES 0)
if(PythonLibsNew_FIND_REQUIRED)
message(FATAL_ERROR
"Python config failure:\n${_PYTHON_ERROR_VALUE}")
endif()
set(PYTHONLIBS_FOUND FALSE)
return()
endif()
# Convert the process output into a list
string(REGEX REPLACE ";" "\\\\;" _PYTHON_VALUES ${_PYTHON_VALUES})
string(REGEX REPLACE "\n" ";" _PYTHON_VALUES ${_PYTHON_VALUES})
list(GET _PYTHON_VALUES 0 _PYTHON_VERSION_LIST)
list(GET _PYTHON_VALUES 1 PYTHON_PREFIX)
list(GET _PYTHON_VALUES 2 PYTHON_INCLUDE_DIR)
list(GET _PYTHON_VALUES 3 PYTHON_SITE_PACKAGES)
list(GET _PYTHON_VALUES 4 PYTHON_MODULE_EXTENSION)
list(GET _PYTHON_VALUES 5 PYTHON_IS_DEBUG)
list(GET _PYTHON_VALUES 6 PYTHON_SIZEOF_VOID_P)
list(GET _PYTHON_VALUES 7 PYTHON_LIBRARY_SUFFIX)
# Make sure the Python has the same pointer-size as the chosen compiler
# Skip if CMAKE_SIZEOF_VOID_P is not defined
if(CMAKE_SIZEOF_VOID_P AND (NOT "${PYTHON_SIZEOF_VOID_P}" STREQUAL "${CMAKE_SIZEOF_VOID_P}"))
if(PythonLibsNew_FIND_REQUIRED)
math(EXPR _PYTHON_BITS "${PYTHON_SIZEOF_VOID_P} * 8")
math(EXPR _CMAKE_BITS "${CMAKE_SIZEOF_VOID_P} * 8")
message(FATAL_ERROR
"Python config failure: Python is ${_PYTHON_BITS}-bit, "
"chosen compiler is ${_CMAKE_BITS}-bit")
endif()
set(PYTHONLIBS_FOUND FALSE)
return()
endif()
# The built-in FindPython didn't always give the version numbers
string(REGEX REPLACE "\\." ";" _PYTHON_VERSION_LIST ${_PYTHON_VERSION_LIST})
list(GET _PYTHON_VERSION_LIST 0 PYTHON_VERSION_MAJOR)
list(GET _PYTHON_VERSION_LIST 1 PYTHON_VERSION_MINOR)
list(GET _PYTHON_VERSION_LIST 2 PYTHON_VERSION_PATCH)
# Make sure all directory separators are '/'
string(REGEX REPLACE "\\\\" "/" PYTHON_PREFIX ${PYTHON_PREFIX})
string(REGEX REPLACE "\\\\" "/" PYTHON_INCLUDE_DIR ${PYTHON_INCLUDE_DIR})
string(REGEX REPLACE "\\\\" "/" PYTHON_SITE_PACKAGES ${PYTHON_SITE_PACKAGES})
# TODO: All the nuances of CPython debug builds have not been dealt with/tested.
if(PYTHON_IS_DEBUG)
set(PYTHON_MODULE_EXTENSION "_d${PYTHON_MODULE_EXTENSION}")
endif()
if(CMAKE_HOST_WIN32)
set(PYTHON_LIBRARY
"${PYTHON_PREFIX}/libs/Python${PYTHON_LIBRARY_SUFFIX}.lib")
elseif(APPLE)
set(PYTHON_LIBRARY
"${PYTHON_PREFIX}/lib/libpython${PYTHON_LIBRARY_SUFFIX}.dylib")
else()
if(${PYTHON_SIZEOF_VOID_P} MATCHES 8)
set(_PYTHON_LIBS_SEARCH "${PYTHON_PREFIX}/lib64" "${PYTHON_PREFIX}/lib")
else()
set(_PYTHON_LIBS_SEARCH "${PYTHON_PREFIX}/lib")
endif()
#message(STATUS "Searching for Python libs in ${_PYTHON_LIBS_SEARCH}")
# Probably this needs to be more involved. It would be nice if the config
# information the python interpreter itself gave us were more complete.
find_library(PYTHON_LIBRARY
NAMES "python${PYTHON_LIBRARY_SUFFIX}"
PATHS ${_PYTHON_LIBS_SEARCH}
NO_DEFAULT_PATH)
# If all else fails, just set the name/version and let the linker figure out the path.
if(NOT PYTHON_LIBRARY)
set(PYTHON_LIBRARY python${PYTHON_LIBRARY_SUFFIX})
endif()
endif()
# For backward compatibility, set PYTHON_INCLUDE_PATH, but make it internal.
SET(PYTHON_INCLUDE_PATH "${PYTHON_INCLUDE_DIR}" CACHE INTERNAL
"Path to where Python.h is found (deprecated)")
MARK_AS_ADVANCED(
PYTHON_LIBRARY
PYTHON_INCLUDE_DIR
)
# We use PYTHON_INCLUDE_DIR, PYTHON_LIBRARY and PYTHON_DEBUG_LIBRARY for the
# cache entries because they are meant to specify the location of a single
# library. We now set the variables listed by the documentation for this
# module.
SET(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}")
SET(PYTHON_LIBRARIES "${PYTHON_LIBRARY}")
SET(PYTHON_DEBUG_LIBRARIES "${PYTHON_DEBUG_LIBRARY}")
find_package_message(PYTHON
"Found PythonLibs: ${PYTHON_LIBRARY}"
"${PYTHON_EXECUTABLE}${PYTHON_VERSION}")