Permalink
Browse files

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

  • Loading branch information...
1 parent 4b89cc3 commit 7c6f0728cde677e8d87bc231893264bcae4f2a6b @dalcinl dalcinl committed May 20, 2011
View
@@ -8,6 +8,7 @@ Cython/Runtime/refnanny.c
BUILD/
build/
+!tests/build/
dist/
.gitrev
.coverage
@@ -1166,39 +1166,19 @@ def put_goto(self, lbl):
self.funcstate.use_label(lbl)
self.putln("goto %s;" % lbl)
- def put_var_declarations(self, entries, static = 0, 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):
+ def put_var_declaration(self, entry, storage_class="",
+ dll_linkage = None, definition = True):
#print "Code.put_var_declaration:", entry.name, "definition =", definition ###
- if entry.in_closure:
- return
- visibility = entry.visibility
- if visibility == 'private' and not definition:
- #print "...private and not definition, skipping" ###
+ if entry.visibility == 'private' and not (definition or entry.defined_in_pxd):
+ #print "...private and not definition, skipping", entry.cname ###
return
- if not entry.used and visibility == "private":
- #print "not used and private, skipping", entry.cname ###
+ if entry.visibility == "private" and not entry.used:
+ #print "...private and not used, skipping", entry.cname ###
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:
self.put("%s " % storage_class)
- if visibility != 'public':
- dll_linkage = None
- self.put(entry.type.declaration_code(entry.cname,
- dll_linkage = dll_linkage))
+ self.put(entry.type.declaration_code(
+ entry.cname, dll_linkage = dll_linkage))
if entry.init is not None:
self.put_safe(" = %s" % entry.type.literal_code(entry.init))
self.putln(";")
@@ -201,7 +201,7 @@ def api_entries(entries, pxd=0):
h_code.putln("")
for entry in api_vars:
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("#define %s (*%s)" % (entry.name, cname))
h_code.put(import_module_utility_code.impl)
@@ -223,7 +223,7 @@ def api_entries(entries, pxd=0):
'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)
+ cname = env.mangle(Naming.varptr_prefix, entry.name)
sig = entry.type.declaration_code("")
h_code.putln(
'if (__Pyx_ImportVoidPtr(module, "%s", (void **)&%s, "%s") < 0) goto bad;'
@@ -290,7 +290,7 @@ def generate_c_code(self, env, options, result):
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("")
- code.putln("/* Implementation of %s */" % env.qualified_name)
+ code.putln("/* Implementation of '%s' */" % env.qualified_name)
code = globalstate['all_the_rest']
@@ -449,17 +449,18 @@ def generate_type_definitions(self, env, modules, vtab_list, vtabslot_list, code
def generate_declarations_for_modules(self, env, modules, globalstate):
typecode = globalstate['type_declarations']
typecode.putln("")
- typecode.putln("/* Type declarations */")
+ typecode.putln("/*--- Type declarations ---*/")
vtab_list, vtabslot_list = self.sort_type_hierarchy(modules, env)
self.generate_type_definitions(
env, modules, vtab_list, vtabslot_list, typecode)
modulecode = globalstate['module_declarations']
for module in modules:
defined_here = module is env
- modulecode.putln("/* Module declarations from %s */" %
- module.qualified_name)
- self.generate_global_declarations(module, modulecode, defined_here)
- self.generate_cfunction_predeclarations(module, modulecode, defined_here)
+ modulecode.putln("")
+ modulecode.putln("/* Module declarations from '%s' */" % module.qualified_name)
+ self.generate_c_class_declarations(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):
code.putln("/* Generated by Cython %s on %s */" % (
@@ -978,25 +979,68 @@ def generate_objstruct_definition(self, type, code):
# Only for exposing public typedef name.
code.putln("typedef struct %s %s;" % (type.objstruct_cname, type.objtypedef_cname))
- def generate_global_declarations(self, env, code, definition):
- code.putln("")
+ def generate_c_class_declarations(self, env, code, definition):
for entry in env.c_class_entries:
if definition or entry.defined_in_pxd:
code.putln("static PyTypeObject *%s = 0;" %
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:
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 == 'public':
- storage_class = ""
- dll_linkage = "DL_EXPORT"
- elif entry.visibility == 'extern':
+ if entry.visibility == 'extern':
storage_class = "%s " % Naming.extern_c_macro
dll_linkage = "DL_IMPORT"
+ elif entry.visibility == 'public':
+ storage_class = ""
+ dll_linkage = "DL_EXPORT"
elif entry.visibility == 'private':
storage_class = "static "
dll_linkage = None
@@ -1009,6 +1053,7 @@ def generate_cfunction_predeclarations(self, env, code, definition):
storage_class = "static "
dll_linkage = None
type = CPtrType(type)
+
header = type.declaration_code(entry.cname,
dll_linkage = dll_linkage)
if entry.func_modifiers:
@@ -1851,6 +1896,10 @@ def generate_module_init_func(self, imported_modules, env, code):
for module in imported_modules:
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 ---*/")
for module in imported_modules:
self.generate_c_function_import_code_for_module(module, env, code)
@@ -2030,21 +2079,27 @@ def generate_global_init_code(self, env, code):
def generate_c_variable_export_code(self, env, code):
# Generate code to create PyCFunction wrappers for exported C functions.
+ entries = []
for entry in env.var_entries:
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("")
code.putln('if (__Pyx_ExportVoidPtr("%s", (void *)&%s, "%s") < 0) %s' % (
- entry.name,
- entry.cname,
- signature,
+ 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.
+ entries = []
for entry in env.cfunc_entries:
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()
code.putln('if (__Pyx_ExportFunction("%s", (void (*)(void))%s, "%s") < 0) %s' % (
entry.name,
@@ -2060,6 +2115,34 @@ def generate_type_import_code_for_module(self, module, env, code):
if entry.defined_in_pxd:
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):
# Generate import code for all exported C functions in a cimported module.
entries = []
@@ -36,6 +36,7 @@
type_prefix = pyrex_prefix + "t_"
typeobj_prefix = pyrex_prefix + "type_"
var_prefix = pyrex_prefix + "v_"
+varptr_prefix = pyrex_prefix + "vp_"
wrapperbase_prefix= pyrex_prefix + "wrapperbase_"
bufstruct_prefix = pyrex_prefix + "bstruct_"
bufstride_prefix = pyrex_prefix + "bstride_"
@@ -969,18 +969,16 @@ def analyse_declarations(self, env, dest_scope = None):
return
if type.is_cfunction:
entry = dest_scope.declare_cfunction(name, type, declarator.pos,
- cname = cname, visibility = self.visibility, in_pxd = self.in_pxd,
- api = self.api)
+ cname = cname, visibility = self.visibility,
+ in_pxd = self.in_pxd, api = self.api)
if entry is not None:
entry.directive_locals = copy.copy(self.directive_locals)
else:
if self.directive_locals:
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,
- 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):
@@ -1700,9 +1698,8 @@ def analyse_declarations(self, env):
cname = name_declarator.cname
self.entry = env.declare_cfunction(
name, type, self.pos,
- cname = cname, visibility = self.visibility,
- defining = self.body is not None,
- api = self.api, modifiers = self.modifiers)
+ cname = cname, visibility = self.visibility, api = self.api,
+ defining = self.body is not None, modifiers = self.modifiers)
self.entry.inline_func_in_pxd = self.inline_in_pxd
self.return_type = type.return_type
if self.return_type.is_array and visibility != 'extern':
Oops, something went wrong.

0 comments on commit 7c6f072

Please sign in to comment.