@@ -784,28 +784,15 @@ def generate_shared_lib_init(self, emitter: Emitter) -> None:
784784 assert self .group_name is not None
785785
786786 emitter .emit_line ()
787+
788+ short_name = shared_lib_name (self .group_name ).split ("." )[- 1 ]
789+
787790 emitter .emit_lines (
788- "PyMODINIT_FUNC PyInit_{}(void)" .format (
789- shared_lib_name (self .group_name ).split ("." )[- 1 ]
790- ),
791+ f"static int exec_{ short_name } (PyObject *module)" ,
791792 "{" ,
792- (
793- 'static PyModuleDef def = {{ PyModuleDef_HEAD_INIT, "{}", NULL, -1, NULL, NULL }};' .format (
794- shared_lib_name (self .group_name )
795- )
796- ),
797793 "int res;" ,
798794 "PyObject *capsule;" ,
799795 "PyObject *tmp;" ,
800- "static PyObject *module;" ,
801- "if (module) {" ,
802- "Py_INCREF(module);" ,
803- "return module;" ,
804- "}" ,
805- "module = PyModule_Create(&def);" ,
806- "if (!module) {" ,
807- "goto fail;" ,
808- "}" ,
809796 "" ,
810797 )
811798
@@ -827,15 +814,26 @@ def generate_shared_lib_init(self, emitter: Emitter) -> None:
827814
828815 for mod in self .modules :
829816 name = exported_name (mod )
817+ if self .multi_phase_init :
818+ capsule_func_prefix = "CPyExec_"
819+ capsule_name_prefix = "exec_"
820+ emitter .emit_line (f"extern int CPyExec_{ name } (PyObject *);" )
821+ else :
822+ capsule_func_prefix = "CPyInit_"
823+ capsule_name_prefix = "init_"
824+ emitter .emit_line (f"extern PyObject *CPyInit_{ name } (void);" )
830825 emitter .emit_lines (
831- f"extern PyObject *CPyInit_{ name } (void);" ,
832- 'capsule = PyCapsule_New((void *)CPyInit_{}, "{}.init_{}", NULL);' .format (
833- name , shared_lib_name (self .group_name ), name
826+ 'capsule = PyCapsule_New((void *){}{}, "{}.{}{}", NULL);' .format (
827+ capsule_func_prefix ,
828+ name ,
829+ shared_lib_name (self .group_name ),
830+ capsule_name_prefix ,
831+ name ,
834832 ),
835833 "if (!capsule) {" ,
836834 "goto fail;" ,
837835 "}" ,
838- f'res = PyObject_SetAttrString(module, "init_ { name } ", capsule);' ,
836+ f'res = PyObject_SetAttrString(module, "{ capsule_name_prefix } { name } ", capsule);' ,
839837 "Py_DECREF(capsule);" ,
840838 "if (res < 0) {" ,
841839 "goto fail;" ,
@@ -861,7 +859,56 @@ def generate_shared_lib_init(self, emitter: Emitter) -> None:
861859 "" ,
862860 )
863861
864- emitter .emit_lines ("return module;" , "fail:" , "Py_XDECREF(module);" , "return NULL;" , "}" )
862+ emitter .emit_lines ("return 0;" , "fail:" , "return -1;" , "}" )
863+
864+ if self .multi_phase_init :
865+ emitter .emit_lines (
866+ f"static PyModuleDef_Slot slots_{ short_name } [] = {{" ,
867+ f"{{Py_mod_exec, exec_{ short_name } }}," ,
868+ "{Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}," ,
869+ "{Py_mod_gil, Py_MOD_GIL_NOT_USED}," ,
870+ "{0, NULL}," ,
871+ "};" ,
872+ )
873+
874+ size = 0 if self .multi_phase_init else - 1
875+ emitter .emit_lines (
876+ f"static PyModuleDef module_def_{ short_name } = {{" ,
877+ "PyModuleDef_HEAD_INIT," ,
878+ f'.m_name = "{ shared_lib_name (self .group_name )} ",' ,
879+ ".m_doc = NULL," ,
880+ f".m_size = { size } ," ,
881+ ".m_methods = NULL," ,
882+ )
883+ if self .multi_phase_init :
884+ emitter .emit_line (f".m_slots = slots_{ short_name } ," )
885+ emitter .emit_line ("};" )
886+
887+ if self .multi_phase_init :
888+ emitter .emit_lines (
889+ f"PyMODINIT_FUNC PyInit_{ short_name } (void) {{" ,
890+ f"return PyModuleDef_Init(&module_def_{ short_name } );" ,
891+ "}" ,
892+ )
893+ else :
894+ emitter .emit_lines (
895+ f"PyMODINIT_FUNC PyInit_{ short_name } (void) {{" ,
896+ "static PyObject *module = NULL;" ,
897+ "if (module) {" ,
898+ "Py_INCREF(module);" ,
899+ "return module;" ,
900+ "}" ,
901+ f"module = PyModule_Create(&module_def_{ short_name } );" ,
902+ "if (!module) {" ,
903+ "return NULL;" ,
904+ "}" ,
905+ f"if (exec_{ short_name } (module) < 0) {{" ,
906+ "Py_DECREF(module);" ,
907+ "return NULL;" ,
908+ "}" ,
909+ "return module;" ,
910+ "}" ,
911+ )
865912
866913 def generate_globals_init (self , emitter : Emitter ) -> None :
867914 emitter .emit_lines (
@@ -887,16 +934,22 @@ def generate_globals_init(self, emitter: Emitter) -> None:
887934 def generate_module_def (self , emitter : Emitter , module_name : str , module : ModuleIR ) -> None :
888935 """Emit the PyModuleDef struct for a module and the module init function."""
889936 module_prefix = emitter .names .private_name (module_name )
890- self .emit_module_exec_func (emitter , module_name , module_prefix , module )
891- if self .multi_phase_init :
892- self .emit_module_def_slots (emitter , module_prefix )
893937 self .emit_module_methods (emitter , module_name , module_prefix , module )
894- self .emit_module_def_struct (emitter , module_name , module_prefix )
895- self .emit_module_init_func (emitter , module_name , module_prefix )
938+ self .emit_module_exec_func (emitter , module_name , module_prefix , module )
896939
897- def emit_module_def_slots (self , emitter : Emitter , module_prefix : str ) -> None :
940+ # If using multi-phase init and a shared lib, parts of module definition
941+ # will happen in the shim modules, so we skip some steps here.
942+ if not (self .multi_phase_init and self .use_shared_lib ):
943+ if self .multi_phase_init :
944+ self .emit_module_def_slots (emitter , module_prefix , module_name )
945+ self .emit_module_def_struct (emitter , module_name , module_prefix )
946+ self .emit_module_init_func (emitter , module_name , module_prefix )
947+
948+ def emit_module_def_slots (
949+ self , emitter : Emitter , module_prefix : str , module_name : str
950+ ) -> None :
898951 name = f"{ module_prefix } _slots"
899- exec_name = f"{ module_prefix } _exec "
952+ exec_name = f"CPyExec_ { exported_name ( module_name ) } "
900953
901954 emitter .emit_line (f"static PyModuleDef_Slot { name } [] = {{" )
902955 emitter .emit_line (f"{{Py_mod_exec, { exec_name } }}," )
@@ -951,7 +1004,7 @@ def emit_module_def_struct(
9511004 "0, /* size of per-interpreter state of the module */" ,
9521005 f"{ module_prefix } module_methods," ,
9531006 )
954- if self .multi_phase_init :
1007+ if self .multi_phase_init and not self . use_shared_lib :
9551008 slots_name = f"{ module_prefix } _slots"
9561009 emitter .emit_line (f"{ slots_name } , /* m_slots */" )
9571010 else :
@@ -962,15 +1015,16 @@ def emit_module_def_struct(
9621015 def emit_module_exec_func (
9631016 self , emitter : Emitter , module_name : str , module_prefix : str , module : ModuleIR
9641017 ) -> None :
965- """Emit the module init function.
1018+ """Emit the module exec function.
9661019
967- If we are compiling just one module, this will be the C API init
968- function. If we are compiling 2+ modules, we generate a shared
1020+ If we are compiling just one module, this will be the normal C API
1021+ exec function. If we are compiling 2+ modules, we generate a shared
9691022 library for the modules and shims that call into the shared
970- library, and in this case we use an internal module initialized
971- function that will be called by the shim.
1023+ library, and in this case the shared module defines an internal
1024+ exec function for each module and these will be called by the shims
1025+ via Capsules.
9721026 """
973- declaration = f"static int { module_prefix } _exec (PyObject *module)"
1027+ declaration = f"int CPyExec_ { exported_name ( module_name ) } (PyObject *module)"
9741028 module_static = self .module_internal_static_name (module_name , emitter )
9751029 emitter .emit_lines (declaration , "{" )
9761030 emitter .emit_line ("PyObject* modname = NULL;" )
@@ -987,6 +1041,12 @@ def emit_module_exec_func(
9871041 " goto fail;" ,
9881042 )
9891043
1044+ if self .multi_phase_init :
1045+ emitter .emit_lines (
1046+ f"if (PyModule_AddFunctions(module, { module_prefix } module_methods) < 0)" ,
1047+ " goto fail;" ,
1048+ )
1049+
9901050 # HACK: Manually instantiate generated classes here
9911051 type_structs : list [str ] = []
9921052 for cl in module .classes :
@@ -1038,7 +1098,7 @@ def emit_module_init_func(
10381098 emitter .emit_line ("}" )
10391099 return
10401100
1041- exec_func = f"{ module_prefix } _exec "
1101+ exec_func = f"CPyExec_ { exported_name ( module_name ) } "
10421102
10431103 # Store the module reference in a static and return it when necessary.
10441104 # This is separate from the *global* reference to the module that will
0 commit comments