Commit 9266b95e authored by William Stein's avatar William Stein

Merge in C/API patch from lxml-pyrex.

parent 76750ffb
...@@ -39,24 +39,28 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -39,24 +39,28 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self.generate_h_code(env, result) self.generate_h_code(env, result)
def generate_h_code(self, env, result): def generate_h_code(self, env, result):
public_vars_and_funcs = [] public_vars = []
public_funcs = []
public_extension_types = [] public_extension_types = []
for entry in env.var_entries: for entry in env.var_entries:
if entry.visibility == 'public': if entry.visibility == 'public':
public_vars_and_funcs.append(entry) public_vars.append(entry)
for entry in env.cfunc_entries: for entry in env.cfunc_entries:
if entry.visibility == 'public': if entry.visibility == 'public':
public_vars_and_funcs.append(entry) public_funcs.append(entry)
for entry in env.c_class_entries: for entry in env.c_class_entries:
if entry.visibility == 'public': if entry.visibility == 'public':
public_extension_types.append(entry) public_extension_types.append(entry)
if public_vars_and_funcs or public_extension_types: if public_vars or public_funcs or public_extension_types:
result.h_file = replace_suffix(result.c_file, ".h") result.h_file = replace_suffix(result.c_file, ".h")
result.i_file = replace_suffix(result.c_file, ".pxi") result.i_file = replace_suffix(result.c_file, ".pxi")
h_code = Code.CCodeWriter(open_new_file(result.h_file)) h_code = Code.CCodeWriter(open_new_file(result.h_file))
i_code = Code.PyrexCodeWriter(result.i_file) i_code = Code.PyrexCodeWriter(result.i_file)
header_barrier = "__HAS_PYX_" + env.module_name
h_code.putln("#ifndef %s" % header_barrier)
h_code.putln("#define %s" % header_barrier)
self.generate_extern_c_macro_definition(h_code) self.generate_extern_c_macro_definition(h_code)
for entry in public_vars_and_funcs: for entry in public_vars:
h_code.putln("%s %s;" % ( h_code.putln("%s %s;" % (
Naming.extern_c_macro, Naming.extern_c_macro,
entry.type.declaration_code( entry.type.declaration_code(
...@@ -66,7 +70,28 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -66,7 +70,28 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
for entry in public_extension_types: for entry in public_extension_types:
self.generate_cclass_header_code(entry.type, h_code) self.generate_cclass_header_code(entry.type, h_code)
self.generate_cclass_include_code(entry.type, i_code) self.generate_cclass_include_code(entry.type, i_code)
if public_funcs:
sort_public_funcs = [ (func.cname, func)
for func in public_funcs ]
sort_public_funcs.sort()
public_funcs = [ func[1] for func in sort_public_funcs ]
for entry in public_funcs:
h_code.putln(
'static %s;' %
entry.type.declaration_code("(*%s)" % entry.cname))
i_code.putln("cdef extern %s" %
entry.type.declaration_code(entry.cname, pyrex = 1))
h_code.putln(
"static struct {char *s; void **p;} _%s_API[] = {" %
env.module_name)
for entry in public_funcs:
h_code.putln('{"%s", (void*)(&%s)},' % (
entry.cname, entry.cname))
h_code.putln("{0, 0}")
h_code.putln("};")
self.generate_c_api_import_code(env, h_code)
h_code.putln("PyMODINIT_FUNC init%s(void);" % env.module_name) h_code.putln("PyMODINIT_FUNC init%s(void);" % env.module_name)
h_code.putln("#endif /* %s */" % header_barrier)
def generate_cclass_header_code(self, type, h_code): def generate_cclass_header_code(self, type, h_code):
#h_code.putln("extern DL_IMPORT(PyTypeObject) %s;" % type.typeobj_cname) #h_code.putln("extern DL_IMPORT(PyTypeObject) %s;" % type.typeobj_cname)
...@@ -106,6 +131,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -106,6 +131,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self.body.generate_function_definitions(env, code) self.body.generate_function_definitions(env, code)
self.generate_interned_name_table(env, code) self.generate_interned_name_table(env, code)
self.generate_py_string_table(env, code) self.generate_py_string_table(env, code)
self.generate_c_api_table(env, code)
self.generate_typeobj_definitions(env, code) self.generate_typeobj_definitions(env, code)
self.generate_method_table(env, code) self.generate_method_table(env, code)
self.generate_filename_init_prototype(code) self.generate_filename_init_prototype(code)
...@@ -367,7 +393,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -367,7 +393,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
entry.type.typeptr_cname) entry.type.typeptr_cname)
code.put_var_declarations(env.var_entries, static = 1, code.put_var_declarations(env.var_entries, static = 1,
dll_linkage = "DL_EXPORT", definition = definition) dll_linkage = "DL_EXPORT", definition = definition)
code.put_var_declarations(env.default_entries, static = 1) code.put_var_declarations(env.default_entries, static = 1,
definition = definition)
def generate_cfunction_predeclarations(self, env, code): def generate_cfunction_predeclarations(self, env, code):
for entry in env.cfunc_entries: for entry in env.cfunc_entries:
...@@ -378,10 +405,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -378,10 +405,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
dll_linkage = None dll_linkage = None
header = entry.type.declaration_code(entry.cname, header = entry.type.declaration_code(entry.cname,
dll_linkage = dll_linkage) dll_linkage = dll_linkage)
if entry.visibility <> 'private': if entry.visibility == 'private':
storage_class = "static "
elif entry.visibility == 'extern':
storage_class = "%s " % Naming.extern_c_macro storage_class = "%s " % Naming.extern_c_macro
else: else:
storage_class = "static " storage_class = ""
code.putln("%s%s; /*proto*/" % ( code.putln("%s%s; /*proto*/" % (
storage_class, storage_class,
header)) header))
...@@ -1052,6 +1081,74 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1052,6 +1081,74 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln( code.putln(
"};") "};")
def generate_c_api_table(self, env, code):
public_funcs = []
for entry in env.cfunc_entries:
if entry.visibility == 'public':
public_funcs.append(entry.cname)
if public_funcs:
env.use_utility_code(Nodes.c_api_import_code)
code.putln(
"static __Pyx_CApiTabEntry %s[] = {" %
Naming.c_api_tab_cname)
public_funcs.sort()
for entry_cname in public_funcs:
code.putln('{"%s", %s},' % (entry_cname, entry_cname))
code.putln(
"{0, 0}")
code.putln(
"};")
def generate_c_api_import_code(self, env, h_code):
# this is written to the header file!
h_code.put("""
/* Return -1 and set exception on error, 0 on success. */
static int
import_%(name)s(PyObject *module)
{
if (module != NULL)
{
int (*init)(struct {const char *s; const void **p;}*);
PyObject* c_api_init;
c_api_init = PyObject_GetAttrString(module,
"_import_c_api");
if (!c_api_init)
return -1;
if (!PyCObject_Check(c_api_init))
{
Py_DECREF(c_api_init);
PyErr_SetString(PyExc_RuntimeError,
"%(name)s module provided an invalid C-API reference");
return -1;
}
init = PyCObject_AsVoidPtr(c_api_init);
Py_DECREF(c_api_init);
if (!init)
{
PyErr_SetString(PyExc_RuntimeError,
"%(name)s module returned NULL pointer for C-API init function");
return -1;
}
if (init(_%(name)s_API))
return -1;
}
return 0;
}
""".replace('\n ', '\n') % {'name' : env.module_name})
def generate_c_api_init_code(self, env, code):
public_funcs = []
for entry in env.cfunc_entries:
if entry.visibility == 'public':
public_funcs.append(entry)
if public_funcs:
code.putln('if (__Pyx_InitCApi(%s) < 0) %s' % (
Naming.module_cname,
code.error_goto(self.pos)))
def generate_filename_init_prototype(self, code): def generate_filename_init_prototype(self, code):
code.putln(""); code.putln("");
code.putln("static void %s(void); /*proto*/" % Naming.fileinit_cname) code.putln("static void %s(void); /*proto*/" % Naming.fileinit_cname)
...@@ -1071,6 +1168,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1071,6 +1168,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self.generate_intern_code(env, code) self.generate_intern_code(env, code)
#code.putln("/*--- String init code ---*/") #code.putln("/*--- String init code ---*/")
self.generate_string_init_code(env, code) self.generate_string_init_code(env, code)
#code.putln("/*--- External C API setup code ---*/")
self.generate_c_api_init_code(env, code)
#code.putln("/*--- Builtin init code ---*/") #code.putln("/*--- Builtin init code ---*/")
self.generate_builtin_init_code(env, code) self.generate_builtin_init_code(env, code)
#code.putln("/*--- Global init code ---*/") #code.putln("/*--- Global init code ---*/")
......
...@@ -52,5 +52,6 @@ retval_cname = pyrex_prefix + "r" ...@@ -52,5 +52,6 @@ retval_cname = pyrex_prefix + "r"
self_cname = pyrex_prefix + "self" self_cname = pyrex_prefix + "self"
stringtab_cname = pyrex_prefix + "string_tab" stringtab_cname = pyrex_prefix + "string_tab"
vtabslot_cname = pyrex_prefix + "vtab" vtabslot_cname = pyrex_prefix + "vtab"
c_api_tab_cname = pyrex_prefix + "c_api_tab"
extern_c_macro = pyrex_prefix.upper() + "EXTERN_C" extern_c_macro = pyrex_prefix.upper() + "EXTERN_C"
...@@ -709,10 +709,12 @@ class CFuncDefNode(FuncDefNode): ...@@ -709,10 +709,12 @@ class CFuncDefNode(FuncDefNode):
dll_linkage = None dll_linkage = None
header = self.return_type.declaration_code(entity, header = self.return_type.declaration_code(entity,
dll_linkage = dll_linkage) dll_linkage = dll_linkage)
if self.visibility <> 'private': if self.visibility == 'private':
storage_class = "static "
elif self.visibility == 'extern':
storage_class = "%s " % Naming.extern_c_macro storage_class = "%s " % Naming.extern_c_macro
else: else:
storage_class = "static " storage_class = ""
code.putln("%s%s%s {" % ( code.putln("%s%s%s {" % (
storage_class, storage_class,
self.modifiers, self.modifiers,
...@@ -1904,6 +1906,7 @@ class AssertStatNode(StatNode): ...@@ -1904,6 +1906,7 @@ class AssertStatNode(StatNode):
#env.recycle_pending_temps() # TEMPORARY #env.recycle_pending_temps() # TEMPORARY
def generate_execution_code(self, code): def generate_execution_code(self, code):
code.putln("#ifndef PYREX_WITHOUT_ASSERTIONS")
self.cond.generate_evaluation_code(code) self.cond.generate_evaluation_code(code)
if self.value: if self.value:
self.value.generate_evaluation_code(code) self.value.generate_evaluation_code(code)
...@@ -1924,6 +1927,7 @@ class AssertStatNode(StatNode): ...@@ -1924,6 +1927,7 @@ class AssertStatNode(StatNode):
self.cond.generate_disposal_code(code) self.cond.generate_disposal_code(code)
if self.value: if self.value:
self.value.generate_disposal_code(code) self.value.generate_disposal_code(code)
code.putln("#endif")
class IfStatNode(StatNode): class IfStatNode(StatNode):
...@@ -2586,6 +2590,7 @@ class FromImportStatNode(StatNode): ...@@ -2586,6 +2590,7 @@ class FromImportStatNode(StatNode):
utility_function_predeclarations = \ utility_function_predeclarations = \
""" """
typedef struct {const char *s; const void **p;} __Pyx_CApiTabEntry; /*proto*/
typedef struct {PyObject **p; char *s;} __Pyx_InternTabEntry; /*proto*/ typedef struct {PyObject **p; char *s;} __Pyx_InternTabEntry; /*proto*/
typedef struct {PyObject **p; char *s; long n;} __Pyx_StringTabEntry; /*proto*/ typedef struct {PyObject **p; char *s; long n;} __Pyx_StringTabEntry; /*proto*/
...@@ -3096,3 +3101,41 @@ static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { ...@@ -3096,3 +3101,41 @@ static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) {
"""] """]
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
c_api_import_code = [
"""
static int __Pyx_InitCApi(PyObject *module); /*proto*/
static int __Pyx_ImportModuleCApi(__Pyx_CApiTabEntry *t); /*proto*/
""","""
static int __Pyx_ImportModuleCApi(__Pyx_CApiTabEntry *t) {
__Pyx_CApiTabEntry *api_t;
while (t->s) {
if (*t->s == '\\0')
continue; /* shortcut for erased string entries */
api_t = %(API_TAB)s;
while ((api_t->s) && (strcmp(api_t->s, t->s) < 0))
++api_t;
if ((!api_t->p) || (strcmp(api_t->s, t->s) != 0)) {
PyErr_Format(PyExc_ValueError,
"Unknown function name in C API: %%s", t->s);
return -1;
}
*t->p = api_t->p;
++t;
}
return 0;
}
static int __Pyx_InitCApi(PyObject *module) {
int result;
PyObject* cobj = PyCObject_FromVoidPtr(&__Pyx_ImportModuleCApi, NULL);
if (!cobj)
return -1;
result = PyObject_SetAttrString(module, "_import_c_api", cobj);
Py_DECREF(cobj);
return result;
}
""" % {'API_TAB' : Naming.c_api_tab_cname}
]
#------------------------------------------------------------------------------------
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