From fc59f4e6e508f28c0e2896937660b9eae0f5ea51 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 12 Aug 2024 16:51:48 -0400 Subject: [PATCH 01/18] fix(cmake): add required emscripten flags (#5298) * fix(cmake): add required emscripten flags Signed-off-by: Henry Schreiner * Update emscripten.yaml * fix(cmake): add required emscripten flags to headers target Signed-off-by: Henry Schreiner * fix(cmake): incorrect detection of Emscripten Signed-off-by: Henry Schreiner * fix(cmake): allow pybind11::headers to be modified Signed-off-by: Henry Schreiner * fix(cmake): hide a warning when building the tests standalone Signed-off-by: Henry Schreiner * fix(cmake): use explicit variable for is config Signed-off-by: Henry Schreiner * fix(cmake): go back to ALIAS target Signed-off-by: Henry Schreiner * chore: reduce overall diff Signed-off-by: Henry Schreiner * chore: reduce overall diff Signed-off-by: Henry Schreiner * chore: shorten code a bit Signed-off-by: Henry Schreiner --------- Signed-off-by: Henry Schreiner --- .github/workflows/emscripten.yaml | 4 ++-- tests/pyproject.toml | 4 ++++ tools/pybind11Common.cmake | 30 ++++++++++++++++++++++++++++-- tools/pybind11Config.cmake.in | 2 +- 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/.github/workflows/emscripten.yaml b/.github/workflows/emscripten.yaml index cbd7f5d54..14b2b9dc7 100644 --- a/.github/workflows/emscripten.yaml +++ b/.github/workflows/emscripten.yaml @@ -5,6 +5,8 @@ on: pull_request: branches: - master + - stable + - v* concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -23,8 +25,6 @@ jobs: - uses: pypa/cibuildwheel@v2.20 env: PYODIDE_BUILD_EXPORTS: whole_archive - CFLAGS: -fexceptions - LDFLAGS: -fexceptions with: package-dir: tests only: cp312-pyodide_wasm32 diff --git a/tests/pyproject.toml b/tests/pyproject.toml index 469c145df..044bf15c0 100644 --- a/tests/pyproject.toml +++ b/tests/pyproject.toml @@ -10,6 +10,10 @@ name = "pybind11_tests" version = "0.0.1" dependencies = ["pytest", "pytest-timeout", "numpy", "scipy"] +[tool.scikit-build] +# Hide a warning while we also support CMake < 3.15 +cmake.version = ">=3.15" + [tool.scikit-build.cmake.define] PYBIND11_FINDPYTHON = true diff --git a/tools/pybind11Common.cmake b/tools/pybind11Common.cmake index 8467b45d2..585ed3d21 100644 --- a/tools/pybind11Common.cmake +++ b/tools/pybind11Common.cmake @@ -2,7 +2,7 @@ Adds the following targets:: - pybind11::pybind11 - link to headers and pybind11 + pybind11::pybind11 - link to Python headers and pybind11::headers pybind11::module - Adds module links pybind11::embed - Adds embed links pybind11::lto - Link time optimizations (only if CMAKE_INTERPROCEDURAL_OPTIMIZATION is not set) @@ -75,6 +75,32 @@ set_property( APPEND PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11) +# -------------- emscripten requires exceptions enabled ------------- +# _pybind11_no_exceptions is a private mechanism to disable this addition. +# Please open an issue if you need to use it; it will be removed if no one +# needs it. +if(CMAKE_SYSTEM_NAME MATCHES Emscripten AND NOT _pybind11_no_exceptions) + if(CMAKE_VERSION VERSION_LESS 3.13) + message(WARNING "CMake 3.13+ is required to build for Emscripten. Some flags will be missing") + else() + if(_is_config) + set(_tmp_config_target pybind11::pybind11_headers) + else() + set(_tmp_config_target pybind11_headers) + endif() + + set_property( + TARGET ${_tmp_config_target} + APPEND + PROPERTY INTERFACE_LINK_OPTIONS -fexceptions) + set_property( + TARGET ${_tmp_config_target} + APPEND + PROPERTY INTERFACE_COMPILE_OPTIONS -fexceptions) + unset(_tmp_config_target) + endif() +endif() + # --------------------------- link helper --------------------------- add_library(pybind11::python_link_helper IMPORTED INTERFACE ${optional_global}) @@ -329,7 +355,7 @@ function(_pybind11_generate_lto target prefer_thin_lto) if(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64le" OR CMAKE_SYSTEM_PROCESSOR MATCHES "mips64") # Do nothing - elseif(CMAKE_SYSTEM_PROCESSOR MATCHES emscripten) + elseif(CMAKE_SYSTEM_NAME MATCHES Emscripten) # This compile is very costly when cross-compiling, so set this without checking set(PYBIND11_LTO_CXX_FLAGS "-flto${thin}${cxx_append}") set(PYBIND11_LTO_LINKER_FLAGS "-flto${thin}${linker_append}") diff --git a/tools/pybind11Config.cmake.in b/tools/pybind11Config.cmake.in index 304f1d907..2d9fa94f6 100644 --- a/tools/pybind11Config.cmake.in +++ b/tools/pybind11Config.cmake.in @@ -84,7 +84,7 @@ you can either use the basic targets, or use the FindPython tools: # Python method: Python_add_library(MyModule2 src2.cpp) - target_link_libraries(MyModule2 pybind11::headers) + target_link_libraries(MyModule2 PUBLIC pybind11::headers) set_target_properties(MyModule2 PROPERTIES INTERPROCEDURAL_OPTIMIZATION ON CXX_VISIBILITY_PRESET ON From 8d90b83b19de61009779edaa363679cfb9babbb5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2024 19:49:56 -0400 Subject: [PATCH 02/18] chore(deps): bump actions/attest-build-provenance in the actions group (#5297) Bumps the actions group with 1 update: [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance). Updates `actions/attest-build-provenance` from 1.4.0 to 1.4.1 - [Release notes](https://github.com/actions/attest-build-provenance/releases) - [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md) - [Commits](https://github.com/actions/attest-build-provenance/compare/210c1913531870065f03ce1f9440dd87bc0938cd...310b0a4a3b0b78ef57ecda988ee04b132db73ef8) --- updated-dependencies: - dependency-name: actions/attest-build-provenance dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pip.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pip.yml b/.github/workflows/pip.yml index 75074ff7f..3edfa612d 100644 --- a/.github/workflows/pip.yml +++ b/.github/workflows/pip.yml @@ -102,7 +102,7 @@ jobs: - uses: actions/download-artifact@v4 - name: Generate artifact attestation for sdist and wheel - uses: actions/attest-build-provenance@210c1913531870065f03ce1f9440dd87bc0938cd # v1.4.0 + uses: actions/attest-build-provenance@310b0a4a3b0b78ef57ecda988ee04b132db73ef8 # v1.4.1 with: subject-path: "*/pybind11*" From 40f2c7863b68f7d7568910c316291f4f0c51222b Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Tue, 13 Aug 2024 09:04:03 -0400 Subject: [PATCH 03/18] docs: prepare for 2.13.2 (#5299) * docs: prepare for 2.13.2 Signed-off-by: Henry Schreiner * Update changelog.rst * Update changelog.rst --------- Signed-off-by: Henry Schreiner --- docs/changelog.rst | 58 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index ab6c713c1..22b12e409 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -15,6 +15,64 @@ IN DEVELOPMENT Changes will be summarized here periodically. +New Features: + +* Support for Python 3.7 was removed. (Official end-of-life: 2023-06-27). + `#5191 `_ + +Support for CMake older than 3.15 and some older compilers will also be removed. + +Version 2.13.2 (August 13, 2024) +-------------------------------- + +New Features: + +* A ``pybind11::detail::type_caster_std_function_specializations`` feature was added, to support specializations for + ``std::function``'s with return types that require custom to-Python conversion behavior (to primary use case is to catch and + convert exceptions). + `#4597 `_ + + +Changes: + + +* Use ``PyMutex`` instead of ``std::mutex`` for internal locking in the free-threaded build. + `#5219 `_ + +* Add a special type annotation for C++ empty tuple. + `#5214 `_ + +* When compiling for WebAssembly, add the required exception flags (CMake 3.13+). + `#5298 `_ + +Bug fixes: + +* Make ``gil_safe_call_once_and_store`` thread-safe in free-threaded CPython. + `#5246 `_ + +* A missing ``#include `` in pybind11/typing.h was added to fix build errors (in case user code does not already depend + on that include). + `#5208 `_ + +* Fix regression introduced in #5201 for GCC<10.3 in C++20 mode. + `#5205 `_ + + +.. fix(cmake) + +* Remove extra = when assigning flto value in the case for Clang in CMake. + `#5207 `_ + + +Tests: + +* Adding WASM testing to our CI (Pyodide / Emscripten via scikit-build-core). + `#4745 `_ + +* clang-tidy (in GitHub Actions) was updated from clang 15 to clang 18. + `#5272 `_ + + Version 2.13.1 (June 26, 2024) ------------------------------ From 1fe92c7b35f9b80c7e952bb1a91841c4f362a3b1 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Tue, 13 Aug 2024 12:32:32 -0400 Subject: [PATCH 04/18] fix: emscripten cmake issue (#5301) Signed-off-by: Henry Schreiner --- tools/pybind11Common.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pybind11Common.cmake b/tools/pybind11Common.cmake index 585ed3d21..7d8d94b11 100644 --- a/tools/pybind11Common.cmake +++ b/tools/pybind11Common.cmake @@ -83,7 +83,7 @@ if(CMAKE_SYSTEM_NAME MATCHES Emscripten AND NOT _pybind11_no_exceptions) if(CMAKE_VERSION VERSION_LESS 3.13) message(WARNING "CMake 3.13+ is required to build for Emscripten. Some flags will be missing") else() - if(_is_config) + if(is_config) set(_tmp_config_target pybind11::pybind11_headers) else() set(_tmp_config_target pybind11_headers) From 8d9f4d50cc7baa461365e977a0645c6c0d7b1b12 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Tue, 13 Aug 2024 13:02:15 -0400 Subject: [PATCH 05/18] fix: quote paths from pybind11-config (#5302) Signed-off-by: Henry Schreiner --- pybind11/__main__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pybind11/__main__.py b/pybind11/__main__.py index b656ce6fe..dadf24f3c 100644 --- a/pybind11/__main__.py +++ b/pybind11/__main__.py @@ -2,6 +2,7 @@ from __future__ import annotations import argparse +import shlex import sys import sysconfig @@ -22,7 +23,7 @@ def print_includes() -> None: if d and d not in unique_dirs: unique_dirs.append(d) - print(" ".join("-I" + d for d in unique_dirs)) + print(" ".join(shlex.quote(f"-I{d}") for d in unique_dirs)) def main() -> None: @@ -54,9 +55,9 @@ def main() -> None: if args.includes: print_includes() if args.cmakedir: - print(get_cmake_dir()) + print(shlex.quote(get_cmake_dir())) if args.pkgconfigdir: - print(get_pkgconfig_dir()) + print(shlex.quote(get_pkgconfig_dir())) if __name__ == "__main__": From 4a06eca59173cdc8c9bcb28a186e2c512cfc9f97 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Tue, 13 Aug 2024 13:25:23 -0400 Subject: [PATCH 06/18] docs: prepare for 2.13.3 Signed-off-by: Henry Schreiner --- docs/changelog.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 22b12e409..d19a90129 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -22,6 +22,19 @@ New Features: Support for CMake older than 3.15 and some older compilers will also be removed. +Version 2.13.3 (August 13, 2024) +-------------------------------- + +Bug fixes: + +* Quote paths from pybind11-config + `#5302 `_ + + +* Fix typo in Emscripten support when in config mode (CMake) + `#5301 `_ + + Version 2.13.2 (August 13, 2024) -------------------------------- From 0d44d720cb1b911de2d96849860d0c5beb368f95 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 14 Aug 2024 01:42:51 +0700 Subject: [PATCH 07/18] Make stl.h `list|set|map_caster` more user friendly. (#4686) * Add `test_pass_std_vector_int()`, `test_pass_std_set_int()` in test_stl * Change `list_caster` to also accept generator objects (`PyGen_Check(src.ptr()`). Note for completeness: This is a more conservative change than https://github.com/google/pywrapcc/pull/30042 * Drop in (currently unpublished) PyCLIF code, use in `list_caster`, adjust tests. * Use `PyObjectTypeIsConvertibleToStdSet()` in `set_caster`, adjust tests. * Use `PyObjectTypeIsConvertibleToStdMap()` in `map_caster`, add tests. * Simplify `list_caster` `load()` implementation, push str/bytes check into `PyObjectTypeIsConvertibleToStdVector()`. * clang-tidy cleanup with a few extra `(... != 0)` to be more consistent. * Also use `PyObjectTypeIsConvertibleToStdVector()` in `array_caster`. * Update comment pointing to clif/python/runtime.cc (code is unchanged). * Comprehensive test coverage, enhanced set_caster load implementation. * Resolve clang-tidy eror. * Add a long C++ comment explaining what led to the `PyObjectTypeIsConvertibleTo*()` implementations. * Minor function name change in test. * strcmp -> std::strcmp (thanks @Skylion007 for catching this) * Add `PyCallable_Check(items)` in `PyObjectTypeIsConvertibleToStdMap()` * Resolve clang-tidy error * Use `PyMapping_Items()` instead of `src.attr("items")()`, to be internally consistent with `PyMapping_Check()` * Update link to PyCLIF sources. * Fix typo (thanks @wangxf123456 for catching this) * Add `test_pass_std_vector_int()`, `test_pass_std_set_int()` in test_stl * Change `list_caster` to also accept generator objects (`PyGen_Check(src.ptr()`). Note for completeness: This is a more conservative change than https://github.com/google/pywrapcc/pull/30042 * Drop in (currently unpublished) PyCLIF code, use in `list_caster`, adjust tests. * Use `PyObjectTypeIsConvertibleToStdSet()` in `set_caster`, adjust tests. * Use `PyObjectTypeIsConvertibleToStdMap()` in `map_caster`, add tests. * Simplify `list_caster` `load()` implementation, push str/bytes check into `PyObjectTypeIsConvertibleToStdVector()`. * clang-tidy cleanup with a few extra `(... != 0)` to be more consistent. * Also use `PyObjectTypeIsConvertibleToStdVector()` in `array_caster`. * Update comment pointing to clif/python/runtime.cc (code is unchanged). * Comprehensive test coverage, enhanced set_caster load implementation. * Resolve clang-tidy eror. * Add a long C++ comment explaining what led to the `PyObjectTypeIsConvertibleTo*()` implementations. * Minor function name change in test. * strcmp -> std::strcmp (thanks @Skylion007 for catching this) * Add `PyCallable_Check(items)` in `PyObjectTypeIsConvertibleToStdMap()` * Resolve clang-tidy error * Use `PyMapping_Items()` instead of `src.attr("items")()`, to be internally consistent with `PyMapping_Check()` * Update link to PyCLIF sources. * Fix typo (thanks @wangxf123456 for catching this) * Fix typo discovered by new version of codespell. --- include/pybind11/stl.h | 212 ++++++++++++++++++++++++++++++++++------- tests/test_stl.cpp | 34 +++++++ tests/test_stl.py | 126 ++++++++++++++++++++++++ 3 files changed, 338 insertions(+), 34 deletions(-) diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h index 71bc5902e..096301bc7 100644 --- a/include/pybind11/stl.h +++ b/include/pybind11/stl.h @@ -13,6 +13,7 @@ #include "detail/common.h" #include +#include #include #include #include @@ -35,6 +36,89 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(detail) +// +// Begin: Equivalent of +// https://github.com/google/clif/blob/ae4eee1de07cdf115c0c9bf9fec9ff28efce6f6c/clif/python/runtime.cc#L388-L438 +/* +The three `PyObjectTypeIsConvertibleTo*()` functions below are +the result of converging the behaviors of pybind11 and PyCLIF +(http://github.com/google/clif). + +Originally PyCLIF was extremely far on the permissive side of the spectrum, +while pybind11 was very far on the strict side. Originally PyCLIF accepted any +Python iterable as input for a C++ `vector`/`set`/`map` argument, as long as +the elements were convertible. The obvious (in hindsight) problem was that +any empty Python iterable could be passed to any of these C++ types, e.g. `{}` +was accepted for C++ `vector`/`set` arguments, or `[]` for C++ `map` arguments. + +The functions below strike a practical permissive-vs-strict compromise, +informed by tens of thousands of use cases in the wild. A main objective is +to prevent accidents and improve readability: + +- Python literals must match the C++ types. + +- For C++ `set`: The potentially reducing conversion from a Python sequence + (e.g. Python `list` or `tuple`) to a C++ `set` must be explicit, by going + through a Python `set`. + +- However, a Python `set` can still be passed to a C++ `vector`. The rationale + is that this conversion is not reducing. Implicit conversions of this kind + are also fairly commonly used, therefore enforcing explicit conversions + would have an unfavorable cost : benefit ratio; more sloppily speaking, + such an enforcement would be more annoying than helpful. +*/ + +inline bool PyObjectIsInstanceWithOneOfTpNames(PyObject *obj, + std::initializer_list tp_names) { + if (PyType_Check(obj)) { + return false; + } + const char *obj_tp_name = Py_TYPE(obj)->tp_name; + for (const auto *tp_name : tp_names) { + if (std::strcmp(obj_tp_name, tp_name) == 0) { + return true; + } + } + return false; +} + +inline bool PyObjectTypeIsConvertibleToStdVector(PyObject *obj) { + if (PySequence_Check(obj) != 0) { + return !PyUnicode_Check(obj) && !PyBytes_Check(obj); + } + return (PyGen_Check(obj) != 0) || (PyAnySet_Check(obj) != 0) + || PyObjectIsInstanceWithOneOfTpNames( + obj, {"dict_keys", "dict_values", "dict_items", "map", "zip"}); +} + +inline bool PyObjectTypeIsConvertibleToStdSet(PyObject *obj) { + return (PyAnySet_Check(obj) != 0) || PyObjectIsInstanceWithOneOfTpNames(obj, {"dict_keys"}); +} + +inline bool PyObjectTypeIsConvertibleToStdMap(PyObject *obj) { + if (PyDict_Check(obj)) { + return true; + } + // Implicit requirement in the conditions below: + // A type with `.__getitem__()` & `.items()` methods must implement these + // to be compatible with https://docs.python.org/3/c-api/mapping.html + if (PyMapping_Check(obj) == 0) { + return false; + } + PyObject *items = PyObject_GetAttrString(obj, "items"); + if (items == nullptr) { + PyErr_Clear(); + return false; + } + bool is_convertible = (PyCallable_Check(items) != 0); + Py_DECREF(items); + return is_convertible; +} + +// +// End: Equivalent of clif/python/runtime.cc +// + /// Extracts an const lvalue reference or rvalue reference for U based on the type of T (e.g. for /// forwarding a container element). Typically used indirect via forwarded_type(), below. template @@ -66,17 +150,10 @@ private: } void reserve_maybe(const anyset &, void *) {} -public: - bool load(handle src, bool convert) { - if (!isinstance(src)) { - return false; - } - auto s = reinterpret_borrow(src); - value.clear(); - reserve_maybe(s, &value); - for (auto entry : s) { + bool convert_iterable(const iterable &itbl, bool convert) { + for (const auto &it : itbl) { key_conv conv; - if (!conv.load(entry, convert)) { + if (!conv.load(it, convert)) { return false; } value.insert(cast_op(std::move(conv))); @@ -84,6 +161,29 @@ public: return true; } + bool convert_anyset(anyset s, bool convert) { + value.clear(); + reserve_maybe(s, &value); + return convert_iterable(s, convert); + } + +public: + bool load(handle src, bool convert) { + if (!PyObjectTypeIsConvertibleToStdSet(src.ptr())) { + return false; + } + if (isinstance(src)) { + value.clear(); + return convert_anyset(reinterpret_borrow(src), convert); + } + if (!convert) { + return false; + } + assert(isinstance(src)); + value.clear(); + return convert_iterable(reinterpret_borrow(src), convert); + } + template static handle cast(T &&src, return_value_policy policy, handle parent) { if (!std::is_lvalue_reference::value) { @@ -115,15 +215,10 @@ private: } void reserve_maybe(const dict &, void *) {} -public: - bool load(handle src, bool convert) { - if (!isinstance(src)) { - return false; - } - auto d = reinterpret_borrow(src); + bool convert_elements(const dict &d, bool convert) { value.clear(); reserve_maybe(d, &value); - for (auto it : d) { + for (const auto &it : d) { key_conv kconv; value_conv vconv; if (!kconv.load(it.first.ptr(), convert) || !vconv.load(it.second.ptr(), convert)) { @@ -134,6 +229,25 @@ public: return true; } +public: + bool load(handle src, bool convert) { + if (!PyObjectTypeIsConvertibleToStdMap(src.ptr())) { + return false; + } + if (isinstance(src)) { + return convert_elements(reinterpret_borrow(src), convert); + } + if (!convert) { + return false; + } + auto items = reinterpret_steal(PyMapping_Items(src.ptr())); + if (!items) { + throw error_already_set(); + } + assert(isinstance(items)); + return convert_elements(dict(reinterpret_borrow(items)), convert); + } + template static handle cast(T &&src, return_value_policy policy, handle parent) { dict d; @@ -166,20 +280,21 @@ struct list_caster { using value_conv = make_caster; bool load(handle src, bool convert) { - if (!isinstance(src) || isinstance(src) || isinstance(src)) { + if (!PyObjectTypeIsConvertibleToStdVector(src.ptr())) { return false; } - auto s = reinterpret_borrow(src); - value.clear(); - reserve_maybe(s, &value); - for (const auto &it : s) { - value_conv conv; - if (!conv.load(it, convert)) { - return false; - } - value.push_back(cast_op(std::move(conv))); + if (isinstance(src)) { + return convert_elements(src, convert); } - return true; + if (!convert) { + return false; + } + // Designed to be behavior-equivalent to passing tuple(src) from Python: + // The conversion to a tuple will first exhaust the generator object, to ensure that + // the generator is not left in an unpredictable (to the caller) partially-consumed + // state. + assert(isinstance(src)); + return convert_elements(tuple(reinterpret_borrow(src)), convert); } private: @@ -189,6 +304,20 @@ private: } void reserve_maybe(const sequence &, void *) {} + bool convert_elements(handle seq, bool convert) { + auto s = reinterpret_borrow(seq); + value.clear(); + reserve_maybe(s, &value); + for (const auto &it : seq) { + value_conv conv; + if (!conv.load(it, convert)) { + return false; + } + value.push_back(cast_op(std::move(conv))); + } + return true; + } + public: template static handle cast(T &&src, return_value_policy policy, handle parent) { @@ -237,12 +366,8 @@ private: return size == Size; } -public: - bool load(handle src, bool convert) { - if (!isinstance(src)) { - return false; - } - auto l = reinterpret_borrow(src); + bool convert_elements(handle seq, bool convert) { + auto l = reinterpret_borrow(seq); if (!require_size(l.size())) { return false; } @@ -257,6 +382,25 @@ public: return true; } +public: + bool load(handle src, bool convert) { + if (!PyObjectTypeIsConvertibleToStdVector(src.ptr())) { + return false; + } + if (isinstance(src)) { + return convert_elements(src, convert); + } + if (!convert) { + return false; + } + // Designed to be behavior-equivalent to passing tuple(src) from Python: + // The conversion to a tuple will first exhaust the generator object, to ensure that + // the generator is not left in an unpredictable (to the caller) partially-consumed + // state. + assert(isinstance(src)); + return convert_elements(tuple(reinterpret_borrow(src)), convert); + } + template static handle cast(T &&src, return_value_policy policy, handle parent) { list l(src.size()); diff --git a/tests/test_stl.cpp b/tests/test_stl.cpp index 48c907ff3..c35f0d4ca 100644 --- a/tests/test_stl.cpp +++ b/tests/test_stl.cpp @@ -167,6 +167,14 @@ struct type_caster> } // namespace detail } // namespace PYBIND11_NAMESPACE +int pass_std_vector_int(const std::vector &v) { + int zum = 100; + for (const int i : v) { + zum += 2 * i; + } + return zum; +} + TEST_SUBMODULE(stl, m) { // test_vector m.def("cast_vector", []() { return std::vector{1}; }); @@ -546,4 +554,30 @@ TEST_SUBMODULE(stl, m) { []() { return new std::vector(4513); }, // Without explicitly specifying `take_ownership`, this function leaks. py::return_value_policy::take_ownership); + + m.def("pass_std_vector_int", pass_std_vector_int); + m.def("pass_std_vector_pair_int", [](const std::vector> &v) { + int zum = 0; + for (const auto &ij : v) { + zum += ij.first * 100 + ij.second; + } + return zum; + }); + m.def("pass_std_array_int_2", [](const std::array &a) { + return pass_std_vector_int(std::vector(a.begin(), a.end())) + 1; + }); + m.def("pass_std_set_int", [](const std::set &s) { + int zum = 200; + for (const int i : s) { + zum += 3 * i; + } + return zum; + }); + m.def("pass_std_map_int", [](const std::map &m) { + int zum = 500; + for (const auto &p : m) { + zum += p.first * 1000 + p.second; + } + return zum; + }); } diff --git a/tests/test_stl.py b/tests/test_stl.py index 65fda54cc..1896c3221 100644 --- a/tests/test_stl.py +++ b/tests/test_stl.py @@ -381,3 +381,129 @@ def test_return_vector_bool_raw_ptr(): v = m.return_vector_bool_raw_ptr() assert isinstance(v, list) assert len(v) == 4513 + + +@pytest.mark.parametrize( + ("fn", "offset"), [(m.pass_std_vector_int, 0), (m.pass_std_array_int_2, 1)] +) +def test_pass_std_vector_int(fn, offset): + assert fn([7, 13]) == 140 + offset + assert fn({6, 2}) == 116 + offset + assert fn({"x": 8, "y": 11}.values()) == 138 + offset + assert fn({3: None, 9: None}.keys()) == 124 + offset + assert fn(i for i in [4, 17]) == 142 + offset + assert fn(map(lambda i: i * 3, [8, 7])) == 190 + offset # noqa: C417 + with pytest.raises(TypeError): + fn({"x": 0, "y": 1}) + with pytest.raises(TypeError): + fn({}) + + +def test_pass_std_vector_pair_int(): + fn = m.pass_std_vector_pair_int + assert fn({1: 2, 3: 4}.items()) == 406 + assert fn(zip([5, 17], [13, 9])) == 2222 + + +def test_list_caster_fully_consumes_generator_object(): + def gen_invalid(): + yield from [1, 2.0, 3] + + gen_obj = gen_invalid() + with pytest.raises(TypeError): + m.pass_std_vector_int(gen_obj) + assert not tuple(gen_obj) + + +def test_pass_std_set_int(): + fn = m.pass_std_set_int + assert fn({3, 15}) == 254 + assert fn({5: None, 12: None}.keys()) == 251 + with pytest.raises(TypeError): + fn([]) + with pytest.raises(TypeError): + fn({}) + with pytest.raises(TypeError): + fn({}.values()) + with pytest.raises(TypeError): + fn(i for i in []) + + +def test_set_caster_dict_keys_failure(): + dict_keys = {1: None, 2.0: None, 3: None}.keys() + # The asserts does not really exercise anything in pybind11, but if one of + # them fails in some future version of Python, the set_caster load + # implementation may need to be revisited. + assert tuple(dict_keys) == (1, 2.0, 3) + assert tuple(dict_keys) == (1, 2.0, 3) + with pytest.raises(TypeError): + m.pass_std_set_int(dict_keys) + assert tuple(dict_keys) == (1, 2.0, 3) + + +class FakePyMappingMissingItems: + def __getitem__(self, _): + raise RuntimeError("Not expected to be called.") + + +class FakePyMappingWithItems(FakePyMappingMissingItems): + def items(self): + return ((1, 3), (2, 4)) + + +class FakePyMappingBadItems(FakePyMappingMissingItems): + def items(self): + return ((1, 2), (3, "x")) + + +class FakePyMappingItemsNotCallable(FakePyMappingMissingItems): + @property + def items(self): + return ((1, 2), (3, 4)) + + +class FakePyMappingItemsWithArg(FakePyMappingMissingItems): + def items(self, _): + return ((1, 2), (3, 4)) + + +class FakePyMappingGenObj(FakePyMappingMissingItems): + def __init__(self, gen_obj): + super().__init__() + self.gen_obj = gen_obj + + def items(self): + yield from self.gen_obj + + +def test_pass_std_map_int(): + fn = m.pass_std_map_int + assert fn({1: 2, 3: 4}) == 4506 + with pytest.raises(TypeError): + fn([]) + assert fn(FakePyMappingWithItems()) == 3507 + with pytest.raises(TypeError): + fn(FakePyMappingMissingItems()) + with pytest.raises(TypeError): + fn(FakePyMappingBadItems()) + with pytest.raises(TypeError): + fn(FakePyMappingItemsNotCallable()) + with pytest.raises(TypeError): + fn(FakePyMappingItemsWithArg()) + + +@pytest.mark.parametrize( + ("items", "expected_exception"), + [ + (((1, 2), (3, "x"), (4, 5)), TypeError), + (((1, 2), (3, 4, 5), (6, 7)), ValueError), + ], +) +def test_map_caster_fully_consumes_generator_object(items, expected_exception): + def gen_invalid(): + yield from items + + gen_obj = gen_invalid() + with pytest.raises(expected_exception): + m.pass_std_map_int(FakePyMappingGenObj(gen_obj)) + assert not tuple(gen_obj) From 01169061891d8f5609d8cdf10f6dc396ef4ccd44 Mon Sep 17 00:00:00 2001 From: pwdcd Date: Wed, 14 Aug 2024 13:04:10 +0800 Subject: [PATCH 08/18] chore: remove repetitive words (#5308) Signed-off-by: pwdcd --- docs/advanced/cast/eigen.rst | 2 +- docs/compiling.rst | 4 ++-- include/pybind11/detail/common.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/advanced/cast/eigen.rst b/docs/advanced/cast/eigen.rst index a5c11a3f1..894ce97f3 100644 --- a/docs/advanced/cast/eigen.rst +++ b/docs/advanced/cast/eigen.rst @@ -259,7 +259,7 @@ copying to take place: "small"_a // <- This one can be copied if needed ); -With the above binding code, attempting to call the the ``some_method(m)`` +With the above binding code, attempting to call the ``some_method(m)`` method on a ``MyClass`` object, or attempting to call ``some_function(m, m2)`` will raise a ``RuntimeError`` rather than making a temporary copy of the array. It will, however, allow the ``m2`` argument to be copied into a temporary if diff --git a/docs/compiling.rst b/docs/compiling.rst index 0c788335d..65db93c81 100644 --- a/docs/compiling.rst +++ b/docs/compiling.rst @@ -388,7 +388,7 @@ that will be respected instead of the built-in flag search. The ``OPT_SIZE`` flag enables size-based optimization equivalent to the standard ``/Os`` or ``-Os`` compiler flags and the ``MinSizeRel`` build type, -which avoid optimizations that that can substantially increase the size of the +which avoid optimizations that can substantially increase the size of the resulting binary. This flag is particularly useful in projects that are split into performance-critical parts and associated bindings. In this case, we can compile the project in release mode (and hence, optimize performance globally), @@ -719,7 +719,7 @@ customizable pybind11-based wrappers by parsing C++ header files. [litgen]_ is an automatic python bindings generator with a focus on generating documented and discoverable bindings: bindings will nicely reproduce the documentation -found in headers. It is is based on srcML (srcml.org), a highly scalable, multi-language +found in headers. It is based on srcML (srcml.org), a highly scalable, multi-language parsing tool with a developer centric approach. The API that you want to expose to python must be C++14 compatible (but your implementation can use more modern constructs). diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 71a98f064..643fd33d7 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -554,7 +554,7 @@ enum class return_value_policy : uint8_t { object without taking ownership similar to the above return_value_policy::reference policy. In contrast to that policy, the function or property's implicit this argument (called the parent) is - considered to be the the owner of the return value (the child). + considered to be the owner of the return value (the child). pybind11 then couples the lifetime of the parent to the child via a reference relationship that ensures that the parent cannot be garbage collected while Python is still using the child. More advanced From fc97cc41d575d44fa425a0e56765380e15474399 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Wed, 14 Aug 2024 12:36:45 -0400 Subject: [PATCH 09/18] Revert "fix: quote paths from pybind11-config (#5302)" (#5309) This reverts commit 8d9f4d50cc7baa461365e977a0645c6c0d7b1b12. --- pybind11/__main__.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pybind11/__main__.py b/pybind11/__main__.py index dadf24f3c..b656ce6fe 100644 --- a/pybind11/__main__.py +++ b/pybind11/__main__.py @@ -2,7 +2,6 @@ from __future__ import annotations import argparse -import shlex import sys import sysconfig @@ -23,7 +22,7 @@ def print_includes() -> None: if d and d not in unique_dirs: unique_dirs.append(d) - print(" ".join(shlex.quote(f"-I{d}") for d in unique_dirs)) + print(" ".join("-I" + d for d in unique_dirs)) def main() -> None: @@ -55,9 +54,9 @@ def main() -> None: if args.includes: print_includes() if args.cmakedir: - print(shlex.quote(get_cmake_dir())) + print(get_cmake_dir()) if args.pkgconfigdir: - print(shlex.quote(get_pkgconfig_dir())) + print(get_pkgconfig_dir()) if __name__ == "__main__": From d893f9723a938f187a9fc85e7231c9a68eba5d32 Mon Sep 17 00:00:00 2001 From: Markus Bauer Date: Wed, 14 Aug 2024 23:25:37 +0200 Subject: [PATCH 10/18] fix: escape paths with spaces in pybind11-config (#4874) * fix: Escape paths with spaces in include list from --includes * fix: --includes should not use shlex on Windows platforms * Apply suggestions from code review * fix: use custom impl Signed-off-by: Henry Schreiner * Support trailing backslashes Co-authored-by: Henry Schreiner --------- Signed-off-by: Henry Schreiner Co-authored-by: Markus Bauer Co-authored-by: Henry Schreiner --- pybind11/__main__.py | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/pybind11/__main__.py b/pybind11/__main__.py index b656ce6fe..0abc7e211 100644 --- a/pybind11/__main__.py +++ b/pybind11/__main__.py @@ -2,12 +2,35 @@ from __future__ import annotations import argparse +import re import sys import sysconfig from ._version import __version__ from .commands import get_cmake_dir, get_include, get_pkgconfig_dir +# This is the conditional used for os.path being posixpath +if "posix" in sys.builtin_module_names: + from shlex import quote +elif "nt" in sys.builtin_module_names: + # See https://github.com/mesonbuild/meson/blob/db22551ed9d2dd7889abea01cc1c7bba02bf1c75/mesonbuild/utils/universal.py#L1092-L1121 + # and the original documents: + # https://docs.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments and + # https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/ + UNSAFE = re.compile("[ \t\n\r]") + + def quote(s: str) -> str: + if s and not UNSAFE.search(s): + return s + + # Paths cannot contain a '"' on Windows, so we don't need to worry + # about nuanced counting here. + return f'"{s}\\"' if s.endswith("\\") else f'"{s}"' +else: + + def quote(s: str) -> str: + return s + def print_includes() -> None: dirs = [ @@ -22,7 +45,7 @@ def print_includes() -> None: if d and d not in unique_dirs: unique_dirs.append(d) - print(" ".join("-I" + d for d in unique_dirs)) + print(" ".join(quote(f"-I{d}") for d in unique_dirs)) def main() -> None: @@ -54,9 +77,9 @@ def main() -> None: if args.includes: print_includes() if args.cmakedir: - print(get_cmake_dir()) + print(quote(get_cmake_dir())) if args.pkgconfigdir: - print(get_pkgconfig_dir()) + print(quote(get_pkgconfig_dir())) if __name__ == "__main__": From 28dbce4157c89219705801b06e5a94b612d611a5 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Wed, 14 Aug 2024 18:21:04 -0400 Subject: [PATCH 11/18] feat: require CMake 3.15+ (#5304) * feat: require CMake 3.15+ Signed-off-by: Henry Schreiner * Apply suggestions from code review * Update CMakeLists.txt * fix: adapt for CMake 3.30+ (using 3.18+) Signed-off-by: Henry Schreiner --------- Signed-off-by: Henry Schreiner --- .github/CONTRIBUTING.md | 10 +- .github/workflows/configure.yml | 4 +- CMakeLists.txt | 57 ++-------- docs/advanced/embedding.rst | 2 +- docs/compiling.rst | 32 +++--- docs/faq.rst | 16 +-- tests/CMakeLists.txt | 50 +++------ tests/extra_python_package/test_files.py | 1 - tests/pyproject.toml | 4 - .../installed_embed/CMakeLists.txt | 11 +- .../installed_function/CMakeLists.txt | 12 +-- .../installed_target/CMakeLists.txt | 11 +- .../subdirectory_embed/CMakeLists.txt | 11 +- .../subdirectory_function/CMakeLists.txt | 11 +- .../subdirectory_target/CMakeLists.txt | 11 +- tools/pybind11Common.cmake | 101 ++++++------------ tools/pybind11GuessPythonExtSuffix.cmake | 2 +- tools/pybind11NewTools.cmake | 5 - tools/pybind11Tools.cmake | 49 +++------ tools/test-pybind11GuessPythonExtSuffix.cmake | 2 +- 20 files changed, 112 insertions(+), 290 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index f5a08e2d7..f2d8007df 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -81,7 +81,7 @@ nox -s build ### Full setup To setup an ideal development environment, run the following commands on a -system with CMake 3.14+: +system with CMake 3.15+: ```bash python3 -m venv venv @@ -96,8 +96,8 @@ Tips: * You can use `virtualenv` (faster, from PyPI) instead of `venv`. * You can select any name for your environment folder; if it contains "env" it will be ignored by git. -* If you don't have CMake 3.14+, just add "cmake" to the pip install command. -* You can use `-DPYBIND11_FINDPYTHON=ON` to use FindPython on CMake 3.12+ +* If you don't have CMake 3.15+, just add "cmake" to the pip install command. +* You can use `-DPYBIND11_FINDPYTHON=ON` to use FindPython. * In classic mode, you may need to set `-DPYTHON_EXECUTABLE=/path/to/python`. FindPython uses `-DPython_ROOT_DIR=/path/to` or `-DPython_EXECUTABLE=/path/to/python`. @@ -149,8 +149,8 @@ To run the tests, you can "build" the check target: cmake --build build --target check ``` -`--target` can be spelled `-t` in CMake 3.15+. You can also run individual -tests with these targets: +`--target` can be spelled `-t`. You can also run individual tests with these +targets: * `pytest`: Python tests only, using the [pytest](https://docs.pytest.org/en/stable/) framework diff --git a/.github/workflows/configure.yml b/.github/workflows/configure.yml index 0583aa06a..2031ec823 100644 --- a/.github/workflows/configure.yml +++ b/.github/workflows/configure.yml @@ -31,7 +31,7 @@ jobs: include: - runs-on: ubuntu-20.04 arch: x64 - cmake: "3.5" + cmake: "3.15" - runs-on: ubuntu-20.04 arch: x64 @@ -39,7 +39,7 @@ jobs: - runs-on: macos-13 arch: x64 - cmake: "3.8" + cmake: "3.15" - runs-on: windows-2019 arch: x64 # x86 compilers seem to be missing on 2019 image diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e5b8c8f3..ed2971942 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,16 +10,7 @@ if(NOT CMAKE_VERSION VERSION_LESS "3.27") cmake_policy(GET CMP0148 _pybind11_cmp0148) endif() -cmake_minimum_required(VERSION 3.5) - -# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with -# some versions of VS that have a patched CMake 3.11. This forces us to emulate -# the behavior using the following workaround: -if(${CMAKE_VERSION} VERSION_LESS 3.29) - cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) -else() - cmake_policy(VERSION 3.29) -endif() +cmake_minimum_required(VERSION 3.15...3.30) if(_pybind11_cmp0148) cmake_policy(SET CMP0148 ${_pybind11_cmp0148}) @@ -27,9 +18,7 @@ if(_pybind11_cmp0148) endif() # Avoid infinite recursion if tests include this as a subdirectory -if(DEFINED PYBIND11_MASTER_PROJECT) - return() -endif() +include_guard(GLOBAL) # Extract project version from source file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/include/pybind11/detail/common.h" @@ -74,14 +63,6 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) set(PYBIND11_MASTER_PROJECT ON) - if(OSX AND CMAKE_VERSION VERSION_LESS 3.7) - # Bug in macOS CMake < 3.7 is unable to download catch - message(WARNING "CMAKE 3.7+ needed on macOS to download catch, and newer HIGHLY recommended") - elseif(WINDOWS AND CMAKE_VERSION VERSION_LESS 3.8) - # Only tested with 3.8+ in CI. - message(WARNING "CMAKE 3.8+ tested on Windows, previous versions untested") - endif() - message(STATUS "CMake ${CMAKE_VERSION}") if(CMAKE_CXX_STANDARD) @@ -133,8 +114,7 @@ cmake_dependent_option( "Install pybind11 headers in Python include directory instead of default installation prefix" OFF "PYBIND11_INSTALL" OFF) -cmake_dependent_option(PYBIND11_FINDPYTHON "Force new FindPython" ${_pybind11_findpython_default} - "NOT CMAKE_VERSION VERSION_LESS 3.12" OFF) +option(PYBIND11_FINDPYTHON "Force new FindPython" ${_pybind11_findpython_default}) # Allow PYTHON_EXECUTABLE if in FINDPYTHON mode and building pybind11's tests # (makes transition easier while we support both modes). @@ -183,7 +163,7 @@ set(PYBIND11_HEADERS include/pybind11/typing.h) # Compare with grep and warn if mismatched -if(PYBIND11_MASTER_PROJECT AND NOT CMAKE_VERSION VERSION_LESS 3.12) +if(PYBIND11_MASTER_PROJECT) file( GLOB_RECURSE _pybind11_header_check LIST_DIRECTORIES false @@ -201,10 +181,7 @@ if(PYBIND11_MASTER_PROJECT AND NOT CMAKE_VERSION VERSION_LESS 3.12) endif() endif() -# CMake 3.12 added list(TRANSFORM PREPEND -# But we can't use it yet -string(REPLACE "include/" "${CMAKE_CURRENT_SOURCE_DIR}/include/" PYBIND11_HEADERS - "${PYBIND11_HEADERS}") +list(TRANSFORM PYBIND11_HEADERS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/") # Cache variable so this can be used in parent projects set(pybind11_INCLUDE_DIR @@ -274,25 +251,11 @@ if(PYBIND11_INSTALL) tools/${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" INSTALL_DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR}) - if(CMAKE_VERSION VERSION_LESS 3.14) - # Remove CMAKE_SIZEOF_VOID_P from ConfigVersion.cmake since the library does - # not depend on architecture specific settings or libraries. - set(_PYBIND11_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P}) - unset(CMAKE_SIZEOF_VOID_P) - - write_basic_package_version_file( - ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake - VERSION ${PROJECT_VERSION} - COMPATIBILITY AnyNewerVersion) - - set(CMAKE_SIZEOF_VOID_P ${_PYBIND11_CMAKE_SIZEOF_VOID_P}) - else() - # CMake 3.14+ natively supports header-only libraries - write_basic_package_version_file( - ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake - VERSION ${PROJECT_VERSION} - COMPATIBILITY AnyNewerVersion ARCH_INDEPENDENT) - endif() + # CMake natively supports header-only libraries + write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion ARCH_INDEPENDENT) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake diff --git a/docs/advanced/embedding.rst b/docs/advanced/embedding.rst index cbed82158..e78a8f4ce 100644 --- a/docs/advanced/embedding.rst +++ b/docs/advanced/embedding.rst @@ -18,7 +18,7 @@ information, see :doc:`/compiling`. .. code-block:: cmake - cmake_minimum_required(VERSION 3.5...3.29) + cmake_minimum_required(VERSION 3.15...3.30) project(example) find_package(pybind11 REQUIRED) # or `add_subdirectory(pybind11)` diff --git a/docs/compiling.rst b/docs/compiling.rst index 65db93c81..94042c3e5 100644 --- a/docs/compiling.rst +++ b/docs/compiling.rst @@ -18,7 +18,7 @@ A Python extension module can be created with just a few lines of code: .. code-block:: cmake - cmake_minimum_required(VERSION 3.15...3.29) + cmake_minimum_required(VERSION 3.15...3.30) project(example LANGUAGES CXX) set(PYBIND11_FINDPYTHON ON) @@ -319,11 +319,11 @@ Building with CMake 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, as seen above in -the module section. Pybind11 currently supports a lower minimum if you don't -use the modern FindPython, though be aware that CMake 3.27 removed the old -mechanism, so pybind11 will automatically switch if the old mechanism is not -available. Please opt into the new mechanism if at all possible. Our default -may change in future versions. This is the minimum required: +the module section. Pybind11 currently defaults to the old mechanism, though be +aware that CMake 3.27 removed the old mechanism, so pybind11 will automatically +switch if the old mechanism is not available. Please opt into the new mechanism +if at all possible. Our default may change in future versions. This is the +minimum required: @@ -333,6 +333,9 @@ may change in future versions. This is the minimum required: .. versionchanged:: 2.11 CMake 3.5+ is required. +.. versionchanged:: 2.14 + CMake 3.15+ is required. + Further information can be found at :doc:`cmake/index`. @@ -444,7 +447,7 @@ See the `Config file`_ docstring for details of relevant CMake variables. .. code-block:: cmake - cmake_minimum_required(VERSION 3.4...3.18) + cmake_minimum_required(VERSION 3.15...3.30) project(example LANGUAGES CXX) find_package(pybind11 REQUIRED) @@ -483,14 +486,13 @@ can refer to the same [cmake_example]_ repository for a full sample project FindPython mode --------------- -CMake 3.12+ (3.15+ recommended, 3.18.2+ ideal) added a new module called -FindPython that had a highly improved search algorithm and modern targets -and tools. If you use FindPython, pybind11 will detect this and use the -existing targets instead: +Modern CMake (3.18.2+ ideal) added a new module called FindPython that had a +highly improved search algorithm and modern targets and tools. If you use +FindPython, pybind11 will detect this and use the existing targets instead: .. code-block:: cmake - cmake_minimum_required(VERSION 3.15...3.22) + cmake_minimum_required(VERSION 3.15...3.30) project(example LANGUAGES CXX) find_package(Python 3.8 COMPONENTS Interpreter Development REQUIRED) @@ -541,7 +543,7 @@ available in all modes. The targets provided are: Just the "linking" part of pybind11:module ``pybind11::module`` - Everything for extension modules - ``pybind11::pybind11`` + ``Python::Module`` (FindPython CMake 3.15+) or ``pybind11::python_link_helper`` + Everything for extension modules - ``pybind11::pybind11`` + ``Python::Module`` (FindPython) or ``pybind11::python_link_helper`` ``pybind11::embed`` Everything for embedding the Python interpreter - ``pybind11::pybind11`` + ``Python::Python`` (FindPython) or Python libs @@ -568,7 +570,7 @@ You can use these targets to build complex applications. For example, the .. code-block:: cmake - cmake_minimum_required(VERSION 3.5...3.29) + cmake_minimum_required(VERSION 3.15...3.30) project(example LANGUAGES CXX) find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11) @@ -626,7 +628,7 @@ information about usage in C++, see :doc:`/advanced/embedding`. .. code-block:: cmake - cmake_minimum_required(VERSION 3.5...3.29) + cmake_minimum_required(VERSION 3.15...3.30) project(example LANGUAGES CXX) find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11) diff --git a/docs/faq.rst b/docs/faq.rst index 1eb00efad..92777b5b3 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -258,9 +258,9 @@ CMake configure line. (Replace ``$(which python)`` with a path to python if your prefer.) You can alternatively try ``-DPYBIND11_FINDPYTHON=ON``, which will activate the -new CMake FindPython support instead of pybind11's custom search. Requires -CMake 3.12+, and 3.15+ or 3.18.2+ are even better. You can set this in your -``CMakeLists.txt`` before adding or finding pybind11, as well. +new CMake FindPython support instead of pybind11's custom search. Newer CMake, +like, 3.18.2+, is recommended. You can set this in your ``CMakeLists.txt`` +before adding or finding pybind11, as well. Inconsistent detection of Python version in CMake and pybind11 ============================================================== @@ -281,11 +281,11 @@ There are three possible solutions: from CMake and rely on pybind11 in detecting Python version. If this is not possible, the CMake machinery should be called *before* including pybind11. 2. Set ``PYBIND11_FINDPYTHON`` to ``True`` or use ``find_package(Python - COMPONENTS Interpreter Development)`` on modern CMake (3.12+, 3.15+ better, - 3.18.2+ best). Pybind11 in these cases uses the new CMake FindPython instead - of the old, deprecated search tools, and these modules are much better at - finding the correct Python. If FindPythonLibs/Interp are not available - (CMake 3.27+), then this will be ignored and FindPython will be used. + COMPONENTS Interpreter Development)`` on modern CMake ( 3.18.2+ best). + Pybind11 in these cases uses the new CMake FindPython instead of the old, + deprecated search tools, and these modules are much better at finding the + correct Python. If FindPythonLibs/Interp are not available (CMake 3.27+), + then this will be ignored and FindPython will be used. 3. Set ``PYBIND11_NOPYTHON`` to ``TRUE``. Pybind11 will not search for Python. However, you will have to use the target-based system, and do more setup yourself, because it does not know about or include things that depend on diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5b7e3f801..18308731a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,16 +5,7 @@ # All rights reserved. Use of this source code is governed by a # BSD-style license that can be found in the LICENSE file. -cmake_minimum_required(VERSION 3.5) - -# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with -# some versions of VS that have a patched CMake 3.11. This forces us to emulate -# the behavior using the following workaround: -if(${CMAKE_VERSION} VERSION_LESS 3.29) - cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) -else() - cmake_policy(VERSION 3.29) -endif() +cmake_minimum_required(VERSION 3.15...3.30) # Filter out items; print an optional message if any items filtered. This ignores extensions. # @@ -76,8 +67,8 @@ project(pybind11_tests CXX) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../tools") option(PYBIND11_WERROR "Report all warnings as errors" OFF) -option(DOWNLOAD_EIGEN "Download EIGEN (requires CMake 3.11+)" OFF) -option(PYBIND11_CUDA_TESTS "Enable building CUDA tests (requires CMake 3.12+)" OFF) +option(DOWNLOAD_EIGEN "Download EIGEN" OFF) +option(PYBIND11_CUDA_TESTS "Enable building CUDA tests" OFF) set(PYBIND11_TEST_OVERRIDE "" CACHE STRING "Tests from ;-separated list of *.cpp files will be built instead of all tests") @@ -249,25 +240,21 @@ endif() if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1) # Try loading via newer Eigen's Eigen3Config first (bypassing tools/FindEigen3.cmake). # Eigen 3.3.1+ exports a cmake 3.0+ target for handling dependency requirements, but also - # produces a fatal error if loaded from a pre-3.0 cmake. if(DOWNLOAD_EIGEN) - if(CMAKE_VERSION VERSION_LESS 3.11) - message(FATAL_ERROR "CMake 3.11+ required when using DOWNLOAD_EIGEN") + if(CMAKE_VERSION VERSION_LESS 3.18) + set(_opts) + else() + set(_opts SOURCE_SUBDIR no-cmake-build) endif() - include(FetchContent) FetchContent_Declare( eigen GIT_REPOSITORY "${PYBIND11_EIGEN_REPO}" - GIT_TAG "${PYBIND11_EIGEN_VERSION_HASH}") - - FetchContent_GetProperties(eigen) - if(NOT eigen_POPULATED) - message( - STATUS - "Downloading Eigen ${PYBIND11_EIGEN_VERSION_STRING} (${PYBIND11_EIGEN_VERSION_HASH}) from ${PYBIND11_EIGEN_REPO}" - ) - FetchContent_Populate(eigen) + GIT_TAG "${PYBIND11_EIGEN_VERSION_HASH}" + ${_opts}) + FetchContent_MakeAvailable(eigen) + if(NOT CMAKE_VERSION VERSION_LESS 3.18) + set(EIGEN3_INCLUDE_DIR "${eigen_SOURCE_DIR}") endif() set(EIGEN3_INCLUDE_DIR ${eigen_SOURCE_DIR}) @@ -315,8 +302,7 @@ if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1) if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1) list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_EIGEN_I}) endif() - message( - STATUS "Building tests WITHOUT Eigen, use -DDOWNLOAD_EIGEN=ON on CMake 3.11+ to download") + message(STATUS "Building tests WITHOUT Eigen, use -DDOWNLOAD_EIGEN=ON to download") endif() endif() @@ -501,12 +487,10 @@ foreach(target ${test_targets}) endforeach() # Provide nice organisation in IDEs -if(NOT CMAKE_VERSION VERSION_LESS 3.8) - source_group( - TREE "${CMAKE_CURRENT_SOURCE_DIR}/../include" - PREFIX "Header Files" - FILES ${PYBIND11_HEADERS}) -endif() +source_group( + TREE "${CMAKE_CURRENT_SOURCE_DIR}/../include" + PREFIX "Header Files" + FILES ${PYBIND11_HEADERS}) # Make sure pytest is found or produce a warning pybind11_find_import(pytest VERSION 3.1) diff --git a/tests/extra_python_package/test_files.py b/tests/extra_python_package/test_files.py index aedbdf1c1..0a5db9017 100644 --- a/tests/extra_python_package/test_files.py +++ b/tests/extra_python_package/test_files.py @@ -9,7 +9,6 @@ import tarfile import zipfile # These tests must be run explicitly -# They require CMake 3.15+ (--install) DIR = os.path.abspath(os.path.dirname(__file__)) MAIN_DIR = os.path.dirname(os.path.dirname(DIR)) diff --git a/tests/pyproject.toml b/tests/pyproject.toml index 044bf15c0..469c145df 100644 --- a/tests/pyproject.toml +++ b/tests/pyproject.toml @@ -10,10 +10,6 @@ name = "pybind11_tests" version = "0.0.1" dependencies = ["pytest", "pytest-timeout", "numpy", "scipy"] -[tool.scikit-build] -# Hide a warning while we also support CMake < 3.15 -cmake.version = ">=3.15" - [tool.scikit-build.cmake.define] PYBIND11_FINDPYTHON = true diff --git a/tests/test_cmake_build/installed_embed/CMakeLists.txt b/tests/test_cmake_build/installed_embed/CMakeLists.txt index 2be0aa659..5c6267c72 100644 --- a/tests/test_cmake_build/installed_embed/CMakeLists.txt +++ b/tests/test_cmake_build/installed_embed/CMakeLists.txt @@ -1,13 +1,4 @@ -cmake_minimum_required(VERSION 3.5) - -# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with -# some versions of VS that have a patched CMake 3.11. This forces us to emulate -# the behavior using the following workaround: -if(${CMAKE_VERSION} VERSION_LESS 3.29) - cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) -else() - cmake_policy(VERSION 3.29) -endif() +cmake_minimum_required(VERSION 3.15...3.30) project(test_installed_embed CXX) diff --git a/tests/test_cmake_build/installed_function/CMakeLists.txt b/tests/test_cmake_build/installed_function/CMakeLists.txt index fa7795e1e..2945b3d2e 100644 --- a/tests/test_cmake_build/installed_function/CMakeLists.txt +++ b/tests/test_cmake_build/installed_function/CMakeLists.txt @@ -1,14 +1,4 @@ -cmake_minimum_required(VERSION 3.5) -project(test_installed_module CXX) - -# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with -# some versions of VS that have a patched CMake 3.11. This forces us to emulate -# the behavior using the following workaround: -if(${CMAKE_VERSION} VERSION_LESS 3.29) - cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) -else() - cmake_policy(VERSION 3.29) -endif() +cmake_minimum_required(VERSION 3.15...3.30) project(test_installed_function CXX) diff --git a/tests/test_cmake_build/installed_target/CMakeLists.txt b/tests/test_cmake_build/installed_target/CMakeLists.txt index 7e73f4243..344c8bc69 100644 --- a/tests/test_cmake_build/installed_target/CMakeLists.txt +++ b/tests/test_cmake_build/installed_target/CMakeLists.txt @@ -1,13 +1,4 @@ -cmake_minimum_required(VERSION 3.5) - -# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with -# some versions of VS that have a patched CMake 3.11. This forces us to emulate -# the behavior using the following workaround: -if(${CMAKE_VERSION} VERSION_LESS 3.29) - cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) -else() - cmake_policy(VERSION 3.29) -endif() +cmake_minimum_required(VERSION 3.15...3.30) project(test_installed_target CXX) diff --git a/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt b/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt index 33a366472..d0ae0798e 100644 --- a/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt +++ b/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt @@ -1,13 +1,4 @@ -cmake_minimum_required(VERSION 3.5) - -# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with -# some versions of VS that have a patched CMake 3.11. This forces us to emulate -# the behavior using the following workaround: -if(${CMAKE_VERSION} VERSION_LESS 3.29) - cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) -else() - cmake_policy(VERSION 3.29) -endif() +cmake_minimum_required(VERSION 3.15...3.30) project(test_subdirectory_embed CXX) diff --git a/tests/test_cmake_build/subdirectory_function/CMakeLists.txt b/tests/test_cmake_build/subdirectory_function/CMakeLists.txt index 76418a71f..a521f33df 100644 --- a/tests/test_cmake_build/subdirectory_function/CMakeLists.txt +++ b/tests/test_cmake_build/subdirectory_function/CMakeLists.txt @@ -1,13 +1,4 @@ -cmake_minimum_required(VERSION 3.5) - -# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with -# some versions of VS that have a patched CMake 3.11. This forces us to emulate -# the behavior using the following workaround: -if(${CMAKE_VERSION} VERSION_LESS 3.29) - cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) -else() - cmake_policy(VERSION 3.29) -endif() +cmake_minimum_required(VERSION 3.15...3.30) project(test_subdirectory_function CXX) diff --git a/tests/test_cmake_build/subdirectory_target/CMakeLists.txt b/tests/test_cmake_build/subdirectory_target/CMakeLists.txt index 28e903187..4a5a7f2be 100644 --- a/tests/test_cmake_build/subdirectory_target/CMakeLists.txt +++ b/tests/test_cmake_build/subdirectory_target/CMakeLists.txt @@ -1,13 +1,4 @@ -cmake_minimum_required(VERSION 3.5) - -# The `cmake_minimum_required(VERSION 3.5...3.29)` syntax does not work with -# some versions of VS that have a patched CMake 3.11. This forces us to emulate -# the behavior using the following workaround: -if(${CMAKE_VERSION} VERSION_LESS 3.29) - cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) -else() - cmake_policy(VERSION 3.29) -endif() +cmake_minimum_required(VERSION 3.15...3.30) project(test_subdirectory_target CXX) diff --git a/tools/pybind11Common.cmake b/tools/pybind11Common.cmake index 7d8d94b11..450a14156 100644 --- a/tools/pybind11Common.cmake +++ b/tools/pybind11Common.cmake @@ -18,11 +18,7 @@ Adds the following functions:: #]======================================================] -# CMake 3.10 has an include_guard command, but we can't use that yet -# include_guard(global) (pre-CMake 3.10) -if(TARGET pybind11::pybind11) - return() -endif() +include_guard(GLOBAL) # If we are in subdirectory mode, all IMPORTED targets must be GLOBAL. If we # are in CONFIG mode, they should be "normal" targets instead. @@ -80,47 +76,31 @@ set_property( # Please open an issue if you need to use it; it will be removed if no one # needs it. if(CMAKE_SYSTEM_NAME MATCHES Emscripten AND NOT _pybind11_no_exceptions) - if(CMAKE_VERSION VERSION_LESS 3.13) - message(WARNING "CMake 3.13+ is required to build for Emscripten. Some flags will be missing") + if(is_config) + set(_tmp_config_target pybind11::pybind11_headers) else() - if(is_config) - set(_tmp_config_target pybind11::pybind11_headers) - else() - set(_tmp_config_target pybind11_headers) - endif() - - set_property( - TARGET ${_tmp_config_target} - APPEND - PROPERTY INTERFACE_LINK_OPTIONS -fexceptions) - set_property( - TARGET ${_tmp_config_target} - APPEND - PROPERTY INTERFACE_COMPILE_OPTIONS -fexceptions) - unset(_tmp_config_target) + set(_tmp_config_target pybind11_headers) endif() + + set_property( + TARGET ${_tmp_config_target} + APPEND + PROPERTY INTERFACE_LINK_OPTIONS -fexceptions) + set_property( + TARGET ${_tmp_config_target} + APPEND + PROPERTY INTERFACE_COMPILE_OPTIONS -fexceptions) + unset(_tmp_config_target) endif() # --------------------------- link helper --------------------------- add_library(pybind11::python_link_helper IMPORTED INTERFACE ${optional_global}) -if(CMAKE_VERSION VERSION_LESS 3.13) - # In CMake 3.11+, you can set INTERFACE properties via the normal methods, and - # this would be simpler. - set_property( - TARGET pybind11::python_link_helper - APPEND - PROPERTY INTERFACE_LINK_LIBRARIES "$<$:-undefined dynamic_lookup>") -else() - # link_options was added in 3.13+ - # This is safer, because you are ensured the deduplication pass in CMake will not consider - # these separate and remove one but not the other. - set_property( - TARGET pybind11::python_link_helper - APPEND - PROPERTY INTERFACE_LINK_OPTIONS "$<$:LINKER:-undefined,dynamic_lookup>") -endif() +set_property( + TARGET pybind11::python_link_helper + APPEND + PROPERTY INTERFACE_LINK_OPTIONS "$<$:LINKER:-undefined,dynamic_lookup>") # ------------------------ Windows extras ------------------------- @@ -136,22 +116,14 @@ if(MSVC) # That's also clang-cl # /MP enables multithreaded builds (relevant when there are many files) for MSVC if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # no Clang no Intel - if(CMAKE_VERSION VERSION_LESS 3.11) - set_property( - TARGET pybind11::windows_extras - APPEND - PROPERTY INTERFACE_COMPILE_OPTIONS $<$>:/MP>) - else() - # Only set these options for C++ files. This is important so that, for - # instance, projects that include other types of source files like CUDA - # .cu files don't get these options propagated to nvcc since that would - # cause the build to fail. - set_property( - TARGET pybind11::windows_extras - APPEND - PROPERTY INTERFACE_COMPILE_OPTIONS - $<$>:$<$:/MP>>) - endif() + # Only set these options for C++ files. This is important so that, for + # instance, projects that include other types of source files like CUDA + # .cu files don't get these options propagated to nvcc since that would + # cause the build to fail. + set_property( + TARGET pybind11::windows_extras + APPEND + PROPERTY INTERFACE_COMPILE_OPTIONS $<$>:$<$:/MP>>) endif() endif() @@ -397,11 +369,7 @@ function(_pybind11_generate_lto target prefer_thin_lto) set(is_debug "$,$>") set(not_debug "$") set(cxx_lang "$") - if(MSVC AND CMAKE_VERSION VERSION_LESS 3.11) - set(genex "${not_debug}") - else() - set(genex "$") - endif() + set(genex "$") set_property( TARGET ${target} APPEND @@ -416,17 +384,10 @@ function(_pybind11_generate_lto target prefer_thin_lto) endif() if(PYBIND11_LTO_LINKER_FLAGS) - if(CMAKE_VERSION VERSION_LESS 3.11) - set_property( - TARGET ${target} - APPEND - PROPERTY INTERFACE_LINK_LIBRARIES "$<${not_debug}:${PYBIND11_LTO_LINKER_FLAGS}>") - else() - set_property( - TARGET ${target} - APPEND - PROPERTY INTERFACE_LINK_OPTIONS "$<${not_debug}:${PYBIND11_LTO_LINKER_FLAGS}>") - endif() + set_property( + TARGET ${target} + APPEND + PROPERTY INTERFACE_LINK_OPTIONS "$<${not_debug}:${PYBIND11_LTO_LINKER_FLAGS}>") endif() endfunction() diff --git a/tools/pybind11GuessPythonExtSuffix.cmake b/tools/pybind11GuessPythonExtSuffix.cmake index c5fb3b42c..b550f3935 100644 --- a/tools/pybind11GuessPythonExtSuffix.cmake +++ b/tools/pybind11GuessPythonExtSuffix.cmake @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.15...3.30) function(pybind11_guess_python_module_extension python) diff --git a/tools/pybind11NewTools.cmake b/tools/pybind11NewTools.cmake index 444f3aaf5..d3e938fab 100644 --- a/tools/pybind11NewTools.cmake +++ b/tools/pybind11NewTools.cmake @@ -5,10 +5,6 @@ # All rights reserved. Use of this source code is governed by a # BSD-style license that can be found in the LICENSE file. -if(CMAKE_VERSION VERSION_LESS 3.12) - message(FATAL_ERROR "You cannot use the new FindPython module with CMake < 3.12") -endif() - include_guard(DIRECTORY) get_property( @@ -236,7 +232,6 @@ if(TARGET ${_Python}::Python) PROPERTY INTERFACE_LINK_LIBRARIES ${_Python}::Python) endif() -# CMake 3.15+ has this if(TARGET ${_Python}::Module) set_property( TARGET pybind11::module diff --git a/tools/pybind11Tools.cmake b/tools/pybind11Tools.cmake index 021038d95..d91e7670c 100644 --- a/tools/pybind11Tools.cmake +++ b/tools/pybind11Tools.cmake @@ -5,13 +5,7 @@ # All rights reserved. Use of this source code is governed by a # BSD-style license that can be found in the LICENSE file. -# include_guard(global) (pre-CMake 3.10) -if(TARGET pybind11::python_headers) - return() -endif() - -# Built-in in CMake 3.5+ -include(CMakeParseArguments) +include_guard(GLOBAL) if(pybind11_FIND_QUIETLY) set(_pybind11_quiet QUIET) @@ -116,36 +110,19 @@ if(PYTHON_IS_DEBUG) PROPERTY INTERFACE_COMPILE_DEFINITIONS Py_DEBUG) endif() -# The <3.11 code here does not support release/debug builds at the same time, like on vcpkg -if(CMAKE_VERSION VERSION_LESS 3.11) - set_property( - TARGET pybind11::module - APPEND - PROPERTY - INTERFACE_LINK_LIBRARIES - pybind11::python_link_helper - "$<$,$>:$>" - ) +# The IMPORTED INTERFACE library here is to ensure that "debug" and "release" get processed outside +# of a generator expression - https://gitlab.kitware.com/cmake/cmake/-/issues/18424, as they are +# target_link_library keywords rather than real libraries. +add_library(pybind11::_ClassicPythonLibraries IMPORTED INTERFACE) +target_link_libraries(pybind11::_ClassicPythonLibraries INTERFACE ${PYTHON_LIBRARIES}) +target_link_libraries( + pybind11::module + INTERFACE + pybind11::python_link_helper + "$<$,$>:pybind11::_ClassicPythonLibraries>") - set_property( - TARGET pybind11::embed - APPEND - PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11 $) -else() - # The IMPORTED INTERFACE library here is to ensure that "debug" and "release" get processed outside - # of a generator expression - https://gitlab.kitware.com/cmake/cmake/-/issues/18424, as they are - # target_link_library keywords rather than real libraries. - add_library(pybind11::_ClassicPythonLibraries IMPORTED INTERFACE) - target_link_libraries(pybind11::_ClassicPythonLibraries INTERFACE ${PYTHON_LIBRARIES}) - target_link_libraries( - pybind11::module - INTERFACE - pybind11::python_link_helper - "$<$,$>:pybind11::_ClassicPythonLibraries>") - - target_link_libraries(pybind11::embed INTERFACE pybind11::pybind11 - pybind11::_ClassicPythonLibraries) -endif() +target_link_libraries(pybind11::embed INTERFACE pybind11::pybind11 + pybind11::_ClassicPythonLibraries) function(pybind11_extension name) # The prefix and extension are provided by FindPythonLibsNew.cmake diff --git a/tools/test-pybind11GuessPythonExtSuffix.cmake b/tools/test-pybind11GuessPythonExtSuffix.cmake index 0de2c0169..ac90e039b 100644 --- a/tools/test-pybind11GuessPythonExtSuffix.cmake +++ b/tools/test-pybind11GuessPythonExtSuffix.cmake @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.15...3.30) # Tests for pybind11_guess_python_module_extension # Run using `cmake -P tools/test-pybind11GuessPythonExtSuffix.cmake` From bd5951b69194404be14e005da64b9f42fd4d080e Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Wed, 14 Aug 2024 23:57:37 -0400 Subject: [PATCH 12/18] docs: prepare for 2.13.4 (#5312) Signed-off-by: Henry Schreiner --- docs/changelog.rst | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index d19a90129..031d31582 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -20,7 +20,28 @@ New Features: * Support for Python 3.7 was removed. (Official end-of-life: 2023-06-27). `#5191 `_ -Support for CMake older than 3.15 and some older compilers will also be removed. +* stl.h ``list|set|map_caster`` were made more user friendly: it is no longer + necessary to explicitly convert Python iterables to ``tuple()``, ``set()``, + or ``map()`` in many common situations. + `#4686 `_ + +* Support for CMake older than 3.15 removed. CMake 3.15-3.30 supported. + `#5304 `_ + +Version 2.13.4 (August 14, 2024) +-------------------------------- + +Bug fixes: + +* Fix paths with spaces, including on Windows. + (Replaces regression from `#5302 `_) + `#4874 `_ + +Documentation: + +* Remove repetitive words. + `#5308 `_ + Version 2.13.3 (August 13, 2024) -------------------------------- From a1d00916b26b187e583f3bce39cd59c3b0652c32 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 15 Aug 2024 12:30:29 +0700 Subject: [PATCH 13/18] Backport of https://github.com/google/pywrapcc/pull/30034 (#5305) --- include/pybind11/stl.h | 98 +++++++++++++++++++++++++++++++++--------- tests/test_stl.cpp | 17 ++++++++ tests/test_stl.py | 7 +++ 3 files changed, 101 insertions(+), 21 deletions(-) diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h index 096301bc7..6a148e740 100644 --- a/include/pybind11/stl.h +++ b/include/pybind11/stl.h @@ -11,11 +11,14 @@ #include "pybind11.h" #include "detail/common.h" +#include "detail/descr.h" +#include "detail/type_caster_base.h" #include #include #include #include +#include #include #include #include @@ -349,39 +352,68 @@ struct type_caster> : list_caster struct type_caster> : list_caster, Type> {}; +template +ArrayType vector_to_array_impl(V &&v, index_sequence) { + return {{std::move(v[I])...}}; +} + +// Based on https://en.cppreference.com/w/cpp/container/array/to_array +template +ArrayType vector_to_array(V &&v) { + return vector_to_array_impl(std::forward(v), make_index_sequence{}); +} + template struct array_caster { using value_conv = make_caster; private: - template - bool require_size(enable_if_t size) { - if (value.size() != size) { - value.resize(size); - } - return true; - } - template - bool require_size(enable_if_t size) { - return size == Size; - } + std::unique_ptr value; + template = 0> bool convert_elements(handle seq, bool convert) { auto l = reinterpret_borrow(seq); - if (!require_size(l.size())) { - return false; - } + value.reset(new ArrayType{}); + // Using `resize` to preserve the behavior exactly as it was before PR #5305 + // For the `resize` to work, `Value` must be default constructible. + // For `std::valarray`, this is a requirement: + // https://en.cppreference.com/w/cpp/named_req/NumericType + value->resize(l.size()); size_t ctr = 0; for (const auto &it : l) { value_conv conv; if (!conv.load(it, convert)) { return false; } - value[ctr++] = cast_op(std::move(conv)); + (*value)[ctr++] = cast_op(std::move(conv)); } return true; } + template = 0> + bool convert_elements(handle seq, bool convert) { + auto l = reinterpret_borrow(seq); + if (l.size() != Size) { + return false; + } + // The `temp` storage is needed to support `Value` types that are not + // default-constructible. + // Deliberate choice: no template specializations, for simplicity, and + // because the compile time overhead for the specializations is deemed + // more significant than the runtime overhead for the `temp` storage. + std::vector temp; + temp.reserve(l.size()); + for (auto it : l) { + value_conv conv; + if (!conv.load(it, convert)) { + return false; + } + temp.emplace_back(cast_op(std::move(conv))); + } + value.reset(new ArrayType(vector_to_array(std::move(temp)))); + return true; + } + public: bool load(handle src, bool convert) { if (!PyObjectTypeIsConvertibleToStdVector(src.ptr())) { @@ -416,12 +448,36 @@ public: return l.release(); } - PYBIND11_TYPE_CASTER(ArrayType, - const_name(const_name(""), const_name("Annotated[")) - + const_name("list[") + value_conv::name + const_name("]") - + const_name(const_name(""), - const_name(", FixedSize(") - + const_name() + const_name(")]"))); + // Code copied from PYBIND11_TYPE_CASTER macro. + // Intentionally preserving the behavior exactly as it was before PR #5305 + template >::value, int> = 0> + static handle cast(T_ *src, return_value_policy policy, handle parent) { + if (!src) { + return none().release(); + } + if (policy == return_value_policy::take_ownership) { + auto h = cast(std::move(*src), policy, parent); + delete src; // WARNING: Assumes `src` was allocated with `new`. + return h; + } + return cast(*src, policy, parent); + } + + // NOLINTNEXTLINE(google-explicit-constructor) + operator ArrayType *() { return &(*value); } + // NOLINTNEXTLINE(google-explicit-constructor) + operator ArrayType &() { return *value; } + // NOLINTNEXTLINE(google-explicit-constructor) + operator ArrayType &&() && { return std::move(*value); } + + template + using cast_op_type = movable_cast_op_type; + + static constexpr auto name + = const_name(const_name(""), const_name("Annotated[")) + const_name("list[") + + value_conv::name + const_name("]") + + const_name( + const_name(""), const_name(", FixedSize(") + const_name() + const_name(")]")); }; template diff --git a/tests/test_stl.cpp b/tests/test_stl.cpp index c35f0d4ca..6240524a0 100644 --- a/tests/test_stl.cpp +++ b/tests/test_stl.cpp @@ -201,6 +201,23 @@ TEST_SUBMODULE(stl, m) { m.def("cast_array", []() { return std::array{{1, 2}}; }); m.def("load_array", [](const std::array &a) { return a[0] == 1 && a[1] == 2; }); + struct NoDefaultCtor { + explicit constexpr NoDefaultCtor(int val) : val{val} {} + int val; + }; + + struct NoDefaultCtorArray { + explicit constexpr NoDefaultCtorArray(int i) + : arr{{NoDefaultCtor(10 + i), NoDefaultCtor(20 + i)}} {} + std::array arr; + }; + + // test_array_no_default_ctor + py::class_(m, "NoDefaultCtor").def_readonly("val", &NoDefaultCtor::val); + py::class_(m, "NoDefaultCtorArray") + .def(py::init()) + .def_readwrite("arr", &NoDefaultCtorArray::arr); + // test_valarray m.def("cast_valarray", []() { return std::valarray{1, 4, 9}; }); m.def("load_valarray", [](const std::valarray &v) { diff --git a/tests/test_stl.py b/tests/test_stl.py index 1896c3221..6f548789e 100644 --- a/tests/test_stl.py +++ b/tests/test_stl.py @@ -48,6 +48,13 @@ def test_array(doc): ) +def test_array_no_default_ctor(): + lst = m.NoDefaultCtorArray(3) + assert [e.val for e in lst.arr] == [13, 23] + lst.arr = m.NoDefaultCtorArray(4).arr + assert [e.val for e in lst.arr] == [14, 24] + + def test_valarray(doc): """std::valarray <-> list""" lst = m.cast_valarray() From 7d85baa6a194e6c5da46252c49f42ec1d87597c7 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Wed, 21 Aug 2024 13:16:49 -0400 Subject: [PATCH 14/18] fix: never use `..` in a header include (#5321) * fix: never use `..` in a header include Signed-off-by: Henry Schreiner * fix: one more parent include Signed-off-by: Henry Schreiner --------- Signed-off-by: Henry Schreiner --- include/pybind11/detail/class.h | 4 ++-- include/pybind11/detail/internals.h | 4 ++-- include/pybind11/detail/type_caster_base.h | 3 ++- include/pybind11/eigen/matrix.h | 3 ++- include/pybind11/eigen/tensor.h | 3 ++- include/pybind11/stl/filesystem.h | 10 +++++----- 6 files changed, 15 insertions(+), 12 deletions(-) diff --git a/include/pybind11/detail/class.h b/include/pybind11/detail/class.h index 485f7ac63..454c186b9 100644 --- a/include/pybind11/detail/class.h +++ b/include/pybind11/detail/class.h @@ -9,8 +9,8 @@ #pragma once -#include "../attr.h" -#include "../options.h" +#include +#include PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(detail) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index 329d89b93..17e6df824 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -12,10 +12,10 @@ #include "common.h" #if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) -# include "../gil.h" +# include #endif -#include "../pytypes.h" +#include #include #include diff --git a/include/pybind11/detail/type_caster_base.h b/include/pybind11/detail/type_caster_base.h index 481b7c783..bc42252f9 100644 --- a/include/pybind11/detail/type_caster_base.h +++ b/include/pybind11/detail/type_caster_base.h @@ -9,7 +9,8 @@ #pragma once -#include "../pytypes.h" +#include + #include "common.h" #include "descr.h" #include "internals.h" diff --git a/include/pybind11/eigen/matrix.h b/include/pybind11/eigen/matrix.h index 8d4342f81..5cf1f0a2a 100644 --- a/include/pybind11/eigen/matrix.h +++ b/include/pybind11/eigen/matrix.h @@ -9,7 +9,8 @@ #pragma once -#include "../numpy.h" +#include + #include "common.h" /* HINT: To suppress warnings originating from the Eigen headers, use -isystem. diff --git a/include/pybind11/eigen/tensor.h b/include/pybind11/eigen/tensor.h index 14bb91c40..0a9d7c252 100644 --- a/include/pybind11/eigen/tensor.h +++ b/include/pybind11/eigen/tensor.h @@ -7,7 +7,8 @@ #pragma once -#include "../numpy.h" +#include + #include "common.h" #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) diff --git a/include/pybind11/stl/filesystem.h b/include/pybind11/stl/filesystem.h index 935d79481..c16a9ae5c 100644 --- a/include/pybind11/stl/filesystem.h +++ b/include/pybind11/stl/filesystem.h @@ -4,11 +4,11 @@ #pragma once -#include "../pybind11.h" -#include "../detail/common.h" -#include "../detail/descr.h" -#include "../cast.h" -#include "../pytypes.h" +#include +#include +#include +#include +#include #include From 2baf9d683328aa3f91c53139cc61d977a0c2454a Mon Sep 17 00:00:00 2001 From: ObeliskGate <96614155+ObeliskGate@users.noreply.github.com> Date: Thu, 22 Aug 2024 03:33:06 +0800 Subject: [PATCH 15/18] fix: `` support for `py::tuple` and `py::list` (#5314) * feat: add `` support for `py::tuple` and `py::list` * fix: format the code * fix: disable `ranges` in clang < 16 * refactor: move `` test macro to `test_pytypes.h` * refactor: seperate `ranges` test into 3 funcs * style: compress the if statement * style: pre-commit fixes * style: better formatting --------- Co-authored-by: Henry Schreiner Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- include/pybind11/pytypes.h | 2 ++ tests/test_pytypes.cpp | 63 ++++++++++++++++++++++++++++++++++++++ tests/test_pytypes.py | 42 +++++++++++++++++++++++++ 3 files changed, 107 insertions(+) diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index f26c307a8..1e76d7bc1 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -1259,6 +1259,7 @@ protected: using pointer = arrow_proxy; sequence_fast_readonly(handle obj, ssize_t n) : ptr(PySequence_Fast_ITEMS(obj.ptr()) + n) {} + sequence_fast_readonly() = default; // NOLINTNEXTLINE(readability-const-return-type) // PR #3263 reference dereference() const { return *ptr; } @@ -1281,6 +1282,7 @@ protected: using pointer = arrow_proxy; sequence_slow_readwrite(handle obj, ssize_t index) : obj(obj), index(index) {} + sequence_slow_readwrite() = default; reference dereference() const { return {obj, static_cast(index)}; } void increment() { ++index; } diff --git a/tests/test_pytypes.cpp b/tests/test_pytypes.cpp index ecb44939a..19f65ce7e 100644 --- a/tests/test_pytypes.cpp +++ b/tests/test_pytypes.cpp @@ -13,6 +13,14 @@ #include +//__has_include has been part of C++17, no need to check it +#if defined(PYBIND11_CPP20) && __has_include() +# if !defined(PYBIND11_COMPILER_CLANG) || __clang_major__ >= 16 // llvm/llvm-project#52696 +# define PYBIND11_TEST_PYTYPES_HAS_RANGES +# include +# endif +#endif + namespace external { namespace detail { bool check(PyObject *o) { return PyFloat_Check(o) != 0; } @@ -923,4 +931,59 @@ TEST_SUBMODULE(pytypes, m) { #else m.attr("defined_PYBIND11_TYPING_H_HAS_STRING_LITERAL") = false; #endif + +#if defined(PYBIND11_TEST_PYTYPES_HAS_RANGES) + + // test_tuple_ranges + m.def("tuple_iterator_default_initialization", []() { + using TupleIterator = decltype(std::declval().begin()); + static_assert(std::random_access_iterator); + return TupleIterator{} == TupleIterator{}; + }); + + m.def("transform_tuple_plus_one", [](py::tuple &tpl) { + py::list ret{}; + for (auto it : tpl | std::views::transform([](auto &o) { return py::cast(o) + 1; })) { + ret.append(py::int_(it)); + } + return ret; + }); + + // test_list_ranges + m.def("list_iterator_default_initialization", []() { + using ListIterator = decltype(std::declval().begin()); + static_assert(std::random_access_iterator); + return ListIterator{} == ListIterator{}; + }); + + m.def("transform_list_plus_one", [](py::list &lst) { + py::list ret{}; + for (auto it : lst | std::views::transform([](auto &o) { return py::cast(o) + 1; })) { + ret.append(py::int_(it)); + } + return ret; + }); + + // test_dict_ranges + m.def("dict_iterator_default_initialization", []() { + using DictIterator = decltype(std::declval().begin()); + static_assert(std::forward_iterator); + return DictIterator{} == DictIterator{}; + }); + + m.def("transform_dict_plus_one", [](py::dict &dct) { + py::list ret{}; + for (auto it : dct | std::views::transform([](auto &o) { + return std::pair{py::cast(o.first) + 1, + py::cast(o.second) + 1}; + })) { + ret.append(py::make_tuple(py::int_(it.first), py::int_(it.second))); + } + return ret; + }); + + m.attr("defined_PYBIND11_TEST_PYTYPES_HAS_RANGES") = true; +#else + m.attr("defined_PYBIND11_TEST_PYTYPES_HAS_RANGES") = false; +#endif } diff --git a/tests/test_pytypes.py b/tests/test_pytypes.py index 218092b43..1c6335f75 100644 --- a/tests/test_pytypes.py +++ b/tests/test_pytypes.py @@ -1048,3 +1048,45 @@ def test_typevar(doc): assert doc(m.annotate_listT_to_T) == "annotate_listT_to_T(arg0: list[T]) -> T" assert doc(m.annotate_object_to_T) == "annotate_object_to_T(arg0: object) -> T" + + +@pytest.mark.skipif( + not m.defined_PYBIND11_TEST_PYTYPES_HAS_RANGES, + reason=" not available.", +) +@pytest.mark.parametrize( + ("tested_tuple", "expected"), + [((1,), [2]), ((3, 4), [4, 5]), ((7, 8, 9), [8, 9, 10])], +) +def test_tuple_ranges(tested_tuple, expected): + assert m.tuple_iterator_default_initialization() + assert m.transform_tuple_plus_one(tested_tuple) == expected + + +@pytest.mark.skipif( + not m.defined_PYBIND11_TEST_PYTYPES_HAS_RANGES, + reason=" not available.", +) +@pytest.mark.parametrize( + ("tested_list", "expected"), [([1], [2]), ([3, 4], [4, 5]), ([7, 8, 9], [8, 9, 10])] +) +def test_list_ranges(tested_list, expected): + assert m.list_iterator_default_initialization() + assert m.transform_list_plus_one(tested_list) == expected + + +@pytest.mark.skipif( + not m.defined_PYBIND11_TEST_PYTYPES_HAS_RANGES, + reason=" not available.", +) +@pytest.mark.parametrize( + ("tested_dict", "expected"), + [ + ({1: 2}, [(2, 3)]), + ({3: 4, 5: 6}, [(4, 5), (6, 7)]), + ({7: 8, 9: 10, 11: 12}, [(8, 9), (10, 11), (12, 13)]), + ], +) +def test_dict_ranges(tested_dict, expected): + assert m.dict_iterator_default_initialization() + assert m.transform_dict_plus_one(tested_dict) == expected From 9966ad409d5cecaacb19eddb6c6c8c2d45298863 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Thu, 22 Aug 2024 00:27:50 -0400 Subject: [PATCH 16/18] fix: allow -Wpedantic in C++20 mode (#5322) * fix: allow -Wpedantic again Signed-off-by: Henry Schreiner * tests: ignore pedantic warning for PYBIND11_DECLARE_HOLDER_TYPE Signed-off-by: Henry Schreiner * tests: try just turning off pedantic for one file Signed-off-by: Henry Schreiner * tests: only run pedantic in C++20 mode Signed-off-by: Henry Schreiner * Update tests/local_bindings.h --------- Signed-off-by: Henry Schreiner --- docs/advanced/cast/stl.rst | 6 +++--- docs/advanced/smart_ptrs.rst | 6 +++--- include/pybind11/detail/common.h | 3 +++ tests/CMakeLists.txt | 3 +++ tests/local_bindings.h | 16 ++++++++-------- tests/test_callbacks.cpp | 2 +- tests/test_eigen_matrix.cpp | 4 ++-- tests/test_opaque_types.cpp | 2 +- tests/test_sequences_and_iterators.cpp | 4 ++-- tests/test_smart_ptr.cpp | 15 +++++++++------ tests/test_stl.cpp | 2 +- tests/test_tagbased_polymorphic.cpp | 2 +- tests/test_virtual_functions.cpp | 2 +- 13 files changed, 38 insertions(+), 29 deletions(-) diff --git a/docs/advanced/cast/stl.rst b/docs/advanced/cast/stl.rst index 03d49b295..42b85532d 100644 --- a/docs/advanced/cast/stl.rst +++ b/docs/advanced/cast/stl.rst @@ -162,7 +162,7 @@ the declaration .. code-block:: cpp - PYBIND11_MAKE_OPAQUE(std::vector); + PYBIND11_MAKE_OPAQUE(std::vector) before any binding code (e.g. invocations to ``class_::def()``, etc.). This macro must be specified at the top level (and outside of any namespaces), since @@ -207,8 +207,8 @@ The following example showcases usage of :file:`pybind11/stl_bind.h`: // Don't forget this #include - PYBIND11_MAKE_OPAQUE(std::vector); - PYBIND11_MAKE_OPAQUE(std::map); + PYBIND11_MAKE_OPAQUE(std::vector) + PYBIND11_MAKE_OPAQUE(std::map) // ... diff --git a/docs/advanced/smart_ptrs.rst b/docs/advanced/smart_ptrs.rst index 3c40ce123..b9f100cf8 100644 --- a/docs/advanced/smart_ptrs.rst +++ b/docs/advanced/smart_ptrs.rst @@ -124,7 +124,7 @@ top namespace level before any binding code: .. code-block:: cpp - PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr); + PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr) The first argument of :func:`PYBIND11_DECLARE_HOLDER_TYPE` should be a placeholder name that is used as a template parameter of the second argument. @@ -136,7 +136,7 @@ by default. Specify .. code-block:: cpp - PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr, true); + PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr, true) if ``SmartPtr`` can always be initialized from a ``T*`` pointer without the risk of inconsistencies (such as multiple independent ``SmartPtr`` instances @@ -154,7 +154,7 @@ specialized: .. code-block:: cpp // Always needed for custom holder types - PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr); + PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr) // Only needed if the type's `.get()` goes by another name namespace PYBIND11_NAMESPACE { namespace detail { diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 643fd33d7..2a39e88f3 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -479,6 +479,8 @@ PYBIND11_WARNING_POP } \endrst */ +PYBIND11_WARNING_PUSH +PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments") #define PYBIND11_MODULE(name, variable, ...) \ static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name) \ PYBIND11_MAYBE_UNUSED; \ @@ -499,6 +501,7 @@ PYBIND11_WARNING_POP PYBIND11_CATCH_INIT_EXCEPTIONS \ } \ void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ & (variable)) +PYBIND11_WARNING_POP PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 18308731a..cd94ef3e5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -382,6 +382,9 @@ function(pybind11_enable_warnings target_name) -Wdeprecated -Wundef -Wnon-virtual-dtor) + if(DEFINED CMAKE_CXX_STANDARD AND NOT CMAKE_CXX_STANDARD VERSION_LESS 20) + target_compile_options(${target_name} PRIVATE -Wpedantic) + endif() endif() if(PYBIND11_WERROR) diff --git a/tests/local_bindings.h b/tests/local_bindings.h index 01d278535..dea181310 100644 --- a/tests/local_bindings.h +++ b/tests/local_bindings.h @@ -56,13 +56,13 @@ private: std::string message = ""; }; -PYBIND11_MAKE_OPAQUE(LocalVec); -PYBIND11_MAKE_OPAQUE(LocalVec2); -PYBIND11_MAKE_OPAQUE(LocalMap); -PYBIND11_MAKE_OPAQUE(NonLocalVec); -// PYBIND11_MAKE_OPAQUE(NonLocalVec2); // same type as LocalVec2 -PYBIND11_MAKE_OPAQUE(NonLocalMap); -PYBIND11_MAKE_OPAQUE(NonLocalMap2); +PYBIND11_MAKE_OPAQUE(LocalVec) +PYBIND11_MAKE_OPAQUE(LocalVec2) +PYBIND11_MAKE_OPAQUE(LocalMap) +PYBIND11_MAKE_OPAQUE(NonLocalVec) +// PYBIND11_MAKE_OPAQUE(NonLocalVec2) // same type as LocalVec2 +PYBIND11_MAKE_OPAQUE(NonLocalMap) +PYBIND11_MAKE_OPAQUE(NonLocalMap2) // Simple bindings (used with the above): template @@ -70,7 +70,7 @@ py::class_ bind_local(Args &&...args) { return py::class_(std::forward(args)...).def(py::init()).def("get", [](T &i) { return i.i + Adjust; }); -}; +} // Simulate a foreign library base class (to match the example in the docs): namespace pets { diff --git a/tests/test_callbacks.cpp b/tests/test_callbacks.cpp index 2fd05dec7..e303e7656 100644 --- a/tests/test_callbacks.cpp +++ b/tests/test_callbacks.cpp @@ -148,7 +148,7 @@ TEST_SUBMODULE(callbacks, m) { m.def("dummy_function2", [](int i, int j) { return i + j; }); m.def( "roundtrip", - [](std::function f, bool expect_none = false) { + [](std::function f, bool expect_none) { if (expect_none && f) { throw std::runtime_error("Expected None to be converted to empty std::function"); } diff --git a/tests/test_eigen_matrix.cpp b/tests/test_eigen_matrix.cpp index 21261bfc2..cb8e8c625 100644 --- a/tests/test_eigen_matrix.cpp +++ b/tests/test_eigen_matrix.cpp @@ -55,7 +55,7 @@ void reset_refs() { } // Returns element 2,1 from a matrix (used to test copy/nocopy) -double get_elem(const Eigen::Ref &m) { return m(2, 1); }; +double get_elem(const Eigen::Ref &m) { return m(2, 1); } // Returns a matrix with 10*r + 100*c added to each matrix element (to help test that the matrix // reference is referencing rows/columns correctly). @@ -76,7 +76,7 @@ struct CustomOperatorNew { Eigen::Matrix4d a = Eigen::Matrix4d::Zero(); Eigen::Matrix4d b = Eigen::Matrix4d::Identity(); - EIGEN_MAKE_ALIGNED_OPERATOR_NEW; + EIGEN_MAKE_ALIGNED_OPERATOR_NEW }; TEST_SUBMODULE(eigen_matrix, m) { diff --git a/tests/test_opaque_types.cpp b/tests/test_opaque_types.cpp index 154d0a8d3..da3866cd0 100644 --- a/tests/test_opaque_types.cpp +++ b/tests/test_opaque_types.cpp @@ -18,7 +18,7 @@ // This also deliberately doesn't use the below StringList type alias to test // that MAKE_OPAQUE can handle a type containing a `,`. (The `std::allocator` // bit is just the default `std::vector` allocator). -PYBIND11_MAKE_OPAQUE(std::vector>); +PYBIND11_MAKE_OPAQUE(std::vector>) using StringList = std::vector>; diff --git a/tests/test_sequences_and_iterators.cpp b/tests/test_sequences_and_iterators.cpp index 4a1d37f4d..c997b7300 100644 --- a/tests/test_sequences_and_iterators.cpp +++ b/tests/test_sequences_and_iterators.cpp @@ -86,8 +86,8 @@ private: }; using NonCopyableIntPair = std::pair; -PYBIND11_MAKE_OPAQUE(std::vector); -PYBIND11_MAKE_OPAQUE(std::vector); +PYBIND11_MAKE_OPAQUE(std::vector) +PYBIND11_MAKE_OPAQUE(std::vector) template py::list test_random_access_iterator(PythonType x) { diff --git a/tests/test_smart_ptr.cpp b/tests/test_smart_ptr.cpp index 496073b3c..4ab43953f 100644 --- a/tests/test_smart_ptr.cpp +++ b/tests/test_smart_ptr.cpp @@ -11,6 +11,9 @@ #include "object.h" #include "pybind11_tests.h" +// This breaks on PYBIND11_DECLARE_HOLDER_TYPE +PYBIND11_WARNING_DISABLE_GCC("-Wpedantic") + namespace { // This is just a wrapper around unique_ptr, but with extra fields to deliberately bloat up the @@ -279,13 +282,13 @@ struct holder_helper> { } // namespace PYBIND11_NAMESPACE // Make pybind aware of the ref-counted wrapper type (s): -PYBIND11_DECLARE_HOLDER_TYPE(T, ref, true); +PYBIND11_DECLARE_HOLDER_TYPE(T, ref, true) // The following is not required anymore for std::shared_ptr, but it should compile without error: -PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr); -PYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr); -PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr); -PYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_with_addressof_operator); -PYBIND11_DECLARE_HOLDER_TYPE(T, unique_ptr_with_addressof_operator); +PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr) +PYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr) +PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr) +PYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_with_addressof_operator) +PYBIND11_DECLARE_HOLDER_TYPE(T, unique_ptr_with_addressof_operator) TEST_SUBMODULE(smart_ptr, m) { // Please do not interleave `struct` and `class` definitions with bindings code, diff --git a/tests/test_stl.cpp b/tests/test_stl.cpp index 6240524a0..dd93d51d0 100644 --- a/tests/test_stl.cpp +++ b/tests/test_stl.cpp @@ -59,7 +59,7 @@ struct visit_helper { } // namespace PYBIND11_NAMESPACE #endif -PYBIND11_MAKE_OPAQUE(std::vector>); +PYBIND11_MAKE_OPAQUE(std::vector>) /// Issue #528: templated constructor struct TplCtorClass { diff --git a/tests/test_tagbased_polymorphic.cpp b/tests/test_tagbased_polymorphic.cpp index 24b49021b..13e5ed319 100644 --- a/tests/test_tagbased_polymorphic.cpp +++ b/tests/test_tagbased_polymorphic.cpp @@ -145,4 +145,4 @@ TEST_SUBMODULE(tagbased_polymorphic, m) { .def(py::init()) .def("purr", &Panther::purr); m.def("create_zoo", &create_zoo); -}; +} diff --git a/tests/test_virtual_functions.cpp b/tests/test_virtual_functions.cpp index 93b136ad3..a6164eb81 100644 --- a/tests/test_virtual_functions.cpp +++ b/tests/test_virtual_functions.cpp @@ -589,4 +589,4 @@ void initialize_inherited_virtuals(py::module_ &m) { // Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7) m.def("test_gil", &test_gil); m.def("test_gil_from_thread", &test_gil_from_thread); -}; +} From efa2b20d69cd7daa57b41a559a71117b2c34a369 Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Thu, 22 Aug 2024 00:29:21 -0400 Subject: [PATCH 17/18] docs: clarify requirements for including pybind11 (#5326) * DOC: Clarify requirements for including pybind11 Inherited from requirements for including Python.h Closes #4999 * style: pre-commit fixes --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- docs/basics.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/basics.rst b/docs/basics.rst index e9b24c7fa..cd97c100e 100644 --- a/docs/basics.rst +++ b/docs/basics.rst @@ -78,6 +78,13 @@ For brevity, all code examples assume that the following two lines are present: namespace py = pybind11; +.. note:: + + ``pybind11/pybind11.h`` includes ``Python.h``, as such it must be the first file + included in any source file or header for `the same reasons as Python.h`_. + +.. _`the same reasons as Python.h`: https://docs.python.org/3/extending/extending.html#a-simple-example + Some features may require additional headers, but those will be specified as needed. .. _simple_example: From c2291e597ffe4fb028ae4ff97c5cd4fc20a8a7f9 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Thu, 22 Aug 2024 14:12:17 -0400 Subject: [PATCH 18/18] docs: prepare for 2.13.5 (#5327) * docs: prepare for 2.13.5 Signed-off-by: Henry Schreiner * Update docs/changelog.rst --------- Signed-off-by: Henry Schreiner --- docs/changelog.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 031d31582..014531774 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -28,6 +28,23 @@ New Features: * Support for CMake older than 3.15 removed. CMake 3.15-3.30 supported. `#5304 `_ +* The ``array_caster`` in pybind11/stl.h was enhanced to support value types that are not default-constructible. + `#5305 `_ + +Version 2.13.5 (August 22, 2024) +-------------------------------- + +Bug fixes: + +* Fix includes when using Windows long paths (``\\?\`` prefix). + `#5321 `_ + +* Support ``-Wpedantic`` in C++20 mode. + `#5322 `_ + +* Fix and test ```` support for ``py::tuple`` and ``py::list``. + `#5314 `_ + Version 2.13.4 (August 14, 2024) --------------------------------