codekingpro/portable-devtools
114k
1#2# DEPRECATED: implementation for ffi.verify()3#4import sys, os5import types6 7from . import model8from .error import VerificationError9 10 11class VGenericEngine(object):12 _class_key = 'g'13 _gen_python_module = False14 15 def __init__(self, verifier):16 self.verifier = verifier17 self.ffi = verifier.ffi18 self.export_symbols = []19 self._struct_pending_verification = {}20 21 def patch_extension_kwds(self, kwds):22 # add 'export_symbols' to the dictionary. Note that we add the23 # list before filling it. When we fill it, it will thus also show24 # up in kwds['export_symbols'].25 kwds.setdefault('export_symbols', self.export_symbols)26 27 def find_module(self, module_name, path, so_suffixes):28 for so_suffix in so_suffixes:29 basename = module_name + so_suffix30 if path is None:31 path = sys.path32 for dirname in path:33 filename = os.path.join(dirname, basename)34 if os.path.isfile(filename):35 return filename36 37 def collect_types(self):38 pass # not needed in the generic engine39 40 def _prnt(self, what=''):41 self._f.write(what + '\n')42 43 def write_source_to_f(self):44 prnt = self._prnt45 # first paste some standard set of lines that are mostly '#include'46 prnt(cffimod_header)47 # then paste the C source given by the user, verbatim.48 prnt(self.verifier.preamble)49 #50 # call generate_gen_xxx_decl(), for every xxx found from51 # ffi._parser._declarations. This generates all the functions.52 self._generate('decl')53 #54 # on Windows, distutils insists on putting init_cffi_xyz in55 # 'export_symbols', so instead of fighting it, just give up and56 # give it one57 if sys.platform == 'win32':58 if sys.version_info >= (3,):59 prefix = 'PyInit_'60 else:61 prefix = 'init'62 modname = self.verifier.get_module_name()63 prnt("void %s%s(void) { }\n" % (prefix, modname))64 65 def load_library(self, flags=0):66 # import it with the CFFI backend67 backend = self.ffi._backend68 # needs to make a path that contains '/', on Posix69 filename = os.path.join(os.curdir, self.verifier.modulefilename)70 module = backend.load_library(filename, flags)71 #72 # call loading_gen_struct() to get the struct layout inferred by73 # the C compiler74 self._load(module, 'loading')75 76 # build the FFILibrary class and instance, this is a module subclass77 # because modules are expected to have usually-constant-attributes and78 # in PyPy this means the JIT is able to treat attributes as constant,79 # which we want.80 class FFILibrary(types.ModuleType):81 _cffi_generic_module = module82 _cffi_ffi = self.ffi83 _cffi_dir = []84 def __dir__(self):85 return FFILibrary._cffi_dir86 library = FFILibrary("")87 #88 # finally, call the loaded_gen_xxx() functions. This will set89 # up the 'library' object.90 self._load(module, 'loaded', library=library)91 return library92 93 def _get_declarations(self):94 lst = [(key, tp) for (key, (tp, qual)) in95 self.ffi._parser._declarations.items()]96 lst.sort()97 return lst98 99 def _generate(self, step_name):100 for name, tp in self._get_declarations():101 kind, realname = name.split(' ', 1)102 try:103 method = getattr(self, '_generate_gen_%s_%s' % (kind,104 step_name))105 except AttributeError:106 raise VerificationError(107 "not implemented in verify(): %r" % name)108 try:109 method(tp, realname)110 except Exception as e:111 model.attach_exception_info(e, name)112 raise113 114 def _load(self, module, step_name, **kwds):115 for name, tp in self._get_declarations():116 kind, realname = name.split(' ', 1)117 method = getattr(self, '_%s_gen_%s' % (step_name, kind))118 try:119 method(tp, realname, module, **kwds)120 except Exception as e:121 model.attach_exception_info(e, name)122 raise123 124 def _generate_nothing(self, tp, name):125 pass126 127 def _loaded_noop(self, tp, name, module, **kwds):128 pass129 130 # ----------131 # typedefs: generates no code so far132 133 _generate_gen_typedef_decl = _generate_nothing134 _loading_gen_typedef = _loaded_noop135 _loaded_gen_typedef = _loaded_noop136 137 # ----------138 # function declarations139 140 def _generate_gen_function_decl(self, tp, name):141 assert isinstance(tp, model.FunctionPtrType)142 if tp.ellipsis:143 # cannot support vararg functions better than this: check for its144 # exact type (including the fixed arguments), and build it as a145 # constant function pointer (no _cffi_f_%s wrapper)146 self._generate_gen_const(False, name, tp)147 return148 prnt = self._prnt149 numargs = len(tp.args)150 argnames = []151 for i, type in enumerate(tp.args):152 indirection = ''153 if isinstance(type, model.StructOrUnion):154 indirection = '*'155 argnames.append('%sx%d' % (indirection, i))156 context = 'argument of %s' % name157 arglist = [type.get_c_name(' %s' % arg, context)158 for type, arg in zip(tp.args, argnames)]159 tpresult = tp.result160 if isinstance(tpresult, model.StructOrUnion):161 arglist.insert(0, tpresult.get_c_name(' *r', context))162 tpresult = model.void_type163 arglist = ', '.join(arglist) or 'void'164 wrappername = '_cffi_f_%s' % name165 self.export_symbols.append(wrappername)166 if tp.abi:167 abi = tp.abi + ' '168 else:169 abi = ''170 funcdecl = ' %s%s(%s)' % (abi, wrappername, arglist)171 context = 'result of %s' % name172 prnt(tpresult.get_c_name(funcdecl, context))173 prnt('{')174 #175 if isinstance(tp.result, model.StructOrUnion):176 result_code = '*r = '177 elif not isinstance(tp.result, model.VoidType):178 result_code = 'return '179 else:180 result_code = ''181 prnt(' %s%s(%s);' % (result_code, name, ', '.join(argnames)))182 prnt('}')183 prnt()184 185 _loading_gen_function = _loaded_noop186 187 def _loaded_gen_function(self, tp, name, module, library):188 assert isinstance(tp, model.FunctionPtrType)189 if tp.ellipsis:190 newfunction = self._load_constant(False, tp, name, module)191 else:192 indirections = []193 base_tp = tp194 if (any(isinstance(typ, model.StructOrUnion) for typ in tp.args)195 or isinstance(tp.result, model.StructOrUnion)):196 indirect_args = []197 for i, typ in enumerate(tp.args):198 if isinstance(typ, model.StructOrUnion):199 typ = model.PointerType(typ)200 indirections.append((i, typ))201 indirect_args.append(typ)202 indirect_result = tp.result203 if isinstance(indirect_result, model.StructOrUnion):204 if indirect_result.fldtypes is None:205 raise TypeError("'%s' is used as result type, "206 "but is opaque" % (207 indirect_result._get_c_name(),))208 indirect_result = model.PointerType(indirect_result)209 indirect_args.insert(0, indirect_result)210 indirections.insert(0, ("result", indirect_result))211 indirect_result = model.void_type212 tp = model.FunctionPtrType(tuple(indirect_args),213 indirect_result, tp.ellipsis)214 BFunc = self.ffi._get_cached_btype(tp)215 wrappername = '_cffi_f_%s' % name216 newfunction = module.load_function(BFunc, wrappername)217 for i, typ in indirections:218 newfunction = self._make_struct_wrapper(newfunction, i, typ,219 base_tp)220 setattr(library, name, newfunction)221 type(library)._cffi_dir.append(name)222 223 def _make_struct_wrapper(self, oldfunc, i, tp, base_tp):224 backend = self.ffi._backend225 BType = self.ffi._get_cached_btype(tp)226 if i == "result":227 ffi = self.ffi228 def newfunc(*args):229 res = ffi.new(BType)230 oldfunc(res, *args)231 return res[0]232 else:233 def newfunc(*args):234 args = args[:i] + (backend.newp(BType, args[i]),) + args[i+1:]235 return oldfunc(*args)236 newfunc._cffi_base_type = base_tp237 return newfunc238 239 # ----------240 # named structs241 242 def _generate_gen_struct_decl(self, tp, name):243 assert name == tp.name244 self._generate_struct_or_union_decl(tp, 'struct', name)245 246 def _loading_gen_struct(self, tp, name, module):247 self._loading_struct_or_union(tp, 'struct', name, module)248 249 def _loaded_gen_struct(self, tp, name, module, **kwds):250 self._loaded_struct_or_union(tp)251 252 def _generate_gen_union_decl(self, tp, name):253 assert name == tp.name254 self._generate_struct_or_union_decl(tp, 'union', name)255 256 def _loading_gen_union(self, tp, name, module):257 self._loading_struct_or_union(tp, 'union', name, module)258 259 def _loaded_gen_union(self, tp, name, module, **kwds):260 self._loaded_struct_or_union(tp)261 262 def _generate_struct_or_union_decl(self, tp, prefix, name):263 if tp.fldnames is None:264 return # nothing to do with opaque structs265 checkfuncname = '_cffi_check_%s_%s' % (prefix, name)266 layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)267 cname = ('%s %s' % (prefix, name)).strip()268 #269 prnt = self._prnt270 prnt('static void %s(%s *p)' % (checkfuncname, cname))271 prnt('{')272 prnt(' /* only to generate compile-time warnings or errors */')273 prnt(' (void)p;')274 for fname, ftype, fbitsize, fqual in tp.enumfields():275 if (isinstance(ftype, model.PrimitiveType)276 and ftype.is_integer_type()) or fbitsize >= 0:277 # accept all integers, but complain on float or double278 prnt(' (void)((p->%s) << 1);' % fname)279 else:280 # only accept exactly the type declared.281 try:282 prnt(' { %s = &p->%s; (void)tmp; }' % (283 ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual),284 fname))285 except VerificationError as e:286 prnt(' /* %s */' % str(e)) # cannot verify it, ignore287 prnt('}')288 self.export_symbols.append(layoutfuncname)289 prnt('intptr_t %s(intptr_t i)' % (layoutfuncname,))290 prnt('{')291 prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname)292 prnt(' static intptr_t nums[] = {')293 prnt(' sizeof(%s),' % cname)294 prnt(' offsetof(struct _cffi_aligncheck, y),')295 for fname, ftype, fbitsize, fqual in tp.enumfields():296 if fbitsize >= 0:297 continue # xxx ignore fbitsize for now298 prnt(' offsetof(%s, %s),' % (cname, fname))299 if isinstance(ftype, model.ArrayType) and ftype.length is None:300 prnt(' 0, /* %s */' % ftype._get_c_name())301 else:302 prnt(' sizeof(((%s *)0)->%s),' % (cname, fname))303 prnt(' -1')304 prnt(' };')305 prnt(' return nums[i];')306 prnt(' /* the next line is not executed, but compiled */')307 prnt(' %s(0);' % (checkfuncname,))308 prnt('}')309 prnt()310 311 def _loading_struct_or_union(self, tp, prefix, name, module):312 if tp.fldnames is None:313 return # nothing to do with opaque structs314 layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)315 #316 BFunc = self.ffi._typeof_locked("intptr_t(*)(intptr_t)")[0]317 function = module.load_function(BFunc, layoutfuncname)318 layout = []319 num = 0320 while True:321 x = function(num)322 if x < 0: break323 layout.append(x)324 num += 1325 if isinstance(tp, model.StructOrUnion) and tp.partial:326 # use the function()'s sizes and offsets to guide the327 # layout of the struct328 totalsize = layout[0]329 totalalignment = layout[1]330 fieldofs = layout[2::2]331 fieldsize = layout[3::2]332 tp.force_flatten()333 assert len(fieldofs) == len(fieldsize) == len(tp.fldnames)334 tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment335 else:336 cname = ('%s %s' % (prefix, name)).strip()337 self._struct_pending_verification[tp] = layout, cname338 339 def _loaded_struct_or_union(self, tp):340 if tp.fldnames is None:341 return # nothing to do with opaque structs342 self.ffi._get_cached_btype(tp) # force 'fixedlayout' to be considered343 344 if tp in self._struct_pending_verification:345 # check that the layout sizes and offsets match the real ones346 def check(realvalue, expectedvalue, msg):347 if realvalue != expectedvalue:348 raise VerificationError(349 "%s (we have %d, but C compiler says %d)"350 % (msg, expectedvalue, realvalue))351 ffi = self.ffi352 BStruct = ffi._get_cached_btype(tp)353 layout, cname = self._struct_pending_verification.pop(tp)354 check(layout[0], ffi.sizeof(BStruct), "wrong total size")355 check(layout[1], ffi.alignof(BStruct), "wrong total alignment")356 i = 2357 for fname, ftype, fbitsize, fqual in tp.enumfields():358 if fbitsize >= 0:359 continue # xxx ignore fbitsize for now360 check(layout[i], ffi.offsetof(BStruct, fname),361 "wrong offset for field %r" % (fname,))362 if layout[i+1] != 0:363 BField = ffi._get_cached_btype(ftype)364 check(layout[i+1], ffi.sizeof(BField),365 "wrong size for field %r" % (fname,))366 i += 2367 assert i == len(layout)368 369 # ----------370 # 'anonymous' declarations. These are produced for anonymous structs371 # or unions; the 'name' is obtained by a typedef.372 373 def _generate_gen_anonymous_decl(self, tp, name):374 if isinstance(tp, model.EnumType):375 self._generate_gen_enum_decl(tp, name, '')376 else:377 self._generate_struct_or_union_decl(tp, '', name)378 379 def _loading_gen_anonymous(self, tp, name, module):380 if isinstance(tp, model.EnumType):381 self._loading_gen_enum(tp, name, module, '')382 else:383 self._loading_struct_or_union(tp, '', name, module)384 385 def _loaded_gen_anonymous(self, tp, name, module, **kwds):386 if isinstance(tp, model.EnumType):387 self._loaded_gen_enum(tp, name, module, **kwds)388 else:389 self._loaded_struct_or_union(tp)390 391 # ----------392 # constants, likely declared with '#define'393 394 def _generate_gen_const(self, is_int, name, tp=None, category='const',395 check_value=None):396 prnt = self._prnt397 funcname = '_cffi_%s_%s' % (category, name)398 self.export_symbols.append(funcname)399 if check_value is not None:400 assert is_int401 assert category == 'const'402 prnt('int %s(char *out_error)' % funcname)403 prnt('{')404 self._check_int_constant_value(name, check_value)405 prnt(' return 0;')406 prnt('}')407 elif is_int:408 assert category == 'const'409 prnt('int %s(long long *out_value)' % funcname)410 prnt('{')411 prnt(' *out_value = (long long)(%s);' % (name,))412 prnt(' return (%s) <= 0;' % (name,))413 prnt('}')414 else:415 assert tp is not None416 assert check_value is None417 if category == 'var':418 ampersand = '&'419 else:420 ampersand = ''421 extra = ''422 if category == 'const' and isinstance(tp, model.StructOrUnion):423 extra = 'const *'424 ampersand = '&'425 prnt(tp.get_c_name(' %s%s(void)' % (extra, funcname), name))426 prnt('{')427 prnt(' return (%s%s);' % (ampersand, name))428 prnt('}')429 prnt()430 431 def _generate_gen_constant_decl(self, tp, name):432 is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type()433 self._generate_gen_const(is_int, name, tp)434 435 _loading_gen_constant = _loaded_noop436 437 def _load_constant(self, is_int, tp, name, module, check_value=None):438 funcname = '_cffi_const_%s' % name439 if check_value is not None:440 assert is_int441 self._load_known_int_constant(module, funcname)442 value = check_value443 elif is_int:444 BType = self.ffi._typeof_locked("long long*")[0]445 BFunc = self.ffi._typeof_locked("int(*)(long long*)")[0]446 function = module.load_function(BFunc, funcname)447 p = self.ffi.new(BType)448 negative = function(p)449 value = int(p[0])450 if value < 0 and not negative:451 BLongLong = self.ffi._typeof_locked("long long")[0]452 value += (1 << (8*self.ffi.sizeof(BLongLong)))453 else:454 assert check_value is None455 fntypeextra = '(*)(void)'456 if isinstance(tp, model.StructOrUnion):457 fntypeextra = '*' + fntypeextra458 BFunc = self.ffi._typeof_locked(tp.get_c_name(fntypeextra, name))[0]459 function = module.load_function(BFunc, funcname)460 value = function()461 if isinstance(tp, model.StructOrUnion):462 value = value[0]463 return value464 465 def _loaded_gen_constant(self, tp, name, module, library):466 is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type()467 value = self._load_constant(is_int, tp, name, module)468 setattr(library, name, value)469 type(library)._cffi_dir.append(name)470 471 # ----------472 # enums473 474 def _check_int_constant_value(self, name, value):475 prnt = self._prnt476 if value <= 0:477 prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % (478 name, name, value))479 else:480 prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % (481 name, name, value))482 prnt(' char buf[64];')483 prnt(' if ((%s) <= 0)' % name)484 prnt(' sprintf(buf, "%%ld", (long)(%s));' % name)485 prnt(' else')486 prnt(' sprintf(buf, "%%lu", (unsigned long)(%s));' %487 name)488 prnt(' sprintf(out_error, "%s has the real value %s, not %s",')489 prnt(' "%s", buf, "%d");' % (name[:100], value))490 prnt(' return -1;')491 prnt(' }')492 493 def _load_known_int_constant(self, module, funcname):494 BType = self.ffi._typeof_locked("char[]")[0]495 BFunc = self.ffi._typeof_locked("int(*)(char*)")[0]496 function = module.load_function(BFunc, funcname)497 p = self.ffi.new(BType, 256)498 if function(p) < 0:499 error = self.ffi.string(p)500 if sys.version_info >= (3,):501 error = str(error, 'utf-8')502 raise VerificationError(error)503 504 def _enum_funcname(self, prefix, name):505 # "$enum_$1" => "___D_enum____D_1"506 name = name.replace('$', '___D_')507 return '_cffi_e_%s_%s' % (prefix, name)508 509 def _generate_gen_enum_decl(self, tp, name, prefix='enum'):510 if tp.partial:511 for enumerator in tp.enumerators:512 self._generate_gen_const(True, enumerator)513 return514 #515 funcname = self._enum_funcname(prefix, name)516 self.export_symbols.append(funcname)517 prnt = self._prnt518 prnt('int %s(char *out_error)' % funcname)519 prnt('{')520 for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):521 self._check_int_constant_value(enumerator, enumvalue)522 prnt(' return 0;')523 prnt('}')524 prnt()525 526 def _loading_gen_enum(self, tp, name, module, prefix='enum'):527 if tp.partial:528 enumvalues = [self._load_constant(True, tp, enumerator, module)529 for enumerator in tp.enumerators]530 tp.enumvalues = tuple(enumvalues)531 tp.partial_resolved = True532 else:533 funcname = self._enum_funcname(prefix, name)534 self._load_known_int_constant(module, funcname)535 536 def _loaded_gen_enum(self, tp, name, module, library):537 for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):538 setattr(library, enumerator, enumvalue)539 type(library)._cffi_dir.append(enumerator)540 541 # ----------542 # macros: for now only for integers543 544 def _generate_gen_macro_decl(self, tp, name):545 if tp == '...':546 check_value = None547 else:548 check_value = tp # an integer549 self._generate_gen_const(True, name, check_value=check_value)550 551 _loading_gen_macro = _loaded_noop552 553 def _loaded_gen_macro(self, tp, name, module, library):554 if tp == '...':555 check_value = None556 else:557 check_value = tp # an integer558 value = self._load_constant(True, tp, name, module,559 check_value=check_value)560 setattr(library, name, value)561 type(library)._cffi_dir.append(name)562 563 # ----------564 # global variables565 566 def _generate_gen_variable_decl(self, tp, name):567 if isinstance(tp, model.ArrayType):568 if tp.length_is_unknown():569 prnt = self._prnt570 funcname = '_cffi_sizeof_%s' % (name,)571 self.export_symbols.append(funcname)572 prnt("size_t %s(void)" % funcname)573 prnt("{")574 prnt(" return sizeof(%s);" % (name,))575 prnt("}")576 tp_ptr = model.PointerType(tp.item)577 self._generate_gen_const(False, name, tp_ptr)578 else:579 tp_ptr = model.PointerType(tp)580 self._generate_gen_const(False, name, tp_ptr, category='var')581 582 _loading_gen_variable = _loaded_noop583 584 def _loaded_gen_variable(self, tp, name, module, library):585 if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the586 # sense that "a=..." is forbidden587 if tp.length_is_unknown():588 funcname = '_cffi_sizeof_%s' % (name,)589 BFunc = self.ffi._typeof_locked('size_t(*)(void)')[0]590 function = module.load_function(BFunc, funcname)591 size = function()592 BItemType = self.ffi._get_cached_btype(tp.item)593 length, rest = divmod(size, self.ffi.sizeof(BItemType))594 if rest != 0:595 raise VerificationError(596 "bad size: %r does not seem to be an array of %s" %597 (name, tp.item))598 tp = tp.resolve_length(length)599 tp_ptr = model.PointerType(tp.item)600 value = self._load_constant(False, tp_ptr, name, module)601 # 'value' is a <cdata 'type *'> which we have to replace with602 # a <cdata 'type[N]'> if the N is actually known603 if tp.length is not None:604 BArray = self.ffi._get_cached_btype(tp)605 value = self.ffi.cast(BArray, value)606 setattr(library, name, value)607 type(library)._cffi_dir.append(name)608 return609 # remove ptr=<cdata 'int *'> from the library instance, and replace610 # it by a property on the class, which reads/writes into ptr[0].611 funcname = '_cffi_var_%s' % name612 BFunc = self.ffi._typeof_locked(tp.get_c_name('*(*)(void)', name))[0]613 function = module.load_function(BFunc, funcname)614 ptr = function()615 def getter(library):616 return ptr[0]617 def setter(library, value):618 ptr[0] = value619 setattr(type(library), name, property(getter, setter))620 type(library)._cffi_dir.append(name)621 622cffimod_header = r'''623#include <stdio.h>624#include <stddef.h>625#include <stdarg.h>626#include <errno.h>627#include <sys/types.h> /* XXX for ssize_t on some platforms */628 629/* this block of #ifs should be kept exactly identical between630 c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py631 and cffi/_cffi_include.h */632#if defined(_MSC_VER)633# include <malloc.h> /* for alloca() */634# if _MSC_VER < 1600 /* MSVC < 2010 */635 typedef __int8 int8_t;636 typedef __int16 int16_t;637 typedef __int32 int32_t;638 typedef __int64 int64_t;639 typedef unsigned __int8 uint8_t;640 typedef unsigned __int16 uint16_t;641 typedef unsigned __int32 uint32_t;642 typedef unsigned __int64 uint64_t;643 typedef __int8 int_least8_t;644 typedef __int16 int_least16_t;645 typedef __int32 int_least32_t;646 typedef __int64 int_least64_t;647 typedef unsigned __int8 uint_least8_t;648 typedef unsigned __int16 uint_least16_t;649 typedef unsigned __int32 uint_least32_t;650 typedef unsigned __int64 uint_least64_t;651 typedef __int8 int_fast8_t;652 typedef __int16 int_fast16_t;653 typedef __int32 int_fast32_t;654 typedef __int64 int_fast64_t;655 typedef unsigned __int8 uint_fast8_t;656 typedef unsigned __int16 uint_fast16_t;657 typedef unsigned __int32 uint_fast32_t;658 typedef unsigned __int64 uint_fast64_t;659 typedef __int64 intmax_t;660 typedef unsigned __int64 uintmax_t;661# else662# include <stdint.h>663# endif664# if _MSC_VER < 1800 /* MSVC < 2013 */665# ifndef __cplusplus666 typedef unsigned char _Bool;667# endif668# endif669# define _cffi_float_complex_t _Fcomplex /* include <complex.h> for it */670# define _cffi_double_complex_t _Dcomplex /* include <complex.h> for it */671#else672# include <stdint.h>673# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux)674# include <alloca.h>675# endif676# define _cffi_float_complex_t float _Complex677# define _cffi_double_complex_t double _Complex678#endif679'''680 