Skip to content

Commit

Permalink
CMake compiler features now used on CMake 3.8+
Browse files Browse the repository at this point in the history
  • Loading branch information
henryiii committed Apr 10, 2018
1 parent 6c62d27 commit 5b925e9
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 26 deletions.
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ if(NOT (CMAKE_VERSION VERSION_LESS 3.0)) # CMake >= 3.0
target_include_directories(pybind11 INTERFACE $<BUILD_INTERFACE:${PYBIND11_INCLUDE_DIR}>
$<BUILD_INTERFACE:${PYTHON_INCLUDE_DIRS}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
target_compile_options(pybind11 INTERFACE $<BUILD_INTERFACE:${PYBIND11_CPP_STANDARD}>)

_pybind11_target_cxx_std(pybind11)

add_library(module INTERFACE)
add_library(pybind11::module ALIAS module)
Expand Down
4 changes: 4 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ v2.3.0 (Not yet released)
* The ``value()`` method of ``py::enum_`` now accepts an optional docstring
that will be shown in the documentation of the associated enumeration.

* Improved CMake C++ standard discovery for CMake 3.8+, and allow compiler features
to be used on CMake 3.1+. Added C++17 standard check.
`#1098 <https://github.com/pybind/pybind11/pull/1098>`_.

v2.2.2 (February 7, 2018)
-----------------------------------------------------

Expand Down
38 changes: 31 additions & 7 deletions docs/compiling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,32 @@ regular LTO if ``-flto=thin`` is not available.
Configuration variables
-----------------------

By default, pybind11 will compile modules with the C++14 standard, if available
on the target compiler, falling back to C++11 if C++14 support is not
available. Note, however, that this default is subject to change: future
pybind11 releases are expected to migrate to newer C++ standards as they become
available. To override this, the standard flag can be given explicitly in
``PYBIND11_CPP_STANDARD``:
By default, pybind11 will compile modules with the highest C++ standard available
on the target compiler, from the set C++17, C++14, and C++11. With CMake 3.8+, this
uses CMake's compile features mechinism and meta-features to detect your compiler's
abilities. Older CMake versions fall back to manually trying to compile a mini-program
with each flag.

If you want to override this behavior, you have three options:

CMake 3.1+: If you set ``CMAKE_CXX_STANDARD`` before including pybind11, it will be respected and no
futher action will be taken by pybind11.

CMake 3.1+: If you explicitly set a list of compile features in ``PYBIND11_CXX_FEATURES``, that will be used.
See `CMAKE_CXX_KNOWN_FEATURES <https://cmake.org/cmake/help/latest/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.html>`_
for your CMake version.

.. code-block:: cmake
# These meta-features were added in CMake 3.8:
set(PYBIND11_CXX_FEATURES cxx_std_11)
set(PYBIND11_CXX_FEATURES cxx_std_14)
set(PYBIND11_CXX_FEATURES cxx_std_17) # Experimental C++17 support
add_subdirectory(pybind11) # or find_package(pybind11)
CMake 2.8+: If neither of the above is set and you want to explicitly control the flag,
the standard flag can be given as ``PYBIND11_CPP_STANDARD``:

.. code-block:: cmake
Expand All @@ -116,10 +136,14 @@ available. To override this, the standard flag can be given explicitly in
add_subdirectory(pybind11) # or find_package(pybind11)
Note that this and all other configuration variables must be set **before** the
Note that these and all other configuration variables must be set **before** the
call to ``add_subdirectory`` or ``find_package``. The variables can also be set
when calling CMake from the command line using the ``-D<variable>=<value>`` flag.

Mixed C and C++ projects should use the ``PYBIND11_CXX_FEATURES`` mechanism to avoid
adding flags to the C compiler. If you need the latest version of CMake, it is trivial
to install; try ``pip install cmake`` or ``pip install --user cmake``.

The target Python version can be selected by setting ``PYBIND11_PYTHON_VERSION``
or an exact Python installation can be specified with ``PYTHON_EXECUTABLE``.
For example:
Expand Down
6 changes: 3 additions & 3 deletions tools/pybind11Config.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
#
# Python headers, libraries (as needed by platform), and the C++ standard
# are attached to the target. Set PythonLibsNew variables to influence
# python detection and PYBIND11_CPP_STANDARD (-std=c++11 or -std=c++14) to
# influence standard setting. ::
# python detection and PYBIND11_CPP_STANDARD or PYBIND11_CXX_FEATURES to
# influence standard setting or CMake compiler features. ::
#
# find_package(pybind11 CONFIG REQUIRED)
# message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}")
Expand Down Expand Up @@ -90,7 +90,7 @@ if(NOT TARGET ${PN}::pybind11)
set_property(TARGET ${PN}::module APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${PYTHON_LIBRARIES})
endif()

set_property(TARGET ${PN}::pybind11 APPEND PROPERTY INTERFACE_COMPILE_OPTIONS "${PYBIND11_CPP_STANDARD}")
_pybind11_target_cxx_std(${PN}::pybind11)

get_property(_iid TARGET ${PN}::pybind11 PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
get_property(_ill TARGET ${PN}::module PROPERTY INTERFACE_LINK_LIBRARIES)
Expand Down
119 changes: 104 additions & 15 deletions tools/pybind11Tools.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,117 @@ find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} REQUIRED)
include(CheckCXXCompilerFlag)
include(CMakeParseArguments)

