From abfc0b196ae8992795587276cdb30ccc5173889b Mon Sep 17 00:00:00 2001 From: Peter Steneteg <peter@steneteg.se> Date: Tue, 27 May 2025 13:52:17 +0200 Subject: [PATCH 01/14] test: Added test case for visibility of common symbols across shared libraries --- tests/CMakeLists.txt | 3 ++ tests/test_visibility/CMakeLists.txt | 63 +++++++++++++++++++++++ tests/test_visibility/bindings.cpp | 20 +++++++ tests/test_visibility/catch.cpp | 22 ++++++++ tests/test_visibility/lib.cpp | 13 +++++ tests/test_visibility/lib.h | 30 +++++++++++ tests/test_visibility/test_visibility.cpp | 48 +++++++++++++++++ 7 files changed, 199 insertions(+) create mode 100644 tests/test_visibility/CMakeLists.txt create mode 100644 tests/test_visibility/bindings.cpp create mode 100644 tests/test_visibility/catch.cpp create mode 100644 tests/test_visibility/lib.cpp create mode 100644 tests/test_visibility/lib.h create mode 100644 tests/test_visibility/test_visibility.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 069b4f6f38..2546d1d372 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -649,4 +649,7 @@ if(NOT PYBIND11_CUDA_TESTS) # Test CMake build using functions and targets from subdirectory or installed location add_subdirectory(test_cmake_build) + + # Test visibility of common symbols across shared libraries + add_subdirectory(test_visibility) endif() diff --git a/tests/test_visibility/CMakeLists.txt b/tests/test_visibility/CMakeLists.txt new file mode 100644 index 0000000000..21da974d4c --- /dev/null +++ b/tests/test_visibility/CMakeLists.txt @@ -0,0 +1,63 @@ +possibly_uninitialized(PYTHON_MODULE_EXTENSION Python_INTERPRETER_ID) + +if("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" + OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy" + OR "${PYTHON_MODULE_EXTENSION}" MATCHES "graalpy") + message(STATUS "Skipping embed test on PyPy or GraalPy") + add_custom_target(cpptest) # Dummy target on PyPy or GraalPy. Embedding is not supported. + set(_suppress_unused_variable_warning "${DOWNLOAD_CATCH}") + return() +endif() + +if(TARGET Python::Module AND NOT TARGET Python::Python) + message(STATUS "Skipping embed test since no embed libs found") + add_custom_target(cpptest) # Dummy target since embedding is not supported. + set(_suppress_unused_variable_warning "${DOWNLOAD_CATCH}") + return() +endif() + +find_package(Catch 2.13.10) + +if(CATCH_FOUND) + message(STATUS "Building interpreter tests using Catch v${CATCH_VERSION}") +else() + message(STATUS "Catch not detected. Interpreter tests will be skipped. Install Catch headers" + " manually or use `cmake -DDOWNLOAD_CATCH=ON` to fetch them automatically.") + return() +endif() + +include(GenerateExportHeader) + +add_library(test_visibility_lib SHARED lib.h lib.cpp) +add_library(test_visibility_lib::test_visibility_lib ALIAS test_visibility_lib) +target_include_directories(test_visibility_lib PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) +target_include_directories(test_visibility_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +generate_export_header(test_visibility_lib) + +pybind11_add_module(test_visibility_bindings SHARED bindings.cpp) +target_link_libraries(test_visibility_bindings PUBLIC test_visibility_lib::test_visibility_lib) + +add_executable(test_visibility_main catch.cpp test_visibility.cpp) +target_link_libraries(test_visibility_main PUBLIC + test_visibility_lib::test_visibility_lib + pybind11::embed + Catch2::Catch2) + +# Ensure that we have built the python bindings since we load them in main +add_dependencies(test_visibility_main test_visibility_bindings) + +pybind11_enable_warnings(test_visibility_main) +pybind11_enable_warnings(test_visibility_bindings) +pybind11_enable_warnings(test_visibility_lib) + +add_custom_target( + test_visibility + COMMAND "$<TARGET_FILE:test_visibility_main>" + DEPENDS test_visibility_main + WORKING_DIRECTORY "$<TARGET_FILE_DIR:test_visibility_main>") + +set_target_properties(test_visibility_bindings PROPERTIES LIBRARY_OUTPUT_DIRECTORY + "${CMAKE_CURRENT_BINARY_DIR}") + +add_dependencies(check test_visibility) diff --git a/tests/test_visibility/bindings.cpp b/tests/test_visibility/bindings.cpp new file mode 100644 index 0000000000..ccd78e2808 --- /dev/null +++ b/tests/test_visibility/bindings.cpp @@ -0,0 +1,20 @@ +#include <pybind11/pybind11.h> + +#include <lib.h> + +class BaseTrampoline : public lib::Base, public pybind11::trampoline_self_life_support { +public: + using lib::Base::Base; + int get() const override { PYBIND11_OVERLOAD(int, lib::Base, get); } +}; + +PYBIND11_MODULE(test_visibility_bindings, m) { + pybind11::classh<lib::Base, BaseTrampoline>(m, "Base") + .def(pybind11::init<int, int>()) + .def_readwrite("a", &lib::Base::a) + .def_readwrite("b", &lib::Base::b); + + m.def("get_foo", [](int a, int b) -> std::shared_ptr<lib::Base> { + return std::make_shared<lib::Foo>(a, b); + }); +} diff --git a/tests/test_visibility/catch.cpp b/tests/test_visibility/catch.cpp new file mode 100644 index 0000000000..2debc5ff17 --- /dev/null +++ b/tests/test_visibility/catch.cpp @@ -0,0 +1,22 @@ +// The Catch implementation is compiled here. This is a standalone +// translation unit to avoid recompiling it for every test change. + +#include <pybind11/embed.h> + +// Silence MSVC C++17 deprecation warning from Catch regarding std::uncaught_exceptions (up to +// catch 2.0.1; this should be fixed in the next catch release after 2.0.1). +PYBIND11_WARNING_DISABLE_MSVC(4996) + +// Catch uses _ internally, which breaks gettext style defines +#ifdef _ +# undef _ +#endif + +#define CATCH_CONFIG_RUNNER +#include <catch.hpp> + +int main(int argc, char *argv[]) { + pybind11::scoped_interpreter guard{}; + auto result = Catch::Session().run(argc, argv); + return result < 0xff ? result : 0xff; +} diff --git a/tests/test_visibility/lib.cpp b/tests/test_visibility/lib.cpp new file mode 100644 index 0000000000..13b254d445 --- /dev/null +++ b/tests/test_visibility/lib.cpp @@ -0,0 +1,13 @@ +#include <lib.h> + +namespace lib { + +Base::Base(int a, int b) : a(a), b(b) {} + +int Base::get() const { return a + b; } + +Foo::Foo(int a, int b) : Base{a, b} {} + +int Foo::get() const { return 2 * a + b; } + +} // namespace lib diff --git a/tests/test_visibility/lib.h b/tests/test_visibility/lib.h new file mode 100644 index 0000000000..3a82436dd2 --- /dev/null +++ b/tests/test_visibility/lib.h @@ -0,0 +1,30 @@ +#pragma once + +#include <test_visibility_lib_export.h> +#include <memory> + +#if defined(_MSC_VER) +__pragma(warning(disable : 4251)) +#endif + +namespace lib { + +class TEST_VISIBILITY_LIB_EXPORT Base : public std::enable_shared_from_this<Base> { +public: + Base(int a, int b); + virtual ~Base() = default; + + virtual int get() const; + + int a; + int b; +}; + +class TEST_VISIBILITY_LIB_EXPORT Foo : public Base { +public: + Foo(int a, int b); + + int get() const override; +}; + +} // namespace lib diff --git a/tests/test_visibility/test_visibility.cpp b/tests/test_visibility/test_visibility.cpp new file mode 100644 index 0000000000..f5254be1e9 --- /dev/null +++ b/tests/test_visibility/test_visibility.cpp @@ -0,0 +1,48 @@ + +#include <lib.h> +#include <pybind11/pybind11.h> +#include <pybind11/embed.h> + +#include <catch.hpp> + +static constexpr auto script = R"( +import test_visibility_bindings + +class Bar(test_visibility_bindings.Base): + def __init__(self, a, b): + test_visibility_bindings.Base.__init__(self, a, b) + + def get(self): + return 4 * self.a + self.b + + +def get_bar(a, b): + return Bar(a, b) + +)"; + + +TEST_CASE("Simple case where without alias") { + // "Simple" case this will not have "python_instance_is_alias" set in type_cast_base.h:771 + auto bindings = pybind11::module_::import("test_visibility_bindings"); + auto holder = bindings.attr("get_foo")(1,2); + auto foo = holder.cast<std::shared_ptr<lib::Base>>(); + REQUIRE(foo->get() == 4); // 2 * 1 + 2 = 4 +} + +TEST_CASE("Complex case where with alias") { + // "Complex" case this will have "python_instance_is_alias" set in type_cast_base.h:771 + pybind11::exec(script); + auto main = pybind11::module::import("__main__"); + auto holder2 = main.attr("get_bar")(1, 2); + + // this will trigger "std::get_deleter<memory::guarded_delete>" in type_cast_base.h:772 + // This will fail since the program will see two different typeids for "memory::guarded_delete" + // on from the bindings module and one from "main", which will both have + // "__is_type_name_unique" as true and but still have different values. Hence we will not find + // the deleter and the cast fill fail. See "__eq(__type_name_t __lhs, __type_name_t __rhs)" in + // typeinfo in libc++ + auto bar = holder2.cast<std::shared_ptr<lib::Base>>(); + REQUIRE(bar->get() == 6); // 4 * 1 + 2 = 6 + +} From 8637068ac817799b146fbd834f7ec20b38ab67f8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 27 May 2025 13:19:20 +0000 Subject: [PATCH 02/14] style: pre-commit fixes --- tests/test_visibility/CMakeLists.txt | 8 +++--- tests/test_visibility/lib.cpp | 2 +- tests/test_visibility/lib.h | 32 +++++++++++------------ tests/test_visibility/test_visibility.cpp | 10 +++---- 4 files changed, 24 insertions(+), 28 deletions(-) diff --git a/tests/test_visibility/CMakeLists.txt b/tests/test_visibility/CMakeLists.txt index 21da974d4c..05dafd410b 100644 --- a/tests/test_visibility/CMakeLists.txt +++ b/tests/test_visibility/CMakeLists.txt @@ -39,10 +39,8 @@ pybind11_add_module(test_visibility_bindings SHARED bindings.cpp) target_link_libraries(test_visibility_bindings PUBLIC test_visibility_lib::test_visibility_lib) add_executable(test_visibility_main catch.cpp test_visibility.cpp) -target_link_libraries(test_visibility_main PUBLIC - test_visibility_lib::test_visibility_lib - pybind11::embed - Catch2::Catch2) +target_link_libraries(test_visibility_main PUBLIC test_visibility_lib::test_visibility_lib + pybind11::embed Catch2::Catch2) # Ensure that we have built the python bindings since we load them in main add_dependencies(test_visibility_main test_visibility_bindings) @@ -58,6 +56,6 @@ add_custom_target( WORKING_DIRECTORY "$<TARGET_FILE_DIR:test_visibility_main>") set_target_properties(test_visibility_bindings PROPERTIES LIBRARY_OUTPUT_DIRECTORY - "${CMAKE_CURRENT_BINARY_DIR}") + "${CMAKE_CURRENT_BINARY_DIR}") add_dependencies(check test_visibility) diff --git a/tests/test_visibility/lib.cpp b/tests/test_visibility/lib.cpp index 13b254d445..927ed044bc 100644 --- a/tests/test_visibility/lib.cpp +++ b/tests/test_visibility/lib.cpp @@ -10,4 +10,4 @@ Foo::Foo(int a, int b) : Base{a, b} {} int Foo::get() const { return 2 * a + b; } -} // namespace lib +} // namespace lib diff --git a/tests/test_visibility/lib.h b/tests/test_visibility/lib.h index 3a82436dd2..8275b85b5c 100644 --- a/tests/test_visibility/lib.h +++ b/tests/test_visibility/lib.h @@ -1,30 +1,30 @@ #pragma once -#include <test_visibility_lib_export.h> #include <memory> +#include <test_visibility_lib_export.h> #if defined(_MSC_VER) __pragma(warning(disable : 4251)) #endif -namespace lib { + namespace lib { -class TEST_VISIBILITY_LIB_EXPORT Base : public std::enable_shared_from_this<Base> { -public: - Base(int a, int b); - virtual ~Base() = default; + class TEST_VISIBILITY_LIB_EXPORT Base : public std::enable_shared_from_this<Base> { + public: + Base(int a, int b); + virtual ~Base() = default; - virtual int get() const; + virtual int get() const; - int a; - int b; -}; + int a; + int b; + }; -class TEST_VISIBILITY_LIB_EXPORT Foo : public Base { -public: - Foo(int a, int b); + class TEST_VISIBILITY_LIB_EXPORT Foo : public Base { + public: + Foo(int a, int b); - int get() const override; -}; + int get() const override; + }; -} // namespace lib +} // namespace lib diff --git a/tests/test_visibility/test_visibility.cpp b/tests/test_visibility/test_visibility.cpp index f5254be1e9..2412add3c1 100644 --- a/tests/test_visibility/test_visibility.cpp +++ b/tests/test_visibility/test_visibility.cpp @@ -1,9 +1,9 @@ -#include <lib.h> -#include <pybind11/pybind11.h> #include <pybind11/embed.h> +#include <pybind11/pybind11.h> #include <catch.hpp> +#include <lib.h> static constexpr auto script = R"( import test_visibility_bindings @@ -11,7 +11,7 @@ import test_visibility_bindings class Bar(test_visibility_bindings.Base): def __init__(self, a, b): test_visibility_bindings.Base.__init__(self, a, b) - + def get(self): return 4 * self.a + self.b @@ -21,11 +21,10 @@ def get_bar(a, b): )"; - TEST_CASE("Simple case where without alias") { // "Simple" case this will not have "python_instance_is_alias" set in type_cast_base.h:771 auto bindings = pybind11::module_::import("test_visibility_bindings"); - auto holder = bindings.attr("get_foo")(1,2); + auto holder = bindings.attr("get_foo")(1, 2); auto foo = holder.cast<std::shared_ptr<lib::Base>>(); REQUIRE(foo->get() == 4); // 2 * 1 + 2 = 4 } @@ -44,5 +43,4 @@ TEST_CASE("Complex case where with alias") { // typeinfo in libc++ auto bar = holder2.cast<std::shared_ptr<lib::Base>>(); REQUIRE(bar->get() == 6); // 4 * 1 + 2 = 6 - } From d866a8aff28206718ed79c7ff34d6d7026f93942 Mon Sep 17 00:00:00 2001 From: Peter Steneteg <peter@steneteg.se> Date: Tue, 27 May 2025 15:46:17 +0200 Subject: [PATCH 03/14] tests: cmake target name fix --- tests/test_visibility/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_visibility/CMakeLists.txt b/tests/test_visibility/CMakeLists.txt index 05dafd410b..79efae0822 100644 --- a/tests/test_visibility/CMakeLists.txt +++ b/tests/test_visibility/CMakeLists.txt @@ -4,14 +4,14 @@ if("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy" OR "${PYTHON_MODULE_EXTENSION}" MATCHES "graalpy") message(STATUS "Skipping embed test on PyPy or GraalPy") - add_custom_target(cpptest) # Dummy target on PyPy or GraalPy. Embedding is not supported. + add_custom_target(test_visibility) # Dummy target on PyPy or GraalPy. Embedding is not supported. set(_suppress_unused_variable_warning "${DOWNLOAD_CATCH}") return() endif() if(TARGET Python::Module AND NOT TARGET Python::Python) message(STATUS "Skipping embed test since no embed libs found") - add_custom_target(cpptest) # Dummy target since embedding is not supported. + add_custom_target(test_visibility) # Dummy target since embedding is not supported. set(_suppress_unused_variable_warning "${DOWNLOAD_CATCH}") return() endif() From 6b81c9e9b032c3adfecc9706fa8c3ee85fae6ddf Mon Sep 17 00:00:00 2001 From: Peter Steneteg <peter@steneteg.se> Date: Tue, 27 May 2025 18:47:25 +0200 Subject: [PATCH 04/14] tests: Added visibility test to ci --- .github/workflows/ci.yml | 43 +++++++++++++++++++++++ .github/workflows/reusable-standard.yml | 3 ++ tests/test_visibility/CMakeLists.txt | 4 +-- tests/test_visibility/test_visibility.cpp | 18 ++++++---- 4 files changed, 59 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d7d73a665..683000ec14 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -230,6 +230,9 @@ jobs: - name: Interface test run: cmake --build . --target test_cmake_build + - name: Visibility test + run: cmake --build . --target test_visibility + manylinux: name: Manylinux on 🐍 3.13t • GIL @@ -328,6 +331,9 @@ jobs: - name: C++ tests run: cmake --build --preset default --target cpptest + - name: Visibility test + run: cmake --build --preset default --target test_visibility + - name: Run Valgrind on Python tests if: matrix.valgrind run: cmake --build --preset default --target memcheck @@ -386,6 +392,8 @@ jobs: - name: Interface test run: cmake --build build --target test_cmake_build + - name: Visibility test + run: cmake --build build --target test_visibility # Testing NVCC; forces sources to behave like .cu files cuda: @@ -505,6 +513,8 @@ jobs: - name: Interface test run: cmake --build build --target test_cmake_build + - name: Visibility test + run: cmake --build build --target test_visibility # Testing on GCC using the GCC docker images (only recent images supported) gcc: @@ -556,6 +566,9 @@ jobs: - name: Interface test run: cmake --build build --target test_cmake_build + - name: Visibility test + run: cmake --build build --target test_visibility + - name: Configure - Exercise cmake -DPYBIND11_TEST_OVERRIDE if: matrix.gcc == '12' shell: bash @@ -638,6 +651,11 @@ jobs: set +e; source /opt/intel/oneapi/setvars.sh; set -e cmake --build build-11 --target test_cmake_build + - name: Visibility test + run: | + set +e; source /opt/intel/oneapi/setvars.sh; set -e + cmake --build build-11 --target test_visibility + - name: Configure C++17 run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e @@ -670,6 +688,10 @@ jobs: set +e; source /opt/intel/oneapi/setvars.sh; set -e cmake --build build-17 --target test_cmake_build + - name: Visibility test + run: | + set +e; source /opt/intel/oneapi/setvars.sh; set -e + cmake --build build-17 --target test_visibility # Testing on CentOS (manylinux uses a centos base). centos: @@ -732,6 +754,9 @@ jobs: - name: Interface test run: cmake --build build --target test_cmake_build + - name: Visibility test + run: cmake --build build --target test_visibility + # This tests an "install" with the CMake tools install-classic: @@ -961,6 +986,9 @@ jobs: - name: Interface test C++20 run: cmake --build build --target test_cmake_build + - name: Visibility test + run: cmake --build build --target test_visibility + - name: Configure C++20 - Exercise cmake -DPYBIND11_TEST_OVERRIDE run: > cmake -S . -B build_partial @@ -1034,6 +1062,9 @@ jobs: - name: Interface test C++11 run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build --target test_cmake_build + - name: Visibility test + run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build --target test_visibility + - name: Clean directory run: git clean -fdx @@ -1055,6 +1086,9 @@ jobs: - name: Interface test C++14 run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build2 --target test_cmake_build + - name: Visibility test + run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build2 --target test_visibility + - name: Clean directory run: git clean -fdx @@ -1076,6 +1110,9 @@ jobs: - name: Interface test C++17 run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build3 --target test_cmake_build + - name: Visibility test + run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build3 --target test_visibility + windows_clang: if: github.event.pull_request.draft == false @@ -1143,6 +1180,9 @@ jobs: - name: Interface test run: cmake --build . --target test_cmake_build -j 2 + - name: Visibility test + run: cmake --build . --target test_visibility -j 2 + - name: Clean directory run: git clean -fdx @@ -1210,6 +1250,9 @@ jobs: - name: Interface test run: cmake --build . --target test_cmake_build -j 2 + - name: Visibility test + run: cmake --build . --target test_visibility -j 2 + - name: CMake Configure - Exercise cmake -DPYBIND11_TEST_OVERRIDE run: > cmake -S . -B build_partial diff --git a/.github/workflows/reusable-standard.yml b/.github/workflows/reusable-standard.yml index b59949316b..270479f4f5 100644 --- a/.github/workflows/reusable-standard.yml +++ b/.github/workflows/reusable-standard.yml @@ -74,6 +74,9 @@ jobs: - name: Interface test run: cmake --build build --target test_cmake_build + - name: Visibility test + run: cmake --build . --target test_visibility + - name: Setuptools helpers test run: | uv pip install --python=python --system setuptools diff --git a/tests/test_visibility/CMakeLists.txt b/tests/test_visibility/CMakeLists.txt index 79efae0822..cba1dd62d0 100644 --- a/tests/test_visibility/CMakeLists.txt +++ b/tests/test_visibility/CMakeLists.txt @@ -3,14 +3,14 @@ possibly_uninitialized(PYTHON_MODULE_EXTENSION Python_INTERPRETER_ID) if("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy" OR "${PYTHON_MODULE_EXTENSION}" MATCHES "graalpy") - message(STATUS "Skipping embed test on PyPy or GraalPy") + message(STATUS "Skipping visibility test on PyPy or GraalPy") add_custom_target(test_visibility) # Dummy target on PyPy or GraalPy. Embedding is not supported. set(_suppress_unused_variable_warning "${DOWNLOAD_CATCH}") return() endif() if(TARGET Python::Module AND NOT TARGET Python::Python) - message(STATUS "Skipping embed test since no embed libs found") + message(STATUS "Skipping visibility test since no embed libs found") add_custom_target(test_visibility) # Dummy target since embedding is not supported. set(_suppress_unused_variable_warning "${DOWNLOAD_CATCH}") return() diff --git a/tests/test_visibility/test_visibility.cpp b/tests/test_visibility/test_visibility.cpp index 2412add3c1..fe3caed2e5 100644 --- a/tests/test_visibility/test_visibility.cpp +++ b/tests/test_visibility/test_visibility.cpp @@ -21,24 +21,28 @@ def get_bar(a, b): )"; -TEST_CASE("Simple case where without alias") { - // "Simple" case this will not have "python_instance_is_alias" set in type_cast_base.h:771 +TEST_CASE("Simple case where without is_alias") { + // "Simple" case this will not have `python_instance_is_alias` set in type_cast_base.h:771 auto bindings = pybind11::module_::import("test_visibility_bindings"); auto holder = bindings.attr("get_foo")(1, 2); auto foo = holder.cast<std::shared_ptr<lib::Base>>(); REQUIRE(foo->get() == 4); // 2 * 1 + 2 = 4 } -TEST_CASE("Complex case where with alias") { - // "Complex" case this will have "python_instance_is_alias" set in type_cast_base.h:771 +TEST_CASE("Complex case where with it_alias") { + // "Complex" case this will have `python_instance_is_alias` set in type_cast_base.h:771 pybind11::exec(script); auto main = pybind11::module::import("__main__"); + + // The critical part of "Bar" is that it will have the `is_alias` `instance` flag set. + // I'm not quite sure what is required to get that flag, this code is derived from a + // larger code where this issue was observed. auto holder2 = main.attr("get_bar")(1, 2); - // this will trigger "std::get_deleter<memory::guarded_delete>" in type_cast_base.h:772 - // This will fail since the program will see two different typeids for "memory::guarded_delete" + // this will trigger `std::get_deleter<memory::guarded_delete>` in type_cast_base.h:772 + // This will fail since the program will see two different typeids for `memory::guarded_delete` // on from the bindings module and one from "main", which will both have - // "__is_type_name_unique" as true and but still have different values. Hence we will not find + // `__is_type_name_unique` as true and but still have different values. Hence we will not find // the deleter and the cast fill fail. See "__eq(__type_name_t __lhs, __type_name_t __rhs)" in // typeinfo in libc++ auto bar = holder2.cast<std::shared_ptr<lib::Base>>(); From 4cb2f8352518a4145a46981e700e5ac83e2e23c1 Mon Sep 17 00:00:00 2001 From: Henry Schreiner <HenrySchreinerIII@gmail.com> Date: Tue, 27 May 2025 14:46:15 -0400 Subject: [PATCH 05/14] tests: set the default visibility to hidden --- tests/test_visibility/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_visibility/CMakeLists.txt b/tests/test_visibility/CMakeLists.txt index cba1dd62d0..3d724ca28d 100644 --- a/tests/test_visibility/CMakeLists.txt +++ b/tests/test_visibility/CMakeLists.txt @@ -1,5 +1,7 @@ possibly_uninitialized(PYTHON_MODULE_EXTENSION Python_INTERPRETER_ID) +set(CMAKE_CXX_VISIBILITY_PRESET hidden) + if("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy" OR "${PYTHON_MODULE_EXTENSION}" MATCHES "graalpy") From 4205d06a4de25e51fb9ac487cafea05dcbec19c9 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" <rgrossekunst@nvidia.com> Date: Tue, 27 May 2025 13:50:46 -0700 Subject: [PATCH 06/14] prototype/proof-of-concept fix: PYBIND11_EXPORT_GUARDED_DELETE --- include/pybind11/detail/struct_smart_holder.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/pybind11/detail/struct_smart_holder.h b/include/pybind11/detail/struct_smart_holder.h index 758182119c..d1b33665d6 100644 --- a/include/pybind11/detail/struct_smart_holder.h +++ b/include/pybind11/detail/struct_smart_holder.h @@ -58,6 +58,18 @@ High-level aspects: #include <typeinfo> #include <utility> +// IMPORTANT: This code block must stay BELOW the #include <stdexcept> above. +#if !defined(PYBIND11_EXPORT_GUARDED_DELETE) +# if defined(_LIBCPP_EXCEPTION) +# if defined(WIN32) || defined(_WIN32) +# error "UNEXPECTED: defined(_LIBCPP_EXCEPTION) && (defined(WIN32) || defined(_WIN32))" +# endif +# define PYBIND11_EXPORT_GUARDED_DELETE __attribute__((visibility("default"))) +# else +# define PYBIND11_EXPORT_GUARDED_DELETE +# endif +#endif + PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(memory) From 267e01e8bfa1b5932758675a11699461aec21ef0 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" <rgrossekunst@nvidia.com> Date: Tue, 27 May 2025 14:09:42 -0700 Subject: [PATCH 07/14] Fix silly oversight: actually use PYBIND11_EXPORT_GUARDED_DELETE --- include/pybind11/detail/struct_smart_holder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/detail/struct_smart_holder.h b/include/pybind11/detail/struct_smart_holder.h index d1b33665d6..1a08a12e88 100644 --- a/include/pybind11/detail/struct_smart_holder.h +++ b/include/pybind11/detail/struct_smart_holder.h @@ -90,7 +90,7 @@ static constexpr bool type_has_shared_from_this(const void *) { return false; } -struct guarded_delete { +struct PYBIND11_EXPORT_GUARDED_DELETE guarded_delete { std::weak_ptr<void> released_ptr; // Trick to keep the smart_holder memory footprint small. std::function<void(void *)> del_fun; // Rare case. void (*del_ptr)(void *); // Common case. From e9ee4a226f447ecfced31e135b7df0ed0e6915c5 Mon Sep 17 00:00:00 2001 From: Henry Schreiner <HenrySchreinerIII@gmail.com> Date: Thu, 29 May 2025 10:45:32 -0400 Subject: [PATCH 08/14] Update struct_smart_holder.h --- include/pybind11/detail/struct_smart_holder.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/pybind11/detail/struct_smart_holder.h b/include/pybind11/detail/struct_smart_holder.h index 1a08a12e88..94950210d2 100644 --- a/include/pybind11/detail/struct_smart_holder.h +++ b/include/pybind11/detail/struct_smart_holder.h @@ -59,11 +59,11 @@ High-level aspects: #include <utility> // IMPORTANT: This code block must stay BELOW the #include <stdexcept> above. +// This is only requried on some builds with libc++ (one of three implementations +// in https://github.com/llvm/llvm-project/blob/a9b64bb3180dab6d28bf800a641f9a9ad54d2c0c/libcxx/include/typeinfo#L271-L276 +// requiere it) #if !defined(PYBIND11_EXPORT_GUARDED_DELETE) -# if defined(_LIBCPP_EXCEPTION) -# if defined(WIN32) || defined(_WIN32) -# error "UNEXPECTED: defined(_LIBCPP_EXCEPTION) && (defined(WIN32) || defined(_WIN32))" -# endif +# if defined(__libcpp_version) && !defined(WIN32) && !defined(_WIN32) # define PYBIND11_EXPORT_GUARDED_DELETE __attribute__((visibility("default"))) # else # define PYBIND11_EXPORT_GUARDED_DELETE From c5eac1b53c1d1610846e8f5a752a2f42c0a86f27 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 29 May 2025 14:47:31 +0000 Subject: [PATCH 09/14] style: pre-commit fixes --- include/pybind11/detail/struct_smart_holder.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/pybind11/detail/struct_smart_holder.h b/include/pybind11/detail/struct_smart_holder.h index 94950210d2..f34ca94712 100644 --- a/include/pybind11/detail/struct_smart_holder.h +++ b/include/pybind11/detail/struct_smart_holder.h @@ -60,7 +60,8 @@ High-level aspects: // IMPORTANT: This code block must stay BELOW the #include <stdexcept> above. // This is only requried on some builds with libc++ (one of three implementations -// in https://github.com/llvm/llvm-project/blob/a9b64bb3180dab6d28bf800a641f9a9ad54d2c0c/libcxx/include/typeinfo#L271-L276 +// in +// https://github.com/llvm/llvm-project/blob/a9b64bb3180dab6d28bf800a641f9a9ad54d2c0c/libcxx/include/typeinfo#L271-L276 // requiere it) #if !defined(PYBIND11_EXPORT_GUARDED_DELETE) # if defined(__libcpp_version) && !defined(WIN32) && !defined(_WIN32) From a19920c5407a95ea62ed960d3b907eb75e808bed Mon Sep 17 00:00:00 2001 From: Henry Schreiner <HenrySchreinerIII@gmail.com> Date: Thu, 29 May 2025 11:29:27 -0400 Subject: [PATCH 10/14] Update include/pybind11/detail/struct_smart_holder.h --- include/pybind11/detail/struct_smart_holder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/detail/struct_smart_holder.h b/include/pybind11/detail/struct_smart_holder.h index f34ca94712..9747225f96 100644 --- a/include/pybind11/detail/struct_smart_holder.h +++ b/include/pybind11/detail/struct_smart_holder.h @@ -64,7 +64,7 @@ High-level aspects: // https://github.com/llvm/llvm-project/blob/a9b64bb3180dab6d28bf800a641f9a9ad54d2c0c/libcxx/include/typeinfo#L271-L276 // requiere it) #if !defined(PYBIND11_EXPORT_GUARDED_DELETE) -# if defined(__libcpp_version) && !defined(WIN32) && !defined(_WIN32) +# if defined(_LIBCPP_VERSION) && !defined(WIN32) && !defined(_WIN32) # define PYBIND11_EXPORT_GUARDED_DELETE __attribute__((visibility("default"))) # else # define PYBIND11_EXPORT_GUARDED_DELETE From 48f2e94da476ec71d26f2c5b14a915dec73b50fe Mon Sep 17 00:00:00 2001 From: Henry Schreiner <HenrySchreinerIII@gmail.com> Date: Thu, 29 May 2025 11:50:49 -0400 Subject: [PATCH 11/14] Update struct_smart_holder.h --- include/pybind11/detail/struct_smart_holder.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/pybind11/detail/struct_smart_holder.h b/include/pybind11/detail/struct_smart_holder.h index 9747225f96..9b2da87837 100644 --- a/include/pybind11/detail/struct_smart_holder.h +++ b/include/pybind11/detail/struct_smart_holder.h @@ -59,10 +59,10 @@ High-level aspects: #include <utility> // IMPORTANT: This code block must stay BELOW the #include <stdexcept> above. -// This is only requried on some builds with libc++ (one of three implementations +// This is only required on some builds with libc++ (one of three implementations // in // https://github.com/llvm/llvm-project/blob/a9b64bb3180dab6d28bf800a641f9a9ad54d2c0c/libcxx/include/typeinfo#L271-L276 -// requiere it) +// require it) #if !defined(PYBIND11_EXPORT_GUARDED_DELETE) # if defined(_LIBCPP_VERSION) && !defined(WIN32) && !defined(_WIN32) # define PYBIND11_EXPORT_GUARDED_DELETE __attribute__((visibility("default"))) From 29b2853f6d3bc555473f980087a2fe92828359ce Mon Sep 17 00:00:00 2001 From: Henry Schreiner <HenrySchreinerIII@gmail.com> Date: Sun, 1 Jun 2025 01:37:54 -0400 Subject: [PATCH 12/14] ci: fix addition to reusable-standard.yml --- .github/workflows/reusable-standard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reusable-standard.yml b/.github/workflows/reusable-standard.yml index 270479f4f5..e124b65bd4 100644 --- a/.github/workflows/reusable-standard.yml +++ b/.github/workflows/reusable-standard.yml @@ -75,7 +75,7 @@ jobs: run: cmake --build build --target test_cmake_build - name: Visibility test - run: cmake --build . --target test_visibility + run: cmake --build build --target test_visibility - name: Setuptools helpers test run: | From 896b3af749feba6e37ae29966d4c860ccde3b467 Mon Sep 17 00:00:00 2001 From: Henry Schreiner <HenrySchreinerIII@gmail.com> Date: Sun, 1 Jun 2025 03:15:26 -0400 Subject: [PATCH 13/14] Update CMakeLists.txt --- tests/test_visibility/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_visibility/CMakeLists.txt b/tests/test_visibility/CMakeLists.txt index 3d724ca28d..7d045f3f9f 100644 --- a/tests/test_visibility/CMakeLists.txt +++ b/tests/test_visibility/CMakeLists.txt @@ -34,6 +34,7 @@ add_library(test_visibility_lib SHARED lib.h lib.cpp) add_library(test_visibility_lib::test_visibility_lib ALIAS test_visibility_lib) target_include_directories(test_visibility_lib PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) target_include_directories(test_visibility_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_compile_features(test_visibility_lib PUBLIC cxx_std_11) generate_export_header(test_visibility_lib) From f2a5001c1d58d7621a74d35e220380018b52d711 Mon Sep 17 00:00:00 2001 From: Henry Schreiner <henryschreineriii@gmail.com> Date: Tue, 3 Jun 2025 01:54:46 -0400 Subject: [PATCH 14/14] refactor: rename tests to test_cross_module_rtti Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com> --- .github/workflows/ci.yml | 28 ++++---- .github/workflows/reusable-standard.yml | 2 +- CMakePresets.json | 4 +- tests/CMakeLists.txt | 2 +- tests/test_cross_module_rtti/CMakeLists.txt | 68 +++++++++++++++++++ .../bindings.cpp | 2 +- .../catch.cpp | 0 .../lib.cpp | 0 .../lib.h | 6 +- .../test_cross_module_rtti.cpp} | 8 +-- tests/test_visibility/CMakeLists.txt | 64 ----------------- 11 files changed, 94 insertions(+), 90 deletions(-) create mode 100644 tests/test_cross_module_rtti/CMakeLists.txt rename tests/{test_visibility => test_cross_module_rtti}/bindings.cpp (91%) rename tests/{test_visibility => test_cross_module_rtti}/catch.cpp (100%) rename tests/{test_visibility => test_cross_module_rtti}/lib.cpp (100%) rename tests/{test_visibility => test_cross_module_rtti}/lib.h (64%) rename tests/{test_visibility/test_visibility.cpp => test_cross_module_rtti/test_cross_module_rtti.cpp} (87%) delete mode 100644 tests/test_visibility/CMakeLists.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 683000ec14..9e8d3b6fe5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -231,7 +231,7 @@ jobs: run: cmake --build . --target test_cmake_build - name: Visibility test - run: cmake --build . --target test_visibility + run: cmake --build . --target test_cross_module_rtti manylinux: @@ -332,7 +332,7 @@ jobs: run: cmake --build --preset default --target cpptest - name: Visibility test - run: cmake --build --preset default --target test_visibility + run: cmake --build --preset default --target test_cross_module_rtti - name: Run Valgrind on Python tests if: matrix.valgrind @@ -393,7 +393,7 @@ jobs: run: cmake --build build --target test_cmake_build - name: Visibility test - run: cmake --build build --target test_visibility + run: cmake --build build --target test_cross_module_rtti # Testing NVCC; forces sources to behave like .cu files cuda: @@ -514,7 +514,7 @@ jobs: run: cmake --build build --target test_cmake_build - name: Visibility test - run: cmake --build build --target test_visibility + run: cmake --build build --target test_cross_module_rtti # Testing on GCC using the GCC docker images (only recent images supported) gcc: @@ -567,7 +567,7 @@ jobs: run: cmake --build build --target test_cmake_build - name: Visibility test - run: cmake --build build --target test_visibility + run: cmake --build build --target test_cross_module_rtti - name: Configure - Exercise cmake -DPYBIND11_TEST_OVERRIDE if: matrix.gcc == '12' @@ -654,7 +654,7 @@ jobs: - name: Visibility test run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e - cmake --build build-11 --target test_visibility + cmake --build build-11 --target test_cross_module_rtti - name: Configure C++17 run: | @@ -691,7 +691,7 @@ jobs: - name: Visibility test run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e - cmake --build build-17 --target test_visibility + cmake --build build-17 --target test_cross_module_rtti # Testing on CentOS (manylinux uses a centos base). centos: @@ -755,7 +755,7 @@ jobs: run: cmake --build build --target test_cmake_build - name: Visibility test - run: cmake --build build --target test_visibility + run: cmake --build build --target test_cross_module_rtti # This tests an "install" with the CMake tools @@ -987,7 +987,7 @@ jobs: run: cmake --build build --target test_cmake_build - name: Visibility test - run: cmake --build build --target test_visibility + run: cmake --build build --target test_cross_module_rtti - name: Configure C++20 - Exercise cmake -DPYBIND11_TEST_OVERRIDE run: > @@ -1063,7 +1063,7 @@ jobs: run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build --target test_cmake_build - name: Visibility test - run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build --target test_visibility + run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build --target test_cross_module_rtti - name: Clean directory run: git clean -fdx @@ -1087,7 +1087,7 @@ jobs: run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build2 --target test_cmake_build - name: Visibility test - run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build2 --target test_visibility + run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build2 --target test_cross_module_rtti - name: Clean directory run: git clean -fdx @@ -1111,7 +1111,7 @@ jobs: run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build3 --target test_cmake_build - name: Visibility test - run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build3 --target test_visibility + run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build3 --target test_cross_module_rtti windows_clang: if: github.event.pull_request.draft == false @@ -1181,7 +1181,7 @@ jobs: run: cmake --build . --target test_cmake_build -j 2 - name: Visibility test - run: cmake --build . --target test_visibility -j 2 + run: cmake --build . --target test_cross_module_rtti -j 2 - name: Clean directory run: git clean -fdx @@ -1251,7 +1251,7 @@ jobs: run: cmake --build . --target test_cmake_build -j 2 - name: Visibility test - run: cmake --build . --target test_visibility -j 2 + run: cmake --build . --target test_cross_module_rtti -j 2 - name: CMake Configure - Exercise cmake -DPYBIND11_TEST_OVERRIDE run: > diff --git a/.github/workflows/reusable-standard.yml b/.github/workflows/reusable-standard.yml index e124b65bd4..d3c769449a 100644 --- a/.github/workflows/reusable-standard.yml +++ b/.github/workflows/reusable-standard.yml @@ -75,7 +75,7 @@ jobs: run: cmake --build build --target test_cmake_build - name: Visibility test - run: cmake --build build --target test_visibility + run: cmake --build build --target test_cross_module_rtti - name: Setuptools helpers test run: | diff --git a/CMakePresets.json b/CMakePresets.json index c967c25a37..42bf3ade9d 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -61,13 +61,13 @@ "name": "tests", "displayName": "Tests (for workflow)", "configurePreset": "default", - "targets": ["pytest", "cpptest", "test_cmake_build"] + "targets": ["pytest", "cpptest", "test_cmake_build", "test_cross_module_rtti"] }, { "name": "testsvenv", "displayName": "Tests Venv (for workflow)", "configurePreset": "venv", - "targets": ["pytest", "cpptest", "test_cmake_build"] + "targets": ["pytest", "cpptest", "test_cmake_build", "test_cross_module_rtti"] } ], "workflowPresets": [ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2546d1d372..0e76e68786 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -651,5 +651,5 @@ if(NOT PYBIND11_CUDA_TESTS) add_subdirectory(test_cmake_build) # Test visibility of common symbols across shared libraries - add_subdirectory(test_visibility) + add_subdirectory(test_cross_module_rtti) endif() diff --git a/tests/test_cross_module_rtti/CMakeLists.txt b/tests/test_cross_module_rtti/CMakeLists.txt new file mode 100644 index 0000000000..97d2c780cb --- /dev/null +++ b/tests/test_cross_module_rtti/CMakeLists.txt @@ -0,0 +1,68 @@ +possibly_uninitialized(PYTHON_MODULE_EXTENSION Python_INTERPRETER_ID) + +set(CMAKE_CXX_VISIBILITY_PRESET hidden) + +if("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" + OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy" + OR "${PYTHON_MODULE_EXTENSION}" MATCHES "graalpy") + message(STATUS "Skipping visibility test on PyPy or GraalPy") + add_custom_target(test_cross_module_rtti + )# Dummy target on PyPy or GraalPy. Embedding is not supported. + set(_suppress_unused_variable_warning "${DOWNLOAD_CATCH}") + return() +endif() + +if(TARGET Python::Module AND NOT TARGET Python::Python) + message(STATUS "Skipping visibility test since no embed libs found") + add_custom_target(test_cross_module_rtti) # Dummy target since embedding is not supported. + set(_suppress_unused_variable_warning "${DOWNLOAD_CATCH}") + return() +endif() + +find_package(Catch 2.13.10) + +if(CATCH_FOUND) + message(STATUS "Building interpreter tests using Catch v${CATCH_VERSION}") +else() + message(STATUS "Catch not detected. Interpreter tests will be skipped. Install Catch headers" + " manually or use `cmake -DDOWNLOAD_CATCH=ON` to fetch them automatically.") + return() +endif() + +include(GenerateExportHeader) + +add_library(test_cross_module_rtti_lib SHARED lib.h lib.cpp) +add_library(test_cross_module_rtti_lib::test_cross_module_rtti_lib ALIAS + test_cross_module_rtti_lib) +target_include_directories(test_cross_module_rtti_lib PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) +target_include_directories(test_cross_module_rtti_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_compile_features(test_cross_module_rtti_lib PUBLIC cxx_std_11) + +generate_export_header(test_cross_module_rtti_lib) + +pybind11_add_module(test_cross_module_rtti_bindings SHARED bindings.cpp) +target_link_libraries(test_cross_module_rtti_bindings + PUBLIC test_cross_module_rtti_lib::test_cross_module_rtti_lib) + +add_executable(test_cross_module_rtti_main catch.cpp test_cross_module_rtti.cpp) +target_link_libraries( + test_cross_module_rtti_main PUBLIC test_cross_module_rtti_lib::test_cross_module_rtti_lib + pybind11::embed Catch2::Catch2) + +# Ensure that we have built the python bindings since we load them in main +add_dependencies(test_cross_module_rtti_main test_cross_module_rtti_bindings) + +pybind11_enable_warnings(test_cross_module_rtti_main) +pybind11_enable_warnings(test_cross_module_rtti_bindings) +pybind11_enable_warnings(test_cross_module_rtti_lib) + +add_custom_target( + test_cross_module_rtti + COMMAND "$<TARGET_FILE:test_cross_module_rtti_main>" + DEPENDS test_cross_module_rtti_main + WORKING_DIRECTORY "$<TARGET_FILE_DIR:test_cross_module_rtti_main>") + +set_target_properties(test_cross_module_rtti_bindings PROPERTIES LIBRARY_OUTPUT_DIRECTORY + "${CMAKE_CURRENT_BINARY_DIR}") + +add_dependencies(check test_cross_module_rtti) diff --git a/tests/test_visibility/bindings.cpp b/tests/test_cross_module_rtti/bindings.cpp similarity index 91% rename from tests/test_visibility/bindings.cpp rename to tests/test_cross_module_rtti/bindings.cpp index ccd78e2808..94fa6874f8 100644 --- a/tests/test_visibility/bindings.cpp +++ b/tests/test_cross_module_rtti/bindings.cpp @@ -8,7 +8,7 @@ class BaseTrampoline : public lib::Base, public pybind11::trampoline_self_life_s int get() const override { PYBIND11_OVERLOAD(int, lib::Base, get); } }; -PYBIND11_MODULE(test_visibility_bindings, m) { +PYBIND11_MODULE(test_cross_module_rtti_bindings, m) { pybind11::classh<lib::Base, BaseTrampoline>(m, "Base") .def(pybind11::init<int, int>()) .def_readwrite("a", &lib::Base::a) diff --git a/tests/test_visibility/catch.cpp b/tests/test_cross_module_rtti/catch.cpp similarity index 100% rename from tests/test_visibility/catch.cpp rename to tests/test_cross_module_rtti/catch.cpp diff --git a/tests/test_visibility/lib.cpp b/tests/test_cross_module_rtti/lib.cpp similarity index 100% rename from tests/test_visibility/lib.cpp rename to tests/test_cross_module_rtti/lib.cpp diff --git a/tests/test_visibility/lib.h b/tests/test_cross_module_rtti/lib.h similarity index 64% rename from tests/test_visibility/lib.h rename to tests/test_cross_module_rtti/lib.h index 8275b85b5c..0925b084ca 100644 --- a/tests/test_visibility/lib.h +++ b/tests/test_cross_module_rtti/lib.h @@ -1,7 +1,7 @@ #pragma once #include <memory> -#include <test_visibility_lib_export.h> +#include <test_cross_module_rtti_lib_export.h> #if defined(_MSC_VER) __pragma(warning(disable : 4251)) @@ -9,7 +9,7 @@ __pragma(warning(disable : 4251)) namespace lib { - class TEST_VISIBILITY_LIB_EXPORT Base : public std::enable_shared_from_this<Base> { + class TEST_CROSS_MODULE_RTTI_LIB_EXPORT Base : public std::enable_shared_from_this<Base> { public: Base(int a, int b); virtual ~Base() = default; @@ -20,7 +20,7 @@ __pragma(warning(disable : 4251)) int b; }; - class TEST_VISIBILITY_LIB_EXPORT Foo : public Base { + class TEST_CROSS_MODULE_RTTI_LIB_EXPORT Foo : public Base { public: Foo(int a, int b); diff --git a/tests/test_visibility/test_visibility.cpp b/tests/test_cross_module_rtti/test_cross_module_rtti.cpp similarity index 87% rename from tests/test_visibility/test_visibility.cpp rename to tests/test_cross_module_rtti/test_cross_module_rtti.cpp index fe3caed2e5..64988b77a1 100644 --- a/tests/test_visibility/test_visibility.cpp +++ b/tests/test_cross_module_rtti/test_cross_module_rtti.cpp @@ -6,11 +6,11 @@ #include <lib.h> static constexpr auto script = R"( -import test_visibility_bindings +import test_cross_module_rtti_bindings -class Bar(test_visibility_bindings.Base): +class Bar(test_cross_module_rtti_bindings.Base): def __init__(self, a, b): - test_visibility_bindings.Base.__init__(self, a, b) + test_cross_module_rtti_bindings.Base.__init__(self, a, b) def get(self): return 4 * self.a + self.b @@ -23,7 +23,7 @@ def get_bar(a, b): TEST_CASE("Simple case where without is_alias") { // "Simple" case this will not have `python_instance_is_alias` set in type_cast_base.h:771 - auto bindings = pybind11::module_::import("test_visibility_bindings"); + auto bindings = pybind11::module_::import("test_cross_module_rtti_bindings"); auto holder = bindings.attr("get_foo")(1, 2); auto foo = holder.cast<std::shared_ptr<lib::Base>>(); REQUIRE(foo->get() == 4); // 2 * 1 + 2 = 4 diff --git a/tests/test_visibility/CMakeLists.txt b/tests/test_visibility/CMakeLists.txt deleted file mode 100644 index 7d045f3f9f..0000000000 --- a/tests/test_visibility/CMakeLists.txt +++ /dev/null @@ -1,64 +0,0 @@ -possibly_uninitialized(PYTHON_MODULE_EXTENSION Python_INTERPRETER_ID) - -set(CMAKE_CXX_VISIBILITY_PRESET hidden) - -if("${PYTHON_MODULE_EXTENSION}" MATCHES "pypy" - OR "${Python_INTERPRETER_ID}" STREQUAL "PyPy" - OR "${PYTHON_MODULE_EXTENSION}" MATCHES "graalpy") - message(STATUS "Skipping visibility test on PyPy or GraalPy") - add_custom_target(test_visibility) # Dummy target on PyPy or GraalPy. Embedding is not supported. - set(_suppress_unused_variable_warning "${DOWNLOAD_CATCH}") - return() -endif() - -if(TARGET Python::Module AND NOT TARGET Python::Python) - message(STATUS "Skipping visibility test since no embed libs found") - add_custom_target(test_visibility) # Dummy target since embedding is not supported. - set(_suppress_unused_variable_warning "${DOWNLOAD_CATCH}") - return() -endif() - -find_package(Catch 2.13.10) - -if(CATCH_FOUND) - message(STATUS "Building interpreter tests using Catch v${CATCH_VERSION}") -else() - message(STATUS "Catch not detected. Interpreter tests will be skipped. Install Catch headers" - " manually or use `cmake -DDOWNLOAD_CATCH=ON` to fetch them automatically.") - return() -endif() - -include(GenerateExportHeader) - -add_library(test_visibility_lib SHARED lib.h lib.cpp) -add_library(test_visibility_lib::test_visibility_lib ALIAS test_visibility_lib) -target_include_directories(test_visibility_lib PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) -target_include_directories(test_visibility_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -target_compile_features(test_visibility_lib PUBLIC cxx_std_11) - -generate_export_header(test_visibility_lib) - -pybind11_add_module(test_visibility_bindings SHARED bindings.cpp) -target_link_libraries(test_visibility_bindings PUBLIC test_visibility_lib::test_visibility_lib) - -add_executable(test_visibility_main catch.cpp test_visibility.cpp) -target_link_libraries(test_visibility_main PUBLIC test_visibility_lib::test_visibility_lib - pybind11::embed Catch2::Catch2) - -# Ensure that we have built the python bindings since we load them in main -add_dependencies(test_visibility_main test_visibility_bindings) - -pybind11_enable_warnings(test_visibility_main) -pybind11_enable_warnings(test_visibility_bindings) -pybind11_enable_warnings(test_visibility_lib) - -add_custom_target( - test_visibility - COMMAND "$<TARGET_FILE:test_visibility_main>" - DEPENDS test_visibility_main - WORKING_DIRECTORY "$<TARGET_FILE_DIR:test_visibility_main>") - -set_target_properties(test_visibility_bindings PROPERTIES LIBRARY_OUTPUT_DIRECTORY - "${CMAKE_CURRENT_BINARY_DIR}") - -add_dependencies(check test_visibility)