Author: Devin Jeanpierre <jeanpierr...@gmail.com> Branch: seperate-strucmember_h Changeset: r82133:84085c039403 Date: 2016-01-31 01:49 -0800 http://bitbucket.org/pypy/pypy/changeset/84085c039403/
Log: Move structmember.h out of Python.h. Rough breakdown of changes: * Where Python.h is included by .c files, also include structmember.h * Add pypy_structmember_decl.h file which is included by structmember.h * Allow cpython_api functions to change which headers they are added to. The first two are very manual and icky, and I don't like how I did them. It feels like a hack. But I'm not sure of a better way to do it without more substantive rewrites. The last part was an API changes to cpython_api, so very invasive, but clean. Maybe the implementation is dumb. One last note: The header file being added in copy_header_files() doesn't seem to matter. I left it in anyway "just in case". Does it matter? diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -59,7 +59,7 @@ class CConfig: _compilation_info_ = ExternalCompilationInfo( include_dirs=include_dirs, - includes=['Python.h', 'stdarg.h'], + includes=['Python.h', 'stdarg.h', 'structmember.h'], compile_extra=['-DPy_BUILD_CORE'], ) @@ -129,6 +129,7 @@ for name in constant_names: setattr(CConfig_constants, name, rffi_platform.ConstantInteger(name)) udir.join('pypy_decl.h').write("/* Will be filled later */\n") +udir.join('pypy_structmember_decl.h').write("/* Will be filled later */\n") udir.join('pypy_macros.h').write("/* Will be filled later */\n") globals().update(rffi_platform.configure(CConfig_constants)) @@ -147,7 +148,7 @@ # XXX: 20 lines of code to recursively copy a directory, really?? assert dstdir.check(dir=True) headers = include_dir.listdir('*.h') + include_dir.listdir('*.inl') - for name in ("pypy_decl.h", "pypy_macros.h"): + for name in ("pypy_decl.h", "pypy_macros.h", "pypy_structmember_decl.h"): headers.append(udir.join(name)) _copy_header_files(headers, dstdir) @@ -232,7 +233,7 @@ wrapper.c_name = cpyext_namespace.uniquename(self.c_name) return wrapper -def cpython_api(argtypes, restype, error=_NOT_SPECIFIED, external=True, +def cpython_api(argtypes, restype, error=_NOT_SPECIFIED, header='pypy_decl.h', gil=None): """ Declares a function to be exported. @@ -241,8 +242,8 @@ special value 'CANNOT_FAIL' (also when restype is Void) turns an eventual exception into a wrapped SystemError. Unwrapped exceptions also cause a SytemError. - - set `external` to False to get a C function pointer, but not exported by - the API headers. + - `header` is the header file to export the function in, Set to None to get + a C function pointer, but not exported by the API headers. - set `gil` to "acquire", "release" or "around" to acquire the GIL, release the GIL, or both """ @@ -263,7 +264,7 @@ def decorate(func): func_name = func.func_name - if external: + if header is not None: c_name = None else: c_name = func_name @@ -271,7 +272,7 @@ c_name=c_name, gil=gil) func.api_func = api_function - if external: + if header is not None: assert func_name not in FUNCTIONS, ( "%s already registered" % func_name) @@ -363,8 +364,9 @@ unwrapper_catch = make_unwrapper(True) unwrapper_raise = make_unwrapper(False) - if external: + if header is not None: FUNCTIONS[func_name] = api_function + FUNCTIONS_BY_HEADER.setdefault(header, {})[func_name] = api_function INTERPLEVEL_API[func_name] = unwrapper_catch # used in tests return unwrapper_raise # used in 'normal' RPython code. return decorate @@ -383,6 +385,7 @@ INTERPLEVEL_API = {} FUNCTIONS = {} +FUNCTIONS_BY_HEADER = {} # These are C symbols which cpyext will export, but which are defined in .c # files somewhere in the implementation of cpyext (rather than being defined in @@ -811,6 +814,7 @@ global_code = '\n'.join(global_objects) prologue = ("#include <Python.h>\n" + "#include <structmember.h>\n" "#include <src/thread.c>\n") code = (prologue + struct_declaration_code + @@ -956,34 +960,62 @@ pypy_macros_h = udir.join('pypy_macros.h') pypy_macros_h.write('\n'.join(pypy_macros)) +def _header_to_guard(header_name): + return '_PYPY_' + header_name.replace('.', '_').upper() + +def _decl_header_top(header_name): + guard = _header_to_guard(header_name) + header = [ + "#ifndef %s\n" % guard, + "#define %s\n" % guard, + "#ifndef PYPY_STANDALONE\n", + "#ifdef __cplusplus", + "extern \"C\" {", + "#endif\n", + '#define Signed long /* xxx temporary fix */\n', + '#define Unsigned unsigned long /* xxx temporary fix */\n' + ] + if header_name == 'pypy_decl.h': # XXX don't send for code review unless I'm sure this is necessary + for decl in FORWARD_DECLS: + header.append("%s;" % (decl,)) + return header + +def _decl_header_bottom(header_name): + return [ + '#undef Signed /* xxx temporary fix */\n', + '#undef Unsigned /* xxx temporary fix */\n', + "#ifdef __cplusplus", + "}", + "#endif", + "#endif /*PYPY_STANDALONE*/\n", + "#endif /*%s*/\n" % _header_to_guard(header_name), + ] + def generate_decls_and_callbacks(db, export_symbols, api_struct=True): "NOT_RPYTHON" # implement function callbacks and generate function decls functions = [] - pypy_decls = [] - pypy_decls.append("#ifndef _PYPY_PYPY_DECL_H\n") - pypy_decls.append("#define _PYPY_PYPY_DECL_H\n") - pypy_decls.append("#ifndef PYPY_STANDALONE\n") - pypy_decls.append("#ifdef __cplusplus") - pypy_decls.append("extern \"C\" {") - pypy_decls.append("#endif\n") - pypy_decls.append('#define Signed long /* xxx temporary fix */\n') - pypy_decls.append('#define Unsigned unsigned long /* xxx temporary fix */\n') + decls = {} - for decl in FORWARD_DECLS: - pypy_decls.append("%s;" % (decl,)) + for header_name, header_functions in FUNCTIONS_BY_HEADER.iteritems(): + if header_name not in decls: + decls[header_name] = header = [] + header.extend(_decl_header_top(header_name)) + else: + header = decls[header_name] - for name, func in sorted(FUNCTIONS.iteritems()): - restype, args = c_function_signature(db, func) - pypy_decls.append("PyAPI_FUNC(%s) %s(%s);" % (restype, name, args)) - if api_struct: - callargs = ', '.join('arg%d' % (i,) - for i in range(len(func.argtypes))) - if func.restype is lltype.Void: - body = "{ _pypyAPI.%s(%s); }" % (name, callargs) - else: - body = "{ return _pypyAPI.%s(%s); }" % (name, callargs) - functions.append('%s %s(%s)\n%s' % (restype, name, args, body)) + for name, func in sorted(header_functions.iteritems()): + restype, args = c_function_signature(db, func) + header.append("PyAPI_FUNC(%s) %s(%s);" % (restype, name, args)) + if api_struct: + callargs = ', '.join('arg%d' % (i,) + for i in range(len(func.argtypes))) + if func.restype is lltype.Void: + body = "{ _pypyAPI.%s(%s); }" % (name, callargs) + else: + body = "{ return _pypyAPI.%s(%s); }" % (name, callargs) + functions.append('%s %s(%s)\n%s' % (restype, name, args, body)) + pypy_decls = decls['pypy_decl.h'] for name in VA_TP_LIST: name_no_star = process_va_name(name) header = ('%s pypy_va_get_%s(va_list* vp)' % @@ -999,16 +1031,11 @@ typ = 'PyObject*' pypy_decls.append('PyAPI_DATA(%s) %s;' % (typ, name)) - pypy_decls.append('#undef Signed /* xxx temporary fix */\n') - pypy_decls.append('#undef Unsigned /* xxx temporary fix */\n') - pypy_decls.append("#ifdef __cplusplus") - pypy_decls.append("}") - pypy_decls.append("#endif") - pypy_decls.append("#endif /*PYPY_STANDALONE*/\n") - pypy_decls.append("#endif /*_PYPY_PYPY_DECL_H*/\n") + for header_name, header_decls in decls.iteritems(): + header_decls.extend(_decl_header_bottom(header_name)) - pypy_decl_h = udir.join('pypy_decl.h') - pypy_decl_h.write('\n'.join(pypy_decls)) + decl_h = udir.join(header_name) + decl_h.write('\n'.join(header_decls)) return functions separate_module_files = [source_dir / "varargwrapper.c", diff --git a/pypy/module/cpyext/bufferobject.py b/pypy/module/cpyext/bufferobject.py --- a/pypy/module/cpyext/bufferobject.py +++ b/pypy/module/cpyext/bufferobject.py @@ -73,7 +73,7 @@ "Don't know how to realize a buffer")) -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def buffer_dealloc(space, py_obj): py_buf = rffi.cast(PyBufferObject, py_obj) if py_buf.c_b_base: diff --git a/pypy/module/cpyext/frameobject.py b/pypy/module/cpyext/frameobject.py --- a/pypy/module/cpyext/frameobject.py +++ b/pypy/module/cpyext/frameobject.py @@ -39,7 +39,7 @@ py_frame.c_f_locals = make_ref(space, frame.get_w_locals()) rffi.setintfield(py_frame, 'c_f_lineno', frame.getorcreatedebug().f_lineno) -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def frame_dealloc(space, py_obj): py_frame = rffi.cast(PyFrameObject, py_obj) py_code = rffi.cast(PyObject, py_frame.c_f_code) diff --git a/pypy/module/cpyext/funcobject.py b/pypy/module/cpyext/funcobject.py --- a/pypy/module/cpyext/funcobject.py +++ b/pypy/module/cpyext/funcobject.py @@ -56,7 +56,7 @@ assert isinstance(w_obj, Function) py_func.c_func_name = make_ref(space, space.wrap(w_obj.name)) -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def function_dealloc(space, py_obj): py_func = rffi.cast(PyFunctionObject, py_obj) Py_DecRef(space, py_func.c_func_name) @@ -75,7 +75,7 @@ rffi.setintfield(py_code, 'c_co_flags', co_flags) rffi.setintfield(py_code, 'c_co_argcount', w_obj.co_argcount) -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def code_dealloc(space, py_obj): py_code = rffi.cast(PyCodeObject, py_obj) Py_DecRef(space, py_code.c_co_name) diff --git a/pypy/module/cpyext/include/Python.h b/pypy/module/cpyext/include/Python.h --- a/pypy/module/cpyext/include/Python.h +++ b/pypy/module/cpyext/include/Python.h @@ -132,9 +132,6 @@ /* Missing definitions */ #include "missing.h" -// XXX This shouldn't be included here -#include "structmember.h" - #include <pypy_decl.h> /* Define macros for inline documentation. */ diff --git a/pypy/module/cpyext/include/structmember.h b/pypy/module/cpyext/include/structmember.h --- a/pypy/module/cpyext/include/structmember.h +++ b/pypy/module/cpyext/include/structmember.h @@ -55,3 +55,6 @@ } #endif #endif /* !Py_STRUCTMEMBER_H */ + +/* API functions. */ +#include "pypy_structmember_decl.h" diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py --- a/pypy/module/cpyext/methodobject.py +++ b/pypy/module/cpyext/methodobject.py @@ -50,7 +50,7 @@ py_func.c_m_self = make_ref(space, w_obj.w_self) py_func.c_m_module = make_ref(space, w_obj.w_module) -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def cfunction_dealloc(space, py_obj): py_func = rffi.cast(PyCFunctionObject, py_obj) Py_DecRef(space, py_func.c_m_self) diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py --- a/pypy/module/cpyext/pyobject.py +++ b/pypy/module/cpyext/pyobject.py @@ -70,7 +70,7 @@ alloc : allocate and basic initialization of a raw PyObject attach : Function called to tie a raw structure to a pypy object realize : Function called to create a pypy object from a raw struct - dealloc : a cpython_api(external=False), similar to PyObject_dealloc + dealloc : a cpython_api(header=None), similar to PyObject_dealloc """ tp_basestruct = kw.pop('basestruct', PyObject.TO) diff --git a/pypy/module/cpyext/pytraceback.py b/pypy/module/cpyext/pytraceback.py --- a/pypy/module/cpyext/pytraceback.py +++ b/pypy/module/cpyext/pytraceback.py @@ -41,7 +41,7 @@ rffi.setintfield(py_traceback, 'c_tb_lasti', traceback.lasti) rffi.setintfield(py_traceback, 'c_tb_lineno',traceback.get_lineno()) -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def traceback_dealloc(space, py_obj): py_traceback = rffi.cast(PyTracebackObject, py_obj) Py_DecRef(space, rffi.cast(PyObject, py_traceback.c_tb_next)) diff --git a/pypy/module/cpyext/sliceobject.py b/pypy/module/cpyext/sliceobject.py --- a/pypy/module/cpyext/sliceobject.py +++ b/pypy/module/cpyext/sliceobject.py @@ -36,7 +36,7 @@ py_slice.c_stop = make_ref(space, w_obj.w_stop) py_slice.c_step = make_ref(space, w_obj.w_step) -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def slice_dealloc(space, py_obj): """Frees allocated PyStringObject resources. """ diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py --- a/pypy/module/cpyext/slotdefs.py +++ b/pypy/module/cpyext/slotdefs.py @@ -309,7 +309,7 @@ return space.wrap(generic_cpy_call(space, func_target, w_self, w_other)) -@cpython_api([PyTypeObjectPtr, PyObject, PyObject], PyObject, external=False) +@cpython_api([PyTypeObjectPtr, PyObject, PyObject], PyObject, header=None) def slot_tp_new(space, type, w_args, w_kwds): from pypy.module.cpyext.tupleobject import PyTuple_Check pyo = rffi.cast(PyObject, type) @@ -320,30 +320,30 @@ w_args_new = space.newtuple(args_w) return space.call(w_func, w_args_new, w_kwds) -@cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, error=-1, external=False) +@cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, error=-1, header=None) def slot_tp_init(space, w_self, w_args, w_kwds): w_descr = space.lookup(w_self, '__init__') args = Arguments.frompacked(space, w_args, w_kwds) space.get_and_call_args(w_descr, w_self, args) return 0 -@cpython_api([PyObject, PyObject, PyObject], PyObject, external=False) +@cpython_api([PyObject, PyObject, PyObject], PyObject, header=None) def slot_tp_call(space, w_self, w_args, w_kwds): return space.call(w_self, w_args, w_kwds) -@cpython_api([PyObject], PyObject, external=False) +@cpython_api([PyObject], PyObject, header=None) def slot_tp_str(space, w_self): return space.str(w_self) -@cpython_api([PyObject], PyObject, external=False) +@cpython_api([PyObject], PyObject, header=None) def slot_nb_int(space, w_self): return space.int(w_self) -@cpython_api([PyObject], PyObject, external=False) +@cpython_api([PyObject], PyObject, header=None) def slot_tp_iter(space, w_self): return space.iter(w_self) -@cpython_api([PyObject], PyObject, external=False) +@cpython_api([PyObject], PyObject, header=None) def slot_tp_iternext(space, w_self): return space.next(w_self) @@ -371,7 +371,7 @@ return @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, - error=-1, external=True) # XXX should not be exported + error=-1) # XXX should be header=None @func_renamer("cpyext_tp_setattro_%s" % (typedef.name,)) def slot_tp_setattro(space, w_self, w_name, w_value): if w_value is not None: @@ -385,8 +385,7 @@ if getattr_fn is None: return - @cpython_api([PyObject, PyObject], PyObject, - external=True) + @cpython_api([PyObject, PyObject], PyObject) @func_renamer("cpyext_tp_getattro_%s" % (typedef.name,)) def slot_tp_getattro(space, w_self, w_name): return space.call_function(getattr_fn, w_self, w_name) diff --git a/pypy/module/cpyext/stringobject.py b/pypy/module/cpyext/stringobject.py --- a/pypy/module/cpyext/stringobject.py +++ b/pypy/module/cpyext/stringobject.py @@ -103,7 +103,7 @@ track_reference(space, py_obj, w_obj) return w_obj -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def string_dealloc(space, py_obj): """Frees allocated PyStringObject resources. """ diff --git a/pypy/module/cpyext/structmember.py b/pypy/module/cpyext/structmember.py --- a/pypy/module/cpyext/structmember.py +++ b/pypy/module/cpyext/structmember.py @@ -31,8 +31,10 @@ (T_PYSSIZET, rffi.SSIZE_T, PyLong_AsSsize_t), ]) +_HEADER = 'pypy_structmember_decl.h' -@cpython_api([PyObject, lltype.Ptr(PyMemberDef)], PyObject) + +@cpython_api([PyObject, lltype.Ptr(PyMemberDef)], PyObject, header=_HEADER) def PyMember_GetOne(space, obj, w_member): addr = rffi.cast(ADDR, obj) addr += w_member.c_offset @@ -83,7 +85,8 @@ return w_result -@cpython_api([PyObject, lltype.Ptr(PyMemberDef), PyObject], rffi.INT_real, error=-1) +@cpython_api([PyObject, lltype.Ptr(PyMemberDef), PyObject], rffi.INT_real, + error=-1, header=_HEADER) def PyMember_SetOne(space, obj, w_member, w_value): addr = rffi.cast(ADDR, obj) addr += w_member.c_offset diff --git a/pypy/module/cpyext/test/test_translate.py b/pypy/module/cpyext/test/test_translate.py --- a/pypy/module/cpyext/test/test_translate.py +++ b/pypy/module/cpyext/test/test_translate.py @@ -19,7 +19,7 @@ @specialize.memo() def get_tp_function(space, typedef): - @cpython_api([], lltype.Signed, error=-1, external=False) + @cpython_api([], lltype.Signed, error=-1, header=None) def slot_tp_function(space): return typedef.value diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -183,7 +183,7 @@ if pto.c_tp_new: add_tp_new_wrapper(space, dict_w, pto) -@cpython_api([PyObject, PyObject, PyObject], PyObject, external=False) +@cpython_api([PyObject, PyObject, PyObject], PyObject, header=None) def tp_new_wrapper(space, self, w_args, w_kwds): tp_new = rffi.cast(PyTypeObjectPtr, self).c_tp_new @@ -311,7 +311,7 @@ dealloc=type_dealloc) -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def subtype_dealloc(space, obj): pto = obj.c_ob_type base = pto @@ -327,7 +327,7 @@ # hopefully this does not clash with the memory model assumed in # extension modules -@cpython_api([PyObject, Py_ssize_tP], lltype.Signed, external=False, +@cpython_api([PyObject, Py_ssize_tP], lltype.Signed, header=None, error=CANNOT_FAIL) def str_segcount(space, w_obj, ref): if ref: @@ -335,7 +335,7 @@ return 1 @cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed, - external=False, error=-1) + header=None, error=-1) def str_getreadbuffer(space, w_str, segment, ref): from pypy.module.cpyext.stringobject import PyString_AsString if segment != 0: @@ -348,7 +348,7 @@ return space.len_w(w_str) @cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed, - external=False, error=-1) + header=None, error=-1) def str_getcharbuffer(space, w_str, segment, ref): from pypy.module.cpyext.stringobject import PyString_AsString if segment != 0: @@ -361,7 +361,7 @@ return space.len_w(w_str) @cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed, - external=False, error=-1) + header=None, error=-1) def buf_getreadbuffer(space, pyref, segment, ref): from pypy.module.cpyext.bufferobject import PyBufferObject if segment != 0: @@ -393,7 +393,7 @@ buf_getreadbuffer.api_func.get_wrapper(space)) pto.c_tp_as_buffer = c_buf -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def type_dealloc(space, obj): from pypy.module.cpyext.object import PyObject_dealloc obj_pto = rffi.cast(PyTypeObjectPtr, obj) diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py --- a/pypy/module/cpyext/unicodeobject.py +++ b/pypy/module/cpyext/unicodeobject.py @@ -75,7 +75,7 @@ track_reference(space, py_obj, w_obj) return w_obj -@cpython_api([PyObject], lltype.Void, external=False) +@cpython_api([PyObject], lltype.Void, header=None) def unicode_dealloc(space, py_obj): py_unicode = rffi.cast(PyUnicodeObject, py_obj) if py_unicode.c_buffer: _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit