Commit 7c6f0728 authored by Lisandro Dalcin's avatar Lisandro Dalcin

Support pxd/public/api import/export for C variables

parent 4b89cc34
...@@ -8,6 +8,7 @@ Cython/Runtime/refnanny.c ...@@ -8,6 +8,7 @@ Cython/Runtime/refnanny.c
BUILD/ BUILD/
build/ build/
!tests/build/
dist/ dist/
.gitrev .gitrev
.coverage .coverage
......
...@@ -1166,39 +1166,19 @@ class CCodeWriter(object): ...@@ -1166,39 +1166,19 @@ class CCodeWriter(object):
self.funcstate.use_label(lbl) self.funcstate.use_label(lbl)
self.putln("goto %s;" % lbl) self.putln("goto %s;" % lbl)
def put_var_declarations(self, entries, static = 0, dll_linkage = None, def put_var_declaration(self, entry, storage_class="",
definition = True): dll_linkage = None, definition = True):
for entry in entries:
if not entry.in_cinclude:
self.put_var_declaration(entry, static, dll_linkage, definition)
def put_var_declaration(self, entry, static = 0, dll_linkage = None,
definition = True):
#print "Code.put_var_declaration:", entry.name, "definition =", definition ### #print "Code.put_var_declaration:", entry.name, "definition =", definition ###
if entry.in_closure: if entry.visibility == 'private' and not (definition or entry.defined_in_pxd):
return #print "...private and not definition, skipping", entry.cname ###
visibility = entry.visibility
if visibility == 'private' and not definition:
#print "...private and not definition, skipping" ###
return return
if not entry.used and visibility == "private": if entry.visibility == "private" and not entry.used:
#print "not used and private, skipping", entry.cname ### #print "...private and not used, skipping", entry.cname ###
return return
storage_class = ""
if visibility == 'extern':
storage_class = Naming.extern_c_macro
elif visibility == 'public':
if not definition:
storage_class = Naming.extern_c_macro
elif visibility == 'private':
if static:
storage_class = "static"
if storage_class: if storage_class:
self.put("%s " % storage_class) self.put("%s " % storage_class)
if visibility != 'public': self.put(entry.type.declaration_code(
dll_linkage = None entry.cname, dll_linkage = dll_linkage))
self.put(entry.type.declaration_code(entry.cname,
dll_linkage = dll_linkage))
if entry.init is not None: if entry.init is not None:
self.put_safe(" = %s" % entry.type.literal_code(entry.init)) self.put_safe(" = %s" % entry.type.literal_code(entry.init))
self.putln(";") self.putln(";")
......
...@@ -201,7 +201,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -201,7 +201,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
h_code.putln("") h_code.putln("")
for entry in api_vars: for entry in api_vars:
type = CPtrType(entry.type) type = CPtrType(entry.type)
cname = env.mangle(Naming.var_prefix, entry.name) cname = env.mangle(Naming.varptr_prefix, entry.name)
h_code.putln("static %s = 0;" % type.declaration_code(cname)) h_code.putln("static %s = 0;" % type.declaration_code(cname))
h_code.putln("#define %s (*%s)" % (entry.name, cname)) h_code.putln("#define %s (*%s)" % (entry.name, cname))
h_code.put(import_module_utility_code.impl) h_code.put(import_module_utility_code.impl)
...@@ -223,7 +223,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -223,7 +223,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
'if (__Pyx_ImportFunction(module, "%s", (void (**)(void))&%s, "%s") < 0) goto bad;' 'if (__Pyx_ImportFunction(module, "%s", (void (**)(void))&%s, "%s") < 0) goto bad;'
% (entry.name, cname, sig)) % (entry.name, cname, sig))
for entry in api_vars: for entry in api_vars:
cname = env.mangle(Naming.var_prefix, entry.name) cname = env.mangle(Naming.varptr_prefix, entry.name)
sig = entry.type.declaration_code("") sig = entry.type.declaration_code("")
h_code.putln( h_code.putln(
'if (__Pyx_ImportVoidPtr(module, "%s", (void **)&%s, "%s") < 0) goto bad;' 'if (__Pyx_ImportVoidPtr(module, "%s", (void **)&%s, "%s") < 0) goto bad;'
...@@ -290,7 +290,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -290,7 +290,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln('#define __Pyx_MODULE_NAME "%s"' % self.full_module_name) code.putln('#define __Pyx_MODULE_NAME "%s"' % self.full_module_name)
code.putln("int %s%s = 0;" % (Naming.module_is_main, self.full_module_name.replace('.', '__'))) code.putln("int %s%s = 0;" % (Naming.module_is_main, self.full_module_name.replace('.', '__')))
code.putln("") code.putln("")
code.putln("/* Implementation of %s */" % env.qualified_name) code.putln("/* Implementation of '%s' */" % env.qualified_name)
code = globalstate['all_the_rest'] code = globalstate['all_the_rest']
...@@ -449,17 +449,18 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -449,17 +449,18 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def generate_declarations_for_modules(self, env, modules, globalstate): def generate_declarations_for_modules(self, env, modules, globalstate):
typecode = globalstate['type_declarations'] typecode = globalstate['type_declarations']
typecode.putln("") typecode.putln("")
typecode.putln("/* Type declarations */") typecode.putln("/*--- Type declarations ---*/")
vtab_list, vtabslot_list = self.sort_type_hierarchy(modules, env) vtab_list, vtabslot_list = self.sort_type_hierarchy(modules, env)
self.generate_type_definitions( self.generate_type_definitions(
env, modules, vtab_list, vtabslot_list, typecode) env, modules, vtab_list, vtabslot_list, typecode)
modulecode = globalstate['module_declarations'] modulecode = globalstate['module_declarations']
for module in modules: for module in modules:
defined_here = module is env defined_here = module is env
modulecode.putln("/* Module declarations from %s */" % modulecode.putln("")
module.qualified_name) modulecode.putln("/* Module declarations from '%s' */" % module.qualified_name)
self.generate_global_declarations(module, modulecode, defined_here) self.generate_c_class_declarations(module, modulecode, defined_here)
self.generate_cfunction_predeclarations(module, modulecode, defined_here) self.generate_cvariable_declarations(module, modulecode, defined_here)
self.generate_cfunction_declarations(module, modulecode, defined_here)
def generate_module_preamble(self, env, cimported_modules, code): def generate_module_preamble(self, env, cimported_modules, code):
code.putln("/* Generated by Cython %s on %s */" % ( code.putln("/* Generated by Cython %s on %s */" % (
...@@ -978,25 +979,68 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -978,25 +979,68 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
# Only for exposing public typedef name. # Only for exposing public typedef name.
code.putln("typedef struct %s %s;" % (type.objstruct_cname, type.objtypedef_cname)) code.putln("typedef struct %s %s;" % (type.objstruct_cname, type.objtypedef_cname))
def generate_global_declarations(self, env, code, definition): def generate_c_class_declarations(self, env, code, definition):
code.putln("")
for entry in env.c_class_entries: for entry in env.c_class_entries:
if definition or entry.defined_in_pxd: if definition or entry.defined_in_pxd:
code.putln("static PyTypeObject *%s = 0;" % code.putln("static PyTypeObject *%s = 0;" %
entry.type.typeptr_cname) entry.type.typeptr_cname)
code.put_var_declarations(env.var_entries, static = 1,
dll_linkage = "DL_EXPORT", definition = definition)
def generate_cfunction_predeclarations(self, env, code, definition): def generate_cvariable_declarations(self, env, code, definition):
for entry in env.var_entries:
if (entry.in_cinclude or entry.in_closure or
(entry.visibility == 'private' and
not (entry.defined_in_pxd or entry.used))):
continue
storage_class = None
dll_linkage = None
cname = None
init = None
if entry.visibility == 'extern':
storage_class = Naming.extern_c_macro
dll_linkage = "DL_IMPORT"
elif entry.visibility == 'public':
if definition:
dll_linkage = "DL_EXPORT"
else:
storage_class = Naming.extern_c_macro
dll_linkage = "DL_IMPORT"
elif entry.visibility == 'private':
storage_class = "static"
if entry.defined_in_pxd and not definition:
type = CPtrType(entry.type)
storage_class = "static"
dll_linkage = None
cname = env.mangle(Naming.varptr_prefix, entry.name)
init = 0
else:
type = entry.type
cname = entry.cname
if entry.init is not None:
init = type.literal_code(entry.init)
if storage_class:
code.put("%s " % storage_class)
code.put(type.declaration_code(
cname, dll_linkage = dll_linkage))
if init is not None:
code.put_safe(" = %s" % init)
code.putln(";")
if entry.cname != cname:
code.putln("#define %s (*%s)" % (entry.cname, cname))
def generate_cfunction_declarations(self, env, code, definition):
for entry in env.cfunc_entries: for entry in env.cfunc_entries:
if entry.inline_func_in_pxd or (not entry.in_cinclude and (definition if entry.inline_func_in_pxd or (not entry.in_cinclude and (definition
or entry.defined_in_pxd or entry.visibility == 'extern')): or entry.defined_in_pxd or entry.visibility == 'extern')):
if entry.visibility == 'public': if entry.visibility == 'extern':
storage_class = ""
dll_linkage = "DL_EXPORT"
elif entry.visibility == 'extern':
storage_class = "%s " % Naming.extern_c_macro storage_class = "%s " % Naming.extern_c_macro
dll_linkage = "DL_IMPORT" dll_linkage = "DL_IMPORT"
elif entry.visibility == 'public':
storage_class = ""
dll_linkage = "DL_EXPORT"
elif entry.visibility == 'private': elif entry.visibility == 'private':
storage_class = "static " storage_class = "static "
dll_linkage = None dll_linkage = None
...@@ -1009,6 +1053,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1009,6 +1053,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
storage_class = "static " storage_class = "static "
dll_linkage = None dll_linkage = None
type = CPtrType(type) type = CPtrType(type)
header = type.declaration_code(entry.cname, header = type.declaration_code(entry.cname,
dll_linkage = dll_linkage) dll_linkage = dll_linkage)
if entry.func_modifiers: if entry.func_modifiers:
...@@ -1851,6 +1896,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1851,6 +1896,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
for module in imported_modules: for module in imported_modules:
self.generate_type_import_code_for_module(module, env, code) self.generate_type_import_code_for_module(module, env, code)
code.putln("/*--- Variable import code ---*/")
for module in imported_modules:
self.generate_c_variable_import_code_for_module(module, env, code)
code.putln("/*--- Function import code ---*/") code.putln("/*--- Function import code ---*/")
for module in imported_modules: for module in imported_modules:
self.generate_c_function_import_code_for_module(module, env, code) self.generate_c_function_import_code_for_module(module, env, code)
...@@ -2030,21 +2079,27 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -2030,21 +2079,27 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def generate_c_variable_export_code(self, env, code): def generate_c_variable_export_code(self, env, code):
# Generate code to create PyCFunction wrappers for exported C functions. # Generate code to create PyCFunction wrappers for exported C functions.
entries = []
for entry in env.var_entries: for entry in env.var_entries:
if entry.api or entry.defined_in_pxd: if entry.api or entry.defined_in_pxd:
env.use_utility_code(voidptr_export_utility_code) entries.append(entry)
if entries:
env.use_utility_code(voidptr_export_utility_code)
for entry in entries:
signature = entry.type.declaration_code("") signature = entry.type.declaration_code("")
code.putln('if (__Pyx_ExportVoidPtr("%s", (void *)&%s, "%s") < 0) %s' % ( code.putln('if (__Pyx_ExportVoidPtr("%s", (void *)&%s, "%s") < 0) %s' % (
entry.name, entry.name, entry.cname, signature,
entry.cname,
signature,
code.error_goto(self.pos))) code.error_goto(self.pos)))
def generate_c_function_export_code(self, env, code): def generate_c_function_export_code(self, env, code):
# Generate code to create PyCFunction wrappers for exported C functions. # Generate code to create PyCFunction wrappers for exported C functions.
entries = []
for entry in env.cfunc_entries: for entry in env.cfunc_entries:
if entry.api or entry.defined_in_pxd: if entry.api or entry.defined_in_pxd:
env.use_utility_code(function_export_utility_code) entries.append(entry)
if entries:
env.use_utility_code(function_export_utility_code)
for entry in entries:
signature = entry.type.signature_string() signature = entry.type.signature_string()
code.putln('if (__Pyx_ExportFunction("%s", (void (*)(void))%s, "%s") < 0) %s' % ( code.putln('if (__Pyx_ExportFunction("%s", (void (*)(void))%s, "%s") < 0) %s' % (
entry.name, entry.name,
...@@ -2060,6 +2115,34 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -2060,6 +2115,34 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
if entry.defined_in_pxd: if entry.defined_in_pxd:
self.generate_type_import_code(env, entry.type, entry.pos, code) self.generate_type_import_code(env, entry.type, entry.pos, code)
def generate_c_variable_import_code_for_module(self, module, env, code):
# Generate import code for all exported C functions in a cimported module.
entries = []
for entry in module.var_entries:
if entry.defined_in_pxd:
entries.append(entry)
if entries:
env.use_utility_code(import_module_utility_code)
env.use_utility_code(voidptr_import_utility_code)
temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
code.putln(
'%s = __Pyx_ImportModule("%s"); if (!%s) %s' % (
temp,
module.qualified_name,
temp,
code.error_goto(self.pos)))
for entry in entries:
if env is module:
cname = entry.cname
else:
cname = module.mangle(Naming.varptr_prefix, entry.name)
signature = entry.type.declaration_code("")
code.putln(
'if (__Pyx_ImportVoidPtr(%s, "%s", (void **)&%s, "%s") < 0) %s' % (
temp, entry.name, cname, signature,
code.error_goto(self.pos)))
code.putln("Py_DECREF(%s); %s = 0;" % (temp, temp))
def generate_c_function_import_code_for_module(self, module, env, code): def generate_c_function_import_code_for_module(self, module, env, code):
# Generate import code for all exported C functions in a cimported module. # Generate import code for all exported C functions in a cimported module.
entries = [] entries = []
......
...@@ -36,6 +36,7 @@ prop_set_prefix = pyrex_prefix + "setprop_" ...@@ -36,6 +36,7 @@ prop_set_prefix = pyrex_prefix + "setprop_"
type_prefix = pyrex_prefix + "t_" type_prefix = pyrex_prefix + "t_"
typeobj_prefix = pyrex_prefix + "type_" typeobj_prefix = pyrex_prefix + "type_"
var_prefix = pyrex_prefix + "v_" var_prefix = pyrex_prefix + "v_"
varptr_prefix = pyrex_prefix + "vp_"
wrapperbase_prefix= pyrex_prefix + "wrapperbase_" wrapperbase_prefix= pyrex_prefix + "wrapperbase_"
bufstruct_prefix = pyrex_prefix + "bstruct_" bufstruct_prefix = pyrex_prefix + "bstruct_"
bufstride_prefix = pyrex_prefix + "bstride_" bufstride_prefix = pyrex_prefix + "bstride_"
......
...@@ -969,18 +969,16 @@ class CVarDefNode(StatNode): ...@@ -969,18 +969,16 @@ class CVarDefNode(StatNode):
return return
if type.is_cfunction: if type.is_cfunction:
entry = dest_scope.declare_cfunction(name, type, declarator.pos, entry = dest_scope.declare_cfunction(name, type, declarator.pos,
cname = cname, visibility = self.visibility, in_pxd = self.in_pxd, cname = cname, visibility = self.visibility,
api = self.api) in_pxd = self.in_pxd, api = self.api)
if entry is not None: if entry is not None:
entry.directive_locals = copy.copy(self.directive_locals) entry.directive_locals = copy.copy(self.directive_locals)
else: else:
if self.directive_locals: if self.directive_locals:
error(self.pos, "Decorators can only be followed by functions") error(self.pos, "Decorators can only be followed by functions")
if self.in_pxd and self.visibility != 'extern':
error(self.pos,
"Only 'extern' C variable declaration allowed in .pxd file")
entry = dest_scope.declare_var(name, type, declarator.pos, entry = dest_scope.declare_var(name, type, declarator.pos,
cname=cname, visibility=visibility, api=self.api, is_cdef=1) cname = cname, visibility = visibility,
in_pxd = self.in_pxd, api = self.api, is_cdef = 1)
class CStructOrUnionDefNode(StatNode): class CStructOrUnionDefNode(StatNode):
...@@ -1700,9 +1698,8 @@ class CFuncDefNode(FuncDefNode): ...@@ -1700,9 +1698,8 @@ class CFuncDefNode(FuncDefNode):
cname = name_declarator.cname cname = name_declarator.cname
self.entry = env.declare_cfunction( self.entry = env.declare_cfunction(
name, type, self.pos, name, type, self.pos,
cname = cname, visibility = self.visibility, cname = cname, visibility = self.visibility, api = self.api,
defining = self.body is not None, defining = self.body is not None, modifiers = self.modifiers)
api = self.api, modifiers = self.modifiers)
self.entry.inline_func_in_pxd = self.inline_in_pxd self.entry.inline_func_in_pxd = self.inline_in_pxd
self.return_type = type.return_type self.return_type = type.return_type
if self.return_type.is_array and visibility != 'extern': if self.return_type.is_array and visibility != 'extern':
......
...@@ -507,10 +507,11 @@ class Scope(object): ...@@ -507,10 +507,11 @@ class Scope(object):
return entry return entry
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'private', api = 0, is_cdef = 0): cname = None, visibility = 'private',
api = 0, in_pxd = 0, is_cdef = 0):
# Add an entry for a variable. # Add an entry for a variable.
if not cname: if not cname:
if visibility != 'private': if visibility != 'private' or api:
cname = name cname = name
else: else:
cname = self.mangle(Naming.var_prefix, name) cname = self.mangle(Naming.var_prefix, name)
...@@ -520,7 +521,12 @@ class Scope(object): ...@@ -520,7 +521,12 @@ class Scope(object):
error(pos, "C++ class must have a default constructor to be stack allocated") error(pos, "C++ class must have a default constructor to be stack allocated")
entry = self.declare(name, cname, type, pos, visibility) entry = self.declare(name, cname, type, pos, visibility)
entry.is_variable = 1 entry.is_variable = 1
entry.api = api if in_pxd and visibility != 'extern':
entry.defined_in_pxd = 1
entry.used = 1
if api:
entry.api = 1
entry.used = 1
self.control_flow.set_state((), (name, 'initialized'), False) self.control_flow.set_state((), (name, 'initialized'), False)
return entry return entry
...@@ -578,12 +584,11 @@ class Scope(object): ...@@ -578,12 +584,11 @@ class Scope(object):
self.pyfunc_entries.append(entry) self.pyfunc_entries.append(entry)
def declare_cfunction(self, name, type, pos, def declare_cfunction(self, name, type, pos,
cname = None, visibility = 'private', defining = 0, cname = None, visibility = 'private', api = 0, in_pxd = 0,
api = 0, in_pxd = 0, modifiers = (), utility_code = None): defining = 0, modifiers = (), utility_code = None):
# Add an entry for a C function. # Add an entry for a C function.
if not cname: if not cname:
if (visibility == 'extern' or if visibility != 'private' or api:
visibility == 'public'and defining):
cname = name cname = name
else: else:
cname = self.mangle(Naming.func_prefix, name) cname = self.mangle(Naming.func_prefix, name)
...@@ -613,8 +618,6 @@ class Scope(object): ...@@ -613,8 +618,6 @@ class Scope(object):
entry.type = type entry.type = type
else: else:
error(pos, "Function signature does not match previous declaration") error(pos, "Function signature does not match previous declaration")
entry.cname = cname
entry.func_cname = cname
else: else:
entry = self.add_cfunction(name, type, pos, cname, visibility, modifiers) entry = self.add_cfunction(name, type, pos, cname, visibility, modifiers)
entry.func_cname = cname entry.func_cname = cname
...@@ -1027,13 +1030,12 @@ class ModuleScope(Scope): ...@@ -1027,13 +1030,12 @@ class ModuleScope(Scope):
return entry return entry
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'private', api = 0, is_cdef = 0): cname = None, visibility = 'private',
api = 0, in_pxd = 0, is_cdef = 0):
# Add an entry for a global variable. If it is a Python # Add an entry for a global variable. If it is a Python
# object type, and not declared with cdef, it will live # object type, and not declared with cdef, it will live
# in the module dictionary, otherwise it will be a C # in the module dictionary, otherwise it will be a C
# global variable. # global variable.
entry = Scope.declare_var(self, name, type, pos,
cname=cname, visibility=visibility, api=api, is_cdef=is_cdef)
if not visibility in ('private', 'public', 'extern'): if not visibility in ('private', 'public', 'extern'):
error(pos, "Module-level variable cannot be declared %s" % visibility) error(pos, "Module-level variable cannot be declared %s" % visibility)
if not is_cdef: if not is_cdef:
...@@ -1042,12 +1044,66 @@ class ModuleScope(Scope): ...@@ -1042,12 +1044,66 @@ class ModuleScope(Scope):
if not (type.is_pyobject and not type.is_extension_type): if not (type.is_pyobject and not type.is_extension_type):
raise InternalError( raise InternalError(
"Non-cdef global variable is not a generic Python object") "Non-cdef global variable is not a generic Python object")
entry.is_pyglobal = 1
else: if not cname:
defining = not in_pxd
if (visibility == 'extern' or (visibility == 'public' and defining)):
cname = name
else:
cname = self.mangle(Naming.var_prefix, name)
entry = self.lookup_here(name)
if entry and entry.defined_in_pxd:
#if visibility != 'private' and visibility != entry.visibility:
# warning(pos, "Variable '%s' previously declared as '%s'" % (name, entry.visibility), 1)
if not entry.type.same_as(type):
if visibility == 'extern' and entry.visibility == 'extern':
warning(pos, "Variable '%s' type does not match previous declaration" % name, 1)
entry.type = type
#else:
# error(pos, "Variable '%s' type does not match previous declaration" % name)
if entry.visibility != "private":
mangled_cname = self.mangle(Naming.var_prefix, name)
if entry.cname == mangled_cname:
cname = name
entry.cname = name
if not entry.is_implemented:
entry.is_implemented = True
return entry
entry = Scope.declare_var(self, name, type, pos,
cname=cname, visibility=visibility,
api=api, in_pxd=in_pxd, is_cdef=is_cdef)
if is_cdef:
entry.is_cglobal = 1 entry.is_cglobal = 1
if entry.type.is_pyobject: if entry.type.is_pyobject:
entry.init = 0 entry.init = 0
self.var_entries.append(entry) self.var_entries.append(entry)
else:
entry.is_pyglobal = 1
return entry
def declare_cfunction(self, name, type, pos,
cname = None, visibility = 'private', api = 0, in_pxd = 0,
defining = 0, modifiers = (), utility_code = None):
# Add an entry for a C function.
if not cname:
if (visibility == 'extern' or (visibility == 'public' and defining)):
cname = name
else:
cname = self.mangle(Naming.func_prefix, name)
entry = self.lookup_here(name)
if entry and entry.defined_in_pxd:
if entry.visibility != "private":
mangled_cname = self.mangle(Naming.var_prefix, name)
if entry.cname == mangled_cname:
cname = name
entry.cname = cname
entry.func_cname = cname
entry = Scope.declare_cfunction(
self, name, type, pos,
cname = cname, visibility = visibility, api = api, in_pxd = in_pxd,
defining = defining, modifiers = modifiers, utility_code = utility_code)
return entry return entry
def declare_global(self, name, pos): def declare_global(self, name, pos):
...@@ -1315,12 +1371,14 @@ class LocalScope(Scope): ...@@ -1315,12 +1371,14 @@ class LocalScope(Scope):
return entry return entry
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'private', api = 0, is_cdef = 0): cname = None, visibility = 'private',
api = 0, in_pxd = 0, is_cdef = 0):
# Add an entry for a local variable. # Add an entry for a local variable.
if visibility in ('public', 'readonly'): if visibility in ('public', 'readonly'):
error(pos, "Local variable cannot be declared %s" % visibility) error(pos, "Local variable cannot be declared %s" % visibility)
entry = Scope.declare_var(self, name, type, pos, entry = Scope.declare_var(self, name, type, pos,
cname=cname, visibility=visibility, api=api, is_cdef=is_cdef) cname=cname, visibility=visibility,
api=api, in_pxd=in_pxd, is_cdef=is_cdef)
if type.is_pyobject and not Options.init_local_none: if type.is_pyobject and not Options.init_local_none:
entry.init = "0" entry.init = "0"
entry.init_to_none = (type.is_pyobject or type.is_unspecified) and Options.init_local_none entry.init_to_none = (type.is_pyobject or type.is_unspecified) and Options.init_local_none
...@@ -1397,7 +1455,8 @@ class GeneratorExpressionScope(Scope): ...@@ -1397,7 +1455,8 @@ class GeneratorExpressionScope(Scope):
return '%s%s' % (self.genexp_prefix, self.parent_scope.mangle(prefix, name)) return '%s%s' % (self.genexp_prefix, self.parent_scope.mangle(prefix, name))
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'private', api = 0, is_cdef = True): cname = None, visibility = 'private',
api = 0, in_pxd = 0, is_cdef = True):
if type is unspecified_type: if type is unspecified_type:
# if the outer scope defines a type for this variable, inherit it # if the outer scope defines a type for this variable, inherit it
outer_entry = self.outer_scope.lookup(name) outer_entry = self.outer_scope.lookup(name)
...@@ -1446,7 +1505,9 @@ class StructOrUnionScope(Scope): ...@@ -1446,7 +1505,9 @@ class StructOrUnionScope(Scope):
Scope.__init__(self, name, None, None) Scope.__init__(self, name, None, None)
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'private', api = 0, is_cdef = 0, allow_pyobject = 0): cname = None, visibility = 'private',
api = 0, in_pxd = 0, is_cdef = 0,
allow_pyobject = 0):
# Add an entry for an attribute. # Add an entry for an attribute.
if not cname: if not cname:
cname = name cname = name
...@@ -1466,8 +1527,8 @@ class StructOrUnionScope(Scope): ...@@ -1466,8 +1527,8 @@ class StructOrUnionScope(Scope):
return entry return entry
def declare_cfunction(self, name, type, pos, def declare_cfunction(self, name, type, pos,
cname = None, visibility = 'private', defining = 0, cname = None, visibility = 'private', api = 0, in_pxd = 0,
api = 0, in_pxd = 0, modifiers = ()): # currently no utility code ... defining = 0, modifiers = ()): # currently no utility code ...
return self.declare_var(name, type, pos, return self.declare_var(name, type, pos,
cname=cname, visibility=visibility) cname=cname, visibility=visibility)
...@@ -1513,12 +1574,14 @@ class PyClassScope(ClassScope): ...@@ -1513,12 +1574,14 @@ class PyClassScope(ClassScope):
is_py_class_scope = 1 is_py_class_scope = 1
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'private', api = 0, is_cdef = 0): cname = None, visibility = 'private',
api = 0, in_pxd = 0, is_cdef = 0):
if type is unspecified_type: if type is unspecified_type:
type = py_object_type type = py_object_type
# Add an entry for a class attribute. # Add an entry for a class attribute.
entry = Scope.declare_var(self, name, type, pos, entry = Scope.declare_var(self, name, type, pos,
cname=cname, visibility=visibility, api=api, is_cdef=is_cdef) cname=cname, visibility=visibility,
api=api, in_pxd=in_pxd, is_cdef=is_cdef)
entry.is_pyglobal = 1 # FIXME: WTF? entry.is_pyglobal = 1 # FIXME: WTF?
entry.is_pyclass_attr = 1 entry.is_pyclass_attr = 1
return entry return entry
...@@ -1577,7 +1640,8 @@ class CClassScope(ClassScope): ...@@ -1577,7 +1640,8 @@ class CClassScope(ClassScope):
self.parent_type.base_type.scope.needs_gc()) self.parent_type.base_type.scope.needs_gc())
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'private', api = 0, is_cdef = 0): cname = None, visibility = 'private',
api = 0, in_pxd = 0, is_cdef = 0):
if is_cdef: if is_cdef:
# Add an entry for an attribute. # Add an entry for an attribute.
if self.defined: if self.defined:
...@@ -1623,7 +1687,8 @@ class CClassScope(ClassScope): ...@@ -1623,7 +1687,8 @@ class CClassScope(ClassScope):
type = py_object_type type = py_object_type
# Add an entry for a class attribute. # Add an entry for a class attribute.
entry = Scope.declare_var(self, name, type, pos, entry = Scope.declare_var(self, name, type, pos,
cname=cname, visibility=visibility, api=api, is_cdef=is_cdef) cname=cname, visibility=visibility,
api=api, in_pxd=in_pxd, is_cdef=is_cdef)
entry.is_member = 1 entry.is_member = 1
entry.is_pyglobal = 1 # xxx: is_pyglobal changes behaviour in so many places that 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 # I keep it in for now. is_member should be enough
...@@ -1660,9 +1725,8 @@ class CClassScope(ClassScope): ...@@ -1660,9 +1725,8 @@ class CClassScope(ClassScope):
return ClassScope.lookup_here(self, name) return ClassScope.lookup_here(self, name)
def declare_cfunction(self, name, type, pos, def declare_cfunction(self, name, type, pos,
cname = None, visibility = 'private', cname = None, visibility = 'private', api = 0, in_pxd = 0,
defining = 0, api = 0, in_pxd = 0, modifiers = (), defining = 0, modifiers = (), utility_code = None):
utility_code = None):
if get_special_method_signature(name): if get_special_method_signature(name):
error(pos, "Special methods must be declared with 'def', not 'cdef'") error(pos, "Special methods must be declared with 'def', not 'cdef'")
args = type.args args = type.args
...@@ -1765,8 +1829,9 @@ class CppClassScope(Scope): ...@@ -1765,8 +1829,9 @@ class CppClassScope(Scope):
self.inherited_var_entries = [] self.inherited_var_entries = []
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'extern', api = 0, cname = None, visibility = 'extern',
is_cdef = 0, allow_pyobject = 0): api = 0, in_pxd = 0, is_cdef = 0,
allow_pyobject = 0):
# Add an entry for an attribute. # Add an entry for an attribute.
if not cname: if not cname:
cname = name cname = name
...@@ -1807,9 +1872,9 @@ class CppClassScope(Scope): ...@@ -1807,9 +1872,9 @@ class CppClassScope(Scope):
error(pos, "no matching function for call to %s::%s()" % error(pos, "no matching function for call to %s::%s()" %
(self.default_constructor, self.default_constructor)) (self.default_constructor, self.default_constructor))
def declare_cfunction(self, name, type, pos, cname = None, def declare_cfunction(self, name, type, pos,
visibility = 'extern', api = 0, defining = 0, cname = None, visibility = 'extern', api = 0, in_pxd = 0,
in_pxd = 0, modifiers = (), utility_code = None): defining = 0, modifiers = (), utility_code = None):
if name == self.name.split('::')[-1] and cname is None: if name == self.name.split('::')[-1] and cname is None:
self.check_base_default_constructor(pos) self.check_base_default_constructor(pos)
name = '<init>' name = '<init>'
......
PYTHON setup.py build_ext --inplace
PYTHON test.py
######## setup.py ########
from Cython.Build.Dependencies import cythonize
from distutils.core import setup
exts = cythonize("*.pyx")
for e in exts:
if e.name == "d":
e.sources.append("a.c")
setup(
ext_modules = exts,
)
######## a.pxd ########
ctypedef api float flt
cdef int int0
cdef float flt0
cdef api int int1
cdef api float flt1
cdef public api int int2
cdef public api flt flt2
######## a.pyx ########
cdef int int0 = 1, int1 = 1, int2 = 1
cdef float flt0 = 1, flt1 = 1, flt2 = 1
cdef api int int3 = 1
cdef api flt flt3 = 1
cdef public int int4 = 1
cdef public flt flt4 = 1
def get_int():
return (int0, int1, int2, int3, int4)
def get_flt():
return (flt0, flt1, flt2, flt3, flt4)
######## b.pyx ########
from a cimport *
int0 = int1 = int2 = 7
flt0 = flt1 = flt2 = 7
######## c.pyx ########
# distutils: language = c++
cdef extern from "a_api.h":
int import_a() except -1
ctypedef float flt
int int1, int2, int3
flt flt1, flt2, flt3
import_a()
int1 = int2 = int3 = 5
flt1 = flt2 = flt3 = 5
######## inita.h ########
#if PY_MAJOR_VERSION >= 3
void inita(void)
{
PyObject *sys_modules = NULL;
PyObject *mod = NULL;
sys_modules = PyImport_GetModuleDict();
if (!sys_modules) return;
mod = PyInit_a();
if (!mod) return;
PyDict_SetItemString(sys_modules, (char*)"a", mod);
}
#endif
######## d.pyx ########
cdef extern from "a.h":
pass
cdef extern from "inita.h":
pass
cdef extern from "a.h":
void inita() except *
ctypedef float flt
int int2, int4
flt flt2, flt4
inita()
int2 = int4 = 3
flt2 = flt4 = 3
######## test.py ########
import a
assert a.get_int() == (1,1,1,1,1)
assert a.get_flt() == (1,1,1,1,1)
import b
assert a.get_int() == (7,7,7,1,1)
assert a.get_flt() == (7,7,7,1,1)
import c
assert a.get_int() == (7,5,5,5,1)
assert a.get_flt() == (7,5,5,5,1)
import d
import a
assert a.get_int() == (1,1,3,1,3)
assert a.get_flt() == (1,1,3,1,3)
# mode: compile # mode: compile
from publicapi_pxd_mix cimport * from publicapi_pxd_mix cimport *
bar0()
bar1()
bar2()
bar3()
spam0(None)
spam1(None)
spam2(None)
spam3(None)
i0 = 0
i1 = 1
i2 = 2
i3 = 3
...@@ -66,8 +66,9 @@ cdef public api void* spam3(object o) except NULL with gil ...@@ -66,8 +66,9 @@ cdef public api void* spam3(object o) except NULL with gil
# -- # --
#cdef public int i1 cdef int i0 = 0 # XXX implement initialization!!!
#cdef api int i2 cdef public int i1
#cdef public api int i3 cdef api int i2
cdef public api int i3
# -- # --
...@@ -17,3 +17,8 @@ cdef void* spam0(object o) except NULL: return NULL ...@@ -17,3 +17,8 @@ cdef void* spam0(object o) except NULL: return NULL
cdef public void* spam1(object o) except NULL: return NULL cdef public void* spam1(object o) except NULL: return NULL
cdef api void* spam2(object o) nogil 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 cdef public api void* spam3(object o) except NULL with gil: return NULL
cdef int i0 = 0 # XXX This should not be required!
cdef public int i1 = 1
cdef api int i2 = 2
cdef public api int i3 = 3
...@@ -2,6 +2,10 @@ __doc__ = u""" ...@@ -2,6 +2,10 @@ __doc__ = u"""
>>> import sys >>> import sys
>>> sys.getrefcount(Foo.__pyx_vtable__) >>> sys.getrefcount(Foo.__pyx_vtable__)
2 2
>>> sys.getrefcount(__pyx_capi__['bar'])
2
>>> sys.getrefcount(__pyx_capi__['spam'])
2
>>> sys.getrefcount(__pyx_capi__['ten']) >>> sys.getrefcount(__pyx_capi__['ten'])
2 2
>>> sys.getrefcount(__pyx_capi__['pi']) >>> sys.getrefcount(__pyx_capi__['pi'])
...@@ -10,6 +14,8 @@ __doc__ = u""" ...@@ -10,6 +14,8 @@ __doc__ = u"""
2 2
>>> sys.getrefcount(__pyx_capi__['dct']) >>> sys.getrefcount(__pyx_capi__['dct'])
2 2
>>> sys.getrefcount(__pyx_capi__['tpl'])
2
>>> sys.getrefcount(__pyx_capi__['one']) >>> sys.getrefcount(__pyx_capi__['one'])
2 2
>>> sys.getrefcount(__pyx_capi__['two']) >>> sys.getrefcount(__pyx_capi__['two'])
...@@ -22,6 +28,8 @@ cdef public api class Foo [type FooType, object FooObject]: ...@@ -22,6 +28,8 @@ cdef public api class Foo [type FooType, object FooObject]:
cdef void bar(self): cdef void bar(self):
pass pass
cdef public api void bar():
pass
cdef api void spam(): cdef api void spam():
pass pass
...@@ -30,6 +38,7 @@ cdef api double pi = 3.14 ...@@ -30,6 +38,7 @@ cdef api double pi = 3.14
cdef api object obj = object() cdef api object obj = object()
cdef api dict dct = {} cdef api dict dct = {}
cdef public api int one = 1 cdef public api tuple tpl = ()
cdef public int two = 2 cdef public api float one = 1
cdef public float two = 2
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment