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