public/capi: fixes and cleanups, implement exporting cdef variables
authorLisandro Dalcin <dalcinl@gmail.com>
Thu, 31 Mar 2011 06:57:12 +0000 (03:57 -0300)
committerLisandro Dalcin <dalcinl@gmail.com>
Thu, 31 Mar 2011 06:57:12 +0000 (03:57 -0300)
12 files changed:
Cython/Compiler/ModuleNode.py
Cython/Compiler/Nodes.py
Cython/Compiler/Parsing.py
Cython/Compiler/PyrexTypes.py
Cython/Compiler/Symtab.py
tests/compile/a_capi.pyx
tests/compile/publicapi_api.pyx [new file with mode: 0644]
tests/compile/publicapi_mix.pyx [new file with mode: 0644]
tests/compile/publicapi_pub.pyx [new file with mode: 0644]
tests/compile/publicapi_pxd_mix.pxd [new file with mode: 0644]
tests/compile/publicapi_pxd_mix.pyx [new file with mode: 0644]
tests/run/capiimpl.pyx

index ae5c90bf08522fadda6bc5f251b20487cb5f6029..bb4768e44aef592d616e488ed478984229afd24d 100644 (file)
@@ -73,7 +73,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         self.generate_c_code(env, options, result)
         self.generate_h_code(env, options, result)
         self.generate_api_code(env, result)
-
+    
     def has_imported_c_functions(self):
         for module in self.referenced_modules:
             for entry in module.cfunc_entries:
@@ -96,14 +96,16 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                 f.close()
 
     def generate_h_code(self, env, options, result):
-        def h_entries(entries, pxd = 0):
+        def h_entries(entries, api=0, pxd=0):
             return [entry for entry in entries
-                if entry.visibility == 'public' or pxd and entry.defined_in_pxd]
-        h_types = h_entries(env.type_entries)
+                    if ((entry.visibility == 'public') or
+                        (api and entry.api) or
+                        (pxd and entry.defined_in_pxd))]
+        h_types = h_entries(env.type_entries, api=1)
         h_vars = h_entries(env.var_entries)
         h_funcs = h_entries(env.cfunc_entries)
         h_extension_types = h_entries(env.c_class_entries)
-        if h_types or h_vars or h_funcs or h_extension_types:
+        if (h_types or  h_vars or h_funcs or h_extension_types):
             result.h_file = replace_suffix(result.c_file, ".h")
             h_code = Code.CCodeWriter()
             Code.GlobalState(h_code)
@@ -115,31 +117,37 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
 
             h_guard = Naming.h_guard_prefix + self.api_name(env)
             h_code.put_h_guard(h_guard)
-            self.generate_extern_c_macro_definition(h_code)
+            h_code.putln("")
             self.generate_type_header_code(h_types, h_code)
             h_code.putln("")
             api_guard = Naming.api_guard_prefix + self.api_name(env)
             h_code.putln("#ifndef %s" % api_guard)
-            if h_vars:
-                h_code.putln("")
-                for entry in h_vars:
-                    self.generate_public_declaration(entry, h_code, i_code)
-            if h_funcs:
-                h_code.putln("")
-                for entry in h_funcs:
-                    self.generate_public_declaration(entry, h_code, i_code)
+            h_code.putln("")
+            self.generate_extern_c_macro_definition(h_code)
             if h_extension_types:
                 h_code.putln("")
                 for entry in h_extension_types:
                     self.generate_cclass_header_code(entry.type, h_code)
                     if i_code:
                         self.generate_cclass_include_code(entry.type, i_code)
+            if h_funcs:
+                h_code.putln("")
+                for entry in h_funcs:
+                    self.generate_public_declaration(entry, h_code, i_code)
+            if h_vars:
+                h_code.putln("")
+                for entry in h_vars:
+                    self.generate_public_declaration(entry, h_code, i_code)
             h_code.putln("")
-            h_code.putln("#endif")
+            h_code.putln("#endif /* !%s */" % api_guard)
             h_code.putln("")
+            h_code.putln("#if PY_MAJOR_VERSION < 3")
             h_code.putln("PyMODINIT_FUNC init%s(void);" % env.module_name)
-            h_code.putln("")
+            h_code.putln("#else")
+            h_code.putln("PyMODINIT_FUNC PyInit_%s(void);" % env.module_name)
             h_code.putln("#endif")
+            h_code.putln("")
+            h_code.putln("#endif /* !%s */" % h_guard)
 
             f = open_new_file(result.h_file)
             try:
@@ -158,65 +166,70 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
 
     def api_name(self, env):
         return env.qualified_name.replace(".", "__")
-
+    
     def generate_api_code(self, env, result):
-        api_funcs = []
-        public_extension_types = []
-        has_api_extension_types = 0
-        for entry in env.cfunc_entries:
-            if entry.api:
-                api_funcs.append(entry)
-        for entry in env.c_class_entries:
-            if entry.visibility == 'public':
-                public_extension_types.append(entry)
-            if entry.api:
-                has_api_extension_types = 1
-        if api_funcs or has_api_extension_types:
+        def api_entries(entries, pxd=1):
+            return [entry for entry in entries
+                    if entry.api or (pxd and entry.defined_in_pxd)]
+        api_vars = api_entries(env.var_entries)
+        api_funcs = api_entries(env.cfunc_entries)
+        api_extension_types = api_entries(env.c_class_entries)
+        if api_vars or api_funcs or api_extension_types:
             result.api_file = replace_suffix(result.c_file, "_api.h")
             h_code = Code.CCodeWriter()
             Code.GlobalState(h_code)
-            name = self.api_name(env)
-            guard = Naming.api_guard_prefix + name
-            h_code.put_h_guard(guard)
+            api_guard = Naming.api_guard_prefix + self.api_name(env)
+            h_code.put_h_guard(api_guard)
             h_code.putln('#include "Python.h"')
             if result.h_file:
                 h_code.putln('#include "%s"' % os.path.basename(result.h_file))
-            for entry in public_extension_types:
-                type = entry.type
+            if api_extension_types:
                 h_code.putln("")
-                h_code.putln("static PyTypeObject *%s;" % type.typeptr_cname)
-                h_code.putln("#define %s (*%s)" % (
-                    type.typeobj_cname, type.typeptr_cname))
+                for entry in api_extension_types:
+                    type = entry.type
+                    h_code.putln("static PyTypeObject *%s = 0;" % type.typeptr_cname)
+                    h_code.putln("#define %s (*%s)" % (
+                        type.typeobj_cname, type.typeptr_cname))
             if api_funcs:
                 h_code.putln("")
                 for entry in api_funcs:
                     type = CPtrType(entry.type)
