@@ -1255,6 +1255,22 @@ class mod_gil_not_used {
12551255 bool flag_;
12561256};
12571257
1258+ PYBIND11_NAMESPACE_BEGIN (detail)
1259+
1260+ inline bool gil_not_used_option () { return false ; }
1261+ template <typename F, typename ... O>
1262+ bool gil_not_used_option (F &&, O &&...o );
1263+ template <typename ... O>
1264+ inline bool gil_not_used_option (mod_gil_not_used f, O &&...o ) {
1265+ return f.flag () || gil_not_used_option (o...);
1266+ }
1267+ template <typename F, typename ... O>
1268+ inline bool gil_not_used_option (F &&, O &&...o ) {
1269+ return gil_not_used_option (o...);
1270+ }
1271+
1272+ PYBIND11_NAMESPACE_END (detail)
1273+
12581274// / Wrapper for Python extension modules
12591275class module_ : public object {
12601276public:
@@ -1362,16 +1378,15 @@ class module_ : public object {
13621378 = mod_gil_not_used(false )) {
13631379 // module_def is PyModuleDef
13641380 // Placement new (not an allocation).
1365- def = new (def)
1366- PyModuleDef{/* m_base */ PyModuleDef_HEAD_INIT,
1367- /* m_name */ name,
1368- /* m_doc */ options::show_user_defined_docstrings () ? doc : nullptr ,
1369- /* m_size */ -1 ,
1370- /* m_methods */ nullptr ,
1371- /* m_slots */ nullptr ,
1372- /* m_traverse */ nullptr ,
1373- /* m_clear */ nullptr ,
1374- /* m_free */ nullptr };
1381+ new (def) PyModuleDef{/* m_base */ PyModuleDef_HEAD_INIT,
1382+ /* m_name */ name,
1383+ /* m_doc */ options::show_user_defined_docstrings () ? doc : nullptr ,
1384+ /* m_size */ -1 ,
1385+ /* m_methods */ nullptr ,
1386+ /* m_slots */ nullptr ,
1387+ /* m_traverse */ nullptr ,
1388+ /* m_clear */ nullptr ,
1389+ /* m_free */ nullptr };
13751390 auto *m = PyModule_Create (def);
13761391 if (m == nullptr ) {
13771392 if (PyErr_Occurred ()) {
@@ -1389,6 +1404,68 @@ class module_ : public object {
13891404 // For Python 2, reinterpret_borrow was correct.
13901405 return reinterpret_borrow<module_>(m);
13911406 }
1407+
1408+ // / Must be a POD type, and must hold enough entries for all of the possible slots PLUS ONE for
1409+ // / the sentinel (0) end slot.
1410+ using slots_array = std::array<PyModuleDef_Slot, 3 >;
1411+
1412+ /* * \rst
1413+ Initialized a module def for use with multi-phase module initialization.
1414+
1415+ ``def`` should point to a statically allocated module_def.
1416+ ``slots`` must already contain a Py_mod_exec or Py_mod_create slot and will be filled with
1417+ additional slots from the supplied options (and the empty sentinel slot).
1418+ \endrst */
1419+ template <typename ... Options>
1420+ static object initialize_multiphase_module_def (const char *name,
1421+ const char *doc,
1422+ module_def *def,
1423+ slots_array &slots,
1424+ Options &&...options) {
1425+ size_t next_slot = 0 ;
1426+ size_t term_slot = slots.size () - 1 ;
1427+
1428+ // find the end of the supplied slots
1429+ while (next_slot < term_slot && slots[next_slot].slot != 0 ) {
1430+ ++next_slot;
1431+ }
1432+
1433+ bool nogil PYBIND11_MAYBE_UNUSED = detail::gil_not_used_option (options...);
1434+ if (nogil) {
1435+ #if defined(Py_mod_gil) && defined(Py_GIL_DISABLED)
1436+ if (next_slot >= term_slot) {
1437+ pybind11_fail (" initialize_multiphase_module_def: not enough space in slots" );
1438+ }
1439+ slots[next_slot++] = {Py_mod_gil, Py_MOD_GIL_NOT_USED};
1440+ #endif
1441+ }
1442+
1443+ // slots must have a zero end sentinel
1444+ if (next_slot > term_slot) {
1445+ pybind11_fail (" initialize_multiphase_module_def: not enough space in slots" );
1446+ }
1447+ slots[next_slot++] = {0 , nullptr };
1448+
1449+ // module_def is PyModuleDef
1450+ // Placement new (not an allocation).
1451+ new (def) PyModuleDef{/* m_base */ PyModuleDef_HEAD_INIT,
1452+ /* m_name */ name,
1453+ /* m_doc */ options::show_user_defined_docstrings () ? doc : nullptr ,
1454+ /* m_size */ 0 ,
1455+ /* m_methods */ nullptr ,
1456+ /* m_slots */ &slots[0 ],
1457+ /* m_traverse */ nullptr ,
1458+ /* m_clear */ nullptr ,
1459+ /* m_free */ nullptr };
1460+ auto *m = PyModuleDef_Init (def);
1461+ if (m == nullptr ) {
1462+ if (PyErr_Occurred ()) {
1463+ throw error_already_set ();
1464+ }
1465+ pybind11_fail (" Internal error in module_::initialize_multiphase_module_def()" );
1466+ }
1467+ return reinterpret_borrow<object>(m);
1468+ }
13921469};
13931470
13941471PYBIND11_NAMESPACE_BEGIN (detail)
0 commit comments