if(NOT PYBIND11_CPP_STANDARD AND NOT CMAKE_CXX_STANDARD)
if(NOT MSVC)
check_cxx_compiler_flag("-std=c++14" HAS_CPP14_FLAG)
# The following options start out empty and cached; if empty they support "auto" behavior

if (HAS_CPP14_FLAG)
set(PYBIND11_CPP_STANDARD -std=c++14)
else()
check_cxx_compiler_flag("-std=c++11" HAS_CPP11_FLAG)
if (HAS_CPP11_FLAG)
set(PYBIND11_CPP_STANDARD -std=c++11)
## Don't do anything if CMAKE_CXX_STANDARD is set
if(NOT CMAKE_CXX_STANDARD)
# While complile features were introduced in 3.1, only 3.8+ have meta-features
# (And C++17 seems to be mostly supported through the meta-feature)

if(CMAKE_VERSION VERSION_LESS 3.8 AND NOT PYBIND11_CXX_FEATURES)
if(NOT PYBIND_CPP_STANDARD)
# Only try to get the standard manually if CMake doesn't support compiler features
if(MSVC)
set(PYBIND11_CPP_STANDARD "/std:c++14")
message(STATUS "pybind11 selected C++14 flag, MSVC")
else()
message(FATAL_ERROR "Unsupported compiler -- pybind11 requires C++11 support!")
check_cxx_compiler_flag("-std=c++17" HAS_CPP17_FLAG)
check_cxx_compiler_flag("-std=c++14" HAS_CPP14_FLAG)
check_cxx_compiler_flag("-std=c++11" HAS_CPP11_FLAG)

if(HAS_CPP17_FLAG)
set(PYBIND11_CPP_STANDARD "-std=c++17")
message(STATUS "pybind11 selected C++17 flag")
elseif(HAS_CPP14_FLAG)
set(PYBIND11_CPP_STANDARD "-std=c++14")
message(STATUS "pybind11 selected C++14 flag")
elseif(HAS_CPP11_FLAG)
set(PYBIND11_CPP_STANDARD "-std=c++11")
message(STATUS "pybind11 selected C++11 flag")
else()
message(FATAL_ERROR "Unsupported compiler -- pybind11 requires C++11 support!")
endif()
endif()
endif()
elseif(MSVC)
set(PYBIND11_CPP_STANDARD /std:c++14)

# Auto add if CMake >= 3.8 and CXX_FEATURES is not set
elseif(NOT PYBIND11_CXX_FEATURES)
# IN_LIST introduced in CMAKE 3.3
# Safe because this will only activate if CMake >= 3.8
cmake_policy(SET CMP0057 NEW)

