From c348b6a4e37f7be9aa59224e14112106050795bc Mon Sep 17 00:00:00 2001 From: b-pass Date: Sun, 18 May 2025 20:23:24 -0400 Subject: [PATCH 1/4] Move common code from PYBIND11_MODULE and PYBIND11_EMBEDDED_MODULE into one macro The difference between the two is really small, almost all of the code was the same. --- include/pybind11/detail/common.h | 86 ++++++++++++++++++-------------- include/pybind11/embed.h | 51 +++++++------------ 2 files changed, 67 insertions(+), 70 deletions(-) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index e3df32df3e..b7d216baba 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -361,11 +361,50 @@ } \ PyObject *pybind11_init() +PYBIND11_WARNING_PUSH +PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments") +#define PYBIND11_MODULE_BASE(name, variable, pre_init, ...) \ + static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name); \ + static ::pybind11::module_::slots_array PYBIND11_CONCAT(pybind11_module_slots_, name); \ + static int PYBIND11_CONCAT(pybind11_exec_, name)(PyObject *); \ + static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &); \ + PYBIND11_PLUGIN_IMPL(name) { \ + PYBIND11_CHECK_PYTHON_VERSION \ + pre_init; \ + PYBIND11_ENSURE_INTERNALS_READY \ + static auto result = []() { \ + auto &slots = PYBIND11_CONCAT(pybind11_module_slots_, name); \ + slots[0] = {Py_mod_exec, \ + reinterpret_cast(&PYBIND11_CONCAT(pybind11_exec_, name))}; \ + slots[1] = {0, nullptr}; \ + return ::pybind11::module_::initialize_multiphase_module_def( \ + PYBIND11_TOSTRING(name), \ + nullptr, \ + &PYBIND11_CONCAT(pybind11_module_def_, name), \ + slots, \ + ##__VA_ARGS__); \ + }(); \ + return result.ptr(); \ + } \ + int PYBIND11_CONCAT(pybind11_exec_, name)(PyObject * pm) { \ + try { \ + auto m = pybind11::reinterpret_borrow<::pybind11::module_>(pm); \ + PYBIND11_CONCAT(pybind11_init_, name)(m); \ + return 0; \ + } \ + PYBIND11_CATCH_INIT_EXCEPTIONS \ + return -1; \ + } \ + void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ \ + & variable) // NOLINT(bugprone-macro-parentheses) + +PYBIND11_WARNING_POP + /** \rst This macro creates the entry point that will be invoked when the Python interpreter imports an extension module. The module name is given as the first argument and it should not be in quotes. The second macro argument defines a variable of type - `py::module_` which can be used to initialize the module. + ``py::module_`` which can be used to initialize the module. The entry point is marked as "maybe unused" to aid dead-code detection analysis: since the entry point is typically only looked up at runtime and not referenced @@ -382,16 +421,17 @@ }); } - 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. + The third and subsequent macro arguments are optional (available since 2.13.0), and + can be used to mark the extension module as supporting various Python features. + + - ``mod_gil_not_used()`` + - ``multiple_interpreters::per_interpreter_gil()`` + - ``multiple_interpreters::per_interprshareeter_gil()`` .. 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!"; }); @@ -401,38 +441,8 @@ 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); \ - static ::pybind11::module_::slots_array PYBIND11_CONCAT(pybind11_module_slots_, name); \ - static int PYBIND11_CONCAT(pybind11_exec_, name)(PyObject *); \ - static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &); \ - PYBIND11_PLUGIN_IMPL(name) { \ - PYBIND11_CHECK_PYTHON_VERSION \ - PYBIND11_ENSURE_INTERNALS_READY \ - static auto result = []() { \ - auto &slots = PYBIND11_CONCAT(pybind11_module_slots_, name); \ - slots[0] = {Py_mod_exec, \ - reinterpret_cast(&PYBIND11_CONCAT(pybind11_exec_, name))}; \ - slots[1] = {0, nullptr}; \ - return ::pybind11::module_::initialize_multiphase_module_def( \ - PYBIND11_TOSTRING(name), \ - nullptr, \ - &PYBIND11_CONCAT(pybind11_module_def_, name), \ - slots, \ - ##__VA_ARGS__); \ - }(); \ - return result.ptr(); \ - } \ - int PYBIND11_CONCAT(pybind11_exec_, name)(PyObject * pm) { \ - pybind11::detail::get_num_interpreters_seen() += 1; \ - try { \ - auto m = pybind11::reinterpret_borrow<::pybind11::module_>(pm); \ - PYBIND11_CONCAT(pybind11_init_, name)(m); \ - return 0; \ - } \ - PYBIND11_CATCH_INIT_EXCEPTIONS \ - return -1; \ - } \ - void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ & (variable)) + PYBIND11_MODULE_BASE( \ + name, variable, (pybind11::detail::get_num_interpreters_seen() += 1), ##__VA_ARGS__) PYBIND11_WARNING_POP PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) diff --git a/include/pybind11/embed.h b/include/pybind11/embed.h index 99a765ba16..274f59a05f 100644 --- a/include/pybind11/embed.h +++ b/include/pybind11/embed.h @@ -37,43 +37,30 @@ return "Hello, World!"; }); } + + The third and subsequent macro arguments are optional, and can be used to + mark the module as supporting various Python features. + + - ``mod_gil_not_used()`` + - ``multiple_interpreters::per_interpreter_gil()`` + - ``multiple_interpreters::per_interprshareeter_gil()`` + + .. code-block:: cpp + + PYBIND11_EMBEDDED_MODULE(example, m, py::mod_gil_not_used()) { + m.def("foo", []() { + return "Hello, Free-threaded World!"; + }); + } + \endrst */ PYBIND11_WARNING_PUSH PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments") #define PYBIND11_EMBEDDED_MODULE(name, variable, ...) \ - static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name); \ - static ::pybind11::module_::slots_array PYBIND11_CONCAT(pybind11_module_slots_, name); \ - static int PYBIND11_CONCAT(pybind11_exec_, name)(PyObject *); \ - static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &); \ - static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() { \ - static auto result = []() { \ - auto &slots = PYBIND11_CONCAT(pybind11_module_slots_, name); \ - slots[0] = {Py_mod_exec, \ - reinterpret_cast(&PYBIND11_CONCAT(pybind11_exec_, name))}; \ - slots[1] = {0, nullptr}; \ - return ::pybind11::module_::initialize_multiphase_module_def( \ - PYBIND11_TOSTRING(name), \ - nullptr, \ - &PYBIND11_CONCAT(pybind11_module_def_, name), \ - slots, \ - ##__VA_ARGS__); \ - }(); \ - return result.ptr(); \ - } \ - PYBIND11_EMBEDDED_MODULE_IMPL(name) \ + extern "C" PyObject PYBIND11_CONCAT(*PyInit_, name)(); \ ::pybind11::detail::embedded_module PYBIND11_CONCAT(pybind11_module_, name)( \ - PYBIND11_TOSTRING(name), PYBIND11_CONCAT(pybind11_init_impl_, name)); \ - int PYBIND11_CONCAT(pybind11_exec_, name)(PyObject * pm) { \ - try { \ - auto m = pybind11::reinterpret_borrow<::pybind11::module_>(pm); \ - PYBIND11_CONCAT(pybind11_init_, name)(m); \ - return 0; \ - } \ - PYBIND11_CATCH_INIT_EXCEPTIONS \ - return -1; \ - } \ - void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ \ - & variable) // NOLINT(bugprone-macro-parentheses) + PYBIND11_TOSTRING(name), PYBIND11_CONCAT(PyInit_, name)); \ + PYBIND11_MODULE_BASE(name, variable, {}, ##__VA_ARGS__) PYBIND11_WARNING_POP PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) From ad9be965562dca4378d4ae96afe32044cc93773e Mon Sep 17 00:00:00 2001 From: b-pass Date: Sun, 18 May 2025 21:12:11 -0400 Subject: [PATCH 2/4] Use a macro to make the forward decl correct and reduce code duplication --- include/pybind11/detail/common.h | 4 +++- include/pybind11/embed.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index b7d216baba..db1249cad9 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -283,8 +283,10 @@ #define PYBIND11_BUILTINS_MODULE "builtins" // Providing a separate declaration to make Clang's -Wmissing-prototypes happy. // See comment for PYBIND11_MODULE below for why this is marked "maybe unused". +#define PYBIND11_PLUGIN_DECL(name) \ + extern "C" PYBIND11_MAYBE_UNUSED PYBIND11_EXPORT PyObject *PyInit_##name(); #define PYBIND11_PLUGIN_IMPL(name) \ - extern "C" PYBIND11_MAYBE_UNUSED PYBIND11_EXPORT PyObject *PyInit_##name(); \ + PYBIND11_PLUGIN_DECL(name) \ extern "C" PYBIND11_EXPORT PyObject *PyInit_##name() #define PYBIND11_TRY_NEXT_OVERLOAD ((PyObject *) 1) // special failure return code diff --git a/include/pybind11/embed.h b/include/pybind11/embed.h index 274f59a05f..e6925bf454 100644 --- a/include/pybind11/embed.h +++ b/include/pybind11/embed.h @@ -57,7 +57,7 @@ PYBIND11_WARNING_PUSH PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments") #define PYBIND11_EMBEDDED_MODULE(name, variable, ...) \ - extern "C" PyObject PYBIND11_CONCAT(*PyInit_, name)(); \ + PYBIND11_PLUGIN_DECL(name); \ ::pybind11::detail::embedded_module PYBIND11_CONCAT(pybind11_module_, name)( \ PYBIND11_TOSTRING(name), PYBIND11_CONCAT(PyInit_, name)); \ PYBIND11_MODULE_BASE(name, variable, {}, ##__VA_ARGS__) From 88a49d4318b2470f004f28a0d9ed7940cfc711f7 Mon Sep 17 00:00:00 2001 From: b-pass Date: Sun, 18 May 2025 21:51:56 -0400 Subject: [PATCH 3/4] Oops, extra semicolon --- include/pybind11/embed.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/embed.h b/include/pybind11/embed.h index e6925bf454..de540afeed 100644 --- a/include/pybind11/embed.h +++ b/include/pybind11/embed.h @@ -57,7 +57,7 @@ PYBIND11_WARNING_PUSH PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments") #define PYBIND11_EMBEDDED_MODULE(name, variable, ...) \ - PYBIND11_PLUGIN_DECL(name); \ + PYBIND11_PLUGIN_DECL(name) \ ::pybind11::detail::embedded_module PYBIND11_CONCAT(pybind11_module_, name)( \ PYBIND11_TOSTRING(name), PYBIND11_CONCAT(PyInit_, name)); \ PYBIND11_MODULE_BASE(name, variable, {}, ##__VA_ARGS__) From 5577a7f8a1f2dd2d1bf4deb23d19146bc5086b7e Mon Sep 17 00:00:00 2001 From: b-pass Date: Mon, 19 May 2025 16:28:54 -0400 Subject: [PATCH 4/4] Split up the macro into two so we can avoid the redundant decl --- include/pybind11/detail/common.h | 15 +++++++++------ include/pybind11/embed.h | 4 ++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index db1249cad9..d30c3248cd 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -365,7 +365,7 @@ PYBIND11_WARNING_PUSH PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments") -#define PYBIND11_MODULE_BASE(name, variable, pre_init, ...) \ +#define PYBIND11_MODULE_PYINIT(name, pre_init, ...) \ static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name); \ static ::pybind11::module_::slots_array PYBIND11_CONCAT(pybind11_module_slots_, name); \ static int PYBIND11_CONCAT(pybind11_exec_, name)(PyObject *); \ @@ -387,7 +387,11 @@ PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments") ##__VA_ARGS__); \ }(); \ return result.ptr(); \ - } \ + } + +PYBIND11_WARNING_POP + +#define PYBIND11_MODULE_EXEC(name, variable) \ int PYBIND11_CONCAT(pybind11_exec_, name)(PyObject * pm) { \ try { \ auto m = pybind11::reinterpret_borrow<::pybind11::module_>(pm); \ @@ -400,8 +404,6 @@ PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments") void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ \ & variable) // NOLINT(bugprone-macro-parentheses) -PYBIND11_WARNING_POP - /** \rst This macro creates the entry point that will be invoked when the Python interpreter imports an extension module. The module name is given as the first argument and it @@ -443,8 +445,9 @@ PYBIND11_WARNING_POP PYBIND11_WARNING_PUSH PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments") #define PYBIND11_MODULE(name, variable, ...) \ - PYBIND11_MODULE_BASE( \ - name, variable, (pybind11::detail::get_num_interpreters_seen() += 1), ##__VA_ARGS__) + PYBIND11_MODULE_PYINIT( \ + name, (pybind11::detail::get_num_interpreters_seen() += 1), ##__VA_ARGS__) \ + PYBIND11_MODULE_EXEC(name, variable) PYBIND11_WARNING_POP PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) diff --git a/include/pybind11/embed.h b/include/pybind11/embed.h index de540afeed..812dd92e8a 100644 --- a/include/pybind11/embed.h +++ b/include/pybind11/embed.h @@ -57,10 +57,10 @@ PYBIND11_WARNING_PUSH PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments") #define PYBIND11_EMBEDDED_MODULE(name, variable, ...) \ - PYBIND11_PLUGIN_DECL(name) \ + PYBIND11_MODULE_PYINIT(name, {}, ##__VA_ARGS__) \ ::pybind11::detail::embedded_module PYBIND11_CONCAT(pybind11_module_, name)( \ PYBIND11_TOSTRING(name), PYBIND11_CONCAT(PyInit_, name)); \ - PYBIND11_MODULE_BASE(name, variable, {}, ##__VA_ARGS__) + PYBIND11_MODULE_EXEC(name, variable) PYBIND11_WARNING_POP PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)