@@ -1255,6 +1255,22 @@ class mod_gil_not_used {
1255
1255
bool flag_;
1256
1256
};
1257
1257
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
+
1258
1274
// / Wrapper for Python extension modules
1259
1275
class module_ : public object {
1260
1276
public:
@@ -1362,16 +1378,15 @@ class module_ : public object {
1362
1378
= mod_gil_not_used(false )) {
1363
1379
// module_def is PyModuleDef
1364
1380
// 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 };
1375
1390
auto *m = PyModule_Create (def);
1376
1391
if (m == nullptr ) {
1377
1392
if (PyErr_Occurred ()) {
@@ -1389,6 +1404,68 @@ class module_ : public object {
1389
1404
// For Python 2, reinterpret_borrow was correct.
1390
1405
return reinterpret_borrow<module_>(m);
1391
1406
}
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
+ }
1392
1469
};
1393
1470
1394
1471
PYBIND11_NAMESPACE_BEGIN (detail)
0 commit comments