Skip to content

Commit

Permalink
Support pxd/public/api import/export for C variables
Browse files Browse the repository at this point in the history
  • Loading branch information
dalcinl committed May 20, 2011
1 parent 4b89cc3 commit 7c6f072
Show file tree
Hide file tree
Showing 11 changed files with 375 additions and 96 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Cython/Runtime/refnanny.c

BUILD/
build/
!tests/build/
dist/
.gitrev
.coverage
Expand Down
36 changes: 8 additions & 28 deletions Cython/Compiler/Code.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(";")
Expand Down
127 changes: 105 additions & 22 deletions Cython/Compiler/ModuleNode.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;'
Expand Down Expand Up @@ -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']

Expand Down Expand Up @@ -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 */" % (
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand All @@ -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 = []
Expand Down
1 change: 1 addition & 0 deletions Cython/Compiler/Naming.py
Original file line number Diff line number Diff line change
Expand Up @@ -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_"
Expand Down
15 changes: 6 additions & 9 deletions Cython/Compiler/Nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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':
Expand Down
Loading

0 comments on commit 7c6f072

Please sign in to comment.