-                    h_code.putln("static %s;" % type.declaration_code(entry.cname))
-            h_code.putln("")
-            h_code.put_h_guard(Naming.api_func_guard + "import_module")
+                    cname = env.mangle(Naming.func_prefix, entry.name)
+                    h_code.putln("static %s = 0;" % type.declaration_code(cname))
+                    h_code.putln("#define %s %s" % (entry.name, cname))
+            if api_vars:
+                h_code.putln("")
+                for entry in api_vars:
+                    type = CPtrType(entry.type)
+                    cname = env.mangle(Naming.var_prefix, entry.name)
+                    h_code.putln("static %s = 0;" %  type.declaration_code(cname))
+                    h_code.putln("#define %s (*%s)" % (entry.name, cname))
             h_code.put(import_module_utility_code.impl)
-            h_code.putln("")
-            h_code.putln("#endif")
+            if api_vars:
+                h_code.put(voidptr_import_utility_code.impl)
             if api_funcs:
-                h_code.putln("")
                 h_code.put(function_import_utility_code.impl)
-            if public_extension_types:
-                h_code.putln("")
+            if api_extension_types:
                 h_code.put(type_import_utility_code.impl)
             h_code.putln("")
-            h_code.putln("static int import_%s(void) {" % name)
+            h_code.putln("static int import_%s(void) {" % self.api_name(env))
             h_code.putln("PyObject *module = 0;")
             h_code.putln('module = __Pyx_ImportModule("%s");' % env.qualified_name)
             h_code.putln("if (!module) goto bad;")
             for entry in api_funcs:
+                cname = env.mangle(Naming.func_prefix, entry.name)
                 sig = entry.type.signature_string()
                 h_code.putln(
-                    'if (__Pyx_ImportFunction(module, "%s", (void (**)(void))&%s, "%s") < 0) goto bad;' % (
-                        entry.name,
-                        entry.cname,
-                        sig))
+                    'if (__Pyx_ImportFunction(module, "%s", (void (**)(void))&%s, "%s") < 0) goto bad;'
+                    % (entry.name, cname, sig))
+            for entry in api_vars:
+                cname = env.mangle(Naming.var_prefix, entry.name)
+                sig = entry.type.declaration_code("")
+                h_code.putln(
+                    'if (__Pyx_ImportVoidPtr(module, "%s", (void **)&%s, "%s") < 0) goto bad;'
+                    % (entry.name, cname, sig))
             h_code.putln("Py_DECREF(module); module = 0;")
-            for entry in public_extension_types:
+            for entry in api_extension_types:
                 self.generate_type_import_call(
                     entry.type, h_code,
                     "if (!%s) goto bad;" % entry.type.typeptr_cname)
@@ -226,7 +239,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
             h_code.putln("return -1;")
             h_code.putln("}")
             h_code.putln("")
-            h_code.putln("#endif")
+            h_code.putln("#endif /* !%s */" % api_guard)
 
             f = open_new_file(result.api_file)
             try:
@@ -235,8 +248,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                 f.close()
 
     def generate_cclass_header_code(self, type, h_code):
