Skip to content

Commit 9e6fe46

Browse files
authored
chore: consolidate common code in PYBIND11_MODULE and PYBIND11_EMBEDDED_MODULE (#5670)
* 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. * Use a macro to make the forward decl correct and reduce code duplication * Oops, extra semicolon * Split up the macro into two so we can avoid the redundant decl
1 parent 6742435 commit 9e6fe46

File tree

2 files changed

+73
-71
lines changed

2 files changed

+73
-71
lines changed

include/pybind11/detail/common.h

Lines changed: 54 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -283,8 +283,10 @@
283283
#define PYBIND11_BUILTINS_MODULE "builtins"
284284
// Providing a separate declaration to make Clang's -Wmissing-prototypes happy.
285285
// See comment for PYBIND11_MODULE below for why this is marked "maybe unused".
286+
#define PYBIND11_PLUGIN_DECL(name) \
287+
extern "C" PYBIND11_MAYBE_UNUSED PYBIND11_EXPORT PyObject *PyInit_##name();
286288
#define PYBIND11_PLUGIN_IMPL(name) \
287-
extern "C" PYBIND11_MAYBE_UNUSED PYBIND11_EXPORT PyObject *PyInit_##name(); \
289+
PYBIND11_PLUGIN_DECL(name) \
288290
extern "C" PYBIND11_EXPORT PyObject *PyInit_##name()
289291

290292
#define PYBIND11_TRY_NEXT_OVERLOAD ((PyObject *) 1) // special failure return code
@@ -361,11 +363,52 @@
361363
} \
362364
PyObject *pybind11_init()
363365

