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"
syntax highlighted by Code2HTML, v. 0.9.1