-        h_code.putln("%s DL_IMPORT(PyTypeObject) %s;" % (
-            Naming.extern_c_macro,
+        h_code.putln("%s %s %s;" % (
+            Naming.extern_c_macro, 
+            PyrexTypes.public_decl("PyTypeObject", "DL_IMPORT"),
             type.typeobj_cname))
 
     def generate_cclass_include_code(self, type, i_code):
@@ -426,8 +440,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                         self.generate_objstruct_definition(type, code)
         for entry in vtabslot_list:
             self.generate_objstruct_definition(entry.type, code)
+            self.generate_typeobj_predeclaration(entry, code)
         for entry in vtab_list:
-            self.generate_typeobject_predeclaration(entry, code)
+            self.generate_typeobj_predeclaration(entry, code)
             self.generate_exttype_vtable_struct(entry, code)
             self.generate_exttype_vtabptr_declaration(entry, code)
 
@@ -724,10 +739,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
 
     def generate_extern_c_macro_definition(self, code):
         name = Naming.extern_c_macro
-        code.putln("#ifdef __cplusplus")
-        code.putln('#define %s extern "C"' % name)
-        code.putln("#else")
-        code.putln("#define %s extern" % name)
+        code.putln("#ifndef %s" % name)
+        code.putln("  #ifdef __cplusplus")
+        code.putln('    #define %s extern "C"' % name)
+        code.putln("  #else")
+        code.putln("    #define %s extern" % name)
+        code.putln("  #endif")
         code.putln("#endif")
 
     def generate_includes(self, env, cimported_modules, code):
@@ -789,10 +806,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
     def generate_typedef(self, entry, code):
         base_type = entry.type.typedef_base_type
         if base_type.is_numeric:
-            writer = code.globalstate['numeric_typedefs']
+            try:
+                writer = code.globalstate['numeric_typedefs']
+            except KeyError:
+                writer = code
         else:
             writer = code
-        writer.putln("")
+        writer.mark_pos(entry.pos)
         writer.putln("typedef %s;" % base_type.declaration_code(entry.cname))
 
     def sue_header_footer(self, type, kind, name):
@@ -816,7 +836,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                 code.globalstate.use_utility_code(packed_struct_utility_code)
             header, footer = \
                 self.sue_header_footer(type, kind, type.cname)
-            code.putln("")
             if packed:
                 code.putln("#if defined(__SUNPRO_C)")
                 code.putln("  #pragma pack(1)")
@@ -847,7 +866,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         name = entry.cname or entry.name or ""
         header, footer = \
             self.sue_header_footer(type, "enum", name)
-        code.putln("")
         code.putln(header)
         enum_values = entry.enum_values
         if not enum_values:
@@ -873,21 +891,23 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                 code.putln(value_code)
         code.putln(footer)
 
-    def generate_typeobject_predeclaration(self, entry, code):
+    def generate_typeobj_predeclaration(self, entry, code):
         code.putln("")
         name = entry.type.typeobj_cname
         if name:
             if entry.visibility == 'extern' and not entry.in_cinclude:
-                code.putln("%s DL_IMPORT(PyTypeObject) %s;" % (
+                code.putln("%s %s %s;" % (
                     Naming.extern_c_macro,
+                    PyrexTypes.public_decl("PyTypeObject", "DL_IMPORT"),
                     name))
             elif entry.visibility == 'public':
-                code.putln("%s DL_EXPORT(PyTypeObject) %s;" % (
+                code.putln("%s %s %s;" % (
                     Naming.extern_c_macro,
+                    PyrexTypes.public_decl("PyTypeObject", "DL_EXPORT"),
                     name))
             # ??? Do we really need the rest of this? ???
             #else:
-            #    code.putln("staticforward PyTypeObject %s;" % name)
+            #    code.putln("static PyTypeObject %s;" % name)
 
     def generate_exttype_vtable_struct(self, entry, code):
         code.mark_pos(entry.pos)
@@ -927,7 +947,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
             return # Forward declared but never defined
         header, footer = \
             self.sue_header_footer(type, "struct", type.objstruct_cname)
-        code.putln("")
         code.putln(header)
         base_type = type.base_type
         if base_type:
@@ -966,24 +985,26 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         for entry in env.cfunc_entries:
             if entry.inline_func_in_pxd or (not entry.in_cinclude and (definition
                     or entry.defined_in_pxd or entry.visibility == 'extern')):
-                if entry.visibility in ('public', 'extern'):
+                if entry.visibility == 'public':
+                    storage_class = "%s " % Naming.extern_c_macro
                     dll_linkage = "DL_EXPORT"
+                elif entry.visibility == 'extern':
+                    storage_class = "%s " % Naming.extern_c_macro
+                    dll_linkage = "DL_IMPORT"
+                elif entry.visibility == 'private':
+                    storage_class = "static "
+                    dll_linkage = None
                 else:
+                    storage_class = "static "
                     dll_linkage = None
                 type = entry.type
+                
                 if not definition and entry.defined_in_pxd:
                     type = CPtrType(type)
                 header = type.declaration_code(entry.cname,
-                    dll_linkage = dll_linkage)
-                if entry.visibility == 'private':
-                    storage_class = "static "
-                elif entry.visibility == 'public':
-                    storage_class = ""
-                else:
-                    storage_class = "%s " % Naming.extern_c_macro
+                                               dll_linkage = dll_linkage)
                 if entry.func_modifiers:
-                    modifiers = '%s ' % ' '.join([
-                            modifier.upper() for modifier in entry.func_modifiers])
+                    modifiers = "%s " % ' '.join(entry.func_modifiers).upper()
                 else:
                     modifiers = ''
                 code.putln("%s%s%s; /*proto*/" % (
@@ -1806,6 +1827,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         code.putln("/*--- Global init code ---*/")
         self.generate_global_init_code(env, code)
 
+        code.putln("/*--- Variable export code ---*/")
+        self.generate_c_variable_export_code(env, code)
+
         code.putln("/*--- Function export code ---*/")
         self.generate_c_function_export_code(env, code)
 
@@ -1993,6 +2017,18 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                 if entry.type.is_pyobject and entry.used:
                     code.put_init_var_to_py_none(entry, nanny=False)
 
+    def generate_c_variable_export_code(self, env, code):
+        # Generate code to create PyCFunction wrappers for exported C functions.
+        for entry in env.var_entries:
+            if entry.api or entry.defined_in_pxd:
+                env.use_utility_code(voidptr_export_utility_code)
+                signature = entry.type.declaration_code("")
+                code.putln('if (__Pyx_ExportVoidPtr("%s", (void *)&%s, "%s") < 0) %s' % (
+                    entry.name,
+                    entry.cname,
+                    signature,
+                    code.error_goto(self.pos)))
+
     def generate_c_function_export_code(self, env, code):
         # Generate code to create PyCFunction wrappers for exported C functions.
         for entry in env.cfunc_entries:
@@ -2336,6 +2372,45 @@ bad:
 
 #------------------------------------------------------------------------------------
 
+voidptr_export_utility_code = UtilityCode(
+proto = """
+static int __Pyx_ExportVoidPtr(const char *name, void *p, const char *sig); /*proto*/
+""",
+impl = r"""
+static int __Pyx_ExportVoidPtr(const char *name, void *p, const char *sig) {
+    PyObject *d = 0;
+    PyObject *cobj = 0;
+
+    d = PyObject_GetAttrString(%(MODULE)s, (char *)"%(API)s");
+    if (!d) {
+        PyErr_Clear();
+        d = PyDict_New();
+        if (!d)
+            goto bad;
+        Py_INCREF(d);
+        if (PyModule_AddObject(%(MODULE)s, (char *)"%(API)s", d) < 0)
+            goto bad;
+    }
+#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
+    cobj = PyCapsule_New(p, sig, 0);
+#else
+    cobj = PyCObject_FromVoidPtrAndDesc(p, (void *)sig, 0);
+#endif
+    if (!cobj)
+        goto bad;
+    if (PyDict_SetItemString(d, name, cobj) < 0)
+        goto bad;
+    Py_DECREF(cobj);
+    Py_DECREF(d);
+    return 0;
+bad:
+    Py_XDECREF(cobj);
+    Py_XDECREF(d);
+    return -1;
+}
+""" % {'MODULE': Naming.module_cname, 'API': Naming.api_name}
+)
+
 function_export_utility_code = UtilityCode(
 proto = """
 static int __Pyx_ExportFunction(const char *name, void (*f)(void), const char *sig); /*proto*/
@@ -2380,6 +2455,62 @@ bad:
 """ % {'MODULE': Naming.module_cname, 'API': Naming.api_name}
 )
 
+voidptr_import_utility_code = UtilityCode(
+proto = """
+static int __Pyx_ImportVoidPtr(PyObject *module, const char *name, void **p, const char *sig); /*proto*/
+""",
+impl = """
+#ifndef __PYX_HAVE_RT_ImportVoidPtr
+#define __PYX_HAVE_RT_ImportVoidPtr
+static int __Pyx_ImportVoidPtr(PyObject *module, const char *name, void **p, const char *sig) {
+    PyObject *d = 0;
+    PyObject *cobj = 0;
+
+    d = PyObject_GetAttrString(module, (char *)"%(API)s");
+    if (!d)
+        goto bad;
+    cobj = PyDict_GetItemString(d, name);
+    if (!cobj) {
+        PyErr_Format(PyExc_ImportError,
+            "%%s does not export expected C variable %%s",
+                PyModule_GetName(module), name);
+        goto bad;
+    }
+#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
+    if (!PyCapsule_IsValid(cobj, sig)) {
+        PyErr_Format(PyExc_TypeError,
+            "C variable %%s.%%s has wrong signature (expected %%s, got %%s)",
+             PyModule_GetName(module), name, sig, PyCapsule_GetName(cobj));
+        goto bad;
+    }
+    *p = PyCapsule_GetPointer(cobj, sig);
+#else
+    {const char *desc, *s1, *s2;
+    desc = (const char *)PyCObject_GetDesc(cobj);
+    if (!desc)
+        goto bad;
+    s1 = desc; s2 = sig;
+    while (*s1 != '\\0' && *s1 == *s2) { s1++; s2++; }
+    if (*s1 != *s2) {
+        PyErr_Format(PyExc_TypeError,
+            "C variable %%s.%%s has wrong signature (expected %%s, got %%s)",
+             PyModule_GetName(module), name, sig, desc);
+        goto bad;
+    }
+    *p = PyCObject_AsVoidPtr(cobj);}
+#endif
+    if (!(*p))
+        goto bad;
+    Py_DECREF(d);
+    return 0;
+bad:
+    Py_XDECREF(d);
+    return -1;
+}
+#endif
+""" % dict(API = Naming.api_name)
+)
+
 function_import_utility_code = UtilityCode(
 proto = """
 static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (**f)(void), const char *sig); /*proto*/
index 609489f1758a09bde72f7a7476c64ed54c8d809f..7b91add2c5c0f4f2401b00cc5ed049345b5f2ae7 100644 (file)
@@ -970,7 +970,7 @@ class CVarDefNode(StatNode):
                     error(self.pos,
                         "Only 'extern' C variable declaration allowed in .pxd file")
                 entry = dest_scope.declare_var(name, type, declarator.pos,
-                            cname = cname, visibility = visibility, is_cdef = 1)
+                            cname=cname, visibility=visibility, api=self.api, is_cdef=1)
                 entry.needs_property = need_property
 
 
@@ -980,6 +980,7 @@ class CStructOrUnionDefNode(StatNode):
     #  kind          "struct" or "union"
     #  typedef_flag  boolean
     #  visibility    "public" or "private"
+    #  api           boolean
     #  in_pxd        boolean
     #  attributes    [CVarDefNode] or None
     #  entry         Entry
@@ -995,7 +996,8 @@ class CStructOrUnionDefNode(StatNode):
             scope = StructOrUnionScope(self.name)
         self.entry = env.declare_struct_or_union(
             self.name, self.kind, scope, self.typedef_flag, self.pos,
-            self.cname, visibility = self.visibility, packed = self.packed)
+            self.cname, visibility = self.visibility, api = self.api,
+            packed = self.packed)
         if self.attributes is not None:
             if self.in_pxd and not env.in_cinclude:
                 self.entry.defined_in_pxd = 1
@@ -1078,15 +1080,16 @@ class CEnumDefNode(StatNode):
     #  items          [CEnumDefItemNode]
     #  typedef_flag   boolean
     #  visibility     "public" or "private"
+    #  api            boolean
     #  in_pxd         boolean
     #  entry          Entry
-
+    
     child_attrs = ["items"]
 
     def analyse_declarations(self, env):
         self.entry = env.declare_enum(self.name, self.pos,
             cname = self.cname, typedef_flag = self.typedef_flag,
-            visibility = self.visibility)
+            visibility = self.visibility, api = self.api)
         if self.items is not None:
             if self.in_pxd and not env.in_cinclude:
                 self.entry.defined_in_pxd = 1
@@ -1097,7 +1100,7 @@ class CEnumDefNode(StatNode):
         pass
 
     def generate_execution_code(self, code):
-        if self.visibility == 'public':
+        if self.visibility == 'public' or self.api:
             temp = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True)
             for item in self.entry.enum_values:
                 code.putln("%s = PyInt_FromLong(%s); %s" % (
@@ -1127,9 +1130,9 @@ class CEnumDefItemNode(StatNode):
             if not self.value.type.is_int:
                 self.value = self.value.coerce_to(PyrexTypes.c_int_type, env)
                 self.value.analyse_const_expression(env)
-        entry = env.declare_const(self.name, enum_entry.type,
+        entry = env.declare_const(self.name, enum_entry.type, 
             self.value, self.pos, cname = self.cname,
-            visibility = enum_entry.visibility)
+            visibility = enum_entry.visibility, api = enum_entry.api)
         enum_entry.enum_values.append(entry)
 
 
@@ -1137,6 +1140,7 @@ class CTypeDefNode(StatNode):
     #  base_type    CBaseTypeNode
     #  declarator   CDeclaratorNode
     #  visibility   "public" or "private"
+    #  api          boolean
     #  in_pxd       boolean
 
     child_attrs = ["base_type", "declarator"]
@@ -1147,10 +1151,10 @@ class CTypeDefNode(StatNode):
         name = name_declarator.name
         cname = name_declarator.cname
         entry = env.declare_typedef(name, type, self.pos,
-            cname = cname, visibility = self.visibility)
+            cname = cname, visibility = self.visibility, api = self.api)
         if self.in_pxd and not env.in_cinclude:
             entry.defined_in_pxd = 1
-
+    
     def analyse_expressions(self, env):
         pass
     def generate_execution_code(self, code):
@@ -1740,7 +1744,6 @@ class CFuncDefNode(FuncDefNode):
     def generate_function_header(self, code, with_pymethdef, with_opt_args = 1, with_dispatch = 1, cname = None):
         arg_decls = []
         type = self.type
-        visibility = self.entry.visibility
         for arg in type.args[:len(type.args)-type.optional_arg_count]:
             arg_decls.append(arg.declaration_code())
         if with_dispatch and self.overridable:
@@ -1754,24 +1757,20 @@ class CFuncDefNode(FuncDefNode):
         if cname is None:
             cname = self.entry.func_cname
         entity = type.function_header_code(cname, ', '.join(arg_decls))
-        if visibility == 'public':
-            dll_linkage = "DL_EXPORT"
+        if self.entry.visibility == 'private':
+            storage_class = "static "
         else:
-            dll_linkage = None
-        header = self.return_type.declaration_code(entity,
-            dll_linkage = dll_linkage)
-        if visibility == 'extern':
-            storage_class = "%s " % Naming.extern_c_macro
-        elif visibility == 'public':
             storage_class = ""
-        else:
-            storage_class = "static "
+        dll_linkage = None
+        modifiers = ""
         if 'inline' in self.modifiers:
             self.modifiers[self.modifiers.index('inline')] = 'cython_inline'
-        code.putln("%s%s %s {" % (
-            storage_class,
-            ' '.join(self.modifiers).upper(), # macro forms
-            header))
+        if self.modifiers:
+            modifiers = "%s " % ' '.join(self.modifiers).upper()
+        
+        header = self.return_type.declaration_code(entity, dll_linkage=dll_linkage)
+        #print (storage_class, modifiers, header)
+        code.putln("%s%s%s {" % (storage_class, modifiers, header))
 
     def generate_argument_declarations(self, env, code):
         for arg in self.args:
index 91ddf6a7f9ae25881bb97947779054e8f70b5747..fcd0a4e67be198a65f99ea05770e049eb0b011d8 100644 (file)
@@ -2420,7 +2420,7 @@ def p_c_enum_definition(s, pos, ctx):
     return Nodes.CEnumDefNode(
         pos, name = name, cname = cname, items = items,
         typedef_flag = ctx.typedef_flag, visibility = ctx.visibility,
-        in_pxd = ctx.level == 'module_pxd')
+        api = ctx.api, in_pxd = ctx.level == 'module_pxd')
 
 def p_c_enum_line(s, ctx, items):
     if s.sy != 'pass':
@@ -2478,10 +2478,10 @@ def p_c_struct_or_union_definition(s, pos, ctx):
         s.expect_dedent()
     else:
         s.expect_newline("Syntax error in struct or union definition")
-    return Nodes.CStructOrUnionDefNode(pos,
+    return Nodes.CStructOrUnionDefNode(pos, 
         name = name, cname = cname, kind = kind, attributes = attributes,
         typedef_flag = ctx.typedef_flag, visibility = ctx.visibility,
-        in_pxd = ctx.level == 'module_pxd', packed = packed)
+        api = ctx.api, in_pxd = ctx.level == 'module_pxd', packed = packed)
 
 def p_visibility(s, prev_visibility):
     pos = s.position()
@@ -2566,7 +2566,8 @@ def p_ctypedef_statement(s, ctx):
         s.expect_newline("Syntax error in ctypedef statement")
         return Nodes.CTypeDefNode(
             pos, base_type = base_type,
-            declarator = declarator, visibility = visibility,
+            declarator = declarator, 
+            visibility = visibility, api = api,
             in_pxd = ctx.level == 'module_pxd')
 
 def p_decorators(s):
@@ -2693,8 +2694,8 @@ def p_c_class_definition(s, pos,  ctx):
         base_class_module = ".".join(base_class_path[:-1])
         base_class_name = base_class_path[-1]
     if s.sy == '[':
-        if ctx.visibility not in ('public', 'extern'):
-            error(s.position(), "Name options only allowed for 'public' or 'extern' C class")
+        if ctx.visibility not in ('public', 'extern') and not ctx.api:
+            error(s.position(), "Name options only allowed for 'public', 'api', or 'extern' C class")
         objstruct_name, typeobj_name = p_c_class_options(s)
     if s.sy == ':':
         if ctx.level == 'module_pxd':
@@ -2718,7 +2719,10 @@ def p_c_class_definition(s, pos,  ctx):
             error(pos, "Type object name specification required for 'public' C class")
     elif ctx.visibility == 'private':
         if ctx.api:
-            error(pos, "Only 'public' C class can be declared 'api'")
+            if not objstruct_name:
+                error(pos, "Object struct name specification required for 'api' C class")
+            if not typeobj_name:
+                error(pos, "Type object name specification required for 'api' C class")
     else:
         error(pos, "Invalid class visibility '%s'" % ctx.visibility)
     return Nodes.CClassDefNode(pos,
index a5bbb787e0eace26a6c7e1ac4e88e67c36bbccd1..b62a076418faf4b164b6ced63090b9775ddd0a31 100755 (executable)
@@ -1190,8 +1190,8 @@ class CComplexType(CNumericType):
                     visibility="extern")
             scope.parent_type = self
             scope.directives = {}
-            scope.declare_var("real", self.real_type, None, "real", is_cdef=True)
-            scope.declare_var("imag", self.real_type, None, "imag", is_cdef=True)
+            scope.declare_var("real", self.real_type, None, cname="real", is_cdef=True)
+            scope.declare_var("imag", self.real_type, None, cname="imag", is_cdef=True)
             entry = scope.declare_cfunction(
                     "conjugate",
                     CFuncType(self, [CFuncTypeArg("self", self, None)], nogil=True),
index d5c8dd20e3c4a6c530fdbdb8f6f325d8785b9b1f..5b7edc2f32dd95447422c732d7b79214ae31b7df 100644 (file)
@@ -361,10 +361,10 @@ class Scope(object):
     def qualify_name(self, name):
         return EncodedString("%s.%s" % (self.qualified_name, name))
 
-    def declare_const(self, name, type, value, pos, cname = None, visibility = 'private'):
+    def declare_const(self, name, type, value, pos, cname = None, visibility = 'private', api = 0):
         # Add an entry for a named constant.
         if not cname:
-            if self.in_cinclude or visibility == 'public':
+            if self.in_cinclude or (visibility == 'public' or api):
                 cname = name
             else:
                 cname = self.mangle(Naming.enum_prefix, name)
@@ -374,21 +374,22 @@ class Scope(object):
         return entry
 
     def declare_type(self, name, type, pos,
-            cname = None, visibility = 'private', defining = 1, shadow = 0):
+            cname = None, visibility = 'private', api = 0, defining = 1, shadow = 0):
         # Add an entry for a type definition.
         if not cname:
             cname = name
         entry = self.declare(name, cname, type, pos, visibility, shadow)
         entry.is_type = 1
+        entry.api = api
         if defining:
             self.type_entries.append(entry)
         # here we would set as_variable to an object representing this type
         return entry
 
     def declare_typedef(self, name, base_type, pos, cname = None,
-            visibility = 'private'):
+                        visibility = 'private', api = 0):
         if not cname:
-            if self.in_cinclude or visibility == 'public':
+            if self.in_cinclude or (visibility == 'public' or api):
                 cname = name
             else:
                 cname = self.mangle(Naming.type_prefix, name)
@@ -398,16 +399,18 @@ class Scope(object):
         except ValueError, e:
             error(pos, e.args[0])
             type = PyrexTypes.error_type
-        entry = self.declare_type(name, type, pos, cname, visibility)
+        entry = self.declare_type(name, type, pos, cname, 
+                                  visibility = visibility, api = api)
         type.qualified_name = entry.qualified_name
         return entry
-
-    def declare_struct_or_union(self, name, kind, scope,
-            typedef_flag, pos, cname = None, visibility = 'private',
-            packed = False):
+        
+    def declare_struct_or_union(self, name, kind, scope, 
+                                typedef_flag, pos, cname = None, 
+                                visibility = 'private', api = 0,
+                                packed = False):
         # Add an entry for a struct or union definition.
         if not cname:
-            if self.in_cinclude or visibility == 'public':
+            if self.in_cinclude or (visibility == 'public' or api):
                 cname = name
             else:
                 cname = self.mangle(Naming.type_prefix, name)
@@ -416,7 +419,8 @@ class Scope(object):
             type = PyrexTypes.CStructOrUnionType(
                 name, kind, scope, typedef_flag, cname, packed)
             entry = self.declare_type(name, type, pos, cname,
-                visibility = visibility, defining = scope is not None)
+                visibility = visibility, api = api,
+                defining = scope is not None)
             self.sue_entries.append(entry)
             type.entry = entry
         else:
@@ -482,12 +486,12 @@ class Scope(object):
         if entry.visibility != visibility:
             error(pos, "'%s' previously declared as '%s'" % (
                 entry.name, entry.visibility))
-
+    
     def declare_enum(self, name, pos, cname, typedef_flag,
-            visibility = 'private'):
+            visibility = 'private', api = 0):
         if name:
             if not cname:
-                if self.in_cinclude or visibility == 'public':
+                if self.in_cinclude or (visibility == 'public' or api):
                     cname = name
                 else:
                     cname = self.mangle(Naming.type_prefix, name)
@@ -495,13 +499,13 @@ class Scope(object):
         else:
             type = PyrexTypes.c_anon_enum_type
         entry = self.declare_type(name, type, pos, cname = cname,
-            visibility = visibility)
+            visibility = visibility, api = api)
         entry.enum_values = []
         self.sue_entries.append(entry)
-        return entry
+        return entry    
 
     def declare_var(self, name, type, pos,
-            cname = None, visibility = 'private', is_cdef = 0):
+                    cname = None, visibility = 'private', api = 0, is_cdef = 0):
         # Add an entry for a variable.
         if not cname:
             if visibility != 'private':
@@ -514,6 +518,7 @@ class Scope(object):
                 error(pos, "C++ class must have a default constructor to be stack allocated")
         entry = self.declare(name, cname, type, pos, visibility)
         entry.is_variable = 1
+        entry.api = api
         self.control_flow.set_state((), (name, 'initialized'), False)
         return entry
 
@@ -995,13 +1000,13 @@ class ModuleScope(Scope):
         return entry
 
     def declare_var(self, name, type, pos,
-            cname = None, visibility = 'private', is_cdef = 0):
+                    cname = None, visibility = 'private', api = 0, is_cdef = 0):
         # Add an entry for a global variable. If it is a Python
         # object type, and not declared with cdef, it will live
         # in the module dictionary, otherwise it will be a C
         # global variable.
         entry = Scope.declare_var(self, name, type, pos,
-            cname, visibility, is_cdef)
+                                  cname=cname, visibility=visibility, api=api, is_cdef=is_cdef)
         if not visibility in ('private', 'public', 'extern'):
             error(pos, "Module-level variable cannot be declared %s" % visibility)
         if not is_cdef:
@@ -1033,10 +1038,10 @@ class ModuleScope(Scope):
         buffer_defaults = None, shadow = 0):
         # If this is a non-extern typedef class, expose the typedef, but use
         # the non-typedef struct internally to avoid needing forward
-        # declarations for anonymous structs.
+        # declarations for anonymous structs. 
         if typedef_flag and visibility != 'extern':
-            if visibility != 'public':
-                warning(pos, "ctypedef only valid for public and extern classes", 2)
+            if not (visibility == 'public' or api):
+                warning(pos, "ctypedef only valid for 'extern' , 'public', and 'api'", 2)
             objtypedef_cname = objstruct_cname
             typedef_flag = 0
         else:
@@ -1283,12 +1288,12 @@ class LocalScope(Scope):
         return entry
 
     def declare_var(self, name, type, pos,
-            cname = None, visibility = 'private', is_cdef = 0):
+                    cname = None, visibility = 'private', api = 0, is_cdef = 0):
         # Add an entry for a local variable.
         if visibility in ('public', 'readonly'):
             error(pos, "Local variable cannot be declared %s" % visibility)
         entry = Scope.declare_var(self, name, type, pos,
-            cname, visibility, is_cdef)
+                                  cname=cname, visibility=visibility, api=api, is_cdef=is_cdef)
         if type.is_pyobject and not Options.init_local_none:
             entry.init = "0"
         entry.init_to_none = (type.is_pyobject or type.is_unspecified) and Options.init_local_none
@@ -1354,7 +1359,7 @@ class GeneratorExpressionScope(Scope):
         return '%s%s' % (self.genexp_prefix, self.parent_scope.mangle(prefix, name))
 
     def declare_var(self, name, type, pos,
-                    cname = None, visibility = 'private', is_cdef = True):
+                    cname = None, visibility = 'private', api = 0, is_cdef = True):
         if type is unspecified_type:
             # if the outer scope defines a type for this variable, inherit it
             outer_entry = self.outer_scope.lookup(name)
@@ -1397,7 +1402,7 @@ class StructOrUnionScope(Scope):
         Scope.__init__(self, name, None, None)
 
     def declare_var(self, name, type, pos,
-            cname = None, visibility = 'private', is_cdef = 0, allow_pyobject = 0):
+                    cname = None, visibility = 'private', api = 0, is_cdef = 0, allow_pyobject = 0):
         # Add an entry for an attribute.
         if not cname:
             cname = name
@@ -1419,7 +1424,8 @@ class StructOrUnionScope(Scope):
     def declare_cfunction(self, name, type, pos,
                           cname = None, visibility = 'private', defining = 0,
                           api = 0, in_pxd = 0, modifiers = ()): # currently no utility code ...
-        return self.declare_var(name, type, pos, cname, visibility)
+        return self.declare_var(name, type, pos, 
+                                cname=cname, visibility=visibility)
 
 class ClassScope(Scope):
     #  Abstract base class for namespace of
@@ -1463,12 +1469,12 @@ class PyClassScope(ClassScope):
     is_py_class_scope = 1
 
     def declare_var(self, name, type, pos,
-            cname = None, visibility = 'private', is_cdef = 0):
+                    cname = None, visibility = 'private', api = 0, is_cdef = 0):
         if type is unspecified_type:
             type = py_object_type
         # Add an entry for a class attribute.
         entry = Scope.declare_var(self, name, type, pos,
-            cname, visibility, is_cdef)
+                                  cname=cname, visibility=visibility, api=api, is_cdef=is_cdef)
         entry.is_pyglobal = 1
         entry.is_pyclass_attr = 1
         return entry
@@ -1513,7 +1519,7 @@ class CClassScope(ClassScope):
                 self.parent_type.base_type.scope.needs_gc())
 
     def declare_var(self, name, type, pos,
-            cname = None, visibility = 'private', is_cdef = 0):
+                    cname = None, visibility = 'private', api = 0, is_cdef = 0):
         if is_cdef:
             # Add an entry for an attribute.
             if self.defined:
@@ -1553,7 +1559,7 @@ class CClassScope(ClassScope):
                 type = py_object_type
             # Add an entry for a class attribute.
             entry = Scope.declare_var(self, name, type, pos,
-                cname, visibility, is_cdef)
+                                      cname=cname, visibility=visibility, api=api, is_cdef=is_cdef)
             entry.is_member = 1
             entry.is_pyglobal = 1 # xxx: is_pyglobal changes behaviour in so many places that
                                   # I keep it in for now. is_member should be enough
@@ -1569,7 +1575,8 @@ class CClassScope(ClassScope):
         if name == "__new__":
             error(pos, "__new__ method of extension type will change semantics "
                 "in a future version of Pyrex and Cython. Use __cinit__ instead.")
-        entry = self.declare_var(name, py_object_type, pos, visibility='extern')
+        entry = self.declare_var(name, py_object_type, pos, 
+                                 visibility='extern')
         special_sig = get_special_method_signature(name)
         if special_sig:
             # Special methods get put in the method table with a particular
@@ -1694,7 +1701,8 @@ class CppClassScope(Scope):
         self.inherited_var_entries = []
 
     def declare_var(self, name, type, pos,
-            cname = None, visibility = 'extern', is_cdef = 0, allow_pyobject = 0):
+                    cname = None, visibility = 'extern', api = 0, 
+                    is_cdef = 0, allow_pyobject = 0):
         # Add an entry for an attribute.
         if not cname:
             cname = name
@@ -1735,15 +1743,16 @@ class CppClassScope(Scope):
             error(pos, "no matching function for call to %s::%s()" %
                   (self.default_constructor, self.default_constructor))
 
-    def declare_cfunction(self, name, type, pos,
-            cname = None, visibility = 'extern', defining = 0,
-            api = 0, in_pxd = 0, modifiers = (), utility_code = None):
+    def declare_cfunction(self, name, type, pos, cname = None, 
+                          visibility = 'extern', api = 0, defining = 0,
+                          in_pxd = 0, modifiers = (), utility_code = None):
         if name == self.name.split('::')[-1] and cname is None:
             self.check_base_default_constructor(pos)
             name = '<init>'
             type.return_type = self.lookup(self.name).type
         prev_entry = self.lookup_here(name)
-        entry = self.declare_var(name, type, pos, cname, visibility)
+        entry = self.declare_var(name, type, pos, 
+                                 cname=cname, visibility=visibility)
         if prev_entry:
             entry.overloaded_alternatives = prev_entry.all_alternatives()
         entry.utility_code = utility_code
@@ -1767,8 +1776,9 @@ class CppClassScope(Scope):
                 self.inherited_var_entries.append(entry)
         for base_entry in base_scope.cfunc_entries:
             entry = self.declare_cfunction(base_entry.name, base_entry.type,
-                                       base_entry.pos, base_entry.cname,
-                                       base_entry.visibility, base_entry.func_modifiers,
+                                           base_entry.pos, base_entry.cname,
+                                           base_entry.visibility, 0,
+                                           modifiers = base_entry.func_modifiers,
                                            utility_code = base_entry.utility_code)
             entry.is_inherited = 1
 
index 710a7095444d8d5444fc2aa2d63f5c122d97233f..d4acf9c373d88fc7ff62f810debf31444f05b684 100644 (file)
@@ -11,6 +11,12 @@ cdef public class C[type C_Type, object C_Obj]:
 
 cdef public Zax *blarg
 
+cdef public C c_pub = C()
+cdef api    C c_api = C()
+
+cdef public dict o_pub = C()
+cdef api    list o_api = C()
+
 cdef api float f(Foo *x):
     pass
 
diff --git a/tests/compile/publicapi_api.pyx b/tests/compile/publicapi_api.pyx
new file mode 100644 (file)
index 0000000..e65e47a
--- /dev/null
@@ -0,0 +1,65 @@
+# --
+
+ctypedef     int Int0
+ctypedef api int Int1
+
+ctypedef     enum EnumA0: EA0
+ctypedef api enum EnumA1: EA1
+
+cdef     enum EnumB0: EB0=0
+cdef api enum EnumB1: EB1=1
+
+cdef Int0   i0  = 0
+cdef EnumA0 ea0 = EA0
+cdef EnumB0 eb0 = EB0
+
+cdef api Int1   i1  = 0
+cdef api EnumA1 ea1 = EA1
+cdef api EnumB1 eb1 = EB1
+
+# --
+
+ctypedef     struct StructA0:
+    int SA0
+ctypedef api struct StructA1:
+    int SA1
+
+cdef     struct StructB0:
+    int SB0
+cdef api struct StructB1:
+    int SB1
+
+cdef StructA0 sa0 = {'SA0':0}
+cdef StructB0 sb0 = {'SB0':2}
+
+cdef api StructA1 sa1 = {'SA1':1}
+cdef api StructB1 sb1 = {'SB1':3}
+
+# --
+
+ctypedef     class Foo0: pass
+ctypedef api class Foo1 [type PyFoo1_Type, object PyFoo1_Object]: pass
+
+cdef     class Bar0: pass
+cdef api class Bar1 [type PyBar1_Type, object PyBar1_Object]: pass
+
+cdef Foo0 f0 = None
+cdef Bar0 b0 = None
+
+cdef api Foo1 f1 = None
+cdef api Bar1 b1 = None
+
+# --
+
+cdef     void bar0(): pass
+cdef api void bar1(): pass
+
+cdef     void* spam0(object o) except NULL: return NULL
+cdef api void* spam1(object o) except NULL: return NULL
+
+bar0()
+bar1()
+spam0(None)
+spam1(None)
+
+# --
diff --git a/tests/compile/publicapi_mix.pyx b/tests/compile/publicapi_mix.pyx
new file mode 100644 (file)
index 0000000..93bd29e
--- /dev/null
@@ -0,0 +1,77 @@
+# --
+
+ctypedef            int Int0
+ctypedef public     int Int1
+ctypedef        api int Int2
+ctypedef public api int Int3
+
+ctypedef            enum EnumA0: EA0
+ctypedef public     enum EnumA1: EA1
+ctypedef        api enum EnumA2: EA2
+ctypedef public api enum EnumA3: EA3
+
+cdef            enum EnumB0: EB0=0
+cdef public     enum EnumB1: EB1=1
+cdef        api enum EnumB2: EB2=2
+cdef public api enum EnumB3: EB3=3
+
+# --
+
+ctypedef            struct StructA0: 
+    int SA0
+ctypedef public     struct StructA1: 
+    int SA1
+ctypedef        api struct StructA2:
+    int SA2
+ctypedef public api struct StructA3:
+    int SA3
+
+cdef            struct StructB0:
+    int SB0
+cdef public     struct StructB1:
+    int SB1
+cdef        api struct StructB2:
+    int SB2
+cdef public api struct StructB3:
+    int SB3
+
+# --
+
+ctypedef            class Foo0: pass
+ctypedef public     class Foo1 [type PyFoo1_Type, object PyFoo1_Object]: pass
+ctypedef        api class Foo2 [type PyFoo2_Type, object PyFoo2_Object]: pass
+ctypedef public api class Foo3 [type PyFoo3_Type, object PyFoo3_Object]: pass
+
+cdef            class Bar0: pass
+cdef public     class Bar1 [type PyBar1_Type, object PyBar1_Object]: pass
+cdef        api class Bar2 [type PyBar2_Type, object PyBar2_Object]: pass
+cdef public api class Bar3 [type PyBar3_Type, object PyBar3_Object]: pass
+
+# --
+
+cdef            void bar0(): pass
+cdef public     void bar1(): pass
+cdef        api void bar2(): pass
+cdef public api void bar3(): pass
+
+cdef            void* spam0(object o) except NULL: return NULL
+cdef public     void* spam1(object o) except NULL: return NULL
+cdef        api void* spam2(object o) except NULL: return NULL
+cdef public api void* spam3(object o) except NULL: return NULL
+
+bar0()
+spam0(None)
+
+# --
+
+cdef            double d0 = 0
+cdef public     double d1 = 1
+cdef        api double d2 = 2
+cdef public api double d3 = 3
+
+cdef            object o0 = None
+cdef public     object o1 = None
+cdef        api object o2 = None
+cdef public api object o3 = None
+
+# --
diff --git a/tests/compile/publicapi_pub.pyx b/tests/compile/publicapi_pub.pyx
new file mode 100644 (file)
index 0000000..2ff473a
--- /dev/null
@@ -0,0 +1,65 @@
+# --
+
+ctypedef        int Int0
+ctypedef public int Int1
+
+ctypedef        enum EnumA0: EA0
+ctypedef public enum EnumA1: EA1
+
+cdef        enum EnumB0: EB0=0
+cdef public enum EnumB1: EB1=1
+
+cdef Int0   i0  = 0
+cdef EnumA0 ea0 = EA0
+cdef EnumB0 eb0 = EB0
+
+cdef public Int1   i1  = 0
+cdef public EnumA1 ea1 = EA1
+cdef public EnumB1 eb1 = EB1
+
+# --
+
+ctypedef        struct StructA0:
+    int SA0
+ctypedef public struct StructA1:
+    int SA1
+
+cdef        struct StructB0:
+    int SB0
+cdef public struct StructB1:
+    int SB1
+
+cdef StructA0 sa0 = {'SA0':0}
+cdef StructB0 sb0 = {'SB0':2}
+
+cdef public StructA1 sa1 = {'SA1':1}
+cdef public StructB1 sb1 = {'SB1':3}
+
+# --
+
+ctypedef        class Foo0: pass
+ctypedef public class Foo1 [type PyFoo1_Type, object PyFoo1_Object]: pass
+
+cdef        class Bar0: pass
+cdef public class Bar1 [type PyBar1_Type, object PyBar1_Object]: pass
+
+cdef Foo0 f0 = None
+cdef Bar0 b0 = None
+
+cdef public Foo1 f1 = None
+cdef public Bar1 b1 = None
+
+# --
+
+cdef        void bar0(): pass
+cdef public void bar1(): pass
+
+cdef        void* spam0(object o) except NULL: return NULL
+cdef public void* spam1(object o) except NULL: return NULL
+
+bar0()
+bar1()
+spam0(None)
+spam1(None)
+
+# --
diff --git a/tests/compile/publicapi_pxd_mix.pxd b/tests/compile/publicapi_pxd_mix.pxd
new file mode 100644 (file)
index 0000000..1810c10
--- /dev/null
@@ -0,0 +1,68 @@
+# --
+
+ctypedef            int Int0
+ctypedef public     int Int1
+ctypedef        api int Int2
+ctypedef public api int Int3
+
+ctypedef            enum EnumA0: EA0
+ctypedef public     enum EnumA1: EA1
+ctypedef        api enum EnumA2: EA2
+ctypedef public api enum EnumA3: EA3
+
+cdef            enum EnumB0: EB0=0
+cdef public     enum EnumB1: EB1=1
+cdef        api enum EnumB2: EB2=2
+cdef public api enum EnumB3: EB3=3
+
+# --
+
+ctypedef            struct StructA0: 
+    int SA0
+ctypedef public     struct StructA1: 
+    int SA1
+ctypedef        api struct StructA2:
+    int SA2
+ctypedef public api struct StructA3:
+    int SA3
+
+cdef            struct StructB0:
+    int SB0
+cdef public     struct StructB1:
+    int SB1
+cdef        api struct StructB2:
+    int SB2
+cdef public api struct StructB3:
+    int SB3
+
+# --
+
+ctypedef            class Foo0: pass
+ctypedef public     class Foo1 [type PyFoo1_Type, object PyFoo1_Object]: pass
+ctypedef        api class Foo2 [type PyFoo2_Type, object PyFoo2_Object]: pass
+ctypedef public api class Foo3 [type PyFoo3_Type, object PyFoo3_Object]: pass
+
+cdef            class Bar0: pass
+cdef public     class Bar1 [type PyBar1_Type, object PyBar1_Object]: pass
+cdef        api class Bar2 [type PyBar2_Type, object PyBar2_Object]: pass
+cdef public api class Bar3 [type PyBar3_Type, object PyBar3_Object]: pass
+
+# --
+
+cdef inline     void bar0(): pass
+cdef public     void bar1()
+cdef        api void bar2()
+cdef public api void bar3()
+
+cdef inline     void* spam0(object o) except NULL: return NULL
+cdef public     void* spam1(object o) except NULL
+cdef        api void* spam2(object o) nogil except NULL
+cdef public api void* spam3(object o) except NULL with gil
+
+# --
+
+#cdef public     int i1
+#cdef        api int i2
+#cdef public api int i3
+
+# --
diff --git a/tests/compile/publicapi_pxd_mix.pyx b/tests/compile/publicapi_pxd_mix.pyx
new file mode 100644 (file)
index 0000000..242743f
--- /dev/null
@@ -0,0 +1,15 @@
+cdef class Foo1: pass
+cdef class Foo2: pass
+cdef class Foo3: pass
+
+cdef class Bar1: pass
+cdef class Bar2: pass
+cdef class Bar3: pass
+
+cdef public     void bar1(): pass
+cdef        api void bar2(): pass
+cdef public api void bar3(): pass
+
+cdef public     void* spam1(object o) except NULL: return NULL
+cdef        api void* spam2(object o) nogil except NULL: return NULL
+cdef public api void* spam3(object o) except NULL with gil: return NULL
index e7ea7e2b7f8fa89542860ca15468e8ee11c91ed9..4efe058219f0c286dc26d4f04bc9abb52adec0a5 100644 (file)
@@ -2,8 +2,20 @@ __doc__ = u"""
 >>> import sys
 >>> sys.getrefcount(Foo.__pyx_vtable__)
 2
->>> sys.getrefcount(__pyx_capi__['spam'])
+>>> sys.getrefcount(__pyx_capi__['ten'])
 2
+>>> sys.getrefcount(__pyx_capi__['pi'])
+2
+>>> sys.getrefcount(__pyx_capi__['obj'])
+2
+>>> sys.getrefcount(__pyx_capi__['dct'])
+2
+>>> sys.getrefcount(__pyx_capi__['one'])
+2
+>>> sys.getrefcount(__pyx_capi__['two'])
+Traceback (most recent call last):
+  ...
+KeyError: 'two'
 """
 
 cdef public api class Foo [type FooType, object FooObject]:
@@ -12,3 +24,12 @@ cdef public api class Foo [type FooType, object FooObject]:
 
 cdef api void spam():
     pass
+
+cdef api int    ten = 10
+cdef api double pi = 3.14
+cdef api object obj = object()
+cdef api dict   dct = {}
+
+cdef public api int one = 1
+cdef public     int two = 2
+