mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-25 14:45:12 +00:00
Merge branch 'v2.13' into stable
This commit is contained in:
commit
5211a1715a
@ -57,10 +57,12 @@ Checks: |
|
|||||||
readability-string-compare,
|
readability-string-compare,
|
||||||
readability-suspicious-call-argument,
|
readability-suspicious-call-argument,
|
||||||
readability-uniqueptr-delete-release,
|
readability-uniqueptr-delete-release,
|
||||||
|
-bugprone-chained-comparison,
|
||||||
-bugprone-easily-swappable-parameters,
|
-bugprone-easily-swappable-parameters,
|
||||||
-bugprone-exception-escape,
|
-bugprone-exception-escape,
|
||||||
-bugprone-reserved-identifier,
|
-bugprone-reserved-identifier,
|
||||||
-bugprone-unused-raii,
|
-bugprone-unused-raii,
|
||||||
|
-performance-enum-size,
|
||||||
|
|
||||||
CheckOptions:
|
CheckOptions:
|
||||||
- key: modernize-use-equals-default.IgnoreMacros
|
- key: modernize-use-equals-default.IgnoreMacros
|
||||||
|
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@ -340,6 +340,12 @@ jobs:
|
|||||||
- clang: 16
|
- clang: 16
|
||||||
std: 20
|
std: 20
|
||||||
container_suffix: "-bullseye"
|
container_suffix: "-bullseye"
|
||||||
|
- clang: 17
|
||||||
|
std: 20
|
||||||
|
container_suffix: "-bookworm"
|
||||||
|
- clang: 18
|
||||||
|
std: 20
|
||||||
|
container_suffix: "-bookworm"
|
||||||
|
|
||||||
name: "🐍 3 • Clang ${{ matrix.clang }} • C++${{ matrix.std }} • x64"
|
name: "🐍 3 • Clang ${{ matrix.clang }} • C++${{ matrix.std }} • x64"
|
||||||
container: "silkeh/clang:${{ matrix.clang }}${{ matrix.container_suffix }}"
|
container: "silkeh/clang:${{ matrix.clang }}${{ matrix.container_suffix }}"
|
||||||
@ -501,7 +507,9 @@ jobs:
|
|||||||
- { gcc: 7, std: 17 }
|
- { gcc: 7, std: 17 }
|
||||||
- { gcc: 8, std: 14 }
|
- { gcc: 8, std: 14 }
|
||||||
- { gcc: 8, std: 17 }
|
- { gcc: 8, std: 17 }
|
||||||
|
- { gcc: 9, std: 20 }
|
||||||
- { gcc: 10, std: 17 }
|
- { gcc: 10, std: 17 }
|
||||||
|
- { gcc: 10, std: 20 }
|
||||||
- { gcc: 11, std: 20 }
|
- { gcc: 11, std: 20 }
|
||||||
- { gcc: 12, std: 20 }
|
- { gcc: 12, std: 20 }
|
||||||
- { gcc: 13, std: 20 }
|
- { gcc: 13, std: 20 }
|
||||||
|
30
.github/workflows/emscripten.yaml
vendored
Normal file
30
.github/workflows/emscripten.yaml
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
name: WASM
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- stable
|
||||||
|
- v*
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-wasm-emscripten:
|
||||||
|
name: Pyodide wheel
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- uses: pypa/cibuildwheel@v2.20
|
||||||
|
env:
|
||||||
|
PYODIDE_BUILD_EXPORTS: whole_archive
|
||||||
|
with:
|
||||||
|
package-dir: tests
|
||||||
|
only: cp312-pyodide_wasm32
|
2
.github/workflows/format.yml
vendored
2
.github/workflows/format.yml
vendored
@ -41,7 +41,7 @@ jobs:
|
|||||||
# in .github/CONTRIBUTING.md and update as needed.
|
# in .github/CONTRIBUTING.md and update as needed.
|
||||||
name: Clang-Tidy
|
name: Clang-Tidy
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: silkeh/clang:15-bullseye
|
container: silkeh/clang:18-bookworm
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
2
.github/workflows/pip.yml
vendored
2
.github/workflows/pip.yml
vendored
@ -102,7 +102,7 @@ jobs:
|
|||||||
- uses: actions/download-artifact@v4
|
- uses: actions/download-artifact@v4
|
||||||
|
|
||||||
- name: Generate artifact attestation for sdist and wheel
|
- name: Generate artifact attestation for sdist and wheel
|
||||||
uses: actions/attest-build-provenance@173725a1209d09b31f9d30a3890cf2757ebbff0d # v1.1.2
|
uses: actions/attest-build-provenance@310b0a4a3b0b78ef57ecda988ee04b132db73ef8 # v1.4.1
|
||||||
with:
|
with:
|
||||||
subject-path: "*/pybind11*"
|
subject-path: "*/pybind11*"
|
||||||
|
|
||||||
|
@ -25,14 +25,14 @@ repos:
|
|||||||
|
|
||||||
# Clang format the codebase automatically
|
# Clang format the codebase automatically
|
||||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||||
rev: "v18.1.5"
|
rev: "v18.1.8"
|
||||||
hooks:
|
hooks:
|
||||||
- id: clang-format
|
- id: clang-format
|
||||||
types_or: [c++, c, cuda]
|
types_or: [c++, c, cuda]
|
||||||
|
|
||||||
# Ruff, the Python auto-correcting linter/formatter written in Rust
|
# Ruff, the Python auto-correcting linter/formatter written in Rust
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: v0.4.7
|
rev: v0.5.6
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff
|
- id: ruff
|
||||||
args: ["--fix", "--show-fixes"]
|
args: ["--fix", "--show-fixes"]
|
||||||
@ -40,7 +40,7 @@ repos:
|
|||||||
|
|
||||||
# Check static types with mypy
|
# Check static types with mypy
|
||||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||||
rev: "v1.10.0"
|
rev: "v1.11.1"
|
||||||
hooks:
|
hooks:
|
||||||
- id: mypy
|
- id: mypy
|
||||||
args: []
|
args: []
|
||||||
@ -79,7 +79,7 @@ repos:
|
|||||||
|
|
||||||
# Also code format the docs
|
# Also code format the docs
|
||||||
- repo: https://github.com/adamchainz/blacken-docs
|
- repo: https://github.com/adamchainz/blacken-docs
|
||||||
rev: "1.16.0"
|
rev: "1.18.0"
|
||||||
hooks:
|
hooks:
|
||||||
- id: blacken-docs
|
- id: blacken-docs
|
||||||
additional_dependencies:
|
additional_dependencies:
|
||||||
@ -142,14 +142,14 @@ repos:
|
|||||||
|
|
||||||
# PyLint has native support - not always usable, but works for us
|
# PyLint has native support - not always usable, but works for us
|
||||||
- repo: https://github.com/PyCQA/pylint
|
- repo: https://github.com/PyCQA/pylint
|
||||||
rev: "v3.2.2"
|
rev: "v3.2.6"
|
||||||
hooks:
|
hooks:
|
||||||
- id: pylint
|
- id: pylint
|
||||||
files: ^pybind11
|
files: ^pybind11
|
||||||
|
|
||||||
# Check schemas on some of our YAML files
|
# Check schemas on some of our YAML files
|
||||||
- repo: https://github.com/python-jsonschema/check-jsonschema
|
- repo: https://github.com/python-jsonschema/check-jsonschema
|
||||||
rev: 0.28.4
|
rev: 0.29.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-readthedocs
|
- id: check-readthedocs
|
||||||
- id: check-github-workflows
|
- id: check-github-workflows
|
||||||
|
@ -154,6 +154,7 @@ set(PYBIND11_HEADERS
|
|||||||
include/pybind11/detail/internals.h
|
include/pybind11/detail/internals.h
|
||||||
include/pybind11/detail/type_caster_base.h
|
include/pybind11/detail/type_caster_base.h
|
||||||
include/pybind11/detail/typeid.h
|
include/pybind11/detail/typeid.h
|
||||||
|
include/pybind11/detail/value_and_holder.h
|
||||||
include/pybind11/attr.h
|
include/pybind11/attr.h
|
||||||
include/pybind11/buffer_info.h
|
include/pybind11/buffer_info.h
|
||||||
include/pybind11/cast.h
|
include/pybind11/cast.h
|
||||||
|
@ -259,7 +259,7 @@ copying to take place:
|
|||||||
"small"_a // <- This one can be copied if needed
|
"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)``
|
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.
|
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
|
It will, however, allow the ``m2`` argument to be copied into a temporary if
|
||||||
|
@ -15,6 +15,98 @@ IN DEVELOPMENT
|
|||||||
|
|
||||||
Changes will be summarized here periodically.
|
Changes will be summarized here periodically.
|
||||||
|
|
||||||
|
New Features:
|
||||||
|
|
||||||
|
* Support for Python 3.7 was removed. (Official end-of-life: 2023-06-27).
|
||||||
|
`#5191 <https://github.com/pybind/pybind11/pull/5191>`_
|
||||||
|
|
||||||
|
* 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 <https://github.com/pybind/pybind11/pull/4686>`_
|
||||||
|
|
||||||
|
* Support for CMake older than 3.15 removed. CMake 3.15-3.30 supported.
|
||||||
|
`#5304 <https://github.com/pybind/pybind11/pull/5304>`_
|
||||||
|
|
||||||
|
Version 2.13.4 (August 14, 2024)
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* Fix paths with spaces, including on Windows.
|
||||||
|
(Replaces regression from `#5302 <https://github.com/pybind/pybind11/pull/5302>`_)
|
||||||
|
`#4874 <https://github.com/pybind/pybind11/pull/4874>`_
|
||||||
|
|
||||||
|
Documentation:
|
||||||
|
|
||||||
|
* Remove repetitive words.
|
||||||
|
`#5308 <https://github.com/pybind/pybind11/pull/5308>`_
|
||||||
|
|
||||||
|
|
||||||
|
Version 2.13.3 (August 13, 2024)
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* Quote paths from pybind11-config
|
||||||
|
`#5302 <https://github.com/pybind/pybind11/pull/5302>`_
|
||||||
|
|
||||||
|
|
||||||
|
* Fix typo in Emscripten support when in config mode (CMake)
|
||||||
|
`#5301 <https://github.com/pybind/pybind11/pull/5301>`_
|
||||||
|
|
||||||
|
|
||||||
|
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 <https://github.com/pybind/pybind11/pull/4597>`_
|
||||||
|
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
|
||||||
|
* Use ``PyMutex`` instead of ``std::mutex`` for internal locking in the free-threaded build.
|
||||||
|
`#5219 <https://github.com/pybind/pybind11/pull/5219>`_
|
||||||
|
|
||||||
|
* Add a special type annotation for C++ empty tuple.
|
||||||
|
`#5214 <https://github.com/pybind/pybind11/pull/5214>`_
|
||||||
|
|
||||||
|
* When compiling for WebAssembly, add the required exception flags (CMake 3.13+).
|
||||||
|
`#5298 <https://github.com/pybind/pybind11/pull/5298>`_
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
|
||||||
|
* Make ``gil_safe_call_once_and_store`` thread-safe in free-threaded CPython.
|
||||||
|
`#5246 <https://github.com/pybind/pybind11/pull/5246>`_
|
||||||
|
|
||||||
|
* A missing ``#include <algorithm>`` in pybind11/typing.h was added to fix build errors (in case user code does not already depend
|
||||||
|
on that include).
|
||||||
|
`#5208 <https://github.com/pybind/pybind11/pull/5208>`_
|
||||||
|
|
||||||
|
* Fix regression introduced in #5201 for GCC<10.3 in C++20 mode.
|
||||||
|
`#5205 <https://github.com/pybind/pybind11/pull/5205>`_
|
||||||
|
|
||||||
|
|
||||||
|
.. fix(cmake)
|
||||||
|
|
||||||
|
* Remove extra = when assigning flto value in the case for Clang in CMake.
|
||||||
|
`#5207 <https://github.com/pybind/pybind11/pull/5207>`_
|
||||||
|
|
||||||
|
|
||||||
|
Tests:
|
||||||
|
|
||||||
|
* Adding WASM testing to our CI (Pyodide / Emscripten via scikit-build-core).
|
||||||
|
`#4745 <https://github.com/pybind/pybind11/pull/4745>`_
|
||||||
|
|
||||||
|
* clang-tidy (in GitHub Actions) was updated from clang 15 to clang 18.
|
||||||
|
`#5272 <https://github.com/pybind/pybind11/pull/5272>`_
|
||||||
|
|
||||||
|
|
||||||
Version 2.13.1 (June 26, 2024)
|
Version 2.13.1 (June 26, 2024)
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ A Python extension module can be created with just a few lines of code:
|
|||||||
find_package(pybind11 CONFIG REQUIRED)
|
find_package(pybind11 CONFIG REQUIRED)
|
||||||
|
|
||||||
pybind11_add_module(example example.cpp)
|
pybind11_add_module(example example.cpp)
|
||||||
install(TARGET example DESTINATION .)
|
install(TARGETS example DESTINATION .)
|
||||||
|
|
||||||
(You use the ``add_subdirectory`` instead, see the example in :ref:`cmake`.) In
|
(You use the ``add_subdirectory`` instead, see the example in :ref:`cmake`.) In
|
||||||
this example, the code is located in a file named :file:`example.cpp`. Either
|
this example, the code is located in a file named :file:`example.cpp`. Either
|
||||||
@ -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
|
The ``OPT_SIZE`` flag enables size-based optimization equivalent to the
|
||||||
standard ``/Os`` or ``-Os`` compiler flags and the ``MinSizeRel`` build type,
|
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
|
resulting binary. This flag is particularly useful in projects that are split
|
||||||
into performance-critical parts and associated bindings. In this case, we can
|
into performance-critical parts and associated bindings. In this case, we can
|
||||||
compile the project in release mode (and hence, optimize performance globally),
|
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
|
[litgen]_ is an automatic python bindings generator with a focus on generating
|
||||||
documented and discoverable bindings: bindings will nicely reproduce the documentation
|
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
|
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).
|
must be C++14 compatible (but your implementation can use more modern constructs).
|
||||||
|
|
||||||
|
@ -50,10 +50,6 @@ clean, well written patch would likely be accepted to solve them.
|
|||||||
One consequence is that containers of ``char *`` are currently not supported.
|
One consequence is that containers of ``char *`` are currently not supported.
|
||||||
`#2245 <https://github.com/pybind/pybind11/issues/2245>`_
|
`#2245 <https://github.com/pybind/pybind11/issues/2245>`_
|
||||||
|
|
||||||
- The ``cpptest`` does not run on Windows with Python 3.8 or newer, due to DLL
|
|
||||||
loader changes. User code that is correctly installed should not be affected.
|
|
||||||
`#2560 <https://github.com/pybind/pybind11/issue/2560>`_
|
|
||||||
|
|
||||||
Python 3.9.0 warning
|
Python 3.9.0 warning
|
||||||
^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
@ -16,9 +16,9 @@ breathe==4.35.0 \
|
|||||||
--hash=sha256:5165541c3c67b6c7adde8b3ecfe895c6f7844783c4076b6d8d287e4f33d62386 \
|
--hash=sha256:5165541c3c67b6c7adde8b3ecfe895c6f7844783c4076b6d8d287e4f33d62386 \
|
||||||
--hash=sha256:52c581f42ca4310737f9e435e3851c3d1f15446205a85fbc272f1f97ed74f5be
|
--hash=sha256:52c581f42ca4310737f9e435e3851c3d1f15446205a85fbc272f1f97ed74f5be
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
certifi==2024.2.2 \
|
certifi==2024.7.4 \
|
||||||
--hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \
|
--hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \
|
||||||
--hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1
|
--hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90
|
||||||
# via requests
|
# via requests
|
||||||
charset-normalizer==3.3.2 \
|
charset-normalizer==3.3.2 \
|
||||||
--hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
|
--hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
|
||||||
|
@ -740,6 +740,13 @@ class type_caster<std::pair<T1, T2>> : public tuple_caster<std::pair, T1, T2> {}
|
|||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
class type_caster<std::tuple<Ts...>> : public tuple_caster<std::tuple, Ts...> {};
|
class type_caster<std::tuple<Ts...>> : public tuple_caster<std::tuple, Ts...> {};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class type_caster<std::tuple<>> : public tuple_caster<std::tuple> {
|
||||||
|
public:
|
||||||
|
// PEP 484 specifies this syntax for an empty tuple
|
||||||
|
static constexpr auto name = const_name("tuple[()]");
|
||||||
|
};
|
||||||
|
|
||||||
/// Helper class which abstracts away certain actions. Users can provide specializations for
|
/// Helper class which abstracts away certain actions. Users can provide specializations for
|
||||||
/// custom holders, but it's only necessary if the type has a non-standard interface.
|
/// custom holders, but it's only necessary if the type has a non-standard interface.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -787,11 +794,11 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool load_value(value_and_holder &&v_h) {
|
void load_value(value_and_holder &&v_h) {
|
||||||
if (v_h.holder_constructed()) {
|
if (v_h.holder_constructed()) {
|
||||||
value = v_h.value_ptr();
|
value = v_h.value_ptr();
|
||||||
holder = v_h.template holder<holder_type>();
|
holder = v_h.template holder<holder_type>();
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
throw cast_error("Unable to cast from non-held to held instance (T& to Holder<T>) "
|
throw cast_error("Unable to cast from non-held to held instance (T& to Holder<T>) "
|
||||||
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
||||||
|
@ -11,11 +11,11 @@
|
|||||||
|
|
||||||
#define PYBIND11_VERSION_MAJOR 2
|
#define PYBIND11_VERSION_MAJOR 2
|
||||||
#define PYBIND11_VERSION_MINOR 13
|
#define PYBIND11_VERSION_MINOR 13
|
||||||
#define PYBIND11_VERSION_PATCH 1
|
#define PYBIND11_VERSION_PATCH 4
|
||||||
|
|
||||||
// Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html
|
// Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html
|
||||||
// Additional convention: 0xD = dev
|
// Additional convention: 0xD = dev
|
||||||
#define PYBIND11_VERSION_HEX 0x020D0100
|
#define PYBIND11_VERSION_HEX 0x020D0400
|
||||||
|
|
||||||
// Define some generic pybind11 helper macros for warning management.
|
// Define some generic pybind11 helper macros for warning management.
|
||||||
//
|
//
|
||||||
@ -462,6 +462,22 @@ PYBIND11_WARNING_POP
|
|||||||
return "Hello, World!";
|
return "Hello, World!";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
The third macro argument is optional (available since 2.13.0), and can be used to
|
||||||
|
mark the extension module as safe to run without the GIL under a free-threaded CPython
|
||||||
|
interpreter. Passing this argument has no effect on other interpreters.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
PYBIND11_MODULE(example, m, py::mod_gil_not_used()) {
|
||||||
|
m.doc() = "pybind11 example module safe to run without the GIL";
|
||||||
|
|
||||||
|
// Add bindings here
|
||||||
|
m.def("foo", []() {
|
||||||
|
return "Hello, Free-threaded World!";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
\endrst */
|
\endrst */
|
||||||
#define PYBIND11_MODULE(name, variable, ...) \
|
#define PYBIND11_MODULE(name, variable, ...) \
|
||||||
static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name) \
|
static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name) \
|
||||||
@ -538,7 +554,7 @@ enum class return_value_policy : uint8_t {
|
|||||||
object without taking ownership similar to the above
|
object without taking ownership similar to the above
|
||||||
return_value_policy::reference policy. In contrast to that policy, the
|
return_value_policy::reference policy. In contrast to that policy, the
|
||||||
function or property's implicit this argument (called the parent) is
|
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
|
pybind11 then couples the lifetime of the parent to the child via a
|
||||||
reference relationship that ensures that the parent cannot be garbage
|
reference relationship that ensures that the parent cannot be garbage
|
||||||
collected while Python is still using the child. More advanced
|
collected while Python is still using the child. More advanced
|
||||||
|
@ -128,11 +128,13 @@ void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) {
|
|||||||
// the holder and destruction happens when we leave the C++ scope, and the holder
|
// the holder and destruction happens when we leave the C++ scope, and the holder
|
||||||
// class gets to handle the destruction however it likes.
|
// class gets to handle the destruction however it likes.
|
||||||
v_h.value_ptr() = ptr;
|
v_h.value_ptr() = ptr;
|
||||||
v_h.set_instance_registered(true); // To prevent init_instance from registering it
|
v_h.set_instance_registered(true); // Trick to prevent init_instance from registering it
|
||||||
v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder
|
// DANGER ZONE BEGIN: exceptions will leave v_h in an invalid state.
|
||||||
|
v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder
|
||||||
Holder<Class> temp_holder(std::move(v_h.holder<Holder<Class>>())); // Steal the holder
|
Holder<Class> temp_holder(std::move(v_h.holder<Holder<Class>>())); // Steal the holder
|
||||||
v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null
|
v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null
|
||||||
v_h.set_instance_registered(false);
|
v_h.set_instance_registered(false);
|
||||||
|
// DANGER ZONE END.
|
||||||
|
|
||||||
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(*ptr));
|
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(*ptr));
|
||||||
} else {
|
} else {
|
||||||
|
@ -148,20 +148,35 @@ struct override_hash {
|
|||||||
|
|
||||||
using instance_map = std::unordered_multimap<const void *, instance *>;
|
using instance_map = std::unordered_multimap<const void *, instance *>;
|
||||||
|
|
||||||
|
#ifdef Py_GIL_DISABLED
|
||||||
|
// Wrapper around PyMutex to provide BasicLockable semantics
|
||||||
|
class pymutex {
|
||||||
|
PyMutex mutex;
|
||||||
|
|
||||||
|
public:
|
||||||
|
pymutex() : mutex({}) {}
|
||||||
|
void lock() { PyMutex_Lock(&mutex); }
|
||||||
|
void unlock() { PyMutex_Unlock(&mutex); }
|
||||||
|
};
|
||||||
|
|
||||||
// Instance map shards are used to reduce mutex contention in free-threaded Python.
|
// Instance map shards are used to reduce mutex contention in free-threaded Python.
|
||||||
struct instance_map_shard {
|
struct instance_map_shard {
|
||||||
std::mutex mutex;
|
|
||||||
instance_map registered_instances;
|
instance_map registered_instances;
|
||||||
|
pymutex mutex;
|
||||||
// alignas(64) would be better, but causes compile errors in macOS before 10.14 (see #5200)
|
// alignas(64) would be better, but causes compile errors in macOS before 10.14 (see #5200)
|
||||||
char padding[64 - (sizeof(std::mutex) + sizeof(instance_map)) % 64];
|
char padding[64 - (sizeof(instance_map) + sizeof(pymutex)) % 64];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(instance_map_shard) % 64 == 0,
|
||||||
|
"instance_map_shard size is not a multiple of 64 bytes");
|
||||||
|
#endif
|
||||||
|
|
||||||
/// Internal data structure used to track registered instances and types.
|
/// Internal data structure used to track registered instances and types.
|
||||||
/// Whenever binary incompatible changes are made to this structure,
|
/// Whenever binary incompatible changes are made to this structure,
|
||||||
/// `PYBIND11_INTERNALS_VERSION` must be incremented.
|
/// `PYBIND11_INTERNALS_VERSION` must be incremented.
|
||||||
struct internals {
|
struct internals {
|
||||||
#ifdef Py_GIL_DISABLED
|
#ifdef Py_GIL_DISABLED
|
||||||
std::mutex mutex;
|
pymutex mutex;
|
||||||
#endif
|
#endif
|
||||||
// std::type_index -> pybind11's type information
|
// std::type_index -> pybind11's type information
|
||||||
type_map<type_info *> registered_types_cpp;
|
type_map<type_info *> registered_types_cpp;
|
||||||
@ -538,7 +553,7 @@ PYBIND11_NOINLINE internals &get_internals() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
internals_ptr->istate = tstate->interp;
|
internals_ptr->istate = tstate->interp;
|
||||||
state_dict[PYBIND11_INTERNALS_ID] = capsule(internals_pp);
|
state_dict[PYBIND11_INTERNALS_ID] = capsule(reinterpret_cast<void *>(internals_pp));
|
||||||
internals_ptr->registered_exception_translators.push_front(&translate_exception);
|
internals_ptr->registered_exception_translators.push_front(&translate_exception);
|
||||||
internals_ptr->static_property_type = make_static_property_type();
|
internals_ptr->static_property_type = make_static_property_type();
|
||||||
internals_ptr->default_metaclass = make_default_metaclass();
|
internals_ptr->default_metaclass = make_default_metaclass();
|
||||||
@ -614,7 +629,7 @@ inline local_internals &get_local_internals() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef Py_GIL_DISABLED
|
#ifdef Py_GIL_DISABLED
|
||||||
# define PYBIND11_LOCK_INTERNALS(internals) std::unique_lock<std::mutex> lock((internals).mutex)
|
# define PYBIND11_LOCK_INTERNALS(internals) std::unique_lock<pymutex> lock((internals).mutex)
|
||||||
#else
|
#else
|
||||||
# define PYBIND11_LOCK_INTERNALS(internals)
|
# define PYBIND11_LOCK_INTERNALS(internals)
|
||||||
#endif
|
#endif
|
||||||
@ -651,7 +666,7 @@ inline auto with_instance_map(const void *ptr,
|
|||||||
auto idx = static_cast<size_t>(hash & internals.instance_shards_mask);
|
auto idx = static_cast<size_t>(hash & internals.instance_shards_mask);
|
||||||
|
|
||||||
auto &shard = internals.instance_shards[idx];
|
auto &shard = internals.instance_shards[idx];
|
||||||
std::unique_lock<std::mutex> lock(shard.mutex);
|
std::unique_lock<pymutex> lock(shard.mutex);
|
||||||
return cb(shard.registered_instances);
|
return cb(shard.registered_instances);
|
||||||
#else
|
#else
|
||||||
(void) ptr;
|
(void) ptr;
|
||||||
@ -667,7 +682,7 @@ inline size_t num_registered_instances() {
|
|||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
for (size_t i = 0; i <= internals.instance_shards_mask; ++i) {
|
for (size_t i = 0; i <= internals.instance_shards_mask; ++i) {
|
||||||
auto &shard = internals.instance_shards[i];
|
auto &shard = internals.instance_shards[i];
|
||||||
std::unique_lock<std::mutex> lock(shard.mutex);
|
std::unique_lock<pymutex> lock(shard.mutex);
|
||||||
count += shard.registered_instances.size();
|
count += shard.registered_instances.size();
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "descr.h"
|
#include "descr.h"
|
||||||
#include "internals.h"
|
#include "internals.h"
|
||||||
#include "typeid.h"
|
#include "typeid.h"
|
||||||
|
#include "value_and_holder.h"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
@ -259,67 +260,6 @@ PYBIND11_NOINLINE handle find_registered_python_instance(void *src,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
struct value_and_holder {
|
|
||||||
instance *inst = nullptr;
|
|
||||||
size_t index = 0u;
|
|
||||||
const detail::type_info *type = nullptr;
|
|
||||||
void **vh = nullptr;
|
|
||||||
|
|
||||||
// Main constructor for a found value/holder:
|
|
||||||
value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index)
|
|
||||||
: inst{i}, index{index}, type{type},
|
|
||||||
vh{inst->simple_layout ? inst->simple_value_holder
|
|
||||||
: &inst->nonsimple.values_and_holders[vpos]} {}
|
|
||||||
|
|
||||||
// Default constructor (used to signal a value-and-holder not found by get_value_and_holder())
|
|
||||||
value_and_holder() = default;
|
|
||||||
|
|
||||||
// Used for past-the-end iterator
|
|
||||||
explicit value_and_holder(size_t index) : index{index} {}
|
|
||||||
|
|
||||||
template <typename V = void>
|
|
||||||
V *&value_ptr() const {
|
|
||||||
return reinterpret_cast<V *&>(vh[0]);
|
|
||||||
}
|
|
||||||
// True if this `value_and_holder` has a non-null value pointer
|
|
||||||
explicit operator bool() const { return value_ptr() != nullptr; }
|
|
||||||
|
|
||||||
template <typename H>
|
|
||||||
H &holder() const {
|
|
||||||
return reinterpret_cast<H &>(vh[1]);
|
|
||||||
}
|
|
||||||
bool holder_constructed() const {
|
|
||||||
return inst->simple_layout
|
|
||||||
? inst->simple_holder_constructed
|
|
||||||
: (inst->nonsimple.status[index] & instance::status_holder_constructed) != 0u;
|
|
||||||
}
|
|
||||||
// NOLINTNEXTLINE(readability-make-member-function-const)
|
|
||||||
void set_holder_constructed(bool v = true) {
|
|
||||||
if (inst->simple_layout) {
|
|
||||||
inst->simple_holder_constructed = v;
|
|
||||||
} else if (v) {
|
|
||||||
inst->nonsimple.status[index] |= instance::status_holder_constructed;
|
|
||||||
} else {
|
|
||||||
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_holder_constructed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool instance_registered() const {
|
|
||||||
return inst->simple_layout
|
|
||||||
? inst->simple_instance_registered
|
|
||||||
: ((inst->nonsimple.status[index] & instance::status_instance_registered) != 0);
|
|
||||||
}
|
|
||||||
// NOLINTNEXTLINE(readability-make-member-function-const)
|
|
||||||
void set_instance_registered(bool v = true) {
|
|
||||||
if (inst->simple_layout) {
|
|
||||||
inst->simple_instance_registered = v;
|
|
||||||
} else if (v) {
|
|
||||||
inst->nonsimple.status[index] |= instance::status_instance_registered;
|
|
||||||
} else {
|
|
||||||
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_instance_registered;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Container for accessing and iterating over an instance's values/holders
|
// Container for accessing and iterating over an instance's values/holders
|
||||||
struct values_and_holders {
|
struct values_and_holders {
|
||||||
private:
|
private:
|
||||||
@ -488,7 +428,7 @@ PYBIND11_NOINLINE void instance::allocate_layout() {
|
|||||||
// NOLINTNEXTLINE(readability-make-member-function-const)
|
// NOLINTNEXTLINE(readability-make-member-function-const)
|
||||||
PYBIND11_NOINLINE void instance::deallocate_layout() {
|
PYBIND11_NOINLINE void instance::deallocate_layout() {
|
||||||
if (!simple_layout) {
|
if (!simple_layout) {
|
||||||
PyMem_Free(nonsimple.values_and_holders);
|
PyMem_Free(reinterpret_cast<void *>(nonsimple.values_and_holders));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
77
include/pybind11/detail/value_and_holder.h
Normal file
77
include/pybind11/detail/value_and_holder.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// Copyright (c) 2016-2024 The Pybind Development Team.
|
||||||
|
// All rights reserved. Use of this source code is governed by a
|
||||||
|
// BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <typeinfo>
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
struct value_and_holder {
|
||||||
|
instance *inst = nullptr;
|
||||||
|
size_t index = 0u;
|
||||||
|
const detail::type_info *type = nullptr;
|
||||||
|
void **vh = nullptr;
|
||||||
|
|
||||||
|
// Main constructor for a found value/holder:
|
||||||
|
value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index)
|
||||||
|
: inst{i}, index{index}, type{type},
|
||||||
|
vh{inst->simple_layout ? inst->simple_value_holder
|
||||||
|
: &inst->nonsimple.values_and_holders[vpos]} {}
|
||||||
|
|
||||||
|
// Default constructor (used to signal a value-and-holder not found by get_value_and_holder())
|
||||||
|
value_and_holder() = default;
|
||||||
|
|
||||||
|
// Used for past-the-end iterator
|
||||||
|
explicit value_and_holder(size_t index) : index{index} {}
|
||||||
|
|
||||||
|
template <typename V = void>
|
||||||
|
V *&value_ptr() const {
|
||||||
|
return reinterpret_cast<V *&>(vh[0]);
|
||||||
|
}
|
||||||
|
// True if this `value_and_holder` has a non-null value pointer
|
||||||
|
explicit operator bool() const { return value_ptr() != nullptr; }
|
||||||
|
|
||||||
|
template <typename H>
|
||||||
|
H &holder() const {
|
||||||
|
return reinterpret_cast<H &>(vh[1]);
|
||||||
|
}
|
||||||
|
bool holder_constructed() const {
|
||||||
|
return inst->simple_layout
|
||||||
|
? inst->simple_holder_constructed
|
||||||
|
: (inst->nonsimple.status[index] & instance::status_holder_constructed) != 0u;
|
||||||
|
}
|
||||||
|
// NOLINTNEXTLINE(readability-make-member-function-const)
|
||||||
|
void set_holder_constructed(bool v = true) {
|
||||||
|
if (inst->simple_layout) {
|
||||||
|
inst->simple_holder_constructed = v;
|
||||||
|
} else if (v) {
|
||||||
|
inst->nonsimple.status[index] |= instance::status_holder_constructed;
|
||||||
|
} else {
|
||||||
|
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_holder_constructed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool instance_registered() const {
|
||||||
|
return inst->simple_layout
|
||||||
|
? inst->simple_instance_registered
|
||||||
|
: ((inst->nonsimple.status[index] & instance::status_instance_registered) != 0);
|
||||||
|
}
|
||||||
|
// NOLINTNEXTLINE(readability-make-member-function-const)
|
||||||
|
void set_instance_registered(bool v = true) {
|
||||||
|
if (inst->simple_layout) {
|
||||||
|
inst->simple_instance_registered = v;
|
||||||
|
} else if (v) {
|
||||||
|
inst->nonsimple.status[index] |= instance::status_instance_registered;
|
||||||
|
} else {
|
||||||
|
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_instance_registered;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
@ -469,9 +469,6 @@ struct type_caster<Eigen::TensorMap<Type, Options>,
|
|||||||
parent_object = reinterpret_borrow<object>(parent);
|
parent_object = reinterpret_borrow<object>(parent);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case return_value_policy::take_ownership:
|
|
||||||
delete src;
|
|
||||||
// fallthrough
|
|
||||||
default:
|
default:
|
||||||
// move, take_ownership don't make any sense for a ref/map:
|
// move, take_ownership don't make any sense for a ref/map:
|
||||||
pybind11_fail("Invalid return_value_policy for Eigen Map type, must be either "
|
pybind11_fail("Invalid return_value_policy for Eigen Map type, must be either "
|
||||||
|
@ -9,12 +9,55 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#define PYBIND11_HAS_TYPE_CASTER_STD_FUNCTION_SPECIALIZATIONS
|
||||||
|
|
||||||
#include "pybind11.h"
|
#include "pybind11.h"
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
PYBIND11_NAMESPACE_BEGIN(type_caster_std_function_specializations)
|
||||||
|
|
||||||
|
// ensure GIL is held during functor destruction
|
||||||
|
struct func_handle {
|
||||||
|
function f;
|
||||||
|
#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17))
|
||||||
|
// This triggers a syntax error under very special conditions (very weird indeed).
|
||||||
|
explicit
|
||||||
|
#endif
|
||||||
|
func_handle(function &&f_) noexcept
|
||||||
|
: f(std::move(f_)) {
|
||||||
|
}
|
||||||
|
func_handle(const func_handle &f_) { operator=(f_); }
|
||||||
|
func_handle &operator=(const func_handle &f_) {
|
||||||
|
gil_scoped_acquire acq;
|
||||||
|
f = f_.f;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
~func_handle() {
|
||||||
|
gil_scoped_acquire acq;
|
||||||
|
function kill_f(std::move(f));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// to emulate 'move initialization capture' in C++11
|
||||||
|
struct func_wrapper_base {
|
||||||
|
func_handle hfunc;
|
||||||
|
explicit func_wrapper_base(func_handle &&hf) noexcept : hfunc(hf) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Return, typename... Args>
|
||||||
|
struct func_wrapper : func_wrapper_base {
|
||||||
|
using func_wrapper_base::func_wrapper_base;
|
||||||
|
Return operator()(Args... args) const {
|
||||||
|
gil_scoped_acquire acq;
|
||||||
|
// casts the returned object as a rvalue to the return type
|
||||||
|
return hfunc.f(std::forward<Args>(args)...).template cast<Return>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_END(type_caster_std_function_specializations)
|
||||||
|
|
||||||
template <typename Return, typename... Args>
|
template <typename Return, typename... Args>
|
||||||
struct type_caster<std::function<Return(Args...)>> {
|
struct type_caster<std::function<Return(Args...)>> {
|
||||||
@ -77,40 +120,8 @@ public:
|
|||||||
// See PR #1413 for full details
|
// See PR #1413 for full details
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure GIL is held during functor destruction
|
value = type_caster_std_function_specializations::func_wrapper<Return, Args...>(
|
||||||
struct func_handle {
|
type_caster_std_function_specializations::func_handle(std::move(func)));
|
||||||
function f;
|
|
||||||
#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17))
|
|
||||||
// This triggers a syntax error under very special conditions (very weird indeed).
|
|
||||||
explicit
|
|
||||||
#endif
|
|
||||||
func_handle(function &&f_) noexcept
|
|
||||||
: f(std::move(f_)) {
|
|
||||||
}
|
|
||||||
func_handle(const func_handle &f_) { operator=(f_); }
|
|
||||||
func_handle &operator=(const func_handle &f_) {
|
|
||||||
gil_scoped_acquire acq;
|
|
||||||
f = f_.f;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
~func_handle() {
|
|
||||||
gil_scoped_acquire acq;
|
|
||||||
function kill_f(std::move(f));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// to emulate 'move initialization capture' in C++11
|
|
||||||
struct func_wrapper {
|
|
||||||
func_handle hfunc;
|
|
||||||
explicit func_wrapper(func_handle &&hf) noexcept : hfunc(std::move(hf)) {}
|
|
||||||
Return operator()(Args... args) const {
|
|
||||||
gil_scoped_acquire acq;
|
|
||||||
// casts the returned object as a rvalue to the return type
|
|
||||||
return hfunc.f(std::forward<Args>(args)...).template cast<Return>();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
value = func_wrapper(func_handle(std::move(func)));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,10 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
|
#ifdef Py_GIL_DISABLED
|
||||||
|
# include <atomic>
|
||||||
|
#endif
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
|
||||||
// Use the `gil_safe_call_once_and_store` class below instead of the naive
|
// Use the `gil_safe_call_once_and_store` class below instead of the naive
|
||||||
@ -82,7 +86,12 @@ public:
|
|||||||
private:
|
private:
|
||||||
alignas(T) char storage_[sizeof(T)] = {};
|
alignas(T) char storage_[sizeof(T)] = {};
|
||||||
std::once_flag once_flag_ = {};
|
std::once_flag once_flag_ = {};
|
||||||
bool is_initialized_ = false;
|
#ifdef Py_GIL_DISABLED
|
||||||
|
std::atomic_bool
|
||||||
|
#else
|
||||||
|
bool
|
||||||
|
#endif
|
||||||
|
is_initialized_{false};
|
||||||
// The `is_initialized_`-`storage_` pair is very similar to `std::optional`,
|
// The `is_initialized_`-`storage_` pair is very similar to `std::optional`,
|
||||||
// but the latter does not have the triviality properties of former,
|
// but the latter does not have the triviality properties of former,
|
||||||
// therefore `std::optional` is not a viable alternative here.
|
// therefore `std::optional` is not a viable alternative here.
|
||||||
|
@ -901,7 +901,11 @@ public:
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
array(ShapeContainer shape, StridesContainer strides, const T *ptr, handle base = handle())
|
array(ShapeContainer shape, StridesContainer strides, const T *ptr, handle base = handle())
|
||||||
: array(pybind11::dtype::of<T>(), std::move(shape), std::move(strides), ptr, base) {}
|
: array(pybind11::dtype::of<T>(),
|
||||||
|
std::move(shape),
|
||||||
|
std::move(strides),
|
||||||
|
reinterpret_cast<const void *>(ptr),
|
||||||
|
base) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
array(ShapeContainer shape, const T *ptr, handle base = handle())
|
array(ShapeContainer shape, const T *ptr, handle base = handle())
|
||||||
@ -1986,7 +1990,7 @@ private:
|
|||||||
// Pointers to values the function was called with; the vectorized ones set here will start
|
// Pointers to values the function was called with; the vectorized ones set here will start
|
||||||
// out as array_t<T> pointers, but they will be changed them to T pointers before we make
|
// out as array_t<T> pointers, but they will be changed them to T pointers before we make
|
||||||
// call the wrapped function. Non-vectorized pointers are left as-is.
|
// call the wrapped function. Non-vectorized pointers are left as-is.
|
||||||
std::array<void *, N> params{{&args...}};
|
std::array<void *, N> params{{reinterpret_cast<void *>(&args)...}};
|
||||||
|
|
||||||
// The array of `buffer_info`s of vectorized arguments:
|
// The array of `buffer_info`s of vectorized arguments:
|
||||||
std::array<buffer_info, NVectorized> buffers{
|
std::array<buffer_info, NVectorized> buffers{
|
||||||
|
@ -33,6 +33,13 @@
|
|||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
#ifdef PYPY_VERSION
|
||||||
|
# define PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(...) (__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
# define PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(...) \
|
||||||
|
(reinterpret_cast<void *>(__VA_ARGS__))
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(PYBIND11_HAS_FILESYSTEM) || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
|
#if defined(PYBIND11_HAS_FILESYSTEM) || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct path_caster {
|
struct path_caster {
|
||||||
@ -72,7 +79,8 @@ public:
|
|||||||
}
|
}
|
||||||
PyObject *native = nullptr;
|
PyObject *native = nullptr;
|
||||||
if constexpr (std::is_same_v<typename T::value_type, char>) {
|
if constexpr (std::is_same_v<typename T::value_type, char>) {
|
||||||
if (PyUnicode_FSConverter(buf, &native) != 0) {
|
if (PyUnicode_FSConverter(buf, PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(&native))
|
||||||
|
!= 0) {
|
||||||
if (auto *c_str = PyBytes_AsString(native)) {
|
if (auto *c_str = PyBytes_AsString(native)) {
|
||||||
// AsString returns a pointer to the internal buffer, which
|
// AsString returns a pointer to the internal buffer, which
|
||||||
// must not be free'd.
|
// must not be free'd.
|
||||||
@ -80,7 +88,8 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) {
|
} else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) {
|
||||||
if (PyUnicode_FSDecoder(buf, &native) != 0) {
|
if (PyUnicode_FSDecoder(buf, PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(&native))
|
||||||
|
!= 0) {
|
||||||
if (auto *c_str = PyUnicode_AsWideCharString(native, nullptr)) {
|
if (auto *c_str = PyUnicode_AsWideCharString(native, nullptr)) {
|
||||||
// AsWideCharString returns a new string that must be free'd.
|
// AsWideCharString returns a new string that must be free'd.
|
||||||
value = c_str; // Copies the string.
|
value = c_str; // Copies the string.
|
||||||
|
@ -180,7 +180,7 @@ void vector_modifiers(
|
|||||||
v.end());
|
v.end());
|
||||||
try {
|
try {
|
||||||
v.shrink_to_fit();
|
v.shrink_to_fit();
|
||||||
} catch (const std::exception &) {
|
} catch (const std::exception &) { // NOLINT(bugprone-empty-catch)
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
throw;
|
throw;
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
#include "cast.h"
|
#include "cast.h"
|
||||||
#include "pytypes.h"
|
#include "pytypes.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
PYBIND11_NAMESPACE_BEGIN(typing)
|
PYBIND11_NAMESPACE_BEGIN(typing)
|
||||||
|
|
||||||
@ -98,7 +100,10 @@ class Never : public none {
|
|||||||
using none::none;
|
using none::none;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(__cpp_nontype_template_parameter_class)
|
#if defined(__cpp_nontype_template_parameter_class) \
|
||||||
|
&& (/* See #5201 */ !defined(__GNUC__) \
|
||||||
|
|| (__GNUC__ > 10 || (__GNUC__ == 10 && __GNUC_MINOR__ >= 3)))
|
||||||
|
# define PYBIND11_TYPING_H_HAS_STRING_LITERAL
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
struct StringLiteral {
|
struct StringLiteral {
|
||||||
constexpr StringLiteral(const char (&str)[N]) { std::copy_n(str, N, name); }
|
constexpr StringLiteral(const char (&str)[N]) { std::copy_n(str, N, name); }
|
||||||
@ -222,7 +227,7 @@ struct handle_type_name<typing::Never> {
|
|||||||
static constexpr auto name = const_name("Never");
|
static constexpr auto name = const_name("Never");
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(__cpp_nontype_template_parameter_class)
|
#if defined(PYBIND11_TYPING_H_HAS_STRING_LITERAL)
|
||||||
template <typing::StringLiteral... Literals>
|
template <typing::StringLiteral... Literals>
|
||||||
struct handle_type_name<typing::Literal<Literals...>> {
|
struct handle_type_name<typing::Literal<Literals...>> {
|
||||||
static constexpr auto name = const_name("Literal[")
|
static constexpr auto name = const_name("Literal[")
|
||||||
|
@ -2,12 +2,35 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
import sysconfig
|
import sysconfig
|
||||||
|
|
||||||
from ._version import __version__
|
from ._version import __version__
|
||||||
from .commands import get_cmake_dir, get_include, get_pkgconfig_dir
|
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:
|
def print_includes() -> None:
|
||||||
dirs = [
|
dirs = [
|
||||||
@ -22,7 +45,7 @@ def print_includes() -> None:
|
|||||||
if d and d not in unique_dirs:
|
if d and d not in unique_dirs:
|
||||||
unique_dirs.append(d)
|
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:
|
def main() -> None:
|
||||||
@ -54,9 +77,9 @@ def main() -> None:
|
|||||||
if args.includes:
|
if args.includes:
|
||||||
print_includes()
|
print_includes()
|
||||||
if args.cmakedir:
|
if args.cmakedir:
|
||||||
print(get_cmake_dir())
|
print(quote(get_cmake_dir()))
|
||||||
if args.pkgconfigdir:
|
if args.pkgconfigdir:
|
||||||
print(get_pkgconfig_dir())
|
print(quote(get_pkgconfig_dir()))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -8,5 +8,5 @@ def _to_int(s: str) -> int | str:
|
|||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
__version__ = "2.13.1"
|
__version__ = "2.13.4"
|
||||||
version_info = tuple(_to_int(s) for s in __version__.split("."))
|
version_info = tuple(_to_int(s) for s in __version__.split("."))
|
||||||
|
@ -88,7 +88,12 @@ set(PYBIND11_TEST_FILTER
|
|||||||
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||||
# We're being loaded directly, i.e. not via add_subdirectory, so make this
|
# We're being loaded directly, i.e. not via add_subdirectory, so make this
|
||||||
# work as its own project and load the pybind11Config to get the tools we need
|
# work as its own project and load the pybind11Config to get the tools we need
|
||||||
find_package(pybind11 REQUIRED CONFIG)
|
|
||||||
|
if(SKBUILD)
|
||||||
|
add_subdirectory(.. pybind11_src)
|
||||||
|
else()
|
||||||
|
find_package(pybind11 REQUIRED CONFIG)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES)
|
if(NOT CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES)
|
||||||
@ -153,6 +158,7 @@ set(PYBIND11_TEST_FILES
|
|||||||
test_tagbased_polymorphic
|
test_tagbased_polymorphic
|
||||||
test_thread
|
test_thread
|
||||||
test_type_caster_pyobject_ptr
|
test_type_caster_pyobject_ptr
|
||||||
|
test_type_caster_std_function_specializations
|
||||||
test_union
|
test_union
|
||||||
test_unnamed_namespace_a
|
test_unnamed_namespace_a
|
||||||
test_unnamed_namespace_b
|
test_unnamed_namespace_b
|
||||||
@ -489,6 +495,9 @@ foreach(target ${test_targets})
|
|||||||
endforeach()
|
endforeach()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
if(SKBUILD)
|
||||||
|
install(TARGETS ${target} LIBRARY DESTINATION .)
|
||||||
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
# Provide nice organisation in IDEs
|
# Provide nice organisation in IDEs
|
||||||
|
@ -190,7 +190,7 @@ public:
|
|||||||
t1 = &p.first;
|
t1 = &p.first;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (const std::out_of_range &) {
|
} catch (const std::out_of_range &) { // NOLINT(bugprone-empty-catch)
|
||||||
}
|
}
|
||||||
if (!t1) {
|
if (!t1) {
|
||||||
throw std::runtime_error("Unknown class passed to ConstructorStats::get()");
|
throw std::runtime_error("Unknown class passed to ConstructorStats::get()");
|
||||||
|
@ -58,6 +58,7 @@ detail_headers = {
|
|||||||
"include/pybind11/detail/internals.h",
|
"include/pybind11/detail/internals.h",
|
||||||
"include/pybind11/detail/type_caster_base.h",
|
"include/pybind11/detail/type_caster_base.h",
|
||||||
"include/pybind11/detail/typeid.h",
|
"include/pybind11/detail/typeid.h",
|
||||||
|
"include/pybind11/detail/value_and_holder.h",
|
||||||
}
|
}
|
||||||
|
|
||||||
eigen_headers = {
|
eigen_headers = {
|
||||||
|
21
tests/pyproject.toml
Normal file
21
tests/pyproject.toml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Warning: this is currently used for pyodide, and is not a general out-of-tree
|
||||||
|
# builder for the tests (yet). Specifically, wheels can't be built from SDists.
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["scikit-build-core"]
|
||||||
|
build-backend = "scikit_build_core.build"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
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
|
||||||
|
|
||||||
|
[tool.cibuildwheel]
|
||||||
|
test-command = "pytest -o timeout=0 -p no:cacheprovider {project}/tests/test_*.py"
|
@ -1,10 +1,15 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
asyncio = pytest.importorskip("asyncio")
|
asyncio = pytest.importorskip("asyncio")
|
||||||
m = pytest.importorskip("pybind11_tests.async_module")
|
m = pytest.importorskip("pybind11_tests.async_module")
|
||||||
|
|
||||||
|
if sys.platform.startswith("emscripten"):
|
||||||
|
pytest.skip("Can't run a new event_loop in pyodide", allow_module_level=True)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def event_loop():
|
def event_loop():
|
||||||
|
@ -368,6 +368,8 @@ def test_tuple(doc):
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
assert doc(m.empty_tuple) == """empty_tuple() -> tuple[()]"""
|
||||||
|
|
||||||
assert m.rvalue_pair() == ("rvalue", "rvalue")
|
assert m.rvalue_pair() == ("rvalue", "rvalue")
|
||||||
assert m.lvalue_pair() == ("lvalue", "lvalue")
|
assert m.lvalue_pair() == ("lvalue", "lvalue")
|
||||||
assert m.rvalue_tuple() == ("rvalue", "rvalue", "rvalue")
|
assert m.rvalue_tuple() == ("rvalue", "rvalue", "rvalue")
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import sys
|
||||||
import time
|
import time
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
@ -153,6 +154,7 @@ def test_python_builtins():
|
|||||||
assert m.test_sum_builtin(sum, []) == 0
|
assert m.test_sum_builtin(sum, []) == 0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||||
def test_async_callbacks():
|
def test_async_callbacks():
|
||||||
# serves as state for async callback
|
# serves as state for async callback
|
||||||
class Item:
|
class Item:
|
||||||
@ -176,6 +178,7 @@ def test_async_callbacks():
|
|||||||
assert sum(res) == sum(x + 3 for x in work)
|
assert sum(res) == sum(x + 3 for x in work)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||||
def test_async_async_callbacks():
|
def test_async_async_callbacks():
|
||||||
t = Thread(target=test_async_callbacks)
|
t = Thread(target=test_async_callbacks)
|
||||||
t.start()
|
t.start()
|
||||||
|
@ -147,33 +147,39 @@ void init_tensor_module(pybind11::module &m) {
|
|||||||
|
|
||||||
m.def(
|
m.def(
|
||||||
"take_fixed_tensor",
|
"take_fixed_tensor",
|
||||||
|
|
||||||
[]() {
|
[]() {
|
||||||
Eigen::aligned_allocator<
|
Eigen::aligned_allocator<
|
||||||
Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options>>
|
Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options>>
|
||||||
allocator;
|
allocator;
|
||||||
return new (allocator.allocate(1))
|
static auto *obj = new (allocator.allocate(1))
|
||||||
Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options>(
|
Eigen::TensorFixedSize<double, Eigen::Sizes<3, 5, 2>, Options>(
|
||||||
get_fixed_tensor<Options>());
|
get_fixed_tensor<Options>());
|
||||||
|
return obj; // take_ownership will fail.
|
||||||
},
|
},
|
||||||
py::return_value_policy::take_ownership);
|
py::return_value_policy::take_ownership);
|
||||||
|
|
||||||
m.def(
|
m.def(
|
||||||
"take_tensor",
|
"take_tensor",
|
||||||
[]() { return new Eigen::Tensor<double, 3, Options>(get_tensor<Options>()); },
|
[]() {
|
||||||
|
static auto *obj = new Eigen::Tensor<double, 3, Options>(get_tensor<Options>());
|
||||||
|
return obj; // take_ownership will fail.
|
||||||
|
},
|
||||||
py::return_value_policy::take_ownership);
|
py::return_value_policy::take_ownership);
|
||||||
|
|
||||||
m.def(
|
m.def(
|
||||||
"take_const_tensor",
|
"take_const_tensor",
|
||||||
[]() -> const Eigen::Tensor<double, 3, Options> * {
|
[]() -> const Eigen::Tensor<double, 3, Options> * {
|
||||||
return new Eigen::Tensor<double, 3, Options>(get_tensor<Options>());
|
static auto *obj = new Eigen::Tensor<double, 3, Options>(get_tensor<Options>());
|
||||||
|
return obj; // take_ownership will fail.
|
||||||
},
|
},
|
||||||
py::return_value_policy::take_ownership);
|
py::return_value_policy::take_ownership);
|
||||||
|
|
||||||
m.def(
|
m.def(
|
||||||
"take_view_tensor",
|
"take_view_tensor",
|
||||||
[]() -> const Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> * {
|
[]() -> const Eigen::TensorMap<Eigen::Tensor<double, 3, Options>> * {
|
||||||
return new Eigen::TensorMap<Eigen::Tensor<double, 3, Options>>(get_tensor<Options>());
|
static auto *obj
|
||||||
|
= new Eigen::TensorMap<Eigen::Tensor<double, 3, Options>>(get_tensor<Options>());
|
||||||
|
return obj; // take_ownership will fail.
|
||||||
},
|
},
|
||||||
py::return_value_policy::take_ownership);
|
py::return_value_policy::take_ownership);
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ def test_cross_module_exceptions(msg):
|
|||||||
|
|
||||||
# TODO: FIXME
|
# TODO: FIXME
|
||||||
@pytest.mark.xfail(
|
@pytest.mark.xfail(
|
||||||
"env.MACOS and (env.PYPY or pybind11_tests.compiler_info.startswith('Homebrew Clang'))",
|
"env.MACOS and (env.PYPY or pybind11_tests.compiler_info.startswith('Homebrew Clang')) or sys.platform.startswith('emscripten')",
|
||||||
raises=RuntimeError,
|
raises=RuntimeError,
|
||||||
reason="See Issue #2847, PR #2999, PR #4324",
|
reason="See Issue #2847, PR #2999, PR #4324",
|
||||||
)
|
)
|
||||||
|
@ -71,24 +71,28 @@ def test_cross_module_gil_inner_pybind11_acquired():
|
|||||||
m.test_cross_module_gil_inner_pybind11_acquired()
|
m.test_cross_module_gil_inner_pybind11_acquired()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||||
def test_cross_module_gil_nested_custom_released():
|
def test_cross_module_gil_nested_custom_released():
|
||||||
"""Makes sure that the GIL can be nested acquired/released by another module
|
"""Makes sure that the GIL can be nested acquired/released by another module
|
||||||
from a GIL-released state using custom locking logic."""
|
from a GIL-released state using custom locking logic."""
|
||||||
m.test_cross_module_gil_nested_custom_released()
|
m.test_cross_module_gil_nested_custom_released()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||||
def test_cross_module_gil_nested_custom_acquired():
|
def test_cross_module_gil_nested_custom_acquired():
|
||||||
"""Makes sure that the GIL can be nested acquired/acquired by another module
|
"""Makes sure that the GIL can be nested acquired/acquired by another module
|
||||||
from a GIL-acquired state using custom locking logic."""
|
from a GIL-acquired state using custom locking logic."""
|
||||||
m.test_cross_module_gil_nested_custom_acquired()
|
m.test_cross_module_gil_nested_custom_acquired()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||||
def test_cross_module_gil_nested_pybind11_released():
|
def test_cross_module_gil_nested_pybind11_released():
|
||||||
"""Makes sure that the GIL can be nested acquired/released by another module
|
"""Makes sure that the GIL can be nested acquired/released by another module
|
||||||
from a GIL-released state using pybind11 locking logic."""
|
from a GIL-released state using pybind11 locking logic."""
|
||||||
m.test_cross_module_gil_nested_pybind11_released()
|
m.test_cross_module_gil_nested_pybind11_released()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||||
def test_cross_module_gil_nested_pybind11_acquired():
|
def test_cross_module_gil_nested_pybind11_acquired():
|
||||||
"""Makes sure that the GIL can be nested acquired/acquired by another module
|
"""Makes sure that the GIL can be nested acquired/acquired by another module
|
||||||
from a GIL-acquired state using pybind11 locking logic."""
|
from a GIL-acquired state using pybind11 locking logic."""
|
||||||
@ -103,6 +107,7 @@ def test_nested_acquire():
|
|||||||
assert m.test_nested_acquire(0xAB) == "171"
|
assert m.test_nested_acquire(0xAB) == "171"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||||
def test_multi_acquire_release_cross_module():
|
def test_multi_acquire_release_cross_module():
|
||||||
for bits in range(16 * 8):
|
for bits in range(16 * 8):
|
||||||
internals_ids = m.test_multi_acquire_release_cross_module(bits)
|
internals_ids = m.test_multi_acquire_release_cross_module(bits)
|
||||||
@ -204,7 +209,7 @@ def _run_in_threads(test_fn, num_threads, parallel):
|
|||||||
thread.join()
|
thread.join()
|
||||||
|
|
||||||
|
|
||||||
# TODO: FIXME, sometimes returns -11 (segfault) instead of 0 on macOS Python 3.9
|
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||||
@pytest.mark.parametrize("test_fn", ALL_BASIC_TESTS_PLUS_INTENTIONAL_DEADLOCK)
|
@pytest.mark.parametrize("test_fn", ALL_BASIC_TESTS_PLUS_INTENTIONAL_DEADLOCK)
|
||||||
def test_run_in_process_one_thread(test_fn):
|
def test_run_in_process_one_thread(test_fn):
|
||||||
"""Makes sure there is no GIL deadlock when running in a thread.
|
"""Makes sure there is no GIL deadlock when running in a thread.
|
||||||
@ -214,7 +219,7 @@ def test_run_in_process_one_thread(test_fn):
|
|||||||
assert _run_in_process(_run_in_threads, test_fn, num_threads=1, parallel=False) == 0
|
assert _run_in_process(_run_in_threads, test_fn, num_threads=1, parallel=False) == 0
|
||||||
|
|
||||||
|
|
||||||
# TODO: FIXME on macOS Python 3.9
|
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||||
@pytest.mark.parametrize("test_fn", ALL_BASIC_TESTS_PLUS_INTENTIONAL_DEADLOCK)
|
@pytest.mark.parametrize("test_fn", ALL_BASIC_TESTS_PLUS_INTENTIONAL_DEADLOCK)
|
||||||
def test_run_in_process_multiple_threads_parallel(test_fn):
|
def test_run_in_process_multiple_threads_parallel(test_fn):
|
||||||
"""Makes sure there is no GIL deadlock when running in a thread multiple times in parallel.
|
"""Makes sure there is no GIL deadlock when running in a thread multiple times in parallel.
|
||||||
@ -224,7 +229,7 @@ def test_run_in_process_multiple_threads_parallel(test_fn):
|
|||||||
assert _run_in_process(_run_in_threads, test_fn, num_threads=8, parallel=True) == 0
|
assert _run_in_process(_run_in_threads, test_fn, num_threads=8, parallel=True) == 0
|
||||||
|
|
||||||
|
|
||||||
# TODO: FIXME on macOS Python 3.9
|
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||||
@pytest.mark.parametrize("test_fn", ALL_BASIC_TESTS_PLUS_INTENTIONAL_DEADLOCK)
|
@pytest.mark.parametrize("test_fn", ALL_BASIC_TESTS_PLUS_INTENTIONAL_DEADLOCK)
|
||||||
def test_run_in_process_multiple_threads_sequential(test_fn):
|
def test_run_in_process_multiple_threads_sequential(test_fn):
|
||||||
"""Makes sure there is no GIL deadlock when running in a thread multiple times sequentially.
|
"""Makes sure there is no GIL deadlock when running in a thread multiple times sequentially.
|
||||||
@ -234,7 +239,7 @@ def test_run_in_process_multiple_threads_sequential(test_fn):
|
|||||||
assert _run_in_process(_run_in_threads, test_fn, num_threads=8, parallel=False) == 0
|
assert _run_in_process(_run_in_threads, test_fn, num_threads=8, parallel=False) == 0
|
||||||
|
|
||||||
|
|
||||||
# TODO: FIXME on macOS Python 3.9
|
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||||
@pytest.mark.parametrize("test_fn", ALL_BASIC_TESTS_PLUS_INTENTIONAL_DEADLOCK)
|
@pytest.mark.parametrize("test_fn", ALL_BASIC_TESTS_PLUS_INTENTIONAL_DEADLOCK)
|
||||||
def test_run_in_process_direct(test_fn):
|
def test_run_in_process_direct(test_fn):
|
||||||
"""Makes sure there is no GIL deadlock when using processes.
|
"""Makes sure there is no GIL deadlock when using processes.
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import sys
|
||||||
from contextlib import redirect_stderr, redirect_stdout
|
from contextlib import redirect_stderr, redirect_stdout
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
from pybind11_tests import iostream as m
|
from pybind11_tests import iostream as m
|
||||||
|
|
||||||
|
|
||||||
@ -270,6 +273,7 @@ def test_redirect_both(capfd):
|
|||||||
assert stream2.getvalue() == msg2
|
assert stream2.getvalue() == msg2
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||||
def test_threading():
|
def test_threading():
|
||||||
with m.ostream_redirect(stdout=True, stderr=False):
|
with m.ostream_redirect(stdout=True, stderr=False):
|
||||||
# start some threads
|
# start some threads
|
||||||
|
@ -90,32 +90,32 @@ TEST_SUBMODULE(modules, m) {
|
|||||||
try {
|
try {
|
||||||
py::class_<Dupe1>(dm, "Dupe1");
|
py::class_<Dupe1>(dm, "Dupe1");
|
||||||
failures.append("Dupe1 class");
|
failures.append("Dupe1 class");
|
||||||
} catch (std::runtime_error &) {
|
} catch (std::runtime_error &) { // NOLINT(bugprone-empty-catch)
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
dm.def("Dupe1", []() { return Dupe1(); });
|
dm.def("Dupe1", []() { return Dupe1(); });
|
||||||
failures.append("Dupe1 function");
|
failures.append("Dupe1 function");
|
||||||
} catch (std::runtime_error &) {
|
} catch (std::runtime_error &) { // NOLINT(bugprone-empty-catch)
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
py::class_<Dupe3>(dm, "dupe1_factory");
|
py::class_<Dupe3>(dm, "dupe1_factory");
|
||||||
failures.append("dupe1_factory");
|
failures.append("dupe1_factory");
|
||||||
} catch (std::runtime_error &) {
|
} catch (std::runtime_error &) { // NOLINT(bugprone-empty-catch)
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
py::exception<Dupe3>(dm, "Dupe2");
|
py::exception<Dupe3>(dm, "Dupe2");
|
||||||
failures.append("Dupe2");
|
failures.append("Dupe2");
|
||||||
} catch (std::runtime_error &) {
|
} catch (std::runtime_error &) { // NOLINT(bugprone-empty-catch)
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
dm.def("DupeException", []() { return 30; });
|
dm.def("DupeException", []() { return 30; });
|
||||||
failures.append("DupeException1");
|
failures.append("DupeException1");
|
||||||
} catch (std::runtime_error &) {
|
} catch (std::runtime_error &) { // NOLINT(bugprone-empty-catch)
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
py::class_<DupeException>(dm, "DupeException");
|
py::class_<DupeException>(dm, "DupeException");
|
||||||
failures.append("DupeException2");
|
failures.append("DupeException2");
|
||||||
} catch (std::runtime_error &) {
|
} catch (std::runtime_error &) { // NOLINT(bugprone-empty-catch)
|
||||||
}
|
}
|
||||||
|
|
||||||
return failures;
|
return failures;
|
||||||
|
@ -266,6 +266,8 @@ py::array_t<int32_t, 0> test_array_ctors(int i) {
|
|||||||
return fill(arr_t(buf_ndim1_null));
|
return fill(arr_t(buf_ndim1_null));
|
||||||
case 44:
|
case 44:
|
||||||
return fill(py::array(buf_ndim1_null));
|
return fill(py::array(buf_ndim1_null));
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return arr_t();
|
return arr_t();
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ TEST_SUBMODULE(opaque_types, m) {
|
|||||||
|
|
||||||
m.def("return_unique_ptr", []() -> std::unique_ptr<StringList> {
|
m.def("return_unique_ptr", []() -> std::unique_ptr<StringList> {
|
||||||
auto *result = new StringList();
|
auto *result = new StringList();
|
||||||
result->push_back("some value");
|
result->emplace_back("some value");
|
||||||
return std::unique_ptr<StringList>(result);
|
return std::unique_ptr<StringList>(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ void m_defs(py::module_ &m) {
|
|||||||
|
|
||||||
} // namespace handle_from_move_only_type_with_operator_PyObject
|
} // namespace handle_from_move_only_type_with_operator_PyObject
|
||||||
|
|
||||||
#if defined(__cpp_nontype_template_parameter_class)
|
#if defined(PYBIND11_TYPING_H_HAS_STRING_LITERAL)
|
||||||
namespace literals {
|
namespace literals {
|
||||||
enum Color { RED = 0, BLUE = 1 };
|
enum Color { RED = 0, BLUE = 1 };
|
||||||
|
|
||||||
@ -905,7 +905,7 @@ TEST_SUBMODULE(pytypes, m) {
|
|||||||
m.def("annotate_optional_to_object",
|
m.def("annotate_optional_to_object",
|
||||||
[](py::typing::Optional<int> &o) -> py::object { return o; });
|
[](py::typing::Optional<int> &o) -> py::object { return o; });
|
||||||
|
|
||||||
#if defined(__cpp_nontype_template_parameter_class)
|
#if defined(PYBIND11_TYPING_H_HAS_STRING_LITERAL)
|
||||||
py::enum_<literals::Color>(m, "Color")
|
py::enum_<literals::Color>(m, "Color")
|
||||||
.value("RED", literals::Color::RED)
|
.value("RED", literals::Color::RED)
|
||||||
.value("BLUE", literals::Color::BLUE);
|
.value("BLUE", literals::Color::BLUE);
|
||||||
@ -919,8 +919,8 @@ TEST_SUBMODULE(pytypes, m) {
|
|||||||
m.def("annotate_listT_to_T",
|
m.def("annotate_listT_to_T",
|
||||||
[](const py::typing::List<typevar::TypeVarT> &l) -> typevar::TypeVarT { return l[0]; });
|
[](const py::typing::List<typevar::TypeVarT> &l) -> typevar::TypeVarT { return l[0]; });
|
||||||
m.def("annotate_object_to_T", [](const py::object &o) -> typevar::TypeVarT { return o; });
|
m.def("annotate_object_to_T", [](const py::object &o) -> typevar::TypeVarT { return o; });
|
||||||
m.attr("if_defined__cpp_nontype_template_parameter_class") = true;
|
m.attr("defined_PYBIND11_TYPING_H_HAS_STRING_LITERAL") = true;
|
||||||
#else
|
#else
|
||||||
m.attr("if_defined__cpp_nontype_template_parameter_class") = false;
|
m.attr("defined_PYBIND11_TYPING_H_HAS_STRING_LITERAL") = false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -1025,7 +1025,7 @@ def test_optional_object_annotations(doc):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
@pytest.mark.skipif(
|
||||||
not m.if_defined__cpp_nontype_template_parameter_class,
|
not m.defined_PYBIND11_TYPING_H_HAS_STRING_LITERAL,
|
||||||
reason="C++20 feature not available.",
|
reason="C++20 feature not available.",
|
||||||
)
|
)
|
||||||
def test_literal(doc):
|
def test_literal(doc):
|
||||||
@ -1036,7 +1036,7 @@ def test_literal(doc):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
@pytest.mark.skipif(
|
||||||
not m.if_defined__cpp_nontype_template_parameter_class,
|
not m.defined_PYBIND11_TYPING_H_HAS_STRING_LITERAL,
|
||||||
reason="C++20 feature not available.",
|
reason="C++20 feature not available.",
|
||||||
)
|
)
|
||||||
def test_typevar(doc):
|
def test_typevar(doc):
|
||||||
|
@ -74,6 +74,7 @@ std::vector<std::unique_ptr<Animal>> create_zoo() {
|
|||||||
// simulate some new type of Dog that the Python bindings
|
// simulate some new type of Dog that the Python bindings
|
||||||
// haven't been updated for; it should still be considered
|
// haven't been updated for; it should still be considered
|
||||||
// a Dog, not just an Animal.
|
// a Dog, not just an Animal.
|
||||||
|
// NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
|
||||||
ret.emplace_back(new Dog("Ginger", Dog::Kind(150)));
|
ret.emplace_back(new Dog("Ginger", Dog::Kind(150)));
|
||||||
|
|
||||||
ret.emplace_back(new Chihuahua("Hertzl"));
|
ret.emplace_back(new Chihuahua("Hertzl"));
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import sys
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
from pybind11_tests import thread as m
|
from pybind11_tests import thread as m
|
||||||
|
|
||||||
|
|
||||||
@ -24,6 +27,7 @@ class Thread(threading.Thread):
|
|||||||
raise self.e
|
raise self.e
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||||
def test_implicit_conversion():
|
def test_implicit_conversion():
|
||||||
a = Thread(m.test)
|
a = Thread(m.test)
|
||||||
b = Thread(m.test)
|
b = Thread(m.test)
|
||||||
@ -34,6 +38,7 @@ def test_implicit_conversion():
|
|||||||
x.join()
|
x.join()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||||
def test_implicit_conversion_no_gil():
|
def test_implicit_conversion_no_gil():
|
||||||
a = Thread(m.test_no_gil)
|
a = Thread(m.test_no_gil)
|
||||||
b = Thread(m.test_no_gil)
|
b = Thread(m.test_no_gil)
|
||||||
|
46
tests/test_type_caster_std_function_specializations.cpp
Normal file
46
tests/test_type_caster_std_function_specializations.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#include <pybind11/functional.h>
|
||||||
|
#include <pybind11/pybind11.h>
|
||||||
|
|
||||||
|
#include "pybind11_tests.h"
|
||||||
|
|
||||||
|
namespace py = pybind11;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct SpecialReturn {
|
||||||
|
int value = 99;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace pybind11 {
|
||||||
|
namespace detail {
|
||||||
|
namespace type_caster_std_function_specializations {
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
struct func_wrapper<SpecialReturn, Args...> : func_wrapper_base {
|
||||||
|
using func_wrapper_base::func_wrapper_base;
|
||||||
|
SpecialReturn operator()(Args... args) const {
|
||||||
|
gil_scoped_acquire acq;
|
||||||
|
SpecialReturn result;
|
||||||
|
try {
|
||||||
|
result = hfunc.f(std::forward<Args>(args)...).template cast<SpecialReturn>();
|
||||||
|
} catch (error_already_set &) {
|
||||||
|
result.value += 1;
|
||||||
|
}
|
||||||
|
result.value += 100;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace type_caster_std_function_specializations
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace pybind11
|
||||||
|
|
||||||
|
TEST_SUBMODULE(type_caster_std_function_specializations, m) {
|
||||||
|
py::class_<SpecialReturn>(m, "SpecialReturn")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def_readwrite("value", &SpecialReturn::value);
|
||||||
|
m.def("call_callback_with_special_return",
|
||||||
|
[](const std::function<SpecialReturn()> &func) { return func(); });
|
||||||
|
}
|
15
tests/test_type_caster_std_function_specializations.py
Normal file
15
tests/test_type_caster_std_function_specializations.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pybind11_tests import type_caster_std_function_specializations as m
|
||||||
|
|
||||||
|
|
||||||
|
def test_callback_with_special_return():
|
||||||
|
def return_special():
|
||||||
|
return m.SpecialReturn()
|
||||||
|
|
||||||
|
def raise_exception():
|
||||||
|
raise ValueError("called raise_exception.")
|
||||||
|
|
||||||
|
assert return_special().value == 99
|
||||||
|
assert m.call_callback_with_special_return(return_special).value == 199
|
||||||
|
assert m.call_callback_with_special_return(raise_exception).value == 200
|
@ -1,5 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import env # noqa: F401
|
import env # noqa: F401
|
||||||
@ -435,6 +437,7 @@ def test_inherited_virtuals():
|
|||||||
assert obj.say_everything() == "BT -7"
|
assert obj.say_everything() == "BT -7"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||||
def test_issue_1454():
|
def test_issue_1454():
|
||||||
# Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7)
|
# Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7)
|
||||||
m.test_gil()
|
m.test_gil()
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Adds the following targets::
|
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::module - Adds module links
|
||||||
pybind11::embed - Adds embed links
|
pybind11::embed - Adds embed links
|
||||||
pybind11::lto - Link time optimizations (only if CMAKE_INTERPROCEDURAL_OPTIMIZATION is not set)
|
pybind11::lto - Link time optimizations (only if CMAKE_INTERPROCEDURAL_OPTIMIZATION is not set)
|
||||||
@ -75,6 +75,32 @@ set_property(
|
|||||||
APPEND
|
APPEND
|
||||||
PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11)
|
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 ---------------------------
|
# --------------------------- link helper ---------------------------
|
||||||
|
|
||||||
add_library(pybind11::python_link_helper IMPORTED INTERFACE ${optional_global})
|
add_library(pybind11::python_link_helper IMPORTED INTERFACE ${optional_global})
|
||||||
@ -329,13 +355,13 @@ function(_pybind11_generate_lto target prefer_thin_lto)
|
|||||||
|
|
||||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64le" OR CMAKE_SYSTEM_PROCESSOR MATCHES "mips64")
|
if(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64le" OR CMAKE_SYSTEM_PROCESSOR MATCHES "mips64")
|
||||||
# Do nothing
|
# 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
|
# 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_CXX_FLAGS "-flto${thin}${cxx_append}")
|
||||||
set(PYBIND11_LTO_LINKER_FLAGS "-flto${thin}${linker_append}")
|
set(PYBIND11_LTO_LINKER_FLAGS "-flto${thin}${linker_append}")
|
||||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
_pybind11_return_if_cxx_and_linker_flags_work(
|
_pybind11_return_if_cxx_and_linker_flags_work(
|
||||||
HAS_FLTO_THIN "-flto${thin}${cxx_append}" "-flto=${thin}${linker_append}"
|
HAS_FLTO_THIN "-flto${thin}${cxx_append}" "-flto${thin}${linker_append}"
|
||||||
PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS)
|
PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS)
|
||||||
endif()
|
endif()
|
||||||
if(NOT HAS_FLTO_THIN)
|
if(NOT HAS_FLTO_THIN)
|
||||||
|
@ -84,7 +84,7 @@ you can either use the basic targets, or use the FindPython tools:
|
|||||||
|
|
||||||
# Python method:
|
# Python method:
|
||||||
Python_add_library(MyModule2 src2.cpp)
|
Python_add_library(MyModule2 src2.cpp)
|
||||||
target_link_libraries(MyModule2 pybind11::headers)
|
target_link_libraries(MyModule2 PUBLIC pybind11::headers)
|
||||||
set_target_properties(MyModule2 PROPERTIES
|
set_target_properties(MyModule2 PROPERTIES
|
||||||
INTERPROCEDURAL_OPTIMIZATION ON
|
INTERPROCEDURAL_OPTIMIZATION ON
|
||||||
CXX_VISIBILITY_PRESET ON
|
CXX_VISIBILITY_PRESET ON
|
||||||
|
Loading…
Reference in New Issue
Block a user