| | import os, sys, io |
| | from . import ffiplatform, model |
| | from .error import VerificationError |
| | from .cffi_opcode import * |
| |
|
| | VERSION_BASE = 0x2601 |
| | VERSION_EMBEDDED = 0x2701 |
| | VERSION_CHAR16CHAR32 = 0x2801 |
| |
|
| | USE_LIMITED_API = (sys.platform != 'win32' or sys.version_info < (3, 0) or |
| | sys.version_info >= (3, 5)) |
| |
|
| |
|
| | class GlobalExpr: |
| | def __init__(self, name, address, type_op, size=0, check_value=0): |
| | self.name = name |
| | self.address = address |
| | self.type_op = type_op |
| | self.size = size |
| | self.check_value = check_value |
| |
|
| | def as_c_expr(self): |
| | return ' { "%s", (void *)%s, %s, (void *)%s },' % ( |
| | self.name, self.address, self.type_op.as_c_expr(), self.size) |
| |
|
| | def as_python_expr(self): |
| | return "b'%s%s',%d" % (self.type_op.as_python_bytes(), self.name, |
| | self.check_value) |
| |
|
| | class FieldExpr: |
| | def __init__(self, name, field_offset, field_size, fbitsize, field_type_op): |
| | self.name = name |
| | self.field_offset = field_offset |
| | self.field_size = field_size |
| | self.fbitsize = fbitsize |
| | self.field_type_op = field_type_op |
| |
|
| | def as_c_expr(self): |
| | spaces = " " * len(self.name) |
| | return (' { "%s", %s,\n' % (self.name, self.field_offset) + |
| | ' %s %s,\n' % (spaces, self.field_size) + |
| | ' %s %s },' % (spaces, self.field_type_op.as_c_expr())) |
| |
|
| | def as_python_expr(self): |
| | raise NotImplementedError |
| |
|
| | def as_field_python_expr(self): |
| | if self.field_type_op.op == OP_NOOP: |
| | size_expr = '' |
| | elif self.field_type_op.op == OP_BITFIELD: |
| | size_expr = format_four_bytes(self.fbitsize) |
| | else: |
| | raise NotImplementedError |
| | return "b'%s%s%s'" % (self.field_type_op.as_python_bytes(), |
| | size_expr, |
| | self.name) |
| |
|
| | class StructUnionExpr: |
| | def __init__(self, name, type_index, flags, size, alignment, comment, |
| | first_field_index, c_fields): |
| | self.name = name |
| | self.type_index = type_index |
| | self.flags = flags |
| | self.size = size |
| | self.alignment = alignment |
| | self.comment = comment |
| | self.first_field_index = first_field_index |
| | self.c_fields = c_fields |
| |
|
| | def as_c_expr(self): |
| | return (' { "%s", %d, %s,' % (self.name, self.type_index, self.flags) |
| | + '\n %s, %s, ' % (self.size, self.alignment) |
| | + '%d, %d ' % (self.first_field_index, len(self.c_fields)) |
| | + ('/* %s */ ' % self.comment if self.comment else '') |
| | + '},') |
| |
|
| | def as_python_expr(self): |
| | flags = eval(self.flags, G_FLAGS) |
| | fields_expr = [c_field.as_field_python_expr() |
| | for c_field in self.c_fields] |
| | return "(b'%s%s%s',%s)" % ( |
| | format_four_bytes(self.type_index), |
| | format_four_bytes(flags), |
| | self.name, |
| | ','.join(fields_expr)) |
| |
|
| | class EnumExpr: |
| | def __init__(self, name, type_index, size, signed, allenums): |
| | self.name = name |
| | self.type_index = type_index |
| | self.size = size |
| | self.signed = signed |
| | self.allenums = allenums |
| |
|
| | def as_c_expr(self): |
| | return (' { "%s", %d, _cffi_prim_int(%s, %s),\n' |
| | ' "%s" },' % (self.name, self.type_index, |
| | self.size, self.signed, self.allenums)) |
| |
|
| | def as_python_expr(self): |
| | prim_index = { |
| | (1, 0): PRIM_UINT8, (1, 1): PRIM_INT8, |
| | (2, 0): PRIM_UINT16, (2, 1): PRIM_INT16, |
| | (4, 0): PRIM_UINT32, (4, 1): PRIM_INT32, |
| | (8, 0): PRIM_UINT64, (8, 1): PRIM_INT64, |
| | }[self.size, self.signed] |
| | return "b'%s%s%s\\x00%s'" % (format_four_bytes(self.type_index), |
| | format_four_bytes(prim_index), |
| | self.name, self.allenums) |
| |
|
| | class TypenameExpr: |
| | def __init__(self, name, type_index): |
| | self.name = name |
| | self.type_index = type_index |
| |
|
| | def as_c_expr(self): |
| | return ' { "%s", %d },' % (self.name, self.type_index) |
| |
|
| | def as_python_expr(self): |
| | return "b'%s%s'" % (format_four_bytes(self.type_index), self.name) |
| |
|
| |
|
| | |
| |
|
| |
|
| | class Recompiler: |
| | _num_externpy = 0 |
| |
|
| | def __init__(self, ffi, module_name, target_is_python=False): |
| | self.ffi = ffi |
| | self.module_name = module_name |
| | self.target_is_python = target_is_python |
| | self._version = VERSION_BASE |
| |
|
| | def needs_version(self, ver): |
| | self._version = max(self._version, ver) |
| |
|
| | def collect_type_table(self): |
| | self._typesdict = {} |
| | self._generate("collecttype") |
| | |
| | all_decls = sorted(self._typesdict, key=str) |
| | |
| | |
| | self.cffi_types = [] |
| | for tp in all_decls: |
| | if tp.is_raw_function: |
| | assert self._typesdict[tp] is None |
| | self._typesdict[tp] = len(self.cffi_types) |
| | self.cffi_types.append(tp) |
| | for tp1 in tp.args: |
| | assert isinstance(tp1, (model.VoidType, |
| | model.BasePrimitiveType, |
| | model.PointerType, |
| | model.StructOrUnionOrEnum, |
| | model.FunctionPtrType)) |
| | if self._typesdict[tp1] is None: |
| | self._typesdict[tp1] = len(self.cffi_types) |
| | self.cffi_types.append(tp1) |
| | self.cffi_types.append('END') |
| | |
| | |
| | for tp in all_decls: |
| | if not tp.is_raw_function and self._typesdict[tp] is None: |
| | self._typesdict[tp] = len(self.cffi_types) |
| | self.cffi_types.append(tp) |
| | if tp.is_array_type and tp.length is not None: |
| | self.cffi_types.append('LEN') |
| | assert None not in self._typesdict.values() |
| | |
| | |
| | self._struct_unions = {} |
| | self._enums = {} |
| | for tp in all_decls: |
| | if isinstance(tp, model.StructOrUnion): |
| | self._struct_unions[tp] = None |
| | elif isinstance(tp, model.EnumType): |
| | self._enums[tp] = None |
| | for i, tp in enumerate(sorted(self._struct_unions, |
| | key=lambda tp: tp.name)): |
| | self._struct_unions[tp] = i |
| | for i, tp in enumerate(sorted(self._enums, |
| | key=lambda tp: tp.name)): |
| | self._enums[tp] = i |
| | |
| | |
| | for tp in all_decls: |
| | method = getattr(self, '_emit_bytecode_' + tp.__class__.__name__) |
| | method(tp, self._typesdict[tp]) |
| | |
| | |
| | for op in self.cffi_types: |
| | assert isinstance(op, CffiOp) |
| | self.cffi_types = tuple(self.cffi_types) |
| |
|
| | def _enum_fields(self, tp): |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | expand_anonymous_struct_union = not self.target_is_python |
| | return tp.enumfields(expand_anonymous_struct_union) |
| |
|
| | def _do_collect_type(self, tp): |
| | if not isinstance(tp, model.BaseTypeByIdentity): |
| | if isinstance(tp, tuple): |
| | for x in tp: |
| | self._do_collect_type(x) |
| | return |
| | if tp not in self._typesdict: |
| | self._typesdict[tp] = None |
| | if isinstance(tp, model.FunctionPtrType): |
| | self._do_collect_type(tp.as_raw_function()) |
| | elif isinstance(tp, model.StructOrUnion): |
| | if tp.fldtypes is not None and ( |
| | tp not in self.ffi._parser._included_declarations): |
| | for name1, tp1, _, _ in self._enum_fields(tp): |
| | self._do_collect_type(self._field_type(tp, name1, tp1)) |
| | else: |
| | for _, x in tp._get_items(): |
| | self._do_collect_type(x) |
| |
|
| | def _generate(self, step_name): |
| | lst = self.ffi._parser._declarations.items() |
| | for name, (tp, quals) in sorted(lst): |
| | kind, realname = name.split(' ', 1) |
| | try: |
| | method = getattr(self, '_generate_cpy_%s_%s' % (kind, |
| | step_name)) |
| | except AttributeError: |
| | raise VerificationError( |
| | "not implemented in recompile(): %r" % name) |
| | try: |
| | self._current_quals = quals |
| | method(tp, realname) |
| | except Exception as e: |
| | model.attach_exception_info(e, name) |
| | raise |
| |
|
| | |
| |
|
| | ALL_STEPS = ["global", "field", "struct_union", "enum", "typename"] |
| |
|
| | def collect_step_tables(self): |
| | |
| | self._lsts = {} |
| | for step_name in self.ALL_STEPS: |
| | self._lsts[step_name] = [] |
| | self._seen_struct_unions = set() |
| | self._generate("ctx") |
| | self._add_missing_struct_unions() |
| | |
| | for step_name in self.ALL_STEPS: |
| | lst = self._lsts[step_name] |
| | if step_name != "field": |
| | lst.sort(key=lambda entry: entry.name) |
| | self._lsts[step_name] = tuple(lst) |
| | |
| | |
| | |
| | lst = self._lsts["struct_union"] |
| | for tp, i in self._struct_unions.items(): |
| | assert i < len(lst) |
| | assert lst[i].name == tp.name |
| | assert len(lst) == len(self._struct_unions) |
| | |
| | lst = self._lsts["enum"] |
| | for tp, i in self._enums.items(): |
| | assert i < len(lst) |
| | assert lst[i].name == tp.name |
| | assert len(lst) == len(self._enums) |
| |
|
| | |
| |
|
| | def _prnt(self, what=''): |
| | self._f.write(what + '\n') |
| |
|
| | def write_source_to_f(self, f, preamble): |
| | if self.target_is_python: |
| | assert preamble is None |
| | self.write_py_source_to_f(f) |
| | else: |
| | assert preamble is not None |
| | self.write_c_source_to_f(f, preamble) |
| |
|
| | def _rel_readlines(self, filename): |
| | g = open(os.path.join(os.path.dirname(__file__), filename), 'r') |
| | lines = g.readlines() |
| | g.close() |
| | return lines |
| |
|
| | def write_c_source_to_f(self, f, preamble): |
| | self._f = f |
| | prnt = self._prnt |
| | if self.ffi._embedding is not None: |
| | prnt('#define _CFFI_USE_EMBEDDING') |
| | if not USE_LIMITED_API: |
| | prnt('#define _CFFI_NO_LIMITED_API') |
| | |
| | |
| | lines = self._rel_readlines('_cffi_include.h') |
| | i = lines.index('#include "parse_c_type.h"\n') |
| | lines[i:i+1] = self._rel_readlines('parse_c_type.h') |
| | prnt(''.join(lines)) |
| | |
| | |
| | |
| | base_module_name = self.module_name.split('.')[-1] |
| | if self.ffi._embedding is not None: |
| | prnt('#define _CFFI_MODULE_NAME "%s"' % (self.module_name,)) |
| | prnt('static const char _CFFI_PYTHON_STARTUP_CODE[] = {') |
| | self._print_string_literal_in_array(self.ffi._embedding) |
| | prnt('0 };') |
| | prnt('#ifdef PYPY_VERSION') |
| | prnt('# define _CFFI_PYTHON_STARTUP_FUNC _cffi_pypyinit_%s' % ( |
| | base_module_name,)) |
| | prnt('#elif PY_MAJOR_VERSION >= 3') |
| | prnt('# define _CFFI_PYTHON_STARTUP_FUNC PyInit_%s' % ( |
| | base_module_name,)) |
| | prnt('#else') |
| | prnt('# define _CFFI_PYTHON_STARTUP_FUNC init%s' % ( |
| | base_module_name,)) |
| | prnt('#endif') |
| | lines = self._rel_readlines('_embedding.h') |
| | i = lines.index('#include "_cffi_errors.h"\n') |
| | lines[i:i+1] = self._rel_readlines('_cffi_errors.h') |
| | prnt(''.join(lines)) |
| | self.needs_version(VERSION_EMBEDDED) |
| | |
| | |
| | prnt('/************************************************************/') |
| | prnt() |
| | prnt(preamble) |
| | prnt() |
| | prnt('/************************************************************/') |
| | prnt() |
| | |
| | |
| | prnt('static void *_cffi_types[] = {') |
| | typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()]) |
| | for i, op in enumerate(self.cffi_types): |
| | comment = '' |
| | if i in typeindex2type: |
| | comment = ' // ' + typeindex2type[i]._get_c_name() |
| | prnt('/* %2d */ %s,%s' % (i, op.as_c_expr(), comment)) |
| | if not self.cffi_types: |
| | prnt(' 0') |
| | prnt('};') |
| | prnt() |
| | |
| | |
| | |
| | self._seen_constants = set() |
| | self._generate("decl") |
| | |
| | |
| | nums = {} |
| | for step_name in self.ALL_STEPS: |
| | lst = self._lsts[step_name] |
| | nums[step_name] = len(lst) |
| | if nums[step_name] > 0: |
| | prnt('static const struct _cffi_%s_s _cffi_%ss[] = {' % ( |
| | step_name, step_name)) |
| | for entry in lst: |
| | prnt(entry.as_c_expr()) |
| | prnt('};') |
| | prnt() |
| | |
| | |
| | if self.ffi._included_ffis: |
| | prnt('static const char * const _cffi_includes[] = {') |
| | for ffi_to_include in self.ffi._included_ffis: |
| | try: |
| | included_module_name, included_source = ( |
| | ffi_to_include._assigned_source[:2]) |
| | except AttributeError: |
| | raise VerificationError( |
| | "ffi object %r includes %r, but the latter has not " |
| | "been prepared with set_source()" % ( |
| | self.ffi, ffi_to_include,)) |
| | if included_source is None: |
| | raise VerificationError( |
| | "not implemented yet: ffi.include() of a Python-based " |
| | "ffi inside a C-based ffi") |
| | prnt(' "%s",' % (included_module_name,)) |
| | prnt(' NULL') |
| | prnt('};') |
| | prnt() |
| | |
| | |
| | prnt('static const struct _cffi_type_context_s _cffi_type_context = {') |
| | prnt(' _cffi_types,') |
| | for step_name in self.ALL_STEPS: |
| | if nums[step_name] > 0: |
| | prnt(' _cffi_%ss,' % step_name) |
| | else: |
| | prnt(' NULL, /* no %ss */' % step_name) |
| | for step_name in self.ALL_STEPS: |
| | if step_name != "field": |
| | prnt(' %d, /* num_%ss */' % (nums[step_name], step_name)) |
| | if self.ffi._included_ffis: |
| | prnt(' _cffi_includes,') |
| | else: |
| | prnt(' NULL, /* no includes */') |
| | prnt(' %d, /* num_types */' % (len(self.cffi_types),)) |
| | flags = 0 |
| | if self._num_externpy > 0 or self.ffi._embedding is not None: |
| | flags |= 1 |
| | prnt(' %d, /* flags */' % flags) |
| | prnt('};') |
| | prnt() |
| | |
| | |
| | prnt('#ifdef __GNUC__') |
| | prnt('# pragma GCC visibility push(default) /* for -fvisibility= */') |
| | prnt('#endif') |
| | prnt() |
| | prnt('#ifdef PYPY_VERSION') |
| | prnt('PyMODINIT_FUNC') |
| | prnt('_cffi_pypyinit_%s(const void *p[])' % (base_module_name,)) |
| | prnt('{') |
| | if flags & 1: |
| | prnt(' if (((intptr_t)p[0]) >= 0x0A03) {') |
| | prnt(' _cffi_call_python_org = ' |
| | '(void(*)(struct _cffi_externpy_s *, char *))p[1];') |
| | prnt(' }') |
| | prnt(' p[0] = (const void *)0x%x;' % self._version) |
| | prnt(' p[1] = &_cffi_type_context;') |
| | prnt('#if PY_MAJOR_VERSION >= 3') |
| | prnt(' return NULL;') |
| | prnt('#endif') |
| | prnt('}') |
| | |
| | |
| | |
| | prnt('# ifdef _MSC_VER') |
| | prnt(' PyMODINIT_FUNC') |
| | prnt('# if PY_MAJOR_VERSION >= 3') |
| | prnt(' PyInit_%s(void) { return NULL; }' % (base_module_name,)) |
| | prnt('# else') |
| | prnt(' init%s(void) { }' % (base_module_name,)) |
| | prnt('# endif') |
| | prnt('# endif') |
| | prnt('#elif PY_MAJOR_VERSION >= 3') |
| | prnt('PyMODINIT_FUNC') |
| | prnt('PyInit_%s(void)' % (base_module_name,)) |
| | prnt('{') |
| | prnt(' return _cffi_init("%s", 0x%x, &_cffi_type_context);' % ( |
| | self.module_name, self._version)) |
| | prnt('}') |
| | prnt('#else') |
| | prnt('PyMODINIT_FUNC') |
| | prnt('init%s(void)' % (base_module_name,)) |
| | prnt('{') |
| | prnt(' _cffi_init("%s", 0x%x, &_cffi_type_context);' % ( |
| | self.module_name, self._version)) |
| | prnt('}') |
| | prnt('#endif') |
| | prnt() |
| | prnt('#ifdef __GNUC__') |
| | prnt('# pragma GCC visibility pop') |
| | prnt('#endif') |
| | self._version = None |
| |
|
| | def _to_py(self, x): |
| | if isinstance(x, str): |
| | return "b'%s'" % (x,) |
| | if isinstance(x, (list, tuple)): |
| | rep = [self._to_py(item) for item in x] |
| | if len(rep) == 1: |
| | rep.append('') |
| | return "(%s)" % (','.join(rep),) |
| | return x.as_python_expr() |
| |
|
| | def write_py_source_to_f(self, f): |
| | self._f = f |
| | prnt = self._prnt |
| | |
| | |
| | prnt("# auto-generated file") |
| | prnt("import _cffi_backend") |
| | |
| | |
| | num_includes = len(self.ffi._included_ffis or ()) |
| | for i in range(num_includes): |
| | ffi_to_include = self.ffi._included_ffis[i] |
| | try: |
| | included_module_name, included_source = ( |
| | ffi_to_include._assigned_source[:2]) |
| | except AttributeError: |
| | raise VerificationError( |
| | "ffi object %r includes %r, but the latter has not " |
| | "been prepared with set_source()" % ( |
| | self.ffi, ffi_to_include,)) |
| | if included_source is not None: |
| | raise VerificationError( |
| | "not implemented yet: ffi.include() of a C-based " |
| | "ffi inside a Python-based ffi") |
| | prnt('from %s import ffi as _ffi%d' % (included_module_name, i)) |
| | prnt() |
| | prnt("ffi = _cffi_backend.FFI('%s'," % (self.module_name,)) |
| | prnt(" _version = 0x%x," % (self._version,)) |
| | self._version = None |
| | |
| | |
| | self.cffi_types = tuple(self.cffi_types) |
| | types_lst = [op.as_python_bytes() for op in self.cffi_types] |
| | prnt(' _types = %s,' % (self._to_py(''.join(types_lst)),)) |
| | typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()]) |
| | |
| | |
| | for step_name in self.ALL_STEPS: |
| | lst = self._lsts[step_name] |
| | if len(lst) > 0 and step_name != "field": |
| | prnt(' _%ss = %s,' % (step_name, self._to_py(lst))) |
| | |
| | |
| | if num_includes > 0: |
| | prnt(' _includes = (%s,),' % ( |
| | ', '.join(['_ffi%d' % i for i in range(num_includes)]),)) |
| | |
| | |
| | prnt(')') |
| |
|
| | |
| |
|
| | def _gettypenum(self, type): |
| | |
| | return self._typesdict[type] |
| |
|
| | def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): |
| | extraarg = '' |
| | if isinstance(tp, model.BasePrimitiveType) and not tp.is_complex_type(): |
| | if tp.is_integer_type() and tp.name != '_Bool': |
| | converter = '_cffi_to_c_int' |
| | extraarg = ', %s' % tp.name |
| | elif isinstance(tp, model.UnknownFloatType): |
| | |
| | |
| | converter = '(%s)_cffi_to_c_double' % (tp.get_c_name(''),) |
| | else: |
| | cname = tp.get_c_name('') |
| | converter = '(%s)_cffi_to_c_%s' % (cname, |
| | tp.name.replace(' ', '_')) |
| | if cname in ('char16_t', 'char32_t'): |
| | self.needs_version(VERSION_CHAR16CHAR32) |
| | errvalue = '-1' |
| | |
| | elif isinstance(tp, model.PointerType): |
| | self._convert_funcarg_to_c_ptr_or_array(tp, fromvar, |
| | tovar, errcode) |
| | return |
| | |
| | elif (isinstance(tp, model.StructOrUnionOrEnum) or |
| | isinstance(tp, model.BasePrimitiveType)): |
| | |
| | |
| | self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' |
| | % (tovar, self._gettypenum(tp), fromvar)) |
| | self._prnt(' %s;' % errcode) |
| | return |
| | |
| | elif isinstance(tp, model.FunctionPtrType): |
| | converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('') |
| | extraarg = ', _cffi_type(%d)' % self._gettypenum(tp) |
| | errvalue = 'NULL' |
| | |
| | else: |
| | raise NotImplementedError(tp) |
| | |
| | self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg)) |
| | self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % ( |
| | tovar, tp.get_c_name(''), errvalue)) |
| | self._prnt(' %s;' % errcode) |
| |
|
| | def _extra_local_variables(self, tp, localvars, freelines): |
| | if isinstance(tp, model.PointerType): |
| | localvars.add('Py_ssize_t datasize') |
| | localvars.add('struct _cffi_freeme_s *large_args_free = NULL') |
| | freelines.add('if (large_args_free != NULL)' |
| | ' _cffi_free_array_arguments(large_args_free);') |
| |
|
| | def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode): |
| | self._prnt(' datasize = _cffi_prepare_pointer_call_argument(') |
| | self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % ( |
| | self._gettypenum(tp), fromvar, tovar)) |
| | self._prnt(' if (datasize != 0) {') |
| | self._prnt(' %s = ((size_t)datasize) <= 640 ? ' |
| | '(%s)alloca((size_t)datasize) : NULL;' % ( |
| | tovar, tp.get_c_name(''))) |
| | self._prnt(' if (_cffi_convert_array_argument(_cffi_type(%d), %s, ' |
| | '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar)) |
| | self._prnt(' datasize, &large_args_free) < 0)') |
| | self._prnt(' %s;' % errcode) |
| | self._prnt(' }') |
| |
|
| | def _convert_expr_from_c(self, tp, var, context): |
| | if isinstance(tp, model.BasePrimitiveType): |
| | if tp.is_integer_type() and tp.name != '_Bool': |
| | return '_cffi_from_c_int(%s, %s)' % (var, tp.name) |
| | elif isinstance(tp, model.UnknownFloatType): |
| | return '_cffi_from_c_double(%s)' % (var,) |
| | elif tp.name != 'long double' and not tp.is_complex_type(): |
| | cname = tp.name.replace(' ', '_') |
| | if cname in ('char16_t', 'char32_t'): |
| | self.needs_version(VERSION_CHAR16CHAR32) |
| | return '_cffi_from_c_%s(%s)' % (cname, var) |
| | else: |
| | return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( |
| | var, self._gettypenum(tp)) |
| | elif isinstance(tp, (model.PointerType, model.FunctionPtrType)): |
| | return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( |
| | var, self._gettypenum(tp)) |
| | elif isinstance(tp, model.ArrayType): |
| | return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( |
| | var, self._gettypenum(model.PointerType(tp.item))) |
| | elif isinstance(tp, model.StructOrUnion): |
| | if tp.fldnames is None: |
| | raise TypeError("'%s' is used as %s, but is opaque" % ( |
| | tp._get_c_name(), context)) |
| | return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % ( |
| | var, self._gettypenum(tp)) |
| | elif isinstance(tp, model.EnumType): |
| | return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( |
| | var, self._gettypenum(tp)) |
| | else: |
| | raise NotImplementedError(tp) |
| |
|
| | |
| | |
| |
|
| | def _typedef_type(self, tp, name): |
| | return self._global_type(tp, "(*(%s *)0)" % (name,)) |
| |
|
| | def _generate_cpy_typedef_collecttype(self, tp, name): |
| | self._do_collect_type(self._typedef_type(tp, name)) |
| |
|
| | def _generate_cpy_typedef_decl(self, tp, name): |
| | pass |
| |
|
| | def _typedef_ctx(self, tp, name): |
| | type_index = self._typesdict[tp] |
| | self._lsts["typename"].append(TypenameExpr(name, type_index)) |
| |
|
| | def _generate_cpy_typedef_ctx(self, tp, name): |
| | tp = self._typedef_type(tp, name) |
| | self._typedef_ctx(tp, name) |
| | if getattr(tp, "origin", None) == "unknown_type": |
| | self._struct_ctx(tp, tp.name, approxname=None) |
| | elif isinstance(tp, model.NamedPointerType): |
| | self._struct_ctx(tp.totype, tp.totype.name, approxname=tp.name, |
| | named_ptr=tp) |
| |
|
| | |
| | |
| |
|
| | def _generate_cpy_function_collecttype(self, tp, name): |
| | self._do_collect_type(tp.as_raw_function()) |
| | if tp.ellipsis and not self.target_is_python: |
| | self._do_collect_type(tp) |
| |
|
| | def _generate_cpy_function_decl(self, tp, name): |
| | assert not self.target_is_python |
| | assert isinstance(tp, model.FunctionPtrType) |
| | if tp.ellipsis: |
| | |
| | |
| | |
| | self._generate_cpy_constant_decl(tp, name) |
| | return |
| | prnt = self._prnt |
| | numargs = len(tp.args) |
| | if numargs == 0: |
| | argname = 'noarg' |
| | elif numargs == 1: |
| | argname = 'arg0' |
| | else: |
| | argname = 'args' |
| | |
| | |
| | |
| | arguments = [] |
| | call_arguments = [] |
| | context = 'argument of %s' % name |
| | for i, type in enumerate(tp.args): |
| | arguments.append(type.get_c_name(' x%d' % i, context)) |
| | call_arguments.append('x%d' % i) |
| | repr_arguments = ', '.join(arguments) |
| | repr_arguments = repr_arguments or 'void' |
| | if tp.abi: |
| | abi = tp.abi + ' ' |
| | else: |
| | abi = '' |
| | name_and_arguments = '%s_cffi_d_%s(%s)' % (abi, name, repr_arguments) |
| | prnt('static %s' % (tp.result.get_c_name(name_and_arguments),)) |
| | prnt('{') |
| | call_arguments = ', '.join(call_arguments) |
| | result_code = 'return ' |
| | if isinstance(tp.result, model.VoidType): |
| | result_code = '' |
| | prnt(' %s%s(%s);' % (result_code, name, call_arguments)) |
| | prnt('}') |
| | |
| | prnt('#ifndef PYPY_VERSION') |
| | |
| | prnt('static PyObject *') |
| | prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname)) |
| | prnt('{') |
| | |
| | context = 'argument of %s' % name |
| | for i, type in enumerate(tp.args): |
| | arg = type.get_c_name(' x%d' % i, context) |
| | prnt(' %s;' % arg) |
| | |
| | localvars = set() |
| | freelines = set() |
| | for type in tp.args: |
| | self._extra_local_variables(type, localvars, freelines) |
| | for decl in sorted(localvars): |
| | prnt(' %s;' % (decl,)) |
| | |
| | if not isinstance(tp.result, model.VoidType): |
| | result_code = 'result = ' |
| | context = 'result of %s' % name |
| | result_decl = ' %s;' % tp.result.get_c_name(' result', context) |
| | prnt(result_decl) |
| | prnt(' PyObject *pyresult;') |
| | else: |
| | result_decl = None |
| | result_code = '' |
| | |
| | if len(tp.args) > 1: |
| | rng = range(len(tp.args)) |
| | for i in rng: |
| | prnt(' PyObject *arg%d;' % i) |
| | prnt() |
| | prnt(' if (!PyArg_UnpackTuple(args, "%s", %d, %d, %s))' % ( |
| | name, len(rng), len(rng), |
| | ', '.join(['&arg%d' % i for i in rng]))) |
| | prnt(' return NULL;') |
| | prnt() |
| | |
| | for i, type in enumerate(tp.args): |
| | self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i, |
| | 'return NULL') |
| | prnt() |
| | |
| | prnt(' Py_BEGIN_ALLOW_THREADS') |
| | prnt(' _cffi_restore_errno();') |
| | call_arguments = ['x%d' % i for i in range(len(tp.args))] |
| | call_arguments = ', '.join(call_arguments) |
| | prnt(' { %s%s(%s); }' % (result_code, name, call_arguments)) |
| | prnt(' _cffi_save_errno();') |
| | prnt(' Py_END_ALLOW_THREADS') |
| | prnt() |
| | |
| | prnt(' (void)self; /* unused */') |
| | if numargs == 0: |
| | prnt(' (void)noarg; /* unused */') |
| | if result_code: |
| | prnt(' pyresult = %s;' % |
| | self._convert_expr_from_c(tp.result, 'result', 'result type')) |
| | for freeline in freelines: |
| | prnt(' ' + freeline) |
| | prnt(' return pyresult;') |
| | else: |
| | for freeline in freelines: |
| | prnt(' ' + freeline) |
| | prnt(' Py_INCREF(Py_None);') |
| | prnt(' return Py_None;') |
| | prnt('}') |
| | |
| | prnt('#else') |
| | |
| | |
| | |
| | |
| | |
| | def need_indirection(type): |
| | return (isinstance(type, model.StructOrUnion) or |
| | (isinstance(type, model.PrimitiveType) and |
| | type.is_complex_type())) |
| | difference = False |
| | arguments = [] |
| | call_arguments = [] |
| | context = 'argument of %s' % name |
| | for i, type in enumerate(tp.args): |
| | indirection = '' |
| | if need_indirection(type): |
| | indirection = '*' |
| | difference = True |
| | arg = type.get_c_name(' %sx%d' % (indirection, i), context) |
| | arguments.append(arg) |
| | call_arguments.append('%sx%d' % (indirection, i)) |
| | tp_result = tp.result |
| | if need_indirection(tp_result): |
| | context = 'result of %s' % name |
| | arg = tp_result.get_c_name(' *result', context) |
| | arguments.insert(0, arg) |
| | tp_result = model.void_type |
| | result_decl = None |
| | result_code = '*result = ' |
| | difference = True |
| | if difference: |
| | repr_arguments = ', '.join(arguments) |
| | repr_arguments = repr_arguments or 'void' |
| | name_and_arguments = '%s_cffi_f_%s(%s)' % (abi, name, |
| | repr_arguments) |
| | prnt('static %s' % (tp_result.get_c_name(name_and_arguments),)) |
| | prnt('{') |
| | if result_decl: |
| | prnt(result_decl) |
| | call_arguments = ', '.join(call_arguments) |
| | prnt(' { %s%s(%s); }' % (result_code, name, call_arguments)) |
| | if result_decl: |
| | prnt(' return result;') |
| | prnt('}') |
| | else: |
| | prnt('# define _cffi_f_%s _cffi_d_%s' % (name, name)) |
| | |
| | prnt('#endif') |
| | prnt() |
| |
|
| | def _generate_cpy_function_ctx(self, tp, name): |
| | if tp.ellipsis and not self.target_is_python: |
| | self._generate_cpy_constant_ctx(tp, name) |
| | return |
| | type_index = self._typesdict[tp.as_raw_function()] |
| | numargs = len(tp.args) |
| | if self.target_is_python: |
| | meth_kind = OP_DLOPEN_FUNC |
| | elif numargs == 0: |
| | meth_kind = OP_CPYTHON_BLTN_N |
| | elif numargs == 1: |
| | meth_kind = OP_CPYTHON_BLTN_O |
| | else: |
| | meth_kind = OP_CPYTHON_BLTN_V |
| | self._lsts["global"].append( |
| | GlobalExpr(name, '_cffi_f_%s' % name, |
| | CffiOp(meth_kind, type_index), |
| | size='_cffi_d_%s' % name)) |
| |
|
| | |
| | |
| |
|
| | def _field_type(self, tp_struct, field_name, tp_field): |
| | if isinstance(tp_field, model.ArrayType): |
| | actual_length = tp_field.length |
| | if actual_length == '...': |
| | ptr_struct_name = tp_struct.get_c_name('*') |
| | actual_length = '_cffi_array_len(((%s)0)->%s)' % ( |
| | ptr_struct_name, field_name) |
| | tp_item = self._field_type(tp_struct, '%s[0]' % field_name, |
| | tp_field.item) |
| | tp_field = model.ArrayType(tp_item, actual_length) |
| | return tp_field |
| |
|
| | def _struct_collecttype(self, tp): |
| | self._do_collect_type(tp) |
| | if self.target_is_python: |
| | |
| | for fldtype in tp.anonymous_struct_fields(): |
| | self._struct_collecttype(fldtype) |
| |
|
| | def _struct_decl(self, tp, cname, approxname): |
| | if tp.fldtypes is None: |
| | return |
| | prnt = self._prnt |
| | checkfuncname = '_cffi_checkfld_%s' % (approxname,) |
| | prnt('_CFFI_UNUSED_FN') |
| | prnt('static void %s(%s *p)' % (checkfuncname, cname)) |
| | prnt('{') |
| | prnt(' /* only to generate compile-time warnings or errors */') |
| | prnt(' (void)p;') |
| | for fname, ftype, fbitsize, fqual in self._enum_fields(tp): |
| | try: |
| | if ftype.is_integer_type() or fbitsize >= 0: |
| | |
| | if fname != '': |
| | prnt(" (void)((p->%s) | 0); /* check that '%s.%s' is " |
| | "an integer */" % (fname, cname, fname)) |
| | continue |
| | |
| | |
| | |
| | while (isinstance(ftype, model.ArrayType) |
| | and (ftype.length is None or ftype.length == '...')): |
| | ftype = ftype.item |
| | fname = fname + '[0]' |
| | prnt(' { %s = &p->%s; (void)tmp; }' % ( |
| | ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), |
| | fname)) |
| | except VerificationError as e: |
| | prnt(' /* %s */' % str(e)) |
| | prnt('}') |
| | prnt('struct _cffi_align_%s { char x; %s y; };' % (approxname, cname)) |
| | prnt() |
| |
|
| | def _struct_ctx(self, tp, cname, approxname, named_ptr=None): |
| | type_index = self._typesdict[tp] |
| | reason_for_not_expanding = None |
| | flags = [] |
| | if isinstance(tp, model.UnionType): |
| | flags.append("_CFFI_F_UNION") |
| | if tp.fldtypes is None: |
| | flags.append("_CFFI_F_OPAQUE") |
| | reason_for_not_expanding = "opaque" |
| | if (tp not in self.ffi._parser._included_declarations and |
| | (named_ptr is None or |
| | named_ptr not in self.ffi._parser._included_declarations)): |
| | if tp.fldtypes is None: |
| | pass |
| | elif tp.partial or any(tp.anonymous_struct_fields()): |
| | pass |
| | else: |
| | flags.append("_CFFI_F_CHECK_FIELDS") |
| | if tp.packed: |
| | if tp.packed > 1: |
| | raise NotImplementedError( |
| | "%r is declared with 'pack=%r'; only 0 or 1 are " |
| | "supported in API mode (try to use \"...;\", which " |
| | "does not require a 'pack' declaration)" % |
| | (tp, tp.packed)) |
| | flags.append("_CFFI_F_PACKED") |
| | else: |
| | flags.append("_CFFI_F_EXTERNAL") |
| | reason_for_not_expanding = "external" |
| | flags = '|'.join(flags) or '0' |
| | c_fields = [] |
| | if reason_for_not_expanding is None: |
| | enumfields = list(self._enum_fields(tp)) |
| | for fldname, fldtype, fbitsize, fqual in enumfields: |
| | fldtype = self._field_type(tp, fldname, fldtype) |
| | self._check_not_opaque(fldtype, |
| | "field '%s.%s'" % (tp.name, fldname)) |
| | |
| | op = OP_NOOP |
| | if fbitsize >= 0: |
| | op = OP_BITFIELD |
| | size = '%d /* bits */' % fbitsize |
| | elif cname is None or ( |
| | isinstance(fldtype, model.ArrayType) and |
| | fldtype.length is None): |
| | size = '(size_t)-1' |
| | else: |
| | size = 'sizeof(((%s)0)->%s)' % ( |
| | tp.get_c_name('*') if named_ptr is None |
| | else named_ptr.name, |
| | fldname) |
| | if cname is None or fbitsize >= 0: |
| | offset = '(size_t)-1' |
| | elif named_ptr is not None: |
| | offset = '((char *)&((%s)0)->%s) - (char *)0' % ( |
| | named_ptr.name, fldname) |
| | else: |
| | offset = 'offsetof(%s, %s)' % (tp.get_c_name(''), fldname) |
| | c_fields.append( |
| | FieldExpr(fldname, offset, size, fbitsize, |
| | CffiOp(op, self._typesdict[fldtype]))) |
| | first_field_index = len(self._lsts["field"]) |
| | self._lsts["field"].extend(c_fields) |
| | |
| | if cname is None: |
| | size = '(size_t)-2' |
| | align = -2 |
| | comment = "unnamed" |
| | else: |
| | if named_ptr is not None: |
| | size = 'sizeof(*(%s)0)' % (named_ptr.name,) |
| | align = '-1 /* unknown alignment */' |
| | else: |
| | size = 'sizeof(%s)' % (cname,) |
| | align = 'offsetof(struct _cffi_align_%s, y)' % (approxname,) |
| | comment = None |
| | else: |
| | size = '(size_t)-1' |
| | align = -1 |
| | first_field_index = -1 |
| | comment = reason_for_not_expanding |
| | self._lsts["struct_union"].append( |
| | StructUnionExpr(tp.name, type_index, flags, size, align, comment, |
| | first_field_index, c_fields)) |
| | self._seen_struct_unions.add(tp) |
| |
|
| | def _check_not_opaque(self, tp, location): |
| | while isinstance(tp, model.ArrayType): |
| | tp = tp.item |
| | if isinstance(tp, model.StructOrUnion) and tp.fldtypes is None: |
| | raise TypeError( |
| | "%s is of an opaque type (not declared in cdef())" % location) |
| |
|
| | def _add_missing_struct_unions(self): |
| | |
| | |
| | |
| | |
| | lst = list(self._struct_unions.items()) |
| | lst.sort(key=lambda tp_order: tp_order[1]) |
| | for tp, order in lst: |
| | if tp not in self._seen_struct_unions: |
| | if tp.partial: |
| | raise NotImplementedError("internal inconsistency: %r is " |
| | "partial but was not seen at " |
| | "this point" % (tp,)) |
| | if tp.name.startswith('$') and tp.name[1:].isdigit(): |
| | approxname = tp.name[1:] |
| | elif tp.name == '_IO_FILE' and tp.forcename == 'FILE': |
| | approxname = 'FILE' |
| | self._typedef_ctx(tp, 'FILE') |
| | else: |
| | raise NotImplementedError("internal inconsistency: %r" % |
| | (tp,)) |
| | self._struct_ctx(tp, None, approxname) |
| |
|
| | def _generate_cpy_struct_collecttype(self, tp, name): |
| | self._struct_collecttype(tp) |
| | _generate_cpy_union_collecttype = _generate_cpy_struct_collecttype |
| |
|
| | def _struct_names(self, tp): |
| | cname = tp.get_c_name('') |
| | if ' ' in cname: |
| | return cname, cname.replace(' ', '_') |
| | else: |
| | return cname, '_' + cname |
| |
|
| | def _generate_cpy_struct_decl(self, tp, name): |
| | self._struct_decl(tp, *self._struct_names(tp)) |
| | _generate_cpy_union_decl = _generate_cpy_struct_decl |
| |
|
| | def _generate_cpy_struct_ctx(self, tp, name): |
| | self._struct_ctx(tp, *self._struct_names(tp)) |
| | _generate_cpy_union_ctx = _generate_cpy_struct_ctx |
| |
|
| | |
| | |
| | |
| |
|
| | def _generate_cpy_anonymous_collecttype(self, tp, name): |
| | if isinstance(tp, model.EnumType): |
| | self._generate_cpy_enum_collecttype(tp, name) |
| | else: |
| | self._struct_collecttype(tp) |
| |
|
| | def _generate_cpy_anonymous_decl(self, tp, name): |
| | if isinstance(tp, model.EnumType): |
| | self._generate_cpy_enum_decl(tp) |
| | else: |
| | self._struct_decl(tp, name, 'typedef_' + name) |
| |
|
| | def _generate_cpy_anonymous_ctx(self, tp, name): |
| | if isinstance(tp, model.EnumType): |
| | self._enum_ctx(tp, name) |
| | else: |
| | self._struct_ctx(tp, name, 'typedef_' + name) |
| |
|
| | |
| | |
| |
|
| | def _generate_cpy_const(self, is_int, name, tp=None, category='const', |
| | check_value=None): |
| | if (category, name) in self._seen_constants: |
| | raise VerificationError( |
| | "duplicate declaration of %s '%s'" % (category, name)) |
| | self._seen_constants.add((category, name)) |
| | |
| | prnt = self._prnt |
| | funcname = '_cffi_%s_%s' % (category, name) |
| | if is_int: |
| | prnt('static int %s(unsigned long long *o)' % funcname) |
| | prnt('{') |
| | prnt(' int n = (%s) <= 0;' % (name,)) |
| | prnt(' *o = (unsigned long long)((%s) | 0);' |
| | ' /* check that %s is an integer */' % (name, name)) |
| | if check_value is not None: |
| | if check_value > 0: |
| | check_value = '%dU' % (check_value,) |
| | prnt(' if (!_cffi_check_int(*o, n, %s))' % (check_value,)) |
| | prnt(' n |= 2;') |
| | prnt(' return n;') |
| | prnt('}') |
| | else: |
| | assert check_value is None |
| | prnt('static void %s(char *o)' % funcname) |
| | prnt('{') |
| | prnt(' *(%s)o = %s;' % (tp.get_c_name('*'), name)) |
| | prnt('}') |
| | prnt() |
| |
|
| | def _generate_cpy_constant_collecttype(self, tp, name): |
| | is_int = tp.is_integer_type() |
| | if not is_int or self.target_is_python: |
| | self._do_collect_type(tp) |
| |
|
| | def _generate_cpy_constant_decl(self, tp, name): |
| | is_int = tp.is_integer_type() |
| | self._generate_cpy_const(is_int, name, tp) |
| |
|
| | def _generate_cpy_constant_ctx(self, tp, name): |
| | if not self.target_is_python and tp.is_integer_type(): |
| | type_op = CffiOp(OP_CONSTANT_INT, -1) |
| | else: |
| | if self.target_is_python: |
| | const_kind = OP_DLOPEN_CONST |
| | else: |
| | const_kind = OP_CONSTANT |
| | type_index = self._typesdict[tp] |
| | type_op = CffiOp(const_kind, type_index) |
| | self._lsts["global"].append( |
| | GlobalExpr(name, '_cffi_const_%s' % name, type_op)) |
| |
|
| | |
| | |
| |
|
| | def _generate_cpy_enum_collecttype(self, tp, name): |
| | self._do_collect_type(tp) |
| |
|
| | def _generate_cpy_enum_decl(self, tp, name=None): |
| | for enumerator in tp.enumerators: |
| | self._generate_cpy_const(True, enumerator) |
| |
|
| | def _enum_ctx(self, tp, cname): |
| | type_index = self._typesdict[tp] |
| | type_op = CffiOp(OP_ENUM, -1) |
| | if self.target_is_python: |
| | tp.check_not_partial() |
| | for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): |
| | self._lsts["global"].append( |
| | GlobalExpr(enumerator, '_cffi_const_%s' % enumerator, type_op, |
| | check_value=enumvalue)) |
| | |
| | if cname is not None and '$' not in cname and not self.target_is_python: |
| | size = "sizeof(%s)" % cname |
| | signed = "((%s)-1) <= 0" % cname |
| | else: |
| | basetp = tp.build_baseinttype(self.ffi, []) |
| | size = self.ffi.sizeof(basetp) |
| | signed = int(int(self.ffi.cast(basetp, -1)) < 0) |
| | allenums = ",".join(tp.enumerators) |
| | self._lsts["enum"].append( |
| | EnumExpr(tp.name, type_index, size, signed, allenums)) |
| |
|
| | def _generate_cpy_enum_ctx(self, tp, name): |
| | self._enum_ctx(tp, tp._get_c_name()) |
| |
|
| | |
| | |
| |
|
| | def _generate_cpy_macro_collecttype(self, tp, name): |
| | pass |
| |
|
| | def _generate_cpy_macro_decl(self, tp, name): |
| | if tp == '...': |
| | check_value = None |
| | else: |
| | check_value = tp |
| | self._generate_cpy_const(True, name, check_value=check_value) |
| |
|
| | def _generate_cpy_macro_ctx(self, tp, name): |
| | if tp == '...': |
| | if self.target_is_python: |
| | raise VerificationError( |
| | "cannot use the syntax '...' in '#define %s ...' when " |
| | "using the ABI mode" % (name,)) |
| | check_value = None |
| | else: |
| | check_value = tp |
| | type_op = CffiOp(OP_CONSTANT_INT, -1) |
| | self._lsts["global"].append( |
| | GlobalExpr(name, '_cffi_const_%s' % name, type_op, |
| | check_value=check_value)) |
| |
|
| | |
| | |
| |
|
| | def _global_type(self, tp, global_name): |
| | if isinstance(tp, model.ArrayType): |
| | actual_length = tp.length |
| | if actual_length == '...': |
| | actual_length = '_cffi_array_len(%s)' % (global_name,) |
| | tp_item = self._global_type(tp.item, '%s[0]' % global_name) |
| | tp = model.ArrayType(tp_item, actual_length) |
| | return tp |
| |
|
| | def _generate_cpy_variable_collecttype(self, tp, name): |
| | self._do_collect_type(self._global_type(tp, name)) |
| |
|
| | def _generate_cpy_variable_decl(self, tp, name): |
| | prnt = self._prnt |
| | tp = self._global_type(tp, name) |
| | if isinstance(tp, model.ArrayType) and tp.length is None: |
| | tp = tp.item |
| | ampersand = '' |
| | else: |
| | ampersand = '&' |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | decl = '*_cffi_var_%s(void)' % (name,) |
| | prnt('static ' + tp.get_c_name(decl, quals=self._current_quals)) |
| | prnt('{') |
| | prnt(' return %s(%s);' % (ampersand, name)) |
| | prnt('}') |
| | prnt() |
| |
|
| | def _generate_cpy_variable_ctx(self, tp, name): |
| | tp = self._global_type(tp, name) |
| | type_index = self._typesdict[tp] |
| | if self.target_is_python: |
| | op = OP_GLOBAL_VAR |
| | else: |
| | op = OP_GLOBAL_VAR_F |
| | self._lsts["global"].append( |
| | GlobalExpr(name, '_cffi_var_%s' % name, CffiOp(op, type_index))) |
| |
|
| | |
| | |
| |
|
| | def _generate_cpy_extern_python_collecttype(self, tp, name): |
| | assert isinstance(tp, model.FunctionPtrType) |
| | self._do_collect_type(tp) |
| | _generate_cpy_dllexport_python_collecttype = \ |
| | _generate_cpy_extern_python_plus_c_collecttype = \ |
| | _generate_cpy_extern_python_collecttype |
| |
|
| | def _extern_python_decl(self, tp, name, tag_and_space): |
| | prnt = self._prnt |
| | if isinstance(tp.result, model.VoidType): |
| | size_of_result = '0' |
| | else: |
| | context = 'result of %s' % name |
| | size_of_result = '(int)sizeof(%s)' % ( |
| | tp.result.get_c_name('', context),) |
| | prnt('static struct _cffi_externpy_s _cffi_externpy__%s =' % name) |
| | prnt(' { "%s.%s", %s, 0, 0 };' % ( |
| | self.module_name, name, size_of_result)) |
| | prnt() |
| | |
| | arguments = [] |
| | context = 'argument of %s' % name |
| | for i, type in enumerate(tp.args): |
| | arg = type.get_c_name(' a%d' % i, context) |
| | arguments.append(arg) |
| | |
| | repr_arguments = ', '.join(arguments) |
| | repr_arguments = repr_arguments or 'void' |
| | name_and_arguments = '%s(%s)' % (name, repr_arguments) |
| | if tp.abi == "__stdcall": |
| | name_and_arguments = '_cffi_stdcall ' + name_and_arguments |
| | |
| | def may_need_128_bits(tp): |
| | return (isinstance(tp, model.PrimitiveType) and |
| | tp.name == 'long double') |
| | |
| | size_of_a = max(len(tp.args)*8, 8) |
| | if may_need_128_bits(tp.result): |
| | size_of_a = max(size_of_a, 16) |
| | if isinstance(tp.result, model.StructOrUnion): |
| | size_of_a = 'sizeof(%s) > %d ? sizeof(%s) : %d' % ( |
| | tp.result.get_c_name(''), size_of_a, |
| | tp.result.get_c_name(''), size_of_a) |
| | prnt('%s%s' % (tag_and_space, tp.result.get_c_name(name_and_arguments))) |
| | prnt('{') |
| | prnt(' char a[%s];' % size_of_a) |
| | prnt(' char *p = a;') |
| | for i, type in enumerate(tp.args): |
| | arg = 'a%d' % i |
| | if (isinstance(type, model.StructOrUnion) or |
| | may_need_128_bits(type)): |
| | arg = '&' + arg |
| | type = model.PointerType(type) |
| | prnt(' *(%s)(p + %d) = %s;' % (type.get_c_name('*'), i*8, arg)) |
| | prnt(' _cffi_call_python(&_cffi_externpy__%s, p);' % name) |
| | if not isinstance(tp.result, model.VoidType): |
| | prnt(' return *(%s)p;' % (tp.result.get_c_name('*'),)) |
| | prnt('}') |
| | prnt() |
| | self._num_externpy += 1 |
| |
|
| | def _generate_cpy_extern_python_decl(self, tp, name): |
| | self._extern_python_decl(tp, name, 'static ') |
| |
|
| | def _generate_cpy_dllexport_python_decl(self, tp, name): |
| | self._extern_python_decl(tp, name, 'CFFI_DLLEXPORT ') |
| |
|
| | def _generate_cpy_extern_python_plus_c_decl(self, tp, name): |
| | self._extern_python_decl(tp, name, '') |
| |
|
| | def _generate_cpy_extern_python_ctx(self, tp, name): |
| | if self.target_is_python: |
| | raise VerificationError( |
| | "cannot use 'extern \"Python\"' in the ABI mode") |
| | if tp.ellipsis: |
| | raise NotImplementedError("a vararg function is extern \"Python\"") |
| | type_index = self._typesdict[tp] |
| | type_op = CffiOp(OP_EXTERN_PYTHON, type_index) |
| | self._lsts["global"].append( |
| | GlobalExpr(name, '&_cffi_externpy__%s' % name, type_op, name)) |
| |
|
| | _generate_cpy_dllexport_python_ctx = \ |
| | _generate_cpy_extern_python_plus_c_ctx = \ |
| | _generate_cpy_extern_python_ctx |
| |
|
| | def _print_string_literal_in_array(self, s): |
| | prnt = self._prnt |
| | prnt('// # NB. this is not a string because of a size limit in MSVC') |
| | if not isinstance(s, bytes): |
| | s = s.encode('utf-8') |
| | else: |
| | s.decode('utf-8') |
| | try: |
| | s.decode('ascii') |
| | except UnicodeDecodeError: |
| | s = b'# -*- encoding: utf8 -*-\n' + s |
| | for line in s.splitlines(True): |
| | comment = line |
| | if type('//') is bytes: |
| | line = map(ord, line) |
| | else: |
| | |
| | comment = ascii(comment)[1:-1] |
| | prnt(('// ' + comment).rstrip()) |
| | printed_line = '' |
| | for c in line: |
| | if len(printed_line) >= 76: |
| | prnt(printed_line) |
| | printed_line = '' |
| | printed_line += '%d,' % (c,) |
| | prnt(printed_line) |
| |
|
| | |
| | |
| |
|
| | def _emit_bytecode_VoidType(self, tp, index): |
| | self.cffi_types[index] = CffiOp(OP_PRIMITIVE, PRIM_VOID) |
| |
|
| | def _emit_bytecode_PrimitiveType(self, tp, index): |
| | prim_index = PRIMITIVE_TO_INDEX[tp.name] |
| | self.cffi_types[index] = CffiOp(OP_PRIMITIVE, prim_index) |
| |
|
| | def _emit_bytecode_UnknownIntegerType(self, tp, index): |
| | s = ('_cffi_prim_int(sizeof(%s), (\n' |
| | ' ((%s)-1) | 0 /* check that %s is an integer type */\n' |
| | ' ) <= 0)' % (tp.name, tp.name, tp.name)) |
| | self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) |
| |
|
| | def _emit_bytecode_UnknownFloatType(self, tp, index): |
| | s = ('_cffi_prim_float(sizeof(%s) *\n' |
| | ' (((%s)1) / 2) * 2 /* integer => 0, float => 1 */\n' |
| | ' )' % (tp.name, tp.name)) |
| | self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) |
| |
|
| | def _emit_bytecode_RawFunctionType(self, tp, index): |
| | self.cffi_types[index] = CffiOp(OP_FUNCTION, self._typesdict[tp.result]) |
| | index += 1 |
| | for tp1 in tp.args: |
| | realindex = self._typesdict[tp1] |
| | if index != realindex: |
| | if isinstance(tp1, model.PrimitiveType): |
| | self._emit_bytecode_PrimitiveType(tp1, index) |
| | else: |
| | self.cffi_types[index] = CffiOp(OP_NOOP, realindex) |
| | index += 1 |
| | flags = int(tp.ellipsis) |
| | if tp.abi is not None: |
| | if tp.abi == '__stdcall': |
| | flags |= 2 |
| | else: |
| | raise NotImplementedError("abi=%r" % (tp.abi,)) |
| | self.cffi_types[index] = CffiOp(OP_FUNCTION_END, flags) |
| |
|
| | def _emit_bytecode_PointerType(self, tp, index): |
| | self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[tp.totype]) |
| |
|
| | _emit_bytecode_ConstPointerType = _emit_bytecode_PointerType |
| | _emit_bytecode_NamedPointerType = _emit_bytecode_PointerType |
| |
|
| | def _emit_bytecode_FunctionPtrType(self, tp, index): |
| | raw = tp.as_raw_function() |
| | self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[raw]) |
| |
|
| | def _emit_bytecode_ArrayType(self, tp, index): |
| | item_index = self._typesdict[tp.item] |
| | if tp.length is None: |
| | self.cffi_types[index] = CffiOp(OP_OPEN_ARRAY, item_index) |
| | elif tp.length == '...': |
| | raise VerificationError( |
| | "type %s badly placed: the '...' array length can only be " |
| | "used on global arrays or on fields of structures" % ( |
| | str(tp).replace('/*...*/', '...'),)) |
| | else: |
| | assert self.cffi_types[index + 1] == 'LEN' |
| | self.cffi_types[index] = CffiOp(OP_ARRAY, item_index) |
| | self.cffi_types[index + 1] = CffiOp(None, str(tp.length)) |
| |
|
| | def _emit_bytecode_StructType(self, tp, index): |
| | struct_index = self._struct_unions[tp] |
| | self.cffi_types[index] = CffiOp(OP_STRUCT_UNION, struct_index) |
| | _emit_bytecode_UnionType = _emit_bytecode_StructType |
| |
|
| | def _emit_bytecode_EnumType(self, tp, index): |
| | enum_index = self._enums[tp] |
| | self.cffi_types[index] = CffiOp(OP_ENUM, enum_index) |
| |
|
| |
|
| | if sys.version_info >= (3,): |
| | NativeIO = io.StringIO |
| | else: |
| | class NativeIO(io.BytesIO): |
| | def write(self, s): |
| | if isinstance(s, unicode): |
| | s = s.encode('ascii') |
| | super(NativeIO, self).write(s) |
| |
|
| | def _make_c_or_py_source(ffi, module_name, preamble, target_file, verbose): |
| | if verbose: |
| | print("generating %s" % (target_file,)) |
| | recompiler = Recompiler(ffi, module_name, |
| | target_is_python=(preamble is None)) |
| | recompiler.collect_type_table() |
| | recompiler.collect_step_tables() |
| | f = NativeIO() |
| | recompiler.write_source_to_f(f, preamble) |
| | output = f.getvalue() |
| | try: |
| | with open(target_file, 'r') as f1: |
| | if f1.read(len(output) + 1) != output: |
| | raise IOError |
| | if verbose: |
| | print("(already up-to-date)") |
| | return False |
| | except IOError: |
| | tmp_file = '%s.~%d' % (target_file, os.getpid()) |
| | with open(tmp_file, 'w') as f1: |
| | f1.write(output) |
| | try: |
| | os.rename(tmp_file, target_file) |
| | except OSError: |
| | os.unlink(target_file) |
| | os.rename(tmp_file, target_file) |
| | return True |
| |
|
| | def make_c_source(ffi, module_name, preamble, target_c_file, verbose=False): |
| | assert preamble is not None |
| | return _make_c_or_py_source(ffi, module_name, preamble, target_c_file, |
| | verbose) |
| |
|
| | def make_py_source(ffi, module_name, target_py_file, verbose=False): |
| | return _make_c_or_py_source(ffi, module_name, None, target_py_file, |
| | verbose) |
| |
|
| | def _modname_to_file(outputdir, modname, extension): |
| | parts = modname.split('.') |
| | try: |
| | os.makedirs(os.path.join(outputdir, *parts[:-1])) |
| | except OSError: |
| | pass |
| | parts[-1] += extension |
| | return os.path.join(outputdir, *parts), parts |
| |
|
| |
|
| | |
| | |
| | |
| |
|
| | def _patch_meth(patchlist, cls, name, new_meth): |
| | old = getattr(cls, name) |
| | patchlist.append((cls, name, old)) |
| | setattr(cls, name, new_meth) |
| | return old |
| |
|
| | def _unpatch_meths(patchlist): |
| | for cls, name, old_meth in reversed(patchlist): |
| | setattr(cls, name, old_meth) |
| |
|
| | def _patch_for_embedding(patchlist): |
| | if sys.platform == 'win32': |
| | |
| | from distutils.msvc9compiler import MSVCCompiler |
| | _patch_meth(patchlist, MSVCCompiler, '_remove_visual_c_ref', |
| | lambda self, manifest_file: manifest_file) |
| |
|
| | if sys.platform == 'darwin': |
| | |
| | from distutils.ccompiler import CCompiler |
| | def my_link_shared_object(self, *args, **kwds): |
| | if '-bundle' in self.linker_so: |
| | self.linker_so = list(self.linker_so) |
| | i = self.linker_so.index('-bundle') |
| | self.linker_so[i] = '-dynamiclib' |
| | return old_link_shared_object(self, *args, **kwds) |
| | old_link_shared_object = _patch_meth(patchlist, CCompiler, |
| | 'link_shared_object', |
| | my_link_shared_object) |
| |
|
| | def _patch_for_target(patchlist, target): |
| | from distutils.command.build_ext import build_ext |
| | |
| | |
| | |
| | if target.endswith('.*'): |
| | target = target[:-2] |
| | if sys.platform == 'win32': |
| | target += '.dll' |
| | elif sys.platform == 'darwin': |
| | target += '.dylib' |
| | else: |
| | target += '.so' |
| | _patch_meth(patchlist, build_ext, 'get_ext_filename', |
| | lambda self, ext_name: target) |
| |
|
| |
|
| | def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True, |
| | c_file=None, source_extension='.c', extradir=None, |
| | compiler_verbose=1, target=None, debug=None, **kwds): |
| | if not isinstance(module_name, str): |
| | module_name = module_name.encode('ascii') |
| | if ffi._windows_unicode: |
| | ffi._apply_windows_unicode(kwds) |
| | if preamble is not None: |
| | embedding = (ffi._embedding is not None) |
| | if embedding: |
| | ffi._apply_embedding_fix(kwds) |
| | if c_file is None: |
| | c_file, parts = _modname_to_file(tmpdir, module_name, |
| | source_extension) |
| | if extradir: |
| | parts = [extradir] + parts |
| | ext_c_file = os.path.join(*parts) |
| | else: |
| | ext_c_file = c_file |
| | |
| | if target is None: |
| | if embedding: |
| | target = '%s.*' % module_name |
| | else: |
| | target = '*' |
| | |
| | ext = ffiplatform.get_extension(ext_c_file, module_name, **kwds) |
| | updated = make_c_source(ffi, module_name, preamble, c_file, |
| | verbose=compiler_verbose) |
| | if call_c_compiler: |
| | patchlist = [] |
| | cwd = os.getcwd() |
| | try: |
| | if embedding: |
| | _patch_for_embedding(patchlist) |
| | if target != '*': |
| | _patch_for_target(patchlist, target) |
| | if compiler_verbose: |
| | if tmpdir == '.': |
| | msg = 'the current directory is' |
| | else: |
| | msg = 'setting the current directory to' |
| | print('%s %r' % (msg, os.path.abspath(tmpdir))) |
| | os.chdir(tmpdir) |
| | outputfilename = ffiplatform.compile('.', ext, |
| | compiler_verbose, debug) |
| | finally: |
| | os.chdir(cwd) |
| | _unpatch_meths(patchlist) |
| | return outputfilename |
| | else: |
| | return ext, updated |
| | else: |
| | if c_file is None: |
| | c_file, _ = _modname_to_file(tmpdir, module_name, '.py') |
| | updated = make_py_source(ffi, module_name, c_file, |
| | verbose=compiler_verbose) |
| | if call_c_compiler: |
| | return c_file |
| | else: |
| | return None, updated |
| |
|
| |
|