Commit 246a4b97 authored by da-woods's avatar da-woods Committed by GitHub

Support utility code in headers (GH-3779)

Specifically this allows public packed structs but may also allow other public declarations that require small amounts of utility code.
parent aa8b0d9b
...@@ -1145,6 +1145,14 @@ class GlobalState(object): ...@@ -1145,6 +1145,14 @@ class GlobalState(object):
'end' 'end'
] ]
# h files can only have a much smaller list of sections
h_code_layout = [
'h_code',
'utility_code_proto_before_types',
'type_declarations',
'utility_code_proto',
'end'
]
def __init__(self, writer, module_node, code_config, common_utility_include_dir=None): def __init__(self, writer, module_node, code_config, common_utility_include_dir=None):
self.filename_table = {} self.filename_table = {}
...@@ -1215,6 +1223,11 @@ class GlobalState(object): ...@@ -1215,6 +1223,11 @@ class GlobalState(object):
code.putln("") code.putln("")
code.putln("/* --- Runtime support code --- */") code.putln("/* --- Runtime support code --- */")
def initialize_main_h_code(self):
rootwriter = self.rootwriter
for part in self.h_code_layout:
self.parts[part] = rootwriter.insertion_point()
def finalize_main_c_code(self): def finalize_main_c_code(self):
self.close_global_decls() self.close_global_decls()
......
...@@ -191,92 +191,94 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -191,92 +191,94 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
h_extension_types = h_entries(env.c_class_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_encoded(result.c_file, ".h") result.h_file = replace_suffix_encoded(result.c_file, ".h")
h_code = Code.CCodeWriter() h_code_writer = Code.CCodeWriter()
c_code_config = generate_c_code_config(env, options) c_code_config = generate_c_code_config(env, options)
Code.GlobalState(h_code, self, c_code_config) globalstate = Code.GlobalState(h_code_writer, self, c_code_config)
globalstate.initialize_main_h_code() # in-case utility code is used in the header
h_code_start = globalstate.parts['h_code']
h_code_main = globalstate.parts['type_declarations']
h_code_end = globalstate.parts['end']
if options.generate_pxi: if options.generate_pxi:
result.i_file = replace_suffix_encoded(result.c_file, ".pxi") result.i_file = replace_suffix_encoded(result.c_file, ".pxi")
i_code = Code.PyrexCodeWriter(result.i_file) i_code = Code.PyrexCodeWriter(result.i_file)
else: else:
i_code = None i_code = None
h_code.put_generated_by() h_code_start.put_generated_by()
h_guard = self.api_name(Naming.h_guard_prefix, env) h_guard = self.api_name(Naming.h_guard_prefix, env)
h_code.put_h_guard(h_guard) h_code_start.put_h_guard(h_guard)
h_code.putln("") h_code_start.putln("")
h_code.putln('#include "Python.h"') h_code_start.putln('#include "Python.h"')
self.generate_type_header_code(h_types, h_code) self.generate_type_header_code(h_types, h_code_start)
if options.capi_reexport_cincludes: if options.capi_reexport_cincludes:
self.generate_includes(env, [], h_code) self.generate_includes(env, [], h_code_start)
h_code.putln("") h_code_start.putln("")
api_guard = self.api_name(Naming.api_guard_prefix, env) api_guard = self.api_name(Naming.api_guard_prefix, env)
h_code.putln("#ifndef %s" % api_guard) h_code_start.putln("#ifndef %s" % api_guard)
h_code.putln("") h_code_start.putln("")
self.generate_extern_c_macro_definition(h_code) self.generate_extern_c_macro_definition(h_code_start)
h_code.putln("") h_code_start.putln("")
self.generate_dl_import_macro(h_code) self.generate_dl_import_macro(h_code_start)
if h_extension_types: if h_extension_types:
h_code.putln("") h_code_main.putln("")
for entry in h_extension_types: for entry in h_extension_types:
self.generate_cclass_header_code(entry.type, h_code) self.generate_cclass_header_code(entry.type, h_code_main)
if i_code: if i_code:
self.generate_cclass_include_code(entry.type, i_code) self.generate_cclass_include_code(entry.type, i_code)
if h_funcs: if h_funcs:
h_code.putln("") h_code_main.putln("")
for entry in h_funcs: for entry in h_funcs:
self.generate_public_declaration(entry, h_code, i_code) self.generate_public_declaration(entry, h_code_main, i_code)
if h_vars: if h_vars:
h_code.putln("") h_code_main.putln("")
for entry in h_vars: for entry in h_vars:
self.generate_public_declaration(entry, h_code, i_code) self.generate_public_declaration(entry, h_code_main, i_code)
h_code.putln("") h_code_main.putln("")
h_code.putln("#endif /* !%s */" % api_guard) h_code_main.putln("#endif /* !%s */" % api_guard)
h_code.putln("") h_code_main.putln("")
h_code.putln("/* WARNING: the interface of the module init function changed in CPython 3.5. */") h_code_main.putln("/* WARNING: the interface of the module init function changed in CPython 3.5. */")
h_code.putln("/* It now returns a PyModuleDef instance instead of a PyModule instance. */") h_code_main.putln("/* It now returns a PyModuleDef instance instead of a PyModule instance. */")
h_code.putln("") h_code_main.putln("")
h_code.putln("#if PY_MAJOR_VERSION < 3") h_code_main.putln("#if PY_MAJOR_VERSION < 3")
if env.module_name.isascii(): if env.module_name.isascii():
py2_mod_name = env.module_name py2_mod_name = env.module_name
else: else:
py2_mod_name = env.module_name.encode("ascii", errors="ignore").decode("utf-8") py2_mod_name = env.module_name.encode("ascii", errors="ignore").decode("utf-8")
h_code.putln('#error "Unicode module names are not supported in Python 2";') h_code_main.putln('#error "Unicode module names are not supported in Python 2";')
h_code.putln("PyMODINIT_FUNC init%s(void);" % py2_mod_name) h_code_main.putln("PyMODINIT_FUNC init%s(void);" % py2_mod_name)
h_code.putln("#else") h_code_main.putln("#else")
py3_mod_func_name = self.mod_init_func_cname('PyInit', env) py3_mod_func_name = self.mod_init_func_cname('PyInit', env)
warning_string = EncodedString('Use PyImport_AppendInittab("%s", %s) instead of calling %s directly.' % ( warning_string = EncodedString('Use PyImport_AppendInittab("%s", %s) instead of calling %s directly.' % (
py2_mod_name, py3_mod_func_name, py3_mod_func_name)) py2_mod_name, py3_mod_func_name, py3_mod_func_name))
h_code.putln('/* WARNING: %s from Python 3.5 */' % warning_string.rstrip('.')) h_code_main.putln('/* WARNING: %s from Python 3.5 */' % warning_string.rstrip('.'))
h_code.putln("PyMODINIT_FUNC %s(void);" % py3_mod_func_name) h_code_main.putln("PyMODINIT_FUNC %s(void);" % py3_mod_func_name)
h_code.putln("") h_code_main.putln("")
h_code.putln("#if PY_VERSION_HEX >= 0x03050000 " h_code_main.putln("#if PY_VERSION_HEX >= 0x03050000 "
"&& (defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) " "&& (defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) "
"|| (defined(__cplusplus) && __cplusplus >= 201402L))") "|| (defined(__cplusplus) && __cplusplus >= 201402L))")
h_code.putln("#if defined(__cplusplus) && __cplusplus >= 201402L") h_code_main.putln("#if defined(__cplusplus) && __cplusplus >= 201402L")
h_code.putln("[[deprecated(%s)]] inline" % warning_string.as_c_string_literal()) h_code_main.putln("[[deprecated(%s)]] inline" % warning_string.as_c_string_literal())
h_code.putln("#elif defined(__GNUC__) || defined(__clang__)") h_code_main.putln("#elif defined(__GNUC__) || defined(__clang__)")
h_code.putln('__attribute__ ((__deprecated__(%s), __unused__)) __inline__' % ( h_code_main.putln('__attribute__ ((__deprecated__(%s), __unused__)) __inline__' % (
warning_string.as_c_string_literal())) warning_string.as_c_string_literal()))
h_code.putln("#elif defined(_MSC_VER)") h_code_main.putln("#elif defined(_MSC_VER)")
h_code.putln('__declspec(deprecated(%s)) __inline' % ( h_code_main.putln('__declspec(deprecated(%s)) __inline' % (
warning_string.as_c_string_literal())) warning_string.as_c_string_literal()))
h_code.putln('#endif') h_code_main.putln('#endif')
h_code.putln("static PyObject* __PYX_WARN_IF_INIT_CALLED(PyObject* res) {") h_code_main.putln("static PyObject* __PYX_WARN_IF_INIT_CALLED(PyObject* res) {")
h_code.putln("return res;") h_code_main.putln("return res;")
h_code.putln("}") h_code_main.putln("}")
# Function call is converted to warning macro; uncalled (pointer) is not # Function call is converted to warning macro; uncalled (pointer) is not
h_code.putln('#define %s() __PYX_WARN_IF_INIT_CALLED(%s())' % ( h_code_main.putln('#define %s() __PYX_WARN_IF_INIT_CALLED(%s())' % (
py3_mod_func_name, py3_mod_func_name)) py3_mod_func_name, py3_mod_func_name))
h_code.putln('#endif') h_code_main.putln('#endif')
h_code.putln('#endif') h_code_main.putln('#endif')
h_code.putln("")
h_code.putln("#endif /* !%s */" % h_guard)
f = open_new_file(result.h_file) h_code_end.putln("")
try: h_code_end.putln("#endif /* !%s */" % h_guard)
h_code.copyto(f)
finally: with open_new_file(result.h_file) as f:
f.close() h_code_writer.copyto(f)
def generate_public_declaration(self, entry, h_code, i_code): def generate_public_declaration(self, entry, h_code, i_code):
h_code.putln("%s %s;" % ( h_code.putln("%s %s;" % (
......
...@@ -3,3 +3,8 @@ ...@@ -3,3 +3,8 @@
cdef extern from *: cdef extern from *:
cdef packed struct MyStruct: cdef packed struct MyStruct:
char a char a
cdef public packed struct PublicStruct:
int a
unsigned char b
int c
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