From 928fff649fa52ebc7b43860a4914f68e320d2bb2 Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Sun, 22 May 2016 19:48:47 +0200 Subject: [PATCH 01/12] Include a more robust FindPythonLibs module for CMake --- CMakeLists.txt | 18 +--- tools/FindPythonLibsNew.cmake | 187 ++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+), 14 deletions(-) create mode 100644 tools/FindPythonLibsNew.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f10bd375..3a45bef87 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,18 +25,9 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) endif() string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/tools") 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) +find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} 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) @@ -86,14 +77,13 @@ 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}) +include_directories(${PYTHON_INCLUDE_DIRS}) set(PYBIND11_HEADERS include/pybind11/attr.h @@ -184,7 +174,7 @@ if (WIN32) set_target_properties(example PROPERTIES SUFFIX ".pyd") # Link against the Python shared library - target_link_libraries(example ${PYTHON_LIBRARY}) + target_link_libraries(example ${PYTHON_LIBRARIES}) 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 diff --git a/tools/FindPythonLibsNew.cmake b/tools/FindPythonLibsNew.cmake new file mode 100644 index 000000000..c80432a58 --- /dev/null +++ b/tools/FindPythonLibsNew.cmake @@ -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( 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}") From 4563e9a8cd67cec4af61129ef811925cf7a214e8 Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Sun, 22 May 2016 22:23:18 +0200 Subject: [PATCH 02/12] Add CMake function pybind11_add_module() The function creates a pybind11 module using the specified source files. --- CMakeLists.txt | 124 ++++++++++++++++++++++++++----------------------- 1 file changed, 66 insertions(+), 58 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a45bef87..8fb13a9fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ # 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) @@ -30,23 +30,9 @@ set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6 3.7) find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} 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) - 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 -- 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") - # Check for Link Time Optimization support # (GCC/Clang) CHECK_CXX_COMPILER_FLAG("-flto" HAS_LTO_FLAG) @@ -75,15 +61,64 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" OR "${CMAKE_CXX_COMPILER_ID}" set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") 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_MODULE_PREFIX ${PYTHON_MODULE_PREFIX} CACHE INTERNAL "") +set(PYTHON_MODULE_EXTENSION ${PYTHON_MODULE_EXTENSION} CACHE INTERNAL "") -# Check if Eigen is available -find_package(Eigen3 QUIET) +# Build a Python extension module: +# pybind11_add_module( 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}) -# Include path for pybind11 header files -include_directories(include) + # 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}") -# Include path for Python header files -include_directories(${PYTHON_INCLUDE_DIRS}) + # 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. + if(MSVC) + target_link_libraries(${target_name} ${PYTHON_LIBRARIES}) + elseif(APPLE) + # Make sure OS X does not have any issues with missing symbols + set_target_properties(${target_name} PROPERTIES MACOSX_RPATH ".") + target_link_libraries(${target_name} PRIVATE "-undefined dynamic_lookup") + endif() + + # Make sure C++11/14 are enabled + if(NOT MSVC) + check_cxx_compiler_flag("-std=c++14" HAS_CPP14_FLAG) + check_cxx_compiler_flag("-std=c++11" HAS_CPP11_FLAG) + + if (HAS_CPP14_FLAG) + target_compile_options(${target_name} PUBLIC "-std=c++14") + elseif (HAS_CPP11_FLAG) + target_compile_options(${target_name} PUBLIC "-std=c++11") + else() + message(FATAL_ERROR "Unsupported compiler -- pybind11 requires C++11 support!") + endif() + + string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE) + if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) + # Default symbol visibility + target_compile_options(${target_name} PRIVATE "-fvisibility=hidden") + endif() + endif() +endfunction() set(PYBIND11_HEADERS include/pybind11/attr.h @@ -123,24 +158,22 @@ set(PYBIND11_EXAMPLES example/issues.cpp ) +# Check if Eigen is available +find_package(Eigen3 QUIET) + 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} -) - -# Don't add a 'lib' prefix to the shared library -set_target_properties(example PROPERTIES PREFIX "") +pybind11_add_module(example example/example.cpp ${PYBIND11_EXAMPLES}) +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 @@ -169,30 +202,7 @@ if (WIN32) 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_LIBRARIES}) 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") - # Optimize for a small binary size if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) set_target_properties(example PROPERTIES COMPILE_FLAGS "-Os") @@ -200,14 +210,12 @@ elseif (UNIX) # 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.so) + add_custom_command(TARGET example POST_BUILD COMMAND strip -u -r $) endif() else() if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) - add_custom_command(TARGET example POST_BUILD COMMAND strip ${PROJECT_SOURCE_DIR}/example/example.so) + add_custom_command(TARGET example POST_BUILD COMMAND strip $) endif() endif() endif() From b4b70a5d62c0e26799f4261a6de713138ad05cb5 Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Sun, 22 May 2016 22:45:11 +0200 Subject: [PATCH 03/12] Update CMake on Travis CI --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index e52319742..b0d8a0e98 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 From 8c6b0b83332c8cb802391ffb08196fa4ebe1ebec Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Mon, 23 May 2016 00:12:37 +0200 Subject: [PATCH 04/12] Don't build tests when project is used via add_subdirectory --- CMakeLists.txt | 182 +++++++---------------------------------- example/CMakeLists.txt | 135 ++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+), 153 deletions(-) create mode 100644 example/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fb13a9fb..806acc4a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,58 +9,24 @@ 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(MASTER_PROJECT OFF) +if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + set(MASTER_PROJECT ON) +endif () + +option(PYBIND11_INSTALL "Install pybind11 header files?" ${MASTER_PROJECT}) +option(PYBIND11_TEST "Build tests?" ${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") 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) - 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) -if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Intel") - # 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) - # Check for Link Time Optimization support - # (GCC/Clang) - CHECK_CXX_COMPILER_FLAG("-flto" HAS_LTO_FLAG) - if (HAS_LTO_FLAG) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -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) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ipo") - 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") -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 "") @@ -120,118 +86,28 @@ function(pybind11_add_module target_name) endif() endfunction() -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 -) - -# Check if Eigen is available -find_package(Eigen3 QUIET) - -if (EIGEN3_FOUND) - list(APPEND PYBIND11_EXAMPLES example/eigen.cpp) - message(STATUS "Building Eigen testcase") -else() - message(STATUS "NOT Building Eigen testcase") +if (PYBIND11_TEST) + enable_testing() + add_subdirectory(example) endif() -# Create the binding library -pybind11_add_module(example example/example.cpp ${PYBIND11_EXAMPLES}) -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() - -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 - "$<$:/Os>" "$<$:/GL>" - "$<$:/Os>" "$<$:/GL>" - "$<$:/Os>" "$<$:/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() -elseif (UNIX) - # 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) - if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) - add_custom_command(TARGET example POST_BUILD COMMAND strip -u -r $) - endif() - else() - if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) - add_custom_command(TARGET example POST_BUILD COMMAND strip $) - 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) + 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() diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt new file mode 100644 index 000000000..d64a05c18 --- /dev/null +++ b/example/CMakeLists.txt @@ -0,0 +1,135 @@ +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) + +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Intel") + # 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) + # Check for Link Time Optimization support + # (GCC/Clang) + CHECK_CXX_COMPILER_FLAG("-flto" HAS_LTO_FLAG) + if(HAS_LTO_FLAG) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -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) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ipo") + 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") +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}) +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() + +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 + "$<$:/Os>" "$<$:/GL>" + "$<$:/Os>" "$<$:/GL>" + "$<$:/Os>" "$<$:/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() +elseif(UNIX) + # 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) + if(NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) + add_custom_command(TARGET example POST_BUILD COMMAND strip -u -r $) + endif() + else() + if(NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) + add_custom_command(TARGET example POST_BUILD COMMAND strip $) + endif() + endif() +endif() + +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() From 03d6a514d2dd49b263ec6a77c3cfaf9a45ba1d5a Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Wed, 25 May 2016 13:39:32 +0200 Subject: [PATCH 05/12] Fix missing variable for Windows build --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 806acc4a1..5720f2ab0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,7 @@ find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} REQUIRED) # 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 "") From 49720f0353f3114f7008582b5177fcd263a7f6d9 Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Thu, 26 May 2016 22:53:38 +0200 Subject: [PATCH 06/12] Add PYBIND11_ prefix to variable and remove redundant OSX property --- CMakeLists.txt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5720f2ab0..65ff9e267 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,13 +10,13 @@ cmake_minimum_required(VERSION 2.8.12) project(pybind11) # Check if pybind11 is being used directly or via add_subdirectory -set(MASTER_PROJECT OFF) +set(PYBIND11_MASTER_PROJECT OFF) if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) - set(MASTER_PROJECT ON) + set(PYBIND11_MASTER_PROJECT ON) endif () -option(PYBIND11_INSTALL "Install pybind11 header files?" ${MASTER_PROJECT}) -option(PYBIND11_TEST "Build tests?" ${MASTER_PROJECT}) +option(PYBIND11_INSTALL "Install pybind11 header files?" ${PYBIND11_MASTER_PROJECT}) +option(PYBIND11_TEST "Build tests?" ${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") @@ -62,7 +62,6 @@ function(pybind11_add_module target_name) target_link_libraries(${target_name} ${PYTHON_LIBRARIES}) elseif(APPLE) # Make sure OS X does not have any issues with missing symbols - set_target_properties(${target_name} PROPERTIES MACOSX_RPATH ".") target_link_libraries(${target_name} PRIVATE "-undefined dynamic_lookup") endif() From 24ddf4b3f13e264369b2f09060306e6eae9b68a5 Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Fri, 27 May 2016 00:11:52 +0200 Subject: [PATCH 07/12] Update CMake build documentation --- docs/compiling.rst | 150 +++++---------------------------------------- 1 file changed, 16 insertions(+), 134 deletions(-) diff --git a/docs/compiling.rst b/docs/compiling.rst index 5f4d09836..5800694aa 100644 --- a/docs/compiling.rst +++ b/docs/compiling.rst @@ -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( 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 - "$<$:/Os>" "$<$:/GL>" - "$<$:/Os>" "$<$:/GL>" - "$<$:/Os>" "$<$:/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 From 9fb50c56d02eae0b345a7964aacb0b4f16c23a54 Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Fri, 27 May 2016 21:42:43 +0200 Subject: [PATCH 08/12] Add LTO and strip to pybind11_add_module --- CMakeLists.txt | 51 ++++++++++++++++++++++++++++-- example/CMakeLists.txt | 71 ++---------------------------------------- 2 files changed, 51 insertions(+), 71 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 65ff9e267..6e9bc8b4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,14 +59,14 @@ function(pybind11_add_module target_name) # missing symbols, but that's perfectly fine -- they will be resolved at # import time. if(MSVC) - target_link_libraries(${target_name} ${PYTHON_LIBRARIES}) + target_link_libraries(${target_name} PRIVATE ${PYTHON_LIBRARIES}) elseif(APPLE) # Make sure OS X does not have any issues with missing symbols target_link_libraries(${target_name} PRIVATE "-undefined dynamic_lookup") endif() - # Make sure C++11/14 are enabled if(NOT MSVC) + # Make sure C++11/14 are enabled check_cxx_compiler_flag("-std=c++14" HAS_CPP14_FLAG) check_cxx_compiler_flag("-std=c++11" HAS_CPP11_FLAG) @@ -78,11 +78,58 @@ function(pybind11_add_module target_name) 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) 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) + 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 $) + else() + add_custom_command(TARGET ${target_name} POST_BUILD + COMMAND ${CMAKE_STRIP} $) + 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 $<$>:/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() + +# Compile with compiler warnings turned on +function(pybind11_turn_on_warnings target_name) + if(MSVC) + target_compile_options(${target_name} PRIVATE /W4) + else() + target_compile_options(${target_name} PRIVATE -Wall -Wextra) endif() endfunction() diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index d64a05c18..7e2dc3613 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -1,5 +1,3 @@ -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.") @@ -7,39 +5,6 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() -string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE) - -if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Intel") - # 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) - # Check for Link Time Optimization support - # (GCC/Clang) - CHECK_CXX_COMPILER_FLAG("-flto" HAS_LTO_FLAG) - if(HAS_LTO_FLAG) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -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) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ipo") - 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") -endif() set(PYBIND11_EXAMPLES example1.cpp @@ -74,6 +39,8 @@ endif() # Create the binding library pybind11_add_module(example example.cpp ${PYBIND11_EXAMPLES}) +pybind11_turn_on_warnings(example) + if(EIGEN3_FOUND) target_include_directories(example PRIVATE ${EIGEN3_INCLUDE_DIR}) target_compile_definitions(example PRIVATE -DPYBIND11_TEST_EIGEN) @@ -90,40 +57,6 @@ 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 - "$<$:/Os>" "$<$:/GL>" - "$<$:/Os>" "$<$:/GL>" - "$<$:/Os>" "$<$:/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() -elseif(UNIX) - # 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) - if(NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) - add_custom_command(TARGET example POST_BUILD COMMAND strip -u -r $) - endif() - else() - if(NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) - add_custom_command(TARGET example POST_BUILD COMMAND strip $) - endif() - endif() -endif() - 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) From c3c27c425951b7c7360bf1b9ac75e5837ef31d15 Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Sat, 28 May 2016 11:08:16 +0200 Subject: [PATCH 09/12] Make C++ standard configurable --- CMakeLists.txt | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e9bc8b4a..b1f4436b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,12 +21,28 @@ option(PYBIND11_TEST "Build tests?" ${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") -include(CheckCXXCompilerFlag) - 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) + +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(PYBIND11_CPP_STANDARD -std=c++14) + elseif (HAS_CPP11_FLAG) + set(PYBIND11_CPP_STANDARD -std=c++11) + else() + message(FATAL_ERROR "Unsupported compiler -- pybind11 requires C++11 support!") + 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 "") @@ -67,16 +83,7 @@ function(pybind11_add_module target_name) if(NOT MSVC) # Make sure C++11/14 are enabled - check_cxx_compiler_flag("-std=c++14" HAS_CPP14_FLAG) - check_cxx_compiler_flag("-std=c++11" HAS_CPP11_FLAG) - - if (HAS_CPP14_FLAG) - target_compile_options(${target_name} PUBLIC "-std=c++14") - elseif (HAS_CPP11_FLAG) - target_compile_options(${target_name} PUBLIC "-std=c++11") - else() - message(FATAL_ERROR "Unsupported compiler -- pybind11 requires C++11 support!") - endif() + 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) From 67a63929875a2f9b1b5d0abd5371819f8f1fb1e9 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Sun, 29 May 2016 12:35:16 +0200 Subject: [PATCH 10/12] very minor cmake adjustments --- CMakeLists.txt | 38 ++++++++++++++++++++------------------ example/CMakeLists.txt | 2 +- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b1f4436b7..accee6d40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,10 +13,10 @@ project(pybind11) set(PYBIND11_MASTER_PROJECT OFF) if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) set(PYBIND11_MASTER_PROJECT ON) -endif () +endif() option(PYBIND11_INSTALL "Install pybind11 header files?" ${PYBIND11_MASTER_PROJECT}) -option(PYBIND11_TEST "Build tests?" ${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") @@ -61,23 +61,24 @@ function(pybind11_add_module target_name) set_target_properties(${target_name} PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}") set_target_properties(${target_name} PROPERTIES SUFFIX "${PYTHON_MODULE_EXTENSION}") - # 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. - if(MSVC) + if(WIN32) + # Link against the Python shared library on Windows target_link_libraries(${target_name} PRIVATE ${PYTHON_LIBRARIES}) elseif(APPLE) - # Make sure OS X does not have any issues with missing symbols + # 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() @@ -124,6 +125,7 @@ function(pybind11_add_module target_name) # Enforce link time code generation on MSVC, except in debug mode target_compile_options(${target_name} PRIVATE $<$>:/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) @@ -132,7 +134,7 @@ function(pybind11_add_module target_name) endfunction() # Compile with compiler warnings turned on -function(pybind11_turn_on_warnings target_name) +function(pybind11_enable_warnings target_name) if(MSVC) target_compile_options(${target_name} PRIVATE /W4) else() diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 7e2dc3613..547dad74f 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -39,7 +39,7 @@ endif() # Create the binding library pybind11_add_module(example example.cpp ${PYBIND11_EXAMPLES}) -pybind11_turn_on_warnings(example) +pybind11_enable_warnings(example) if(EIGEN3_FOUND) target_include_directories(example PRIVATE ${EIGEN3_INCLUDE_DIR}) From 7da7b67478d3bf0e68c6c539bc84cea470093601 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Sun, 29 May 2016 12:37:11 +0200 Subject: [PATCH 11/12] updated contributors in README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 376f56295..08b58bf72 100644 --- a/README.md +++ b/README.md @@ -101,8 +101,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 From 0a07805ab663b981d72bbe2663b946f8c18e67cf Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Sun, 29 May 2016 13:40:40 +0200 Subject: [PATCH 12/12] fixed many conversion warnings on clang --- example/example6.cpp | 10 +++++----- include/pybind11/cast.h | 12 ++++++------ include/pybind11/common.h | 13 +++++++------ include/pybind11/eigen.h | 20 ++++++++++++++++---- include/pybind11/numpy.h | 14 +++++++------- include/pybind11/pybind11.h | 10 +++++----- include/pybind11/pytypes.h | 17 ++++++++++------- include/pybind11/stl_bind.h | 25 +++++++++++++------------ 8 files changed, 69 insertions(+), 52 deletions(-) diff --git a/example/example6.cpp b/example/example6.cpp index 26552b7e3..e0bfb9e70 100644 --- a/example/example6.cpp +++ b/example/example6.cpp @@ -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::value - int ndim; // Number of dimensions + size_t ndim; // Number of dimensions std::vector shape; // Shape of the tensor (1 entry per dimension) std::vector 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 &shape, const std::vector &strides) : ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim), shape(shape), strides(strides) { - for (int i=0; ibuf), 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]; diff --git a/include/pybind11/eigen.h b/include/pybind11/eigen.h index 96daf48dd..006a7b98e 100644 --- a/include/pybind11/eigen.h +++ b/include/pybind11/eigen.h @@ -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 #include +#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::value>::t auto strides = Strides(info.strides[0] / sizeof(Scalar), 0); value = Eigen::Map( - (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 Strides; @@ -76,7 +86,9 @@ struct type_caster::value>::t info.strides[rowMajor ? 1 : 0] / sizeof(Scalar)); value = Eigen::Map( - (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::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(); } } diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index f97c790ad..0180d95cd 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -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(*buffer_strides_iter); + *strides_iter = static_cast(*buffer_strides_iter); else *strides_iter = 0; @@ -286,12 +286,12 @@ private: }; template -bool broadcast(const std::array& buffers, int& ndim, std::vector& shape) { - ndim = std::accumulate(buffers.begin(), buffers.end(), 0, [](int res, const buffer_info& buf) { +bool broadcast(const std::array& buffers, size_t& ndim, std::vector& 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(static_cast(ndim), 1); + shape = std::vector(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 buffers {{ args.request()... }}; /* Determine dimensions parameters of output array */ - int ndim = 0; + size_t ndim = 0; std::vector shape(0); bool trivial_broadcast = broadcast(buffers, ndim, shape); @@ -337,7 +337,7 @@ struct vectorize_helper { std::vector 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]; } diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 7ac9e5c46..00a7fe0bd 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -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(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]; } diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 2ba03c01d..ad9029b1e 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -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; } }; diff --git a/include/pybind11/stl_bind.h b/include/pybind11/stl_bind.h index 37839826d..7de71c8ab 100644 --- a/include/pybind11/stl_bind.h +++ b/include/pybind11/stl_bind.h @@ -135,6 +135,7 @@ template , typename holder_ty pybind11::class_, holder_type> bind_vector(pybind11::module &m, std::string const &name, Args&&... args) { using Vector = std::vector; using SizeType = typename Vector::size_type; + using DiffType = typename Vector::difference_type; using Class_ = pybind11::class_; Class_ cl(m, name.c_str(), std::forward(args)...); @@ -176,7 +177,7 @@ pybind11::class_, 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_, 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_, 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_, 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_, holder_type> bind_vector(pybind11::m Vector *seq = new Vector(); seq->reserve((size_t) slicelength); - for (int i=0; ipush_back(v[start]); start += step; } @@ -269,14 +270,14 @@ pybind11::class_, 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, 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; } }