Index: Pyrex/Compiler/Nodes.py =================================================================== --- Pyrex/Compiler/Nodes.py (Revision 151) +++ Pyrex/Compiler/Nodes.py (Arbeitskopie) @@ -114,24 +114,28 @@ self.generate_h_code(env, result) def generate_h_code(self, env, result): - public_vars_and_funcs = [] + public_vars = [] + public_funcs = [] public_extension_types = [] for entry in env.var_entries: if entry.visibility == 'public': - public_vars_and_funcs.append(entry) + public_vars.append(entry) for entry in env.cfunc_entries: if entry.visibility == 'public': - public_vars_and_funcs.append(entry) + public_funcs.append(entry) for entry in env.c_class_entries: if entry.visibility == 'public': public_extension_types.append(entry) - if public_vars_and_funcs or public_extension_types: + if public_vars or public_funcs or public_extension_types: result.h_file = replace_suffix(result.c_file, ".h") result.i_file = replace_suffix(result.c_file, ".pxi") h_code = Code.CCodeWriter(result.h_file) i_code = Code.PyrexCodeWriter(result.i_file) + header_barrier = "__HAS_PYX_" + env.module_name + h_code.putln("#ifndef %s" % header_barrier) + h_code.putln("#define %s" % header_barrier) self.generate_extern_c_macro_definition(h_code) - for entry in public_vars_and_funcs: + for entry in public_vars: h_code.putln("%s %s;" % ( Naming.extern_c_macro, entry.type.declaration_code( @@ -141,7 +145,23 @@ for entry in public_extension_types: self.generate_cclass_header_code(entry.type, h_code) self.generate_cclass_include_code(entry.type, i_code) + if public_funcs: + for entry in public_funcs: + h_code.putln( + 'static %s;' % + entry.type.declaration_code("(*%s)" % entry.cname)) + i_code.putln("cdef extern %s" % + entry.type.declaration_code(entry.cname, pyrex = 1)) + h_code.putln( + "static struct {char *s; void **p;} _%s_API[] = {" % + env.module_name) + for entry in public_funcs: + h_code.putln('{"%s", &%s},' % (entry.cname, entry.cname)) + h_code.putln("{0, 0}") + h_code.putln("};") + self.generate_c_api_import_code(env, h_code) h_code.putln("PyMODINIT_FUNC init%s(void);" % env.module_name) + h_code.putln("#endif /* %s */" % header_barrier) def generate_cclass_header_code(self, type, h_code): #h_code.putln("extern DL_IMPORT(PyTypeObject) %s;" % type.typeobj_cname) @@ -180,6 +200,7 @@ self.body.generate_function_definitions(env, code) self.generate_interned_name_table(env, code) self.generate_py_string_table(env, code) + self.generate_c_api_table(env, code) self.generate_typeobj_definitions(env, code) self.generate_method_table(env, code) self.generate_filename_init_prototype(code) @@ -437,10 +458,12 @@ dll_linkage = None header = entry.type.declaration_code(entry.cname, dll_linkage = dll_linkage) - if entry.visibility <> 'private': + if entry.visibility == 'private': + storage_class = "static " + elif entry.visibility == 'extern': storage_class = "%s " % Naming.extern_c_macro else: - storage_class = "static " + storage_class = "" code.putln("%s%s; /*proto*/" % ( storage_class, header)) @@ -1090,6 +1113,63 @@ code.putln( "};") + def generate_c_api_table(self, env, code): + public_funcs = [] + for entry in env.cfunc_entries: + if entry.visibility == 'public': + public_funcs.append(entry.cname) + if public_funcs: + env.use_utility_code(c_api_import_code); + code.putln( + "static __Pyx_CApiTabEntry %s[] = {" % + Naming.c_api_tab_cname) + public_funcs.sort() + for entry_cname in public_funcs: + code.putln('{"%s", %s},' % (entry_cname, entry_cname)) + code.putln( + "{0, 0}") + code.putln( + "};") + + def generate_c_api_import_code(self, env, h_code): + # this is written to the header file! + h_code.put(""" + /* Return -1 and set exception on error, 0 on success. */ + static int + import_%(name)s(PyObject *module) + { + if (module != NULL) { + PyObject *c_api_init = PyObject_GetAttrString( + module, "_import_c_api"); + if (!c_api_init) + return -1; + if (PyCObject_Check(c_api_init)) + { + int (*init)(struct {const char *s; const void **p;}*) = + PyCObject_AsVoidPtr(c_api_init); + if (!init) { + PyErr_SetString(PyExc_RuntimeError, + "module returns NULL pointer for C API call"); + return -1; + } + init(_%(name)s_API); + } + Py_DECREF(c_api_init); + } + return 0; + } + """.replace('\n ', '\n') % {'name' : env.module_name}) + + def generate_c_api_init_code(self, env, code): + public_funcs = [] + for entry in env.cfunc_entries: + if entry.visibility == 'public': + public_funcs.append(entry) + if public_funcs: + code.putln('if (__Pyx_InitCApi(%s) < 0) %s' % ( + Naming.module_cname, + code.error_goto(self.pos))) + def generate_filename_init_prototype(self, code): code.putln(""); code.putln("static void %s(void); /*proto*/" % Naming.fileinit_cname) @@ -1109,6 +1189,8 @@ self.generate_intern_code(env, code) #code.putln("/*--- String init code ---*/") self.generate_string_init_code(env, code) + #code.putln("/*--- External C API setup code ---*/") + self.generate_c_api_init_code(env, code) #code.putln("/*--- Global init code ---*/") self.generate_global_init_code(env, code) #code.putln("/*--- Type import code ---*/") @@ -1862,10 +1944,12 @@ dll_linkage = None header = self.return_type.declaration_code(entity, dll_linkage = dll_linkage) - if self.visibility <> 'private': + if self.visibility == 'private': + storage_class = "static " + elif self.visibility == 'extern': storage_class = "%s " % Naming.extern_c_macro else: - storage_class = "static " + storage_class = "" code.putln("%s%s {" % ( storage_class, header)) @@ -3550,6 +3634,7 @@ utility_function_predeclarations = \ """ +typedef struct {const char *s; const void **p;} __Pyx_CApiTabEntry; /*proto*/ typedef struct {PyObject **p; char *s;} __Pyx_InternTabEntry; /*proto*/ typedef struct {PyObject **p; char *s; long n;} __Pyx_StringTabEntry; /*proto*/ static PyObject *__Pyx_UnpackItem(PyObject *, Py_ssize_t); /*proto*/ @@ -3572,6 +3657,8 @@ static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, char *modname); /*proto*/ static int __Pyx_InternStrings(__Pyx_InternTabEntry *t); /*proto*/ static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/ +static int __Pyx_InitCApi(PyObject *module); /*proto*/ +static int __Pyx_ImportModuleCApi(__Pyx_CApiTabEntry *t); /*proto*/ """ get_name_predeclaration = \ @@ -4056,3 +4143,37 @@ """; #------------------------------------------------------------------------------------ + +c_api_import_code = \ +""" +static int __Pyx_ImportModuleCApi(__Pyx_CApiTabEntry *t) { + __Pyx_CApiTabEntry *api_t; + while (t->s) { + if (*t->s == '\0') + continue; /* shortcut for erased string entries */ + api_t = %(API_TAB)s; + while ((api_t->s) && (strcmp(api_t->s, t->s) < 0)) + ++api_t; + if ((!api_t->p) || (strcmp(api_t->s, t->s) != 0)) { + PyErr_Format(PyExc_ValueError, + "Unknown function name in C API: %%s", t->s); + return -1; + } + *t->p = api_t->p; + ++t; + } + return 0; +} + +static int __Pyx_InitCApi(PyObject *module) { + int result; + PyObject* cobj = PyCObject_FromVoidPtr(&__Pyx_ImportModuleCApi, NULL); + if (!cobj) + return -1; + + result = PyObject_SetAttrString(module, "_import_c_api", cobj); + Py_DECREF(cobj); + return result; +} +""" % {'API_TAB' : Naming.c_api_tab_cname} +#------------------------------------------------------------------------------------ Index: Pyrex/Compiler/Naming.py =================================================================== --- Pyrex/Compiler/Naming.py (Revision 151) +++ Pyrex/Compiler/Naming.py (Arbeitskopie) @@ -50,5 +50,6 @@ self_cname = pyrex_prefix + "self" stringtab_cname = pyrex_prefix + "string_tab" vtabslot_cname = pyrex_prefix + "vtab" +c_api_tab_cname = pyrex_prefix + "c_api_tab" extern_c_macro = pyrex_prefix.upper() + "EXTERN_C"