|
| 1 | +#include <string.h> // memset |
| 2 | + |
| 3 | +PyMODINIT_FUNC PyInit_examplemodule(void); |
| 4 | + |
| 5 | +static PyModuleDef module_def_and_token; |
| 6 | + |
| 7 | +PyMODINIT_FUNC |
| 8 | +PyInit_examplemodule(void) |
| 9 | +{ |
| 10 | + PyModuleDef_Slot *slot = PyModExport_examplemodule(NULL); |
| 11 | + |
| 12 | + if (module_def_and_token.m_name) { |
| 13 | + // Take care to only set up the static PyModuleDef once. |
| 14 | + // (PyModExport might theoretically return different data each time.) |
| 15 | + return PyModuleDef_Init(&module_def_and_token); |
| 16 | + } |
| 17 | + int copying_slots = 1; |
| 18 | + for (/* slot set above */; slot->slot; slot++) { |
| 19 | + switch (slot->slot) { |
| 20 | + // Set PyModuleDef members from slots. These slots must come first. |
| 21 | +# define COPYSLOT_CASE(SLOT, MEMBER, TYPE) \ |
| 22 | + case SLOT: \ |
| 23 | + if (!copying_slots) { \ |
| 24 | + PyErr_SetString(PyExc_SystemError, \ |
| 25 | + #SLOT " must be specified earlier"); \ |
| 26 | + goto error; \ |
| 27 | + } \ |
| 28 | + module_def_and_token.MEMBER = (TYPE)(slot->value); \ |
| 29 | + break; \ |
| 30 | + ///////////////////////////////////////////////////////////////// |
| 31 | + COPYSLOT_CASE(Py_mod_name, m_name, char*) |
| 32 | + COPYSLOT_CASE(Py_mod_doc, m_doc, char*) |
| 33 | + COPYSLOT_CASE(Py_mod_state_size, m_size, Py_ssize_t) |
| 34 | + COPYSLOT_CASE(Py_mod_methods, m_methods, PyMethodDef*) |
| 35 | + COPYSLOT_CASE(Py_mod_state_traverse, m_traverse, traverseproc) |
| 36 | + COPYSLOT_CASE(Py_mod_state_clear, m_clear, inquiry) |
| 37 | + COPYSLOT_CASE(Py_mod_state_free, m_free, freefunc) |
| 38 | + case Py_mod_token: |
| 39 | + // With PyInit_, the PyModuleDef is used as the token. |
| 40 | + if (slot->value != &module_def_and_token) { |
| 41 | + PyErr_SetString(PyExc_SystemError, |
| 42 | + "Py_mod_token must be set to " |
| 43 | + "&module_def_and_token"); |
| 44 | + goto error; |
| 45 | + } |
| 46 | + break; |
| 47 | + default: |
| 48 | + // The remaining slots become m_slots in the def. |
| 49 | + // (`slot` now points to the "rest" of the original |
| 50 | + // zero-terminated array.) |
| 51 | + if (copying_slots) { |
| 52 | + module_def_and_token.m_slots = slot; |
| 53 | + } |
| 54 | + copying_slots = 0; |
| 55 | + break; |
| 56 | + } |
| 57 | + } |
| 58 | + if (!module_def_and_token.m_name) { |
| 59 | + // This function needs m_name as the "is initialized" marker. |
| 60 | + PyErr_SetString(PyExc_SystemError, "Py_mod_name slot is required"); |
| 61 | + goto error; |
| 62 | + } |
| 63 | + return PyModuleDef_Init(&module_def_and_token); |
| 64 | + |
| 65 | +error: |
| 66 | + memset(&module_def_and_token, 0, sizeof(module_def_and_token)); |
| 67 | + return NULL; |
| 68 | +} |
0 commit comments