# The following only print if running the first time,
# and no C++ mode selected
if(cxx_std_17 IN_LIST CMAKE_CXX_COMPILE_FEATURES)
set(PYBIND11_CXX_FEATURES cxx_std_17)
message(STATUS "pybind11 selected C++17 mode, compiler feature")
elseif(cxx_std_14 IN_LIST CMAKE_CXX_COMPILE_FEATURES)
message(STATUS "pybind11 selected C++14 mode, compiler feature")
set(PYBIND11_CXX_FEATURES cxx_std_14)
elseif(cxx_std_11 IN_LIST CMAKE_CXX_COMPILE_FEATURES)
message(STATUS "pybind11 selected C++11 mode, compiler feature")
set(PYBIND11_CXX_FEATURES cxx_std_11)
else()
message(FATAL_ERROR "Unsupported compiler -- pybind11 requires C++11 support!")
endif()
endif()
endif()

# Allow the user to override by setting the cache value after the auto-discovery
# Empty values get filled on first run (PYBIND11_CPP_STANDARD for CMake < 3.8,
# otherwise PYBIND11_CXX_FEATURES), and then at this point are promoted to the CACHE.

set(PYBIND11_CPP_STANDARD ${PYBIND11_CPP_STANDARD} CACHE STRING
"C++ standard flag, e.g. -std=c++11, -std=c++14, /std:c++14. Defaults to C++14 mode." FORCE)
set(PYBIND11_CPP_STANDARD ${PYBIND11_CPP_STANDARD} CACHE STRING
"C++ standard flag, e.g. -std=c++11, -std=c++14, /std:c++14. Defaults to highest supported for CMake 2.8-3.7")

if(NOT CMAKE_VERSION VERSION_LESS 3.1)
#Only provide the option if CMake >= 3.1
set(PYBIND11_CXX_FEATURES ${PYBIND11_CXX_FEATURES} CACHE STRING
"List of compile features for PyBind, will use highest detected C++ version in CMake 3.8+")
elseif(PYBIND11_CXX_FEATURES)
message(FATAL_ERROR "PYBIND11_CXX_FEATURES is not supported for CMake < 3.1")
endif()

function(_pybind11_target_cxx_std target_name)

# Do not do any overriding if global CMAKE_CXX_STANDARD is set
if(NOT CMAKE_CXX_STANDARD)
# See if this is an interface or regular target
get_target_property(PYTYPE ${target_name} TYPE)
get_target_property(PYIMPORTED ${target_name} IMPORTED)

# Allow manual settings (Needed for older CMakes)
# Will always be set for old CMake
if(PYBIND11_CPP_STANDARD)
if(PYTYPE STREQUAL "INTERFACE_LIBRARY")
if(PYIMPORTED)
set_property(TARGET ${target_name} APPEND PROPERTY
INTERFACE_COMPILE_OPTIONS ${PYBIND11_CPP_STANDARD})
else()
target_compile_options(${target_name} INTERFACE ${PYBIND11_CPP_STANDARD})
endif()
else()
target_compile_options(${target_name} PUBLIC ${PYBIND11_CPP_STANDARD})
endif()

# A user of CMake 3.1 can override this, or 3.8 will default to using it
elseif(PYBIND11_CXX_FEATURES)
if(PYTYPE STREQUAL "INTERFACE_LIBRARY")
if(PYIMPORTED)
set_property(TARGET ${target_name} APPEND PROPERTY
INTERFACE_COMPILE_FEATURES ${PYBIND11_CXX_FEATURES})
else()
target_compile_features(${target_name} INTERFACE ${PYBIND11_CXX_FEATURES})
endif()
else()
target_compile_features(${target_name} PUBLIC ${PYBIND11_CXX_FEATURES})
set_target_properties(${target_name} PROPERTIES CXX_EXTENSIONS OFF)
endif()
endif()
endif()
endfunction()


# Checks whether the given CXX/linker flags can compile and link a cxx file. cxxflags and
# linkerflags are lists of flags to use. The result variable is a unique variable name for each set
# of flags: the compilation result will be cached base on the result variable. If the flags work,
Expand Down Expand Up @@ -173,7 +262,7 @@ function(pybind11_add_module target_name)
endif()

# Make sure C++11/14 are enabled
target_compile_options(${target_name} PUBLIC ${PYBIND11_CPP_STANDARD})
_pybind11_target_cxx_std(${target_name})

if(ARG_NO_EXTRAS)
return()
Expand Down

0 comments on commit 5b925e9

Please sign in to comment.