@@ -784,28 +784,15 @@ def generate_shared_lib_init(self, emitter: Emitter) -> None:
784
784
assert self .group_name is not None
785
785
786
786
emitter .emit_line ()
787
+
788
+ short_name = shared_lib_name (self .group_name ).split ("." )[- 1 ]
789
+
787
790
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)" ,
791
792
"{" ,
792
- (
793
- 'static PyModuleDef def = {{ PyModuleDef_HEAD_INIT, "{}", NULL, -1, NULL, NULL }};' .format (
794
- shared_lib_name (self .group_name )
795
- )
796
- ),
797
793
"int res;" ,
798
794
"PyObject *capsule;" ,
799
795
"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
- "}" ,
809
796
"" ,
810
797
)
811
798
@@ -827,15 +814,26 @@ def generate_shared_lib_init(self, emitter: Emitter) -> None:
827
814
828
815
for mod in self .modules :
829
816
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);" )
830
825
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 ,
834
832
),
835
833
"if (!capsule) {" ,
836
834
"goto fail;" ,
837
835
"}" ,
838
- f'res = PyObject_SetAttrString(module, "init_ { name } ", capsule);' ,
836
+ f'res = PyObject_SetAttrString(module, "{ capsule_name_prefix } { name } ", capsule);' ,
839
837
"Py_DECREF(capsule);" ,
840
838
"if (res < 0) {" ,
841
839
"goto fail;" ,
@@ -861,7 +859,56 @@ def generate_shared_lib_init(self, emitter: Emitter) -> None:
861
859
"" ,
862
860
)
863
861
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
+ )
865
912
866
913
def generate_globals_init (self , emitter : Emitter ) -> None :
867
914
emitter .emit_lines (
@@ -887,16 +934,22 @@ def generate_globals_init(self, emitter: Emitter) -> None:
887
934
def generate_module_def (self , emitter : Emitter , module_name : str , module : ModuleIR ) -> None :
888
935
"""Emit the PyModuleDef struct for a module and the module init function."""
889
936
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 )
893
937
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 )
896
939
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 :
898
951
name = f"{ module_prefix } _slots"
899
- exec_name = f"{ module_prefix } _exec "
952
+ exec_name = f"CPyExec_ { exported_name ( module_name ) } "
900
953
901
954
emitter .emit_line (f"static PyModuleDef_Slot { name } [] = {{" )
902
955
emitter .emit_line (f"{{Py_mod_exec, { exec_name } }}," )
@@ -951,7 +1004,7 @@ def emit_module_def_struct(
951
1004
"0, /* size of per-interpreter state of the module */" ,
952
1005
f"{ module_prefix } module_methods," ,
953
1006
)
954
- if self .multi_phase_init :
1007
+ if self .multi_phase_init and not self . use_shared_lib :
955
1008
slots_name = f"{ module_prefix } _slots"
956
1009
emitter .emit_line (f"{ slots_name } , /* m_slots */" )
957
1010
else :
@@ -962,15 +1015,16 @@ def emit_module_def_struct(
962
1015
def emit_module_exec_func (
963
1016
self , emitter : Emitter , module_name : str , module_prefix : str , module : ModuleIR
964
1017
) -> None :
965
- """Emit the module init function.
1018
+ """Emit the module exec function.
966
1019
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
969
1022
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.
972
1026
"""
973
- declaration = f"static int { module_prefix } _exec (PyObject *module)"
1027
+ declaration = f"int CPyExec_ { exported_name ( module_name ) } (PyObject *module)"
974
1028
module_static = self .module_internal_static_name (module_name , emitter )
975
1029
emitter .emit_lines (declaration , "{" )
976
1030
emitter .emit_line ("PyObject* modname = NULL;" )
@@ -987,6 +1041,12 @@ def emit_module_exec_func(
987
1041
" goto fail;" ,
988
1042
)
989
1043
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
+
990
1050
# HACK: Manually instantiate generated classes here
991
1051
type_structs : list [str ] = []
992
1052
for cl in module .classes :
@@ -1038,7 +1098,7 @@ def emit_module_init_func(
1038
1098
emitter .emit_line ("}" )
1039
1099
return
1040
1100
1041
- exec_func = f"{ module_prefix } _exec "
1101
+ exec_func = f"CPyExec_ { exported_name ( module_name ) } "
1042
1102
1043
1103
# Store the module reference in a static and return it when necessary.
1044
1104
# This is separate from the *global* reference to the module that will
0 commit comments