366+
PYBIND11_WARNING_PUSH
367+
PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments")
368+
#define PYBIND11_MODULE_PYINIT(name, pre_init, ...) \
369+
static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name); \
370+
static ::pybind11::module_::slots_array PYBIND11_CONCAT(pybind11_module_slots_, name); \
371+
static int PYBIND11_CONCAT(pybind11_exec_, name)(PyObject *); \
372+
static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &); \
373+
PYBIND11_PLUGIN_IMPL(name) { \
374+
PYBIND11_CHECK_PYTHON_VERSION \
375+
pre_init; \
376+
PYBIND11_ENSURE_INTERNALS_READY \
377+
static auto result = []() { \
378+
auto &slots = PYBIND11_CONCAT(pybind11_module_slots_, name); \
379+
slots[0] = {Py_mod_exec, \
380+
reinterpret_cast<void *>(&PYBIND11_CONCAT(pybind11_exec_, name))}; \
381+
slots[1] = {0, nullptr}; \
382+
return ::pybind11::module_::initialize_multiphase_module_def( \
383+
PYBIND11_TOSTRING(name), \
384+
nullptr, \
385+
&PYBIND11_CONCAT(pybind11_module_def_, name), \
386+
slots, \
387+
##__VA_ARGS__); \
388+
}(); \
389+
return result.ptr(); \
390+
}
391+
392+
PYBIND11_WARNING_POP
393+
394+
#define PYBIND11_MODULE_EXEC(name, variable) \
395+
int PYBIND11_CONCAT(pybind11_exec_, name)(PyObject * pm) { \
396+
try { \
397+
auto m = pybind11::reinterpret_borrow<::pybind11::module_>(pm); \
398+
PYBIND11_CONCAT(pybind11_init_, name)(m); \
399+
return 0; \
400+
} \
401+
PYBIND11_CATCH_INIT_EXCEPTIONS \
402+
return -1; \
403+
} \
404+
void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ \
405+
& variable) // NOLINT(bugprone-macro-parentheses)
406+
364407
/** \rst
365408
This macro creates the entry point that will be invoked when the Python interpreter
366409
imports an extension module. The module name is given as the first argument and it
367410
should not be in quotes. The second macro argument defines a variable of type
368-
`py::module_` which can be used to initialize the module.
411+
``py::module_`` which can be used to initialize the module.
369412
370413
The entry point is marked as "maybe unused" to aid dead-code detection analysis:
371414
since the entry point is typically only looked up at runtime and not referenced
@@ -382,16 +425,17 @@
382425
});
383426
}
384427
385-
The third macro argument is optional (available since 2.13.0), and can be used to
386-
mark the extension module as safe to run without the GIL under a free-threaded CPython
387-
interpreter. Passing this argument has no effect on other interpreters.
428+
The third and subsequent macro arguments are optional (available since 2.13.0), and
429+
can be used to mark the extension module as supporting various Python features.
430+
431+
- ``mod_gil_not_used()``
432+
- ``multiple_interpreters::per_interpreter_gil()``
433+
- ``multiple_interpreters::per_interprshareeter_gil()``
388434
389435
.. code-block:: cpp
390436
391437
PYBIND11_MODULE(example, m, py::mod_gil_not_used()) {
392438
m.doc() = "pybind11 example module safe to run without the GIL";
393-
394-
// Add bindings here
395439
m.def("foo", []() {
396440
return "Hello, Free-threaded World!";
397441
});
@@ -401,38 +445,9 @@
401445
PYBIND11_WARNING_PUSH
402446
PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments")
403447
#define PYBIND11_MODULE(name, variable, ...) \
404-
static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name); \
405-
static ::pybind11::module_::slots_array PYBIND11_CONCAT(pybind11_module_slots_, name); \
406-
static int PYBIND11_CONCAT(pybind11_exec_, name)(PyObject *); \
407-
static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &); \
408-
PYBIND11_PLUGIN_IMPL(name) { \
409-
PYBIND11_CHECK_PYTHON_VERSION \
410-
PYBIND11_ENSURE_INTERNALS_READY \
411-
static auto result = []() { \
412-
auto &slots = PYBIND11_CONCAT(pybind11_module_slots_, name); \
413-
slots[0] = {Py_mod_exec, \
414-
reinterpret_cast<void *>(&PYBIND11_CONCAT(pybind11_exec_, name))}; \
415-
slots[1] = {0, nullptr}; \
416-
return ::pybind11::module_::initialize_multiphase_module_def( \
417-
PYBIND11_TOSTRING(name), \
418-
nullptr, \
419-
&PYBIND11_CONCAT(pybind11_module_def_, name), \
420-
slots, \
421-
##__VA_ARGS__); \
422-
}(); \
423-
return result.ptr(); \
424-
} \
425-
int PYBIND11_CONCAT(pybind11_exec_, name)(PyObject * pm) { \
426-
pybind11::detail::get_num_interpreters_seen() += 1; \
427-
try { \
428-
auto m = pybind11::reinterpret_borrow<::pybind11::module_>(pm); \
429-
PYBIND11_CONCAT(pybind11_init_, name)(m); \
430-
return 0; \
431-
} \
432-
PYBIND11_CATCH_INIT_EXCEPTIONS \
433-
return -1; \
434-
} \
435-
void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ & (variable))
448+
PYBIND11_MODULE_PYINIT( \
449+
name, (pybind11::detail::get_num_interpreters_seen() += 1), ##__VA_ARGS__) \
450+
PYBIND11_MODULE_EXEC(name, variable)
436451
PYBIND11_WARNING_POP
437452

438453
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)

include/pybind11/embed.h

Lines changed: 19 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -37,43 +37,30 @@
3737
return "Hello, World!";
3838
});
3939
}
40+
41+
The third and subsequent macro arguments are optional, and can be used to
42+
mark the module as supporting various Python features.
43+
44+
- ``mod_gil_not_used()``
45+
- ``multiple_interpreters::per_interpreter_gil()``
46+
- ``multiple_interpreters::per_interprshareeter_gil()``
47+
48+
.. code-block:: cpp
49+
50+
PYBIND11_EMBEDDED_MODULE(example, m, py::mod_gil_not_used()) {
51+
m.def("foo", []() {
52+
return "Hello, Free-threaded World!";
53+
});
54+
}
55+
4056
\endrst */
4157
PYBIND11_WARNING_PUSH
4258
PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments")
4359
#define PYBIND11_EMBEDDED_MODULE(name, variable, ...) \
44-
static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name); \
45-
static ::pybind11::module_::slots_array PYBIND11_CONCAT(pybind11_module_slots_, name); \
46-
static int PYBIND11_CONCAT(pybind11_exec_, name)(PyObject *); \
47-
static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &); \
48-
static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() { \
49-
static auto result = []() { \
50-
auto &slots = PYBIND11_CONCAT(pybind11_module_slots_, name); \
51-
slots[0] = {Py_mod_exec, \
52-
reinterpret_cast<void *>(&PYBIND11_CONCAT(pybind11_exec_, name))}; \
53-
slots[1] = {0, nullptr}; \
54-
return ::pybind11::module_::initialize_multiphase_module_def( \
55-
PYBIND11_TOSTRING(name), \
56-
nullptr, \
57-
&PYBIND11_CONCAT(pybind11_module_def_, name), \
58-
slots, \
59-
##__VA_ARGS__); \
60-
}(); \
61-
return result.ptr(); \
62-
} \
63-
PYBIND11_EMBEDDED_MODULE_IMPL(name) \
60+
PYBIND11_MODULE_PYINIT(name, {}, ##__VA_ARGS__) \
6461
::pybind11::detail::embedded_module PYBIND11_CONCAT(pybind11_module_, name)( \
65-
PYBIND11_TOSTRING(name), PYBIND11_CONCAT(pybind11_init_impl_, name)); \
66-
int PYBIND11_CONCAT(pybind11_exec_, name)(PyObject * pm) { \
67-
try { \
68-
auto m = pybind11::reinterpret_borrow<::pybind11::module_>(pm); \
69-
PYBIND11_CONCAT(pybind11_init_, name)(m); \
70-
return 0; \
71-
} \
72-
PYBIND11_CATCH_INIT_EXCEPTIONS \
73-
return -1; \
74-
} \
75-
void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ \
76-
& variable) // NOLINT(bugprone-macro-parentheses)
62+
PYBIND11_TOSTRING(name), PYBIND11_CONCAT(PyInit_, name)); \
63+
PYBIND11_MODULE_EXEC(name, variable)
7764
PYBIND11_WARNING_POP
7865

7966
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)

0 commit comments

Comments
 (0)