mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-22 13:15:12 +00:00
Merge branch 'master' into cygwin
This commit is contained in:
commit
3f3ea26215
@ -9,6 +9,7 @@ addons:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- deadsnakes
|
||||
- kubuntu-backports # cmake 2.8.12
|
||||
packages:
|
||||
- g++-4.8
|
||||
- g++-4.8-multilib
|
||||
@ -17,6 +18,7 @@ addons:
|
||||
- python3.5-dev
|
||||
- python3.5-venv
|
||||
- python3.5-dev:i386
|
||||
- cmake
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
|
337
CMakeLists.txt
337
CMakeLists.txt
@ -5,240 +5,165 @@
|
||||
# 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 2.8)
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
|
||||
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
|
||||
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)
|
||||
|
||||
# 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()
|
||||
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(NOT MSVC AND NOT PYBIND11_CPP_STANDARD)
|
||||
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")
|
||||
set(PYBIND11_CPP_STANDARD -std=c++14)
|
||||
elseif (HAS_CPP11_FLAG)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
set(PYBIND11_CPP_STANDARD -std=c++11)
|
||||
else()
|
||||
message(FATAL_ERROR "Unsupported compiler -- pybind11 requires C++11 support!")
|
||||
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")
|
||||
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()
|
||||
|
||||
# Check for Link Time Optimization support
|
||||
# (GCC/Clang)
|
||||
CHECK_CXX_COMPILER_FLAG("-flto" HAS_LTO_FLAG)
|
||||
if (HAS_LTO_FLAG AND NOT CYGWIN)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto")
|
||||
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 "")
|
||||
|
||||
# Intel equivalent to LTO is called IPO
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Intel")
|
||||
CHECK_CXX_COMPILER_FLAG("-ipo" HAS_IPO_FLAG)
|
||||
if (HAS_IPO_FLAG)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ipo")
|
||||
# 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
|
||||
# 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)
|
||||
# Check for Link Time Optimization support (GCC/Clang)
|
||||
check_cxx_compiler_flag("-flto" HAS_LTO_FLAG)
|
||||
if(HAS_LTO_FLAG AND NOT CYGWIN)
|
||||
target_compile_options(${target_name} PRIVATE -flto)
|
||||
endif()
|
||||
|
||||
# Intel equivalent to LTO is called IPO
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
|
||||
check_cxx_compiler_flag("-ipo" HAS_IPO_FLAG)
|
||||
if(HAS_IPO_FLAG)
|
||||
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()
|
||||
|
||||
# Compile with compiler warnings turned on
|
||||
if(MSVC)
|
||||
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
|
||||
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||
endif()
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wconversion")
|
||||
endif()
|
||||
|
||||
|
||||
# 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
|
||||
include/pybind11/attr.h
|
||||
include/pybind11/cast.h
|
||||
include/pybind11/common.h
|
||||
include/pybind11/complex.h
|
||||
include/pybind11/descr.h
|
||||
include/pybind11/eigen.h
|
||||
include/pybind11/functional.h
|
||||
include/pybind11/numpy.h
|
||||
include/pybind11/operators.h
|
||||
include/pybind11/pybind11.h
|
||||
include/pybind11/pytypes.h
|
||||
include/pybind11/stl.h
|
||||
include/pybind11/stl_bind.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)
|
||||
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
|
||||
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 ")
|
||||
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()
|
||||
endfunction()
|
||||
|
||||
# .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")
|
||||
# Compile with compiler warnings turned on
|
||||
function(pybind11_enable_warnings target_name)
|
||||
if(MSVC)
|
||||
target_compile_options(${target_name} PRIVATE /W4)
|
||||
else()
|
||||
set(SUFFIX ".so")
|
||||
target_compile_options(${target_name} PRIVATE -Wall -Wextra -Wconversion)
|
||||
endif()
|
||||
set_target_properties(example PROPERTIES SUFFIX ${SUFFIX})
|
||||
endfunction()
|
||||
|
||||
# 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()
|
||||
if (PYBIND11_TEST)
|
||||
enable_testing()
|
||||
add_subdirectory(example)
|
||||
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)
|
||||
set(PYBIND11_HEADERS
|
||||
include/pybind11/attr.h
|
||||
include/pybind11/cast.h
|
||||
include/pybind11/common.h
|
||||
include/pybind11/complex.h
|
||||
include/pybind11/descr.h
|
||||
include/pybind11/eigen.h
|
||||
include/pybind11/functional.h
|
||||
include/pybind11/numpy.h
|
||||
include/pybind11/operators.h
|
||||
include/pybind11/pybind11.h
|
||||
include/pybind11/pytypes.h
|
||||
include/pybind11/stl.h
|
||||
include/pybind11/stl_bind.h
|
||||
include/pybind11/typeid.h
|
||||
)
|
||||
|
||||
install(FILES ${PYBIND11_HEADERS} DESTINATION include/pybind11)
|
||||
endif()
|
||||
|
@ -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)
|
||||
3. Microsoft Visual Studio 2015 or newer
|
||||
4. Intel C++ compiler v15 or newer
|
||||
5. Cygwin
|
||||
|
||||
## About
|
||||
|
||||
@ -101,8 +102,10 @@ Axel Huebl,
|
||||
@hulucc,
|
||||
Sergey Lyskov
|
||||
Johan Mabille,
|
||||
Tomasz Miąsko, and
|
||||
Ben Pritchard.
|
||||
Tomasz Miąsko,
|
||||
Dean Moldovan,
|
||||
Ben Pritchard, and
|
||||
Boris Schäling.
|
||||
|
||||
### License
|
||||
|
||||
|
@ -26,146 +26,28 @@ Building with cppimport
|
||||
Building with CMake
|
||||
===================
|
||||
|
||||
For C++ codebases that already have an existing CMake-based build system, the
|
||||
following snippet should be a good starting point to create bindings across
|
||||
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`.
|
||||
For C++ codebases that have an existing CMake-based build system, a Python
|
||||
extension module can be created with just a few lines of code:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
project(example)
|
||||
|
||||
# Add a CMake parameter for choosing a desired Python version
|
||||
set(EXAMPLE_PYTHON_VERSION "" CACHE STRING
|
||||
"Python version to use for compiling the example library")
|
||||
add_subdirectory(pybind11)
|
||||
pybind11_add_module(example example.cpp)
|
||||
|
||||
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.
|
||||
# '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()
|
||||
string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE)
|
||||
The target Python version can be selected by setting the ``PYBIND11_PYTHON_VERSION``
|
||||
variable before adding the pybind11 subdirectory. Alternatively, an exact Python
|
||||
installation can be specified by setting ``PYTHON_EXECUTABLE``.
|
||||
|
||||
# Try to autodetect Python (can be overridden manually if needed)
|
||||
set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6 3.7)
|
||||
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()
|
||||
A working sample project, including a way to invoke CMake from :file:`setup.py` for
|
||||
PyPI integration, can be found in the [cmake_example]_ repository.
|
||||
|
||||
# The above sometimes returns version numbers like "3.4.3+";
|
||||
# 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()
|
||||
.. [cmake_example] https://github.com/dean0x7d/pybind11_cmake_example
|
||||
|
68
example/CMakeLists.txt
Normal file
68
example/CMakeLists.txt
Normal 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()
|
@ -133,22 +133,22 @@ void init_ex6(py::module &m) {
|
||||
.def("__reversed__", [](const Sequence &s) -> Sequence { return s.reversed(); })
|
||||
/// Slicing protocol (optional)
|
||||
.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))
|
||||
throw py::error_already_set();
|
||||
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;
|
||||
}
|
||||
return seq;
|
||||
})
|
||||
.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))
|
||||
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!");
|
||||
for (int i=0; i<slicelength; ++i) {
|
||||
for (size_t i=0; i<slicelength; ++i) {
|
||||
s[start] = value[i]; start += step;
|
||||
}
|
||||
})
|
||||
|
@ -471,13 +471,13 @@ public:
|
||||
ssize_t length;
|
||||
int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(load_src.ptr(), &buffer, &length);
|
||||
if (err == -1) { PyErr_Clear(); return false; } // TypeError
|
||||
value = std::string(buffer, length);
|
||||
value = std::string(buffer, (size_t) length);
|
||||
success = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
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));
|
||||
@ -520,17 +520,17 @@ public:
|
||||
if (temp) {
|
||||
int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), (char **) &buffer, &length);
|
||||
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
|
||||
if (!buffer) { PyErr_Clear(); return false; }
|
||||
value = std::wstring(buffer, length);
|
||||
value = std::wstring(buffer, (size_t) length);
|
||||
success = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
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));
|
||||
@ -570,7 +570,7 @@ public:
|
||||
|
||||
static handle cast(const wchar_t *src, return_value_policy /* policy */, handle /* parent */) {
|
||||
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 */) {
|
||||
|
@ -197,22 +197,23 @@ struct buffer_info {
|
||||
size_t itemsize; // Size of individual items in bytes
|
||||
size_t size; // Total number of entries
|
||||
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> strides; // Number of entries between adjacent entries (for each per dimension)
|
||||
|
||||
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)
|
||||
: ptr(ptr), itemsize(itemsize), size(1), format(format),
|
||||
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)
|
||||
: ptr(view->buf), itemsize(view->itemsize), size(1), format(view->format),
|
||||
ndim(view->ndim), shape(view->ndim), strides(view->ndim), view(view) {
|
||||
for (int i = 0; i < view->ndim; ++i) {
|
||||
: ptr(view->buf), itemsize((size_t) view->itemsize), size(1), format(view->format),
|
||||
ndim((size_t) view->ndim), shape((size_t) view->ndim), strides((size_t) view->ndim), view(view) {
|
||||
for (size_t i = 0; i < (size_t) view->ndim; ++i) {
|
||||
shape[i] = (size_t) view->shape[i];
|
||||
strides[i] = (size_t) view->strides[i];
|
||||
size *= shape[i];
|
||||
|
@ -10,9 +10,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "numpy.h"
|
||||
|
||||
#if defined(__GNUG__) || defined(__clang__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wconversion"
|
||||
#endif
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/SparseCore>
|
||||
|
||||
#if defined(__GNUG__) || defined(__clang__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#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);
|
||||
|
||||
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) {
|
||||
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));
|
||||
|
||||
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 {
|
||||
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.cols() },
|
||||
/* Strides (in bytes) for each index */
|
||||
{ sizeof(Scalar) * (rowMajor ? src.cols() : 1),
|
||||
sizeof(Scalar) * (rowMajor ? 1 : src.rows()) }
|
||||
{ sizeof(Scalar) * (rowMajor ? (size_t) src.cols() : 1),
|
||||
sizeof(Scalar) * (rowMajor ? 1 : (size_t) src.rows()) }
|
||||
)).release();
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ public:
|
||||
if (descr == nullptr)
|
||||
pybind11_fail("NumPy: unsupported buffer format '" + info.format + "'!");
|
||||
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);
|
||||
if (info.ptr && tmp)
|
||||
tmp = object(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */), false);
|
||||
@ -261,7 +261,7 @@ private:
|
||||
|
||||
while (buffer_shape_iter != buffer.shape.rend()) {
|
||||
if (*shape_iter == *buffer_shape_iter)
|
||||
*strides_iter = static_cast<int>(*buffer_strides_iter);
|
||||
*strides_iter = static_cast<size_t>(*buffer_strides_iter);
|
||||
else
|
||||
*strides_iter = 0;
|
||||
|
||||
@ -286,12 +286,12 @@ private:
|
||||
};
|
||||
|
||||
template <size_t N>
|
||||
bool broadcast(const std::array<buffer_info, N>& buffers, int& ndim, std::vector<size_t>& shape) {
|
||||
ndim = std::accumulate(buffers.begin(), buffers.end(), 0, [](int res, const buffer_info& buf) {
|
||||
bool broadcast(const std::array<buffer_info, N>& buffers, size_t& ndim, std::vector<size_t>& shape) {
|
||||
ndim = std::accumulate(buffers.begin(), buffers.end(), size_t(0), [](size_t res, const buffer_info& buf) {
|
||||
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;
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
auto res_iter = shape.rbegin();
|
||||
@ -329,7 +329,7 @@ struct vectorize_helper {
|
||||
std::array<buffer_info, N> buffers {{ args.request()... }};
|
||||
|
||||
/* Determine dimensions parameters of output array */
|
||||
int ndim = 0;
|
||||
size_t ndim = 0;
|
||||
std::vector<size_t> shape(0);
|
||||
bool trivial_broadcast = broadcast(buffers, ndim, shape);
|
||||
|
||||
@ -337,7 +337,7 @@ struct vectorize_helper {
|
||||
std::vector<size_t> strides(ndim);
|
||||
if (ndim > 0) {
|
||||
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];
|
||||
size *= shape[i];
|
||||
}
|
||||
|
@ -336,8 +336,8 @@ protected:
|
||||
*it = overloads;
|
||||
|
||||
/* Need to know how many arguments + keyword arguments there are to pick the right overload */
|
||||
size_t nargs = PyTuple_GET_SIZE(args),
|
||||
nkwargs = kwargs ? PyDict_Size(kwargs) : 0;
|
||||
size_t nargs = (size_t) PyTuple_GET_SIZE(args),
|
||||
nkwargs = kwargs ? (size_t) PyDict_Size(kwargs) : 0;
|
||||
|
||||
handle parent = nargs > 0 ? PyTuple_GET_ITEM(args, 0) : nullptr,
|
||||
result = PYBIND11_TRY_NEXT_OVERLOAD;
|
||||
@ -547,7 +547,7 @@ protected:
|
||||
: std::string(rec->name));
|
||||
/* Basic type attributes */
|
||||
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();
|
||||
rec->base_handle.inc_ref();
|
||||
|
||||
@ -702,14 +702,14 @@ protected:
|
||||
view->ndim = 1;
|
||||
view->internal = info;
|
||||
view->buf = info->ptr;
|
||||
view->itemsize = info->itemsize;
|
||||
view->itemsize = (ssize_t) info->itemsize;
|
||||
view->len = view->itemsize;
|
||||
for (auto s : info->shape)
|
||||
view->len *= s;
|
||||
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
|
||||
view->format = const_cast<char *>(info->format.c_str());
|
||||
if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
|
||||
view->ndim = info->ndim;
|
||||
view->ndim = (int) info->ndim;
|
||||
view->strides = (ssize_t *) &info->strides[0];
|
||||
view->shape = (ssize_t *) &info->shape[0];
|
||||
}
|
||||
|
@ -336,7 +336,7 @@ public:
|
||||
PYBIND11_OBJECT_DEFAULT(str, object, detail::PyUnicode_Check_Permissive)
|
||||
|
||||
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!");
|
||||
}
|
||||
|
||||
@ -352,7 +352,7 @@ public:
|
||||
int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length);
|
||||
if (err == -1)
|
||||
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)
|
||||
|
||||
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!");
|
||||
}
|
||||
|
||||
@ -380,7 +380,7 @@ public:
|
||||
int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length);
|
||||
if (err == -1)
|
||||
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());
|
||||
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 {
|
||||
return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr, length,
|
||||
start, stop, step, slicelength) == 0;
|
||||
bool compute(size_t length, size_t *start, size_t *stop, size_t *step,
|
||||
size_t *slicelength) const {
|
||||
return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr,
|
||||
(ssize_t) length, (ssize_t *) start,
|
||||
(ssize_t *) stop, (ssize_t *) step,
|
||||
(ssize_t *) slicelength) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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) {
|
||||
using Vector = std::vector<T, Allocator>;
|
||||
using SizeType = typename Vector::size_type;
|
||||
using DiffType = typename Vector::difference_type;
|
||||
using Class_ = pybind11::class_<Vector, holder_type>;
|
||||
|
||||
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",
|
||||
[](Vector &v, SizeType i, const T &x) {
|
||||
v.insert(v.begin() + i, x);
|
||||
v.insert(v.begin() + (DiffType) i, x);
|
||||
},
|
||||
arg("i") , arg("x"),
|
||||
"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())
|
||||
throw pybind11::index_error();
|
||||
T t = v[i];
|
||||
v.erase(v.begin() + i);
|
||||
v.erase(v.begin() + (DiffType) i);
|
||||
return t;
|
||||
},
|
||||
arg("i"),
|
||||
@ -232,7 +233,7 @@ pybind11::class_<std::vector<T, Allocator>, holder_type> bind_vector(pybind11::m
|
||||
[](Vector &v, SizeType i) {
|
||||
if (i >= v.size())
|
||||
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"
|
||||
);
|
||||
@ -249,7 +250,7 @@ pybind11::class_<std::vector<T, Allocator>, holder_type> bind_vector(pybind11::m
|
||||
/// Slicing protocol
|
||||
cl.def("__getitem__",
|
||||
[](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))
|
||||
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();
|
||||
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]);
|
||||
start += step;
|
||||
}
|
||||
@ -269,14 +270,14 @@ pybind11::class_<std::vector<T, Allocator>, holder_type> bind_vector(pybind11::m
|
||||
|
||||
cl.def("__setitem__",
|
||||
[](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))
|
||||
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!");
|
||||
|
||||
for (int i=0; i<slicelength; ++i) {
|
||||
for (size_t i=0; i<slicelength; ++i) {
|
||||
v[start] = value[i];
|
||||
start += step;
|
||||
}
|
||||
@ -286,16 +287,16 @@ pybind11::class_<std::vector<T, Allocator>, holder_type> bind_vector(pybind11::m
|
||||
|
||||
cl.def("__delitem__",
|
||||
[](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))
|
||||
throw pybind11::error_already_set();
|
||||
|
||||
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 {
|
||||
for (ssize_t i = 0; i < slicelength; ++i) {
|
||||
v.erase(v.begin() + start);
|
||||
for (size_t i = 0; i < slicelength; ++i) {
|
||||
v.erase(v.begin() + DiffType(start));
|
||||
start += step - 1;
|
||||
}
|
||||
}
|
||||
|
187
tools/FindPythonLibsNew.cmake
Normal file
187
tools/FindPythonLibsNew.cmake
Normal 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}")
|
Loading…
Reference in New Issue
Block a user