diff --git a/.travis.yml b/.travis.yml index e52319742a..b0d8a0e98e 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 diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f10bd3756..b1f4436b73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,187 +5,62 @@ # 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 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) - -# 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) -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) + +include(CheckCXXCompilerFlag) -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") - - # 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") + set(PYBIND11_CPP_STANDARD ${PYBIND11_CPP_STANDARD} CACHE STRING + "C++ standard flag, e.g. -std=c++11 or -std=c++14. Defaults to latest available.") endif() +# Cache variables so pybind11_add_module can be used in parent projects +set(PYBIND11_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/include" CACHE INTERNAL "") +set(PYTHON_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS} CACHE INTERNAL "") +set(PYTHON_LIBRARIES ${PYTHON_LIBRARIES} CACHE INTERNAL "") +set(PYTHON_MODULE_PREFIX ${PYTHON_MODULE_PREFIX} CACHE INTERNAL "") +set(PYTHON_MODULE_EXTENSION ${PYTHON_MODULE_EXTENSION} CACHE INTERNAL "") -# 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} -) - -# Don't add a 'lib' prefix to the shared library -set_target_properties(example PROPERTIES PREFIX "") - -# Always write the output file directly into the 'example' directory (even on MSVC) -set(CompilerFlags - LIBRARY_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY_RELEASE LIBRARY_OUTPUT_DIRECTORY_DEBUG - LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO - RUNTIME_OUTPUT_DIRECTORY RUNTIME_OUTPUT_DIRECTORY_RELEASE RUNTIME_OUTPUT_DIRECTORY_DEBUG - RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO) - -foreach(CompilerFlag ${CompilerFlags}) - set_target_properties(example PROPERTIES ${CompilerFlag} ${PROJECT_SOURCE_DIR}/example) -endforeach() - -if (WIN32) - if (MSVC) - # /MP enables multithreaded builds (relevant when there are many files), /bigobj is - # needed for bigger binding projects due to the limit to 64k addressable sections - set_property(TARGET example APPEND PROPERTY COMPILE_OPTIONS /MP /bigobj) - # Enforce size-based optimization and link time code generation on MSVC - # (~30% smaller binaries in experiments); do nothing in debug mode. - set_property(TARGET example APPEND PROPERTY COMPILE_OPTIONS - "$<$:/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() +# 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}) - # .PYD file extension on Windows - set_target_properties(example PROPERTIES SUFFIX ".pyd") + # 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}") - # 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. @@ -199,41 +74,94 @@ elseif (UNIX) # 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") + if(MSVC) + 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() - # 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) - endif() - else() + 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) - add_custom_command(TARGET example POST_BUILD COMMAND strip ${PROJECT_SOURCE_DIR}/example/example.so) + # 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() -endif() +endfunction() -enable_testing() +# 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() -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) +if (PYBIND11_TEST) + enable_testing() + add_subdirectory(example) 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/docs/compiling.rst b/docs/compiling.rst index 5f4d09836a..5800694aa7 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") - - 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) - - # 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() - - # 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() + add_subdirectory(pybind11) + pybind11_add_module(example example.cpp) + +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. + +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``. + +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. + +.. [cmake_example] https://github.com/dean0x7d/pybind11_cmake_example diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt new file mode 100644 index 0000000000..7e2dc36130 --- /dev/null +++ b/example/CMakeLists.txt @@ -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_turn_on_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() diff --git a/tools/FindPythonLibsNew.cmake b/tools/FindPythonLibsNew.cmake new file mode 100644 index 0000000000..c80432a58b --- /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}")