fix: support nvcc and test (#2461)

* fix: support nvcc and test

* fixup! fix: support nvcc and test

* docs: mention what compilers fail

* fix: much simpler logic

* refactor: slightly faster / clearer
This commit is contained in:
Henry Schreiner 2020-09-10 11:49:26 -04:00 committed by GitHub
parent fbc7563623
commit 621906b3e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 89 additions and 17 deletions

View File

@ -289,6 +289,28 @@ jobs:
- name: Interface test - name: Interface test
run: cmake --build build --target test_cmake_build run: cmake --build build --target test_cmake_build
cuda:
runs-on: ubuntu-latest
name: "🐍 3.8 • CUDA 11 • Ubuntu 20.04"
container: nvidia/cuda:11.0-devel-ubuntu20.04
steps:
- uses: actions/checkout@v2
# tzdata will try to ask for the timezone, so set the DEBIAN_FRONTEND
- name: Install 🐍 3
run: apt-get update && DEBIAN_FRONTEND="noninteractive" apt-get install -y cmake python3-dev python3-pytest
- name: Configure
run: cmake -S . -B build -DPYBIND11_CUDA_TESTS=ON -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON
- name: Build
run: cmake --build build -j2 -v
- name: Python tests
run: cmake --build build --target pytest
install-classic: install-classic:
name: "🐍 3.5 • Debian • x86 • Install" name: "🐍 3.5 • Debian • x86 • Install"
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@ -98,6 +98,7 @@ In addition to the core functionality, pybind11 provides some extra goodies:
4. Intel C++ compiler 17 or newer (16 with pybind11 v2.0 and 15 with pybind11 4. Intel C++ compiler 17 or newer (16 with pybind11 v2.0 and 15 with pybind11
v2.0 and a [workaround][intel-15-workaround]) v2.0 and a [workaround][intel-15-workaround])
5. Cygwin/GCC (tested on 2.5.1) 5. Cygwin/GCC (tested on 2.5.1)
6. NVCC (CUDA 11 tested)
## About ## About

View File

@ -1006,6 +1006,7 @@ template <typename CharT> using is_std_char_type = any_of<
std::is_same<CharT, wchar_t> /* std::wstring */ std::is_same<CharT, wchar_t> /* std::wstring */
>; >;
template <typename T> template <typename T>
struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value && !is_std_char_type<T>::value>> { struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value && !is_std_char_type<T>::value>> {
using _py_type_0 = conditional_t<sizeof(T) <= sizeof(long), long, long long>; using _py_type_0 = conditional_t<sizeof(T) <= sizeof(long), long, long long>;
@ -1034,12 +1035,12 @@ public:
: (py_type) PYBIND11_LONG_AS_LONGLONG(src.ptr()); : (py_type) PYBIND11_LONG_AS_LONGLONG(src.ptr());
} }
// Python API reported an error
bool py_err = py_value == (py_type) -1 && PyErr_Occurred(); bool py_err = py_value == (py_type) -1 && PyErr_Occurred();
// Protect std::numeric_limits::min/max with parentheses // Check to see if the conversion is valid (integers should match exactly)
if (py_err || (std::is_integral<T>::value && sizeof(py_type) != sizeof(T) && // Signed/unsigned checks happen elsewhere
(py_value < (py_type) (std::numeric_limits<T>::min)() || if (py_err || (std::is_integral<T>::value && sizeof(py_type) != sizeof(T) && py_value != (py_type) (T) py_value)) {
py_value > (py_type) (std::numeric_limits<T>::max)()))) {
bool type_error = py_err && PyErr_ExceptionMatches( bool type_error = py_err && PyErr_ExceptionMatches(
#if PY_VERSION_HEX < 0x03000000 && !defined(PYPY_VERSION) #if PY_VERSION_HEX < 0x03000000 && !defined(PYPY_VERSION)
PyExc_SystemError PyExc_SystemError

View File

@ -1483,7 +1483,14 @@ struct vectorize_arg {
template <typename Func, typename Return, typename... Args> template <typename Func, typename Return, typename... Args>
struct vectorize_helper { struct vectorize_helper {
// NVCC for some reason breaks if NVectorized is private
#ifdef __CUDACC__
public:
#else
private: private:
#endif
static constexpr size_t N = sizeof...(Args); static constexpr size_t N = sizeof...(Args);
static constexpr size_t NVectorized = constexpr_sum(vectorize_arg<Args>::vectorize...); static constexpr size_t NVectorized = constexpr_sum(vectorize_arg<Args>::vectorize...);
static_assert(NVectorized >= 1, static_assert(NVectorized >= 1,

View File

@ -30,6 +30,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../tools")
option(PYBIND11_WERROR "Report all warnings as errors" OFF) option(PYBIND11_WERROR "Report all warnings as errors" OFF)
option(DOWNLOAD_EIGEN "Download EIGEN (requires CMake 3.11+)" OFF) option(DOWNLOAD_EIGEN "Download EIGEN (requires CMake 3.11+)" OFF)
option(PYBIND11_CUDA_TESTS "Enable building CUDA tests (requires CMake 3.12+)" OFF)
set(PYBIND11_TEST_OVERRIDE set(PYBIND11_TEST_OVERRIDE
"" ""
CACHE STRING "Tests from ;-separated list of *.cpp files will be built instead of all tests") CACHE STRING "Tests from ;-separated list of *.cpp files will be built instead of all tests")
@ -49,6 +50,14 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
"RelWithDebInfo") "RelWithDebInfo")
endif() endif()
if(PYBIND11_CUDA_TESTS)
enable_language(CUDA)
if(DEFINED CMAKE_CXX_STANDARD)
set(CMAKE_CUDA_STANDARD ${CMAKE_CXX_STANDARD})
endif()
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
endif()
# Full set of test files (you can override these; see below) # Full set of test files (you can override these; see below)
set(PYBIND11_TEST_FILES set(PYBIND11_TEST_FILES
test_async.cpp test_async.cpp
@ -104,6 +113,16 @@ if((PYBIND11_TEST_FILES_ASYNC_I GREATER -1) AND (PYTHON_VERSION VERSION_LESS 3.5
list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_ASYNC_I}) list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_ASYNC_I})
endif() endif()
# Skip tests for CUDA check:
# /pybind11/tests/test_constants_and_functions.cpp(125):
# error: incompatible exception specifications
list(FIND PYBIND11_TEST_FILES test_constants_and_functions.cpp PYBIND11_TEST_FILES_CAF_I)
if((PYBIND11_TEST_FILES_CAF_I GREATER -1) AND PYBIND11_CUDA_TESTS)
message(
STATUS "Skipping test_constants_and_functions due to incompatible exception specifications")
list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_CAF_I})
endif()
string(REPLACE ".cpp" ".py" PYBIND11_PYTEST_FILES "${PYBIND11_TEST_FILES}") string(REPLACE ".cpp" ".py" PYBIND11_PYTEST_FILES "${PYBIND11_TEST_FILES}")
# Contains the set of test files that require pybind11_cross_module_tests to be # Contains the set of test files that require pybind11_cross_module_tests to be
@ -195,7 +214,7 @@ endif()
function(pybind11_enable_warnings target_name) function(pybind11_enable_warnings target_name)
if(MSVC) if(MSVC)
target_compile_options(${target_name} PRIVATE /W4) target_compile_options(${target_name} PRIVATE /W4)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)") elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)" AND NOT PYBIND11_CUDA_TESTS)
target_compile_options(${target_name} PRIVATE -Wall -Wextra -Wconversion -Wcast-qual target_compile_options(${target_name} PRIVATE -Wall -Wextra -Wconversion -Wcast-qual
-Wdeprecated) -Wdeprecated)
endif() endif()
@ -203,6 +222,8 @@ function(pybind11_enable_warnings target_name)
if(PYBIND11_WERROR) if(PYBIND11_WERROR)
if(MSVC) if(MSVC)
target_compile_options(${target_name} PRIVATE /WX) target_compile_options(${target_name} PRIVATE /WX)
elseif(PYBIND11_CUDA_TESTS)
target_compile_options(${target_name} PRIVATE "SHELL:-Werror all-warnings")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)") elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)")
target_compile_options(${target_name} PRIVATE -Werror) target_compile_options(${target_name} PRIVATE -Werror)
endif() endif()
@ -239,12 +260,22 @@ foreach(t ${PYBIND11_CROSS_MODULE_GIL_TESTS})
endif() endif()
endforeach() endforeach()
# Support CUDA testing by forcing the target file to compile with NVCC
if(PYBIND11_CUDA_TESTS)
set_property(SOURCE ${PYBIND11_TEST_FILES} PROPERTY LANGUAGE CUDA)
endif()
foreach(target ${test_targets}) foreach(target ${test_targets})
set(test_files ${PYBIND11_TEST_FILES}) set(test_files ${PYBIND11_TEST_FILES})
if(NOT "${target}" STREQUAL "pybind11_tests") if(NOT "${target}" STREQUAL "pybind11_tests")
set(test_files "") set(test_files "")
endif() endif()
# Support CUDA testing by forcing the target file to compile with NVCC
if(PYBIND11_CUDA_TESTS)
set_property(SOURCE ${target}.cpp PROPERTY LANGUAGE CUDA)
endif()
# Create the binding library # Create the binding library
pybind11_add_module(${target} THIN_LTO ${target}.cpp ${test_files} ${PYBIND11_HEADERS}) pybind11_add_module(${target} THIN_LTO ${target}.cpp ${test_files} ${PYBIND11_HEADERS})
pybind11_enable_warnings(${target}) pybind11_enable_warnings(${target})
@ -354,8 +385,10 @@ add_custom_command(
$<TARGET_FILE:pybind11_tests> $<TARGET_FILE:pybind11_tests>
${CMAKE_CURRENT_BINARY_DIR}/sosize-$<TARGET_FILE_NAME:pybind11_tests>.txt) ${CMAKE_CURRENT_BINARY_DIR}/sosize-$<TARGET_FILE_NAME:pybind11_tests>.txt)
if(NOT PYBIND11_CUDA_TESTS)
# Test embedding the interpreter. Provides the `cpptest` target. # Test embedding the interpreter. Provides the `cpptest` target.
add_subdirectory(test_embed) add_subdirectory(test_embed)
# Test CMake build using functions and targets from subdirectory or installed location # Test CMake build using functions and targets from subdirectory or installed location
add_subdirectory(test_cmake_build) add_subdirectory(test_cmake_build)
endif()

View File

@ -1,5 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from pybind11_tests import constants_and_functions as m import pytest
m = pytest.importorskip("pybind11_tests.constants_and_functions")
def test_constants(): def test_constants():

View File

@ -175,14 +175,20 @@ TEST_SUBMODULE(copy_move_policies, m) {
m.attr("has_optional") = false; m.attr("has_optional") = false;
#endif #endif
// #70 compilation issue if operator new is not public // #70 compilation issue if operator new is not public - simple body added
// but not needed on most compilers; MSVC and nvcc don't like a local
// struct not having a method defined when declared, since it can not be
// added later.
struct PrivateOpNew { struct PrivateOpNew {
int value = 1; int value = 1;
private: private:
#if defined(_MSC_VER) void *operator new(size_t bytes) {
# pragma warning(disable: 4822) // warning C4822: local class member function does not have a body void *ptr = std::malloc(bytes);
#endif if (ptr)
void *operator new(size_t bytes); return ptr;
else
throw std::bad_alloc{};
}
}; };
py::class_<PrivateOpNew>(m, "PrivateOpNew").def_readonly("value", &PrivateOpNew::value); py::class_<PrivateOpNew>(m, "PrivateOpNew").def_readonly("value", &PrivateOpNew::value);
m.def("private_op_new_value", []() { return PrivateOpNew(); }); m.def("private_op_new_value", []() { return PrivateOpNew(); });

View File

@ -139,7 +139,7 @@ public:
std::string print_movable(int a, int b) { return get_movable(a, b).get_value(); } std::string print_movable(int a, int b) { return get_movable(a, b).get_value(); }
}; };
class NCVirtTrampoline : public NCVirt { class NCVirtTrampoline : public NCVirt {
#if !defined(__INTEL_COMPILER) #if !defined(__INTEL_COMPILER) && !defined(__CUDACC__)
NonCopyable get_noncopyable(int a, int b) override { NonCopyable get_noncopyable(int a, int b) override {
PYBIND11_OVERLOAD(NonCopyable, NCVirt, get_noncopyable, a, b); PYBIND11_OVERLOAD(NonCopyable, NCVirt, get_noncopyable, a, b);
} }
@ -205,7 +205,7 @@ TEST_SUBMODULE(virtual_functions, m) {
.def(py::init<int, int>()); .def(py::init<int, int>());
// test_move_support // test_move_support
#if !defined(__INTEL_COMPILER) #if !defined(__INTEL_COMPILER) && !defined(__CUDACC__)
py::class_<NCVirt, NCVirtTrampoline>(m, "NCVirt") py::class_<NCVirt, NCVirtTrampoline>(m, "NCVirt")
.def(py::init<>()) .def(py::init<>())
.def("get_noncopyable", &NCVirt::get_noncopyable) .def("get_noncopyable", &NCVirt::get_noncopyable)