1import os, sys, io 2from . import ffiplatform, model 3from .error import VerificationError 4from .cffi_opcode import * 5 6VERSION_BASE = 0x2601 7VERSION_EMBEDDED = 0x2701 8VERSION_CHAR16CHAR32 = 0x2801 9 10 11class GlobalExpr: 12 def __init__(self, name, address, type_op, size=0, check_value=0): 13 self.name = name 14 self.address = address 15 self.type_op = type_op 16 self.size = size 17 self.check_value = check_value 18 19 def as_c_expr(self): 20 return ' { "%s", (void *)%s, %s, (void *)%s },' % ( 21 self.name, self.address, self.type_op.as_c_expr(), self.size) 22 23 def as_python_expr(self): 24 return "b'%s%s',%d" % (self.type_op.as_python_bytes(), self.name, 25 self.check_value) 26 27class FieldExpr: 28 def __init__(self, name, field_offset, field_size, fbitsize, field_type_op): 29 self.name = name 30 self.field_offset = field_offset 31 self.field_size = field_size 32 self.fbitsize = fbitsize 33 self.field_type_op = field_type_op 34 35 def as_c_expr(self): 36 spaces = " " * len(self.name) 37 return (' { "%s", %s,\n' % (self.name, self.field_offset) + 38 ' %s %s,\n' % (spaces, self.field_size) + 39 ' %s %s },' % (spaces, self.field_type_op.as_c_expr())) 40 41 def as_python_expr(self): 42 raise NotImplementedError 43 44 def as_field_python_expr(self): 45 if self.field_type_op.op == OP_NOOP: 46 size_expr = '' 47 elif self.field_type_op.op == OP_BITFIELD: 48 size_expr = format_four_bytes(self.fbitsize) 49 else: 50 raise NotImplementedError 51 return "b'%s%s%s'" % (self.field_type_op.as_python_bytes(), 52 size_expr, 53 self.name) 54 55class StructUnionExpr: 56 def __init__(self, name, type_index, flags, size, alignment, comment, 57 first_field_index, c_fields): 58 self.name = name 59 self.type_index = type_index 60 self.flags = flags 61 self.size = size 62 self.alignment = alignment 63 self.comment = comment 64 self.first_field_index = first_field_index 65 self.c_fields = c_fields 66 67 def as_c_expr(self): 68 return (' { "%s", %d, %s,' % (self.name, self.type_index, self.flags) 69 + '\n %s, %s, ' % (self.size, self.alignment) 70 + '%d, %d ' % (self.first_field_index, len(self.c_fields)) 71 + ('/* %s */ ' % self.comment if self.comment else '') 72 + '},') 73 74 def as_python_expr(self): 75 flags = eval(self.flags, G_FLAGS) 76 fields_expr = [c_field.as_field_python_expr() 77 for c_field in self.c_fields] 78 return "(b'%s%s%s',%s)" % ( 79 format_four_bytes(self.type_index), 80 format_four_bytes(flags), 81 self.name, 82 ','.join(fields_expr)) 83 84class EnumExpr: 85 def __init__(self, name, type_index, size, signed, allenums): 86 self.name = name 87 self.type_index = type_index 88 self.size = size 89 self.signed = signed 90 self.allenums = allenums 91 92 def as_c_expr(self): 93 return (' { "%s", %d, _cffi_prim_int(%s, %s),\n' 94 ' "%s" },' % (self.name, self.type_index, 95 self.size, self.signed, self.allenums)) 96 97 def as_python_expr(self): 98 prim_index = { 99 (1, 0): PRIM_UINT8, (1, 1): PRIM_INT8, 100 (2, 0): PRIM_UINT16, (2, 1): PRIM_INT16, 101 (4, 0): PRIM_UINT32, (4, 1): PRIM_INT32, 102 (8, 0): PRIM_UINT64, (8, 1): PRIM_INT64, 103 }[self.size, self.signed] 104 return "b'%s%s%s\\x00%s'" % (format_four_bytes(self.type_index), 105 format_four_bytes(prim_index), 106 self.name, self.allenums) 107 108class TypenameExpr: 109 def __init__(self, name, type_index): 110 self.name = name 111 self.type_index = type_index 112 113 def as_c_expr(self): 114 return ' { "%s", %d },' % (self.name, self.type_index) 115 116 def as_python_expr(self): 117 return "b'%s%s'" % (format_four_bytes(self.type_index), self.name) 118 119 120# ____________________________________________________________ 121 122 123class Recompiler: 124 _num_externpy = 0 125 126 def __init__(self, ffi, module_name, target_is_python=False): 127 self.ffi = ffi 128 self.module_name = module_name 129 self.target_is_python = target_is_python 130 self._version = VERSION_BASE 131 132 def needs_version(self, ver): 133 self._version = max(self._version, ver) 134 135 def collect_type_table(self): 136 self._typesdict = {} 137 self._generate("collecttype") 138 # 139 all_decls = sorted(self._typesdict, key=str) 140 # 141 # prepare all FUNCTION bytecode sequences first 142 self.cffi_types = [] 143 for tp in all_decls: 144 if tp.is_raw_function: 145 assert self._typesdict[tp] is None 146 self._typesdict[tp] = len(self.cffi_types) 147 self.cffi_types.append(tp) # placeholder 148 for tp1 in tp.args: 149 assert isinstance(tp1, (model.VoidType, 150 model.BasePrimitiveType, 151 model.PointerType, 152 model.StructOrUnionOrEnum, 153 model.FunctionPtrType)) 154 if self._typesdict[tp1] is None: 155 self._typesdict[tp1] = len(self.cffi_types) 156 self.cffi_types.append(tp1) # placeholder 157 self.cffi_types.append('END') # placeholder 158 # 159 # prepare all OTHER bytecode sequences 160 for tp in all_decls: 161 if not tp.is_raw_function and self._typesdict[tp] is None: 162 self._typesdict[tp] = len(self.cffi_types) 163 self.cffi_types.append(tp) # placeholder 164 if tp.is_array_type and tp.length is not None: 165 self.cffi_types.append('LEN') # placeholder 166 assert None not in self._typesdict.values() 167 # 168 # collect all structs and unions and enums 169 self._struct_unions = {} 170 self._enums = {} 171 for tp in all_decls: 172 if isinstance(tp, model.StructOrUnion): 173 self._struct_unions[tp] = None 174 elif isinstance(tp, model.EnumType): 175 self._enums[tp] = None 176 for i, tp in enumerate(sorted(self._struct_unions, 177 key=lambda tp: tp.name)): 178 self._struct_unions[tp] = i 179 for i, tp in enumerate(sorted(self._enums, 180 key=lambda tp: tp.name)): 181 self._enums[tp] = i 182 # 183 # emit all bytecode sequences now 184 for tp in all_decls: 185 method = getattr(self, '_emit_bytecode_' + tp.__class__.__name__) 186 method(tp, self._typesdict[tp]) 187 # 188 # consistency check 189 for op in self.cffi_types: 190 assert isinstance(op, CffiOp) 191 self.cffi_types = tuple(self.cffi_types) # don't change any more 192 193 def _do_collect_type(self, tp): 194 if not isinstance(tp, model.BaseTypeByIdentity): 195 if isinstance(tp, tuple): 196 for x in tp: 197 self._do_collect_type(x) 198 return 199 if tp not in self._typesdict: 200 self._typesdict[tp] = None 201 if isinstance(tp, model.FunctionPtrType): 202 self._do_collect_type(tp.as_raw_function()) 203 elif isinstance(tp, model.StructOrUnion): 204 if tp.fldtypes is not None and ( 205 tp not in self.ffi._parser._included_declarations): 206 for name1, tp1, _, _ in tp.enumfields(): 207 self._do_collect_type(self._field_type(tp, name1, tp1)) 208 else: 209 for _, x in tp._get_items(): 210 self._do_collect_type(x) 211 212 def _generate(self, step_name): 213 lst = self.ffi._parser._declarations.items() 214 for name, (tp, quals) in sorted(lst): 215 kind, realname = name.split(' ', 1) 216 try: 217 method = getattr(self, '_generate_cpy_%s_%s' % (kind, 218 step_name)) 219 except AttributeError: 220 raise VerificationError( 221 "not implemented in recompile(): %r" % name) 222 try: 223 self._current_quals = quals 224 method(tp, realname) 225 except Exception as e: 226 model.attach_exception_info(e, name) 227 raise 228 229 # ---------- 230 231 ALL_STEPS = ["global", "field", "struct_union", "enum", "typename"] 232 233 def collect_step_tables(self): 234 # collect the declarations for '_cffi_globals', '_cffi_typenames', etc. 235 self._lsts = {} 236 for step_name in self.ALL_STEPS: 237 self._lsts[step_name] = [] 238 self._seen_struct_unions = set() 239 self._generate("ctx") 240 self._add_missing_struct_unions() 241 # 242 for step_name in self.ALL_STEPS: 243 lst = self._lsts[step_name] 244 if step_name != "field": 245 lst.sort(key=lambda entry: entry.name) 246 self._lsts[step_name] = tuple(lst) # don't change any more 247 # 248 # check for a possible internal inconsistency: _cffi_struct_unions 249 # should have been generated with exactly self._struct_unions 250 lst = self._lsts["struct_union"] 251 for tp, i in self._struct_unions.items(): 252 assert i < len(lst) 253 assert lst[i].name == tp.name 254 assert len(lst) == len(self._struct_unions) 255 # same with enums 256 lst = self._lsts["enum"] 257 for tp, i in self._enums.items(): 258 assert i < len(lst) 259 assert lst[i].name == tp.name 260 assert len(lst) == len(self._enums) 261 262 # ---------- 263 264 def _prnt(self, what=''): 265 self._f.write(what + '\n') 266 267 def write_source_to_f(self, f, preamble): 268 if self.target_is_python: 269 assert preamble is None 270 self.write_py_source_to_f(f) 271 else: 272 assert preamble is not None 273 self.write_c_source_to_f(f, preamble) 274 275 def _rel_readlines(self, filename): 276 g = open(os.path.join(os.path.dirname(__file__), filename), 'r') 277 lines = g.readlines() 278 g.close() 279 return lines 280 281 def write_c_source_to_f(self, f, preamble): 282 self._f = f 283 prnt = self._prnt 284 if self.ffi._embedding is not None: 285 prnt('#define _CFFI_USE_EMBEDDING') 286 # 287 # first the '#include' (actually done by inlining the file's content) 288 lines = self._rel_readlines('_cffi_include.h') 289 i = lines.index('#include "parse_c_type.h"\n') 290 lines[i:i+1] = self._rel_readlines('parse_c_type.h') 291 prnt(''.join(lines)) 292 # 293 # if we have ffi._embedding != None, we give it here as a macro 294 # and include an extra file 295 base_module_name = self.module_name.split('.')[-1] 296 if self.ffi._embedding is not None: 297 prnt('#define _CFFI_MODULE_NAME "%s"' % (self.module_name,)) 298 prnt('static const char _CFFI_PYTHON_STARTUP_CODE[] = {') 299 self._print_string_literal_in_array(self.ffi._embedding) 300 prnt('0 };') 301 prnt('#ifdef PYPY_VERSION') 302 prnt('# define _CFFI_PYTHON_STARTUP_FUNC _cffi_pypyinit_%s' % ( 303 base_module_name,)) 304 prnt('#elif PY_MAJOR_VERSION >= 3') 305 prnt('# define _CFFI_PYTHON_STARTUP_FUNC PyInit_%s' % ( 306 base_module_name,)) 307 prnt('#else') 308 prnt('# define _CFFI_PYTHON_STARTUP_FUNC init%s' % ( 309 base_module_name,)) 310 prnt('#endif') 311 lines = self._rel_readlines('_embedding.h') 312 i = lines.index('#include "_cffi_errors.h"\n') 313 lines[i:i+1] = self._rel_readlines('_cffi_errors.h') 314 prnt(''.join(lines)) 315 self.needs_version(VERSION_EMBEDDED) 316 # 317 # then paste the C source given by the user, verbatim. 318 prnt('/************************************************************/') 319 prnt() 320 prnt(preamble) 321 prnt() 322 prnt('/************************************************************/') 323 prnt() 324 # 325 # the declaration of '_cffi_types' 326 prnt('static void *_cffi_types[] = {') 327 typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()]) 328 for i, op in enumerate(self.cffi_types): 329 comment = '' 330 if i in typeindex2type: 331 comment = ' // ' + typeindex2type[i]._get_c_name() 332 prnt('/* %2d */ %s,%s' % (i, op.as_c_expr(), comment)) 333 if not self.cffi_types: 334 prnt(' 0') 335 prnt('};') 336 prnt() 337 # 338 # call generate_cpy_xxx_decl(), for every xxx found from 339 # ffi._parser._declarations. This generates all the functions. 340 self._seen_constants = set() 341 self._generate("decl") 342 # 343 # the declaration of '_cffi_globals' and '_cffi_typenames' 344 nums = {} 345 for step_name in self.ALL_STEPS: 346 lst = self._lsts[step_name] 347 nums[step_name] = len(lst) 348 if nums[step_name] > 0: 349 prnt('static const struct _cffi_%s_s _cffi_%ss[] = {' % ( 350 step_name, step_name)) 351 for entry in lst: 352 prnt(entry.as_c_expr()) 353 prnt('};') 354 prnt() 355 # 356 # the declaration of '_cffi_includes' 357 if self.ffi._included_ffis: 358 prnt('static const char * const _cffi_includes[] = {') 359 for ffi_to_include in self.ffi._included_ffis: 360 try: 361 included_module_name, included_source = ( 362 ffi_to_include._assigned_source[:2]) 363 except AttributeError: 364 raise VerificationError( 365 "ffi object %r includes %r, but the latter has not " 366 "been prepared with set_source()" % ( 367 self.ffi, ffi_to_include,)) 368 if included_source is None: 369 raise VerificationError( 370 "not implemented yet: ffi.include() of a Python-based " 371 "ffi inside a C-based ffi") 372 prnt(' "%s",' % (included_module_name,)) 373 prnt(' NULL') 374 prnt('};') 375 prnt() 376 # 377 # the declaration of '_cffi_type_context' 378 prnt('static const struct _cffi_type_context_s _cffi_type_context = {') 379 prnt(' _cffi_types,') 380 for step_name in self.ALL_STEPS: 381 if nums[step_name] > 0: 382 prnt(' _cffi_%ss,' % step_name) 383 else: 384 prnt(' NULL, /* no %ss */' % step_name) 385 for step_name in self.ALL_STEPS: 386 if step_name != "field": 387 prnt(' %d, /* num_%ss */' % (nums[step_name], step_name)) 388 if self.ffi._included_ffis: 389 prnt(' _cffi_includes,') 390 else: 391 prnt(' NULL, /* no includes */') 392 prnt(' %d, /* num_types */' % (len(self.cffi_types),)) 393 flags = 0 394 if self._num_externpy: 395 flags |= 1 # set to mean that we use extern "Python" 396 prnt(' %d, /* flags */' % flags) 397 prnt('};') 398 prnt() 399 # 400 # the init function 401 prnt('#ifdef __GNUC__') 402 prnt('# pragma GCC visibility push(default) /* for -fvisibility= */') 403 prnt('#endif') 404 prnt() 405 prnt('#ifdef PYPY_VERSION') 406 prnt('PyMODINIT_FUNC') 407 prnt('_cffi_pypyinit_%s(const void *p[])' % (base_module_name,)) 408 prnt('{') 409 if self._num_externpy: 410 prnt(' if (((intptr_t)p[0]) >= 0x0A03) {') 411 prnt(' _cffi_call_python_org = ' 412 '(void(*)(struct _cffi_externpy_s *, char *))p[1];') 413 prnt(' }') 414 prnt(' p[0] = (const void *)0x%x;' % self._version) 415 prnt(' p[1] = &_cffi_type_context;') 416 prnt('#if PY_MAJOR_VERSION >= 3') 417 prnt(' return NULL;') 418 prnt('#endif') 419 prnt('}') 420 # on Windows, distutils insists on putting init_cffi_xyz in 421 # 'export_symbols', so instead of fighting it, just give up and 422 # give it one 423 prnt('# ifdef _MSC_VER') 424 prnt(' PyMODINIT_FUNC') 425 prnt('# if PY_MAJOR_VERSION >= 3') 426 prnt(' PyInit_%s(void) { return NULL; }' % (base_module_name,)) 427 prnt('# else') 428 prnt(' init%s(void) { }' % (base_module_name,)) 429 prnt('# endif') 430 prnt('# endif') 431 prnt('#elif PY_MAJOR_VERSION >= 3') 432 prnt('PyMODINIT_FUNC') 433 prnt('PyInit_%s(void)' % (base_module_name,)) 434 prnt('{') 435 prnt(' return _cffi_init("%s", 0x%x, &_cffi_type_context);' % ( 436 self.module_name, self._version)) 437 prnt('}') 438 prnt('#else') 439 prnt('PyMODINIT_FUNC') 440 prnt('init%s(void)' % (base_module_name,)) 441 prnt('{') 442 prnt(' _cffi_init("%s", 0x%x, &_cffi_type_context);' % ( 443 self.module_name, self._version)) 444 prnt('}') 445 prnt('#endif') 446 prnt() 447 prnt('#ifdef __GNUC__') 448 prnt('# pragma GCC visibility pop') 449 prnt('#endif') 450 self._version = None 451 452 def _to_py(self, x): 453 if isinstance(x, str): 454 return "b'%s'" % (x,) 455 if isinstance(x, (list, tuple)): 456 rep = [self._to_py(item) for item in x] 457 if len(rep) == 1: 458 rep.append('') 459 return "(%s)" % (','.join(rep),) 460 return x.as_python_expr() # Py2: unicode unexpected; Py3: bytes unexp. 461 462 def write_py_source_to_f(self, f): 463 self._f = f 464 prnt = self._prnt 465 # 466 # header 467 prnt("# auto-generated file") 468 prnt("import _cffi_backend") 469 # 470 # the 'import' of the included ffis 471 num_includes = len(self.ffi._included_ffis or ()) 472 for i in range(num_includes): 473 ffi_to_include = self.ffi._included_ffis[i] 474 try: 475 included_module_name, included_source = ( 476 ffi_to_include._assigned_source[:2]) 477 except AttributeError: 478 raise VerificationError( 479 "ffi object %r includes %r, but the latter has not " 480 "been prepared with set_source()" % ( 481 self.ffi, ffi_to_include,)) 482 if included_source is not None: 483 raise VerificationError( 484 "not implemented yet: ffi.include() of a C-based " 485 "ffi inside a Python-based ffi") 486 prnt('from %s import ffi as _ffi%d' % (included_module_name, i)) 487 prnt() 488 prnt("ffi = _cffi_backend.FFI('%s'," % (self.module_name,)) 489 prnt(" _version = 0x%x," % (self._version,)) 490 self._version = None 491 # 492 # the '_types' keyword argument 493 self.cffi_types = tuple(self.cffi_types) # don't change any more 494 types_lst = [op.as_python_bytes() for op in self.cffi_types] 495 prnt(' _types = %s,' % (self._to_py(''.join(types_lst)),)) 496 typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()]) 497 # 498 # the keyword arguments from ALL_STEPS 499 for step_name in self.ALL_STEPS: 500 lst = self._lsts[step_name] 501 if len(lst) > 0 and step_name != "field": 502 prnt(' _%ss = %s,' % (step_name, self._to_py(lst))) 503 # 504 # the '_includes' keyword argument 505 if num_includes > 0: 506 prnt(' _includes = (%s,),' % ( 507 ', '.join(['_ffi%d' % i for i in range(num_includes)]),)) 508 # 509 # the footer 510 prnt(')') 511 512 # ---------- 513 514 def _gettypenum(self, type): 515 # a KeyError here is a bug. please report it! :-) 516 return self._typesdict[type] 517 518 def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): 519 extraarg = '' 520 if isinstance(tp, model.BasePrimitiveType) and not tp.is_complex_type(): 521 if tp.is_integer_type() and tp.name != '_Bool': 522 converter = '_cffi_to_c_int' 523 extraarg = ', %s' % tp.name 524 elif isinstance(tp, model.UnknownFloatType): 525 # don't check with is_float_type(): it may be a 'long 526 # double' here, and _cffi_to_c_double would loose precision 527 converter = '(%s)_cffi_to_c_double' % (tp.get_c_name(''),) 528 else: 529 cname = tp.get_c_name('') 530 converter = '(%s)_cffi_to_c_%s' % (cname, 531 tp.name.replace(' ', '_')) 532 if cname in ('char16_t', 'char32_t'): 533 self.needs_version(VERSION_CHAR16CHAR32) 534 errvalue = '-1' 535 # 536 elif isinstance(tp, model.PointerType): 537 self._convert_funcarg_to_c_ptr_or_array(tp, fromvar, 538 tovar, errcode) 539 return 540 # 541 elif (isinstance(tp, model.StructOrUnionOrEnum) or 542 isinstance(tp, model.BasePrimitiveType)): 543 # a struct (not a struct pointer) as a function argument; 544 # or, a complex (the same code works) 545 self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' 546 % (tovar, self._gettypenum(tp), fromvar)) 547 self._prnt(' %s;' % errcode) 548 return 549 # 550 elif isinstance(tp, model.FunctionPtrType): 551 converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('') 552 extraarg = ', _cffi_type(%d)' % self._gettypenum(tp) 553 errvalue = 'NULL' 554 # 555 else: 556 raise NotImplementedError(tp) 557 # 558 self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg)) 559 self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % ( 560 tovar, tp.get_c_name(''), errvalue)) 561 self._prnt(' %s;' % errcode) 562 563 def _extra_local_variables(self, tp, localvars): 564 if isinstance(tp, model.PointerType): 565 localvars.add('Py_ssize_t datasize') 566 567 def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode): 568 self._prnt(' datasize = _cffi_prepare_pointer_call_argument(') 569 self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % ( 570 self._gettypenum(tp), fromvar, tovar)) 571 self._prnt(' if (datasize != 0) {') 572 self._prnt(' if (datasize < 0)') 573 self._prnt(' %s;' % errcode) 574 self._prnt(' %s = (%s)alloca((size_t)datasize);' % ( 575 tovar, tp.get_c_name(''))) 576 self._prnt(' memset((void *)%s, 0, (size_t)datasize);' % (tovar,)) 577 self._prnt(' if (_cffi_convert_array_from_object(' 578 '(char *)%s, _cffi_type(%d), %s) < 0)' % ( 579 tovar, self._gettypenum(tp), fromvar)) 580 self._prnt(' %s;' % errcode) 581 self._prnt(' }') 582 583 def _convert_expr_from_c(self, tp, var, context): 584 if isinstance(tp, model.BasePrimitiveType): 585 if tp.is_integer_type() and tp.name != '_Bool': 586 return '_cffi_from_c_int(%s, %s)' % (var, tp.name) 587 elif isinstance(tp, model.UnknownFloatType): 588 return '_cffi_from_c_double(%s)' % (var,) 589 elif tp.name != 'long double' and not tp.is_complex_type(): 590 cname = tp.name.replace(' ', '_') 591 if cname in ('char16_t', 'char32_t'): 592 self.needs_version(VERSION_CHAR16CHAR32) 593 return '_cffi_from_c_%s(%s)' % (cname, var) 594 else: 595 return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( 596 var, self._gettypenum(tp)) 597 elif isinstance(tp, (model.PointerType, model.FunctionPtrType)): 598 return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( 599 var, self._gettypenum(tp)) 600 elif isinstance(tp, model.ArrayType): 601 return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( 602 var, self._gettypenum(model.PointerType(tp.item))) 603 elif isinstance(tp, model.StructOrUnion): 604 if tp.fldnames is None: 605 raise TypeError("'%s' is used as %s, but is opaque" % ( 606 tp._get_c_name(), context)) 607 return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % ( 608 var, self._gettypenum(tp)) 609 elif isinstance(tp, model.EnumType): 610 return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( 611 var, self._gettypenum(tp)) 612 else: 613 raise NotImplementedError(tp) 614 615 # ---------- 616 # typedefs 617 618 def _typedef_type(self, tp, name): 619 return self._global_type(tp, "(*(%s *)0)" % (name,)) 620 621 def _generate_cpy_typedef_collecttype(self, tp, name): 622 self._do_collect_type(self._typedef_type(tp, name)) 623 624 def _generate_cpy_typedef_decl(self, tp, name): 625 pass 626 627 def _typedef_ctx(self, tp, name): 628 type_index = self._typesdict[tp] 629 self._lsts["typename"].append(TypenameExpr(name, type_index)) 630 631 def _generate_cpy_typedef_ctx(self, tp, name): 632 tp = self._typedef_type(tp, name) 633 self._typedef_ctx(tp, name) 634 if getattr(tp, "origin", None) == "unknown_type": 635 self._struct_ctx(tp, tp.name, approxname=None) 636 elif isinstance(tp, model.NamedPointerType): 637 self._struct_ctx(tp.totype, tp.totype.name, approxname=tp.name, 638 named_ptr=tp) 639 640 # ---------- 641 # function declarations 642 643 def _generate_cpy_function_collecttype(self, tp, name): 644 self._do_collect_type(tp.as_raw_function()) 645 if tp.ellipsis and not self.target_is_python: 646 self._do_collect_type(tp) 647 648 def _generate_cpy_function_decl(self, tp, name): 649 assert not self.target_is_python 650 assert isinstance(tp, model.FunctionPtrType) 651 if tp.ellipsis: 652 # cannot support vararg functions better than this: check for its 653 # exact type (including the fixed arguments), and build it as a 654 # constant function pointer (no CPython wrapper) 655 self._generate_cpy_constant_decl(tp, name) 656 return 657 prnt = self._prnt 658 numargs = len(tp.args) 659 if numargs == 0: 660 argname = 'noarg' 661 elif numargs == 1: 662 argname = 'arg0' 663 else: 664 argname = 'args' 665 # 666 # ------------------------------ 667 # the 'd' version of the function, only for addressof(lib, 'func') 668 arguments = [] 669 call_arguments = [] 670 context = 'argument of %s' % name 671 for i, type in enumerate(tp.args): 672 arguments.append(type.get_c_name(' x%d' % i, context)) 673 call_arguments.append('x%d' % i) 674 repr_arguments = ', '.join(arguments) 675 repr_arguments = repr_arguments or 'void' 676 if tp.abi: 677 abi = tp.abi + ' ' 678 else: 679 abi = '' 680 name_and_arguments = '%s_cffi_d_%s(%s)' % (abi, name, repr_arguments) 681 prnt('static %s' % (tp.result.get_c_name(name_and_arguments),)) 682 prnt('{') 683 call_arguments = ', '.join(call_arguments) 684 result_code = 'return ' 685 if isinstance(tp.result, model.VoidType): 686 result_code = '' 687 prnt(' %s%s(%s);' % (result_code, name, call_arguments)) 688 prnt('}') 689 # 690 prnt('#ifndef PYPY_VERSION') # ------------------------------ 691 # 692 prnt('static PyObject *') 693 prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname)) 694 prnt('{') 695 # 696 context = 'argument of %s' % name 697 for i, type in enumerate(tp.args): 698 arg = type.get_c_name(' x%d' % i, context) 699 prnt(' %s;' % arg) 700 # 701 localvars = set() 702 for type in tp.args: 703 self._extra_local_variables(type, localvars) 704 for decl in localvars: 705 prnt(' %s;' % (decl,)) 706 # 707 if not isinstance(tp.result, model.VoidType): 708 result_code = 'result = ' 709 context = 'result of %s' % name 710 result_decl = ' %s;' % tp.result.get_c_name(' result', context) 711 prnt(result_decl) 712 else: 713 result_decl = None 714 result_code = '' 715 # 716 if len(tp.args) > 1: 717 rng = range(len(tp.args)) 718 for i in rng: 719 prnt(' PyObject *arg%d;' % i) 720 prnt() 721 prnt(' if (!PyArg_UnpackTuple(args, "%s", %d, %d, %s))' % ( 722 name, len(rng), len(rng), 723 ', '.join(['&arg%d' % i for i in rng]))) 724 prnt(' return NULL;') 725 prnt() 726 # 727 for i, type in enumerate(tp.args): 728 self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i, 729 'return NULL') 730 prnt() 731 # 732 prnt(' Py_BEGIN_ALLOW_THREADS') 733 prnt(' _cffi_restore_errno();') 734 call_arguments = ['x%d' % i for i in range(len(tp.args))] 735 call_arguments = ', '.join(call_arguments) 736 prnt(' { %s%s(%s); }' % (result_code, name, call_arguments)) 737 prnt(' _cffi_save_errno();') 738 prnt(' Py_END_ALLOW_THREADS') 739 prnt() 740 # 741 prnt(' (void)self; /* unused */') 742 if numargs == 0: 743 prnt(' (void)noarg; /* unused */') 744 if result_code: 745 prnt(' return %s;' % 746 self._convert_expr_from_c(tp.result, 'result', 'result type')) 747 else: 748 prnt(' Py_INCREF(Py_None);') 749 prnt(' return Py_None;') 750 prnt('}') 751 # 752 prnt('#else') # ------------------------------ 753 # 754 # the PyPy version: need to replace struct/union arguments with 755 # pointers, and if the result is a struct/union, insert a first 756 # arg that is a pointer to the result. We also do that for 757 # complex args and return type. 758 def need_indirection(type): 759 return (isinstance(type, model.StructOrUnion) or 760 (isinstance(type, model.PrimitiveType) and 761 type.is_complex_type())) 762 difference = False 763 arguments = [] 764 call_arguments = [] 765 context = 'argument of %s' % name 766 for i, type in enumerate(tp.args): 767 indirection = '' 768 if need_indirection(type): 769 indirection = '*' 770 difference = True 771 arg = type.get_c_name(' %sx%d' % (indirection, i), context) 772 arguments.append(arg) 773 call_arguments.append('%sx%d' % (indirection, i)) 774 tp_result = tp.result 775 if need_indirection(tp_result): 776 context = 'result of %s' % name 777 arg = tp_result.get_c_name(' *result', context) 778 arguments.insert(0, arg) 779 tp_result = model.void_type 780 result_decl = None 781 result_code = '*result = ' 782 difference = True 783 if difference: 784 repr_arguments = ', '.join(arguments) 785 repr_arguments = repr_arguments or 'void' 786 name_and_arguments = '%s_cffi_f_%s(%s)' % (abi, name, 787 repr_arguments) 788 prnt('static %s' % (tp_result.get_c_name(name_and_arguments),)) 789 prnt('{') 790 if result_decl: 791 prnt(result_decl) 792 call_arguments = ', '.join(call_arguments) 793 prnt(' { %s%s(%s); }' % (result_code, name, call_arguments)) 794 if result_decl: 795 prnt(' return result;') 796 prnt('}') 797 else: 798 prnt('# define _cffi_f_%s _cffi_d_%s' % (name, name)) 799 # 800 prnt('#endif') # ------------------------------ 801 prnt() 802 803 def _generate_cpy_function_ctx(self, tp, name): 804 if tp.ellipsis and not self.target_is_python: 805 self._generate_cpy_constant_ctx(tp, name) 806 return 807 type_index = self._typesdict[tp.as_raw_function()] 808 numargs = len(tp.args) 809 if self.target_is_python: 810 meth_kind = OP_DLOPEN_FUNC 811 elif numargs == 0: 812 meth_kind = OP_CPYTHON_BLTN_N # 'METH_NOARGS' 813 elif numargs == 1: 814 meth_kind = OP_CPYTHON_BLTN_O # 'METH_O' 815 else: 816 meth_kind = OP_CPYTHON_BLTN_V # 'METH_VARARGS' 817 self._lsts["global"].append( 818 GlobalExpr(name, '_cffi_f_%s' % name, 819 CffiOp(meth_kind, type_index), 820 size='_cffi_d_%s' % name)) 821 822 # ---------- 823 # named structs or unions 824 825 def _field_type(self, tp_struct, field_name, tp_field): 826 if isinstance(tp_field, model.ArrayType): 827 actual_length = tp_field.length 828 if actual_length == '...': 829 ptr_struct_name = tp_struct.get_c_name('*') 830 actual_length = '_cffi_array_len(((%s)0)->%s)' % ( 831 ptr_struct_name, field_name) 832 tp_item = self._field_type(tp_struct, '%s[0]' % field_name, 833 tp_field.item) 834 tp_field = model.ArrayType(tp_item, actual_length) 835 return tp_field 836 837 def _struct_collecttype(self, tp): 838 self._do_collect_type(tp) 839 if self.target_is_python: 840 # also requires nested anon struct/unions in ABI mode, recursively 841 for fldtype in tp.anonymous_struct_fields(): 842 self._struct_collecttype(fldtype) 843 844 def _struct_decl(self, tp, cname, approxname): 845 if tp.fldtypes is None: 846 return 847 prnt = self._prnt 848 checkfuncname = '_cffi_checkfld_%s' % (approxname,) 849 prnt('_CFFI_UNUSED_FN') 850 prnt('static void %s(%s *p)' % (checkfuncname, cname)) 851 prnt('{') 852 prnt(' /* only to generate compile-time warnings or errors */') 853 prnt(' (void)p;') 854 for fname, ftype, fbitsize, fqual in tp.enumfields(): 855 try: 856 if ftype.is_integer_type() or fbitsize >= 0: 857 # accept all integers, but complain on float or double 858 prnt(" (void)((p->%s) | 0); /* check that '%s.%s' is " 859 "an integer */" % (fname, cname, fname)) 860 continue 861 # only accept exactly the type declared, except that '[]' 862 # is interpreted as a '*' and so will match any array length. 863 # (It would also match '*', but that's harder to detect...) 864 while (isinstance(ftype, model.ArrayType) 865 and (ftype.length is None or ftype.length == '...')): 866 ftype = ftype.item 867 fname = fname + '[0]' 868 prnt(' { %s = &p->%s; (void)tmp; }' % ( 869 ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), 870 fname)) 871 except VerificationError as e: 872 prnt(' /* %s */' % str(e)) # cannot verify it, ignore 873 prnt('}') 874 prnt('struct _cffi_align_%s { char x; %s y; };' % (approxname, cname)) 875 prnt() 876 877 def _struct_ctx(self, tp, cname, approxname, named_ptr=None): 878 type_index = self._typesdict[tp] 879 reason_for_not_expanding = None 880 flags = [] 881 if isinstance(tp, model.UnionType): 882 flags.append("_CFFI_F_UNION") 883 if tp.fldtypes is None: 884 flags.append("_CFFI_F_OPAQUE") 885 reason_for_not_expanding = "opaque" 886 if (tp not in self.ffi._parser._included_declarations and 887 (named_ptr is None or 888 named_ptr not in self.ffi._parser._included_declarations)): 889 if tp.fldtypes is None: 890 pass # opaque 891 elif tp.partial or any(tp.anonymous_struct_fields()): 892 pass # field layout obtained silently from the C compiler 893 else: 894 flags.append("_CFFI_F_CHECK_FIELDS") 895 if tp.packed: 896 if tp.packed > 1: 897 raise NotImplementedError( 898 "%r is declared with 'pack=%r'; only 0 or 1 are " 899 "supported in API mode (try to use \"...;\", which " 900 "does not require a 'pack' declaration)" % 901 (tp, tp.packed)) 902 flags.append("_CFFI_F_PACKED") 903 else: 904 flags.append("_CFFI_F_EXTERNAL") 905 reason_for_not_expanding = "external" 906 flags = '|'.join(flags) or '0' 907 c_fields = [] 908 if reason_for_not_expanding is None: 909 expand_anonymous_struct_union = not self.target_is_python 910 enumfields = list(tp.enumfields(expand_anonymous_struct_union)) 911 for fldname, fldtype, fbitsize, fqual in enumfields: 912 fldtype = self._field_type(tp, fldname, fldtype) 913 self._check_not_opaque(fldtype, 914 "field '%s.%s'" % (tp.name, fldname)) 915 # cname is None for _add_missing_struct_unions() only 916 op = OP_NOOP 917 if fbitsize >= 0: 918 op = OP_BITFIELD 919 size = '%d /* bits */' % fbitsize 920 elif cname is None or ( 921 isinstance(fldtype, model.ArrayType) and 922 fldtype.length is None): 923 size = '(size_t)-1' 924 else: 925 size = 'sizeof(((%s)0)->%s)' % ( 926 tp.get_c_name('*') if named_ptr is None 927 else named_ptr.name, 928 fldname) 929 if cname is None or fbitsize >= 0: 930 offset = '(size_t)-1' 931 elif named_ptr is not None: 932 offset = '((char *)&((%s)0)->%s) - (char *)0' % ( 933 named_ptr.name, fldname) 934 else: 935 offset = 'offsetof(%s, %s)' % (tp.get_c_name(''), fldname) 936 c_fields.append( 937 FieldExpr(fldname, offset, size, fbitsize, 938 CffiOp(op, self._typesdict[fldtype]))) 939 first_field_index = len(self._lsts["field"]) 940 self._lsts["field"].extend(c_fields) 941 # 942 if cname is None: # unknown name, for _add_missing_struct_unions 943 size = '(size_t)-2' 944 align = -2 945 comment = "unnamed" 946 else: 947 if named_ptr is not None: 948 size = 'sizeof(*(%s)0)' % (named_ptr.name,) 949 align = '-1 /* unknown alignment */' 950 else: 951 size = 'sizeof(%s)' % (cname,) 952 align = 'offsetof(struct _cffi_align_%s, y)' % (approxname,) 953 comment = None 954 else: 955 size = '(size_t)-1' 956 align = -1 957 first_field_index = -1 958 comment = reason_for_not_expanding 959 self._lsts["struct_union"].append( 960 StructUnionExpr(tp.name, type_index, flags, size, align, comment, 961 first_field_index, c_fields)) 962 self._seen_struct_unions.add(tp) 963 964 def _check_not_opaque(self, tp, location): 965 while isinstance(tp, model.ArrayType): 966 tp = tp.item 967 if isinstance(tp, model.StructOrUnion) and tp.fldtypes is None: 968 raise TypeError( 969 "%s is of an opaque type (not declared in cdef())" % location) 970 971 def _add_missing_struct_unions(self): 972 # not very nice, but some struct declarations might be missing 973 # because they don't have any known C name. Check that they are 974 # not partial (we can't complete or verify them!) and emit them 975 # anonymously. 976 lst = list(self._struct_unions.items()) 977 lst.sort(key=lambda tp_order: tp_order[1]) 978 for tp, order in lst: 979 if tp not in self._seen_struct_unions: 980 if tp.partial: 981 raise NotImplementedError("internal inconsistency: %r is " 982 "partial but was not seen at " 983 "this point" % (tp,)) 984 if tp.name.startswith('$') and tp.name[1:].isdigit(): 985 approxname = tp.name[1:] 986 elif tp.name == '_IO_FILE' and tp.forcename == 'FILE': 987 approxname = 'FILE' 988 self._typedef_ctx(tp, 'FILE') 989 else: 990 raise NotImplementedError("internal inconsistency: %r" % 991 (tp,)) 992 self._struct_ctx(tp, None, approxname) 993 994 def _generate_cpy_struct_collecttype(self, tp, name): 995 self._struct_collecttype(tp) 996 _generate_cpy_union_collecttype = _generate_cpy_struct_collecttype 997 998 def _struct_names(self, tp): 999 cname = tp.get_c_name('') 1000 if ' ' in cname: 1001 return cname, cname.replace(' ', '_') 1002 else: 1003 return cname, '_' + cname 1004 1005 def _generate_cpy_struct_decl(self, tp, name): 1006 self._struct_decl(tp, *self._struct_names(tp)) 1007 _generate_cpy_union_decl = _generate_cpy_struct_decl 1008 1009 def _generate_cpy_struct_ctx(self, tp, name): 1010 self._struct_ctx(tp, *self._struct_names(tp)) 1011 _generate_cpy_union_ctx = _generate_cpy_struct_ctx 1012 1013 # ---------- 1014 # 'anonymous' declarations. These are produced for anonymous structs 1015 # or unions; the 'name' is obtained by a typedef. 1016 1017 def _generate_cpy_anonymous_collecttype(self, tp, name): 1018 if isinstance(tp, model.EnumType): 1019 self._generate_cpy_enum_collecttype(tp, name) 1020 else: 1021 self._struct_collecttype(tp) 1022 1023 def _generate_cpy_anonymous_decl(self, tp, name): 1024 if isinstance(tp, model.EnumType): 1025 self._generate_cpy_enum_decl(tp) 1026 else: 1027 self._struct_decl(tp, name, 'typedef_' + name) 1028 1029 def _generate_cpy_anonymous_ctx(self, tp, name): 1030 if isinstance(tp, model.EnumType): 1031 self._enum_ctx(tp, name) 1032 else: 1033 self._struct_ctx(tp, name, 'typedef_' + name) 1034 1035 # ---------- 1036 # constants, declared with "static const ..." 1037 1038 def _generate_cpy_const(self, is_int, name, tp=None, category='const', 1039 check_value=None): 1040 if (category, name) in self._seen_constants: 1041 raise VerificationError( 1042 "duplicate declaration of %s '%s'" % (category, name)) 1043 self._seen_constants.add((category, name)) 1044 # 1045 prnt = self._prnt 1046 funcname = '_cffi_%s_%s' % (category, name) 1047 if is_int: 1048 prnt('static int %s(unsigned long long *o)' % funcname) 1049 prnt('{') 1050 prnt(' int n = (%s) <= 0;' % (name,)) 1051 prnt(' *o = (unsigned long long)((%s) | 0);' 1052 ' /* check that %s is an integer */' % (name, name)) 1053 if check_value is not None: 1054 if check_value > 0: 1055 check_value = '%dU' % (check_value,) 1056 prnt(' if (!_cffi_check_int(*o, n, %s))' % (check_value,)) 1057 prnt(' n |= 2;') 1058 prnt(' return n;') 1059 prnt('}') 1060 else: 1061 assert check_value is None 1062 prnt('static void %s(char *o)' % funcname) 1063 prnt('{') 1064 prnt(' *(%s)o = %s;' % (tp.get_c_name('*'), name)) 1065 prnt('}') 1066 prnt() 1067 1068 def _generate_cpy_constant_collecttype(self, tp, name): 1069 is_int = tp.is_integer_type() 1070 if not is_int or self.target_is_python: 1071 self._do_collect_type(tp) 1072 1073 def _generate_cpy_constant_decl(self, tp, name): 1074 is_int = tp.is_integer_type() 1075 self._generate_cpy_const(is_int, name, tp) 1076 1077 def _generate_cpy_constant_ctx(self, tp, name): 1078 if not self.target_is_python and tp.is_integer_type(): 1079 type_op = CffiOp(OP_CONSTANT_INT, -1) 1080 else: 1081 if self.target_is_python: 1082 const_kind = OP_DLOPEN_CONST 1083 else: 1084 const_kind = OP_CONSTANT 1085 type_index = self._typesdict[tp] 1086 type_op = CffiOp(const_kind, type_index) 1087 self._lsts["global"].append( 1088 GlobalExpr(name, '_cffi_const_%s' % name, type_op)) 1089 1090 # ---------- 1091 # enums 1092 1093 def _generate_cpy_enum_collecttype(self, tp, name): 1094 self._do_collect_type(tp) 1095 1096 def _generate_cpy_enum_decl(self, tp, name=None): 1097 for enumerator in tp.enumerators: 1098 self._generate_cpy_const(True, enumerator) 1099 1100 def _enum_ctx(self, tp, cname): 1101 type_index = self._typesdict[tp] 1102 type_op = CffiOp(OP_ENUM, -1) 1103 if self.target_is_python: 1104 tp.check_not_partial() 1105 for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): 1106 self._lsts["global"].append( 1107 GlobalExpr(enumerator, '_cffi_const_%s' % enumerator, type_op, 1108 check_value=enumvalue)) 1109 # 1110 if cname is not None and '$' not in cname and not self.target_is_python: 1111 size = "sizeof(%s)" % cname 1112 signed = "((%s)-1) <= 0" % cname 1113 else: 1114 basetp = tp.build_baseinttype(self.ffi, []) 1115 size = self.ffi.sizeof(basetp) 1116 signed = int(int(self.ffi.cast(basetp, -1)) < 0) 1117 allenums = ",".join(tp.enumerators) 1118 self._lsts["enum"].append( 1119 EnumExpr(tp.name, type_index, size, signed, allenums)) 1120 1121 def _generate_cpy_enum_ctx(self, tp, name): 1122 self._enum_ctx(tp, tp._get_c_name()) 1123 1124 # ---------- 1125 # macros: for now only for integers 1126 1127 def _generate_cpy_macro_collecttype(self, tp, name): 1128 pass 1129 1130 def _generate_cpy_macro_decl(self, tp, name): 1131 if tp == '...': 1132 check_value = None 1133 else: 1134 check_value = tp # an integer 1135 self._generate_cpy_const(True, name, check_value=check_value) 1136 1137 def _generate_cpy_macro_ctx(self, tp, name): 1138 if tp == '...': 1139 if self.target_is_python: 1140 raise VerificationError( 1141 "cannot use the syntax '...' in '#define %s ...' when " 1142 "using the ABI mode" % (name,)) 1143 check_value = None 1144 else: 1145 check_value = tp # an integer 1146 type_op = CffiOp(OP_CONSTANT_INT, -1) 1147 self._lsts["global"].append( 1148 GlobalExpr(name, '_cffi_const_%s' % name, type_op, 1149 check_value=check_value)) 1150 1151 # ---------- 1152 # global variables 1153 1154 def _global_type(self, tp, global_name): 1155 if isinstance(tp, model.ArrayType): 1156 actual_length = tp.length 1157 if actual_length == '...': 1158 actual_length = '_cffi_array_len(%s)' % (global_name,) 1159 tp_item = self._global_type(tp.item, '%s[0]' % global_name) 1160 tp = model.ArrayType(tp_item, actual_length) 1161 return tp 1162 1163 def _generate_cpy_variable_collecttype(self, tp, name): 1164 self._do_collect_type(self._global_type(tp, name)) 1165 1166 def _generate_cpy_variable_decl(self, tp, name): 1167 prnt = self._prnt 1168 tp = self._global_type(tp, name) 1169 if isinstance(tp, model.ArrayType) and tp.length is None: 1170 tp = tp.item 1171 ampersand = '' 1172 else: 1173 ampersand = '&' 1174 # This code assumes that casts from "tp *" to "void *" is a 1175 # no-op, i.e. a function that returns a "tp *" can be called 1176 # as if it returned a "void *". This should be generally true 1177 # on any modern machine. The only exception to that rule (on 1178 # uncommon architectures, and as far as I can tell) might be 1179 # if 'tp' were a function type, but that is not possible here. 1180 # (If 'tp' is a function _pointer_ type, then casts from "fn_t 1181 # **" to "void *" are again no-ops, as far as I can tell.) 1182 decl = '*_cffi_var_%s(void)' % (name,) 1183 prnt('static ' + tp.get_c_name(decl, quals=self._current_quals)) 1184 prnt('{') 1185 prnt(' return %s(%s);' % (ampersand, name)) 1186 prnt('}') 1187 prnt() 1188 1189 def _generate_cpy_variable_ctx(self, tp, name): 1190 tp = self._global_type(tp, name) 1191 type_index = self._typesdict[tp] 1192 if self.target_is_python: 1193 op = OP_GLOBAL_VAR 1194 else: 1195 op = OP_GLOBAL_VAR_F 1196 self._lsts["global"].append( 1197 GlobalExpr(name, '_cffi_var_%s' % name, CffiOp(op, type_index))) 1198 1199 # ---------- 1200 # extern "Python" 1201 1202 def _generate_cpy_extern_python_collecttype(self, tp, name): 1203 assert isinstance(tp, model.FunctionPtrType) 1204 self._do_collect_type(tp) 1205 _generate_cpy_dllexport_python_collecttype = \ 1206 _generate_cpy_extern_python_plus_c_collecttype = \ 1207 _generate_cpy_extern_python_collecttype 1208 1209 def _extern_python_decl(self, tp, name, tag_and_space): 1210 prnt = self._prnt 1211 if isinstance(tp.result, model.VoidType): 1212 size_of_result = '0' 1213 else: 1214 context = 'result of %s' % name 1215 size_of_result = '(int)sizeof(%s)' % ( 1216 tp.result.get_c_name('', context),) 1217 prnt('static struct _cffi_externpy_s _cffi_externpy__%s =' % name) 1218 prnt(' { "%s.%s", %s };' % (self.module_name, name, size_of_result)) 1219 prnt() 1220 # 1221 arguments = [] 1222 context = 'argument of %s' % name 1223 for i, type in enumerate(tp.args): 1224 arg = type.get_c_name(' a%d' % i, context) 1225 arguments.append(arg) 1226 # 1227 repr_arguments = ', '.join(arguments) 1228 repr_arguments = repr_arguments or 'void' 1229 name_and_arguments = '%s(%s)' % (name, repr_arguments) 1230 if tp.abi == "__stdcall": 1231 name_and_arguments = '_cffi_stdcall ' + name_and_arguments 1232 # 1233 def may_need_128_bits(tp): 1234 return (isinstance(tp, model.PrimitiveType) and 1235 tp.name == 'long double') 1236 # 1237 size_of_a = max(len(tp.args)*8, 8) 1238 if may_need_128_bits(tp.result): 1239 size_of_a = max(size_of_a, 16) 1240 if isinstance(tp.result, model.StructOrUnion): 1241 size_of_a = 'sizeof(%s) > %d ? sizeof(%s) : %d' % ( 1242 tp.result.get_c_name(''), size_of_a, 1243 tp.result.get_c_name(''), size_of_a) 1244 prnt('%s%s' % (tag_and_space, tp.result.get_c_name(name_and_arguments))) 1245 prnt('{') 1246 prnt(' char a[%s];' % size_of_a) 1247 prnt(' char *p = a;') 1248 for i, type in enumerate(tp.args): 1249 arg = 'a%d' % i 1250 if (isinstance(type, model.StructOrUnion) or 1251 may_need_128_bits(type)): 1252 arg = '&' + arg 1253 type = model.PointerType(type) 1254 prnt(' *(%s)(p + %d) = %s;' % (type.get_c_name('*'), i*8, arg)) 1255 prnt(' _cffi_call_python(&_cffi_externpy__%s, p);' % name) 1256 if not isinstance(tp.result, model.VoidType): 1257 prnt(' return *(%s)p;' % (tp.result.get_c_name('*'),)) 1258 prnt('}') 1259 prnt() 1260 self._num_externpy += 1 1261 1262 def _generate_cpy_extern_python_decl(self, tp, name): 1263 self._extern_python_decl(tp, name, 'static ') 1264 1265 def _generate_cpy_dllexport_python_decl(self, tp, name): 1266 self._extern_python_decl(tp, name, 'CFFI_DLLEXPORT ') 1267 1268 def _generate_cpy_extern_python_plus_c_decl(self, tp, name): 1269 self._extern_python_decl(tp, name, '') 1270 1271 def _generate_cpy_extern_python_ctx(self, tp, name): 1272 if self.target_is_python: 1273 raise VerificationError( 1274 "cannot use 'extern \"Python\"' in the ABI mode") 1275 if tp.ellipsis: 1276 raise NotImplementedError("a vararg function is extern \"Python\"") 1277 type_index = self._typesdict[tp] 1278 type_op = CffiOp(OP_EXTERN_PYTHON, type_index) 1279 self._lsts["global"].append( 1280 GlobalExpr(name, '&_cffi_externpy__%s' % name, type_op, name)) 1281 1282 _generate_cpy_dllexport_python_ctx = \ 1283 _generate_cpy_extern_python_plus_c_ctx = \ 1284 _generate_cpy_extern_python_ctx 1285 1286 def _print_string_literal_in_array(self, s): 1287 prnt = self._prnt 1288 prnt('// # NB. this is not a string because of a size limit in MSVC') 1289 for line in s.splitlines(True): 1290 prnt(('// ' + line).rstrip()) 1291 printed_line = '' 1292 for c in line: 1293 if len(printed_line) >= 76: 1294 prnt(printed_line) 1295 printed_line = '' 1296 printed_line += '%d,' % (ord(c),) 1297 prnt(printed_line) 1298 1299 # ---------- 1300 # emitting the opcodes for individual types 1301 1302 def _emit_bytecode_VoidType(self, tp, index): 1303 self.cffi_types[index] = CffiOp(OP_PRIMITIVE, PRIM_VOID) 1304 1305 def _emit_bytecode_PrimitiveType(self, tp, index): 1306 prim_index = PRIMITIVE_TO_INDEX[tp.name] 1307 self.cffi_types[index] = CffiOp(OP_PRIMITIVE, prim_index) 1308 1309 def _emit_bytecode_UnknownIntegerType(self, tp, index): 1310 s = ('_cffi_prim_int(sizeof(%s), (\n' 1311 ' ((%s)-1) | 0 /* check that %s is an integer type */\n' 1312 ' ) <= 0)' % (tp.name, tp.name, tp.name)) 1313 self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) 1314 1315 def _emit_bytecode_UnknownFloatType(self, tp, index): 1316 s = ('_cffi_prim_float(sizeof(%s) *\n' 1317 ' (((%s)1) / 2) * 2 /* integer => 0, float => 1 */\n' 1318 ' )' % (tp.name, tp.name)) 1319 self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) 1320 1321 def _emit_bytecode_RawFunctionType(self, tp, index): 1322 self.cffi_types[index] = CffiOp(OP_FUNCTION, self._typesdict[tp.result]) 1323 index += 1 1324 for tp1 in tp.args: 1325 realindex = self._typesdict[tp1] 1326 if index != realindex: 1327 if isinstance(tp1, model.PrimitiveType): 1328 self._emit_bytecode_PrimitiveType(tp1, index) 1329 else: 1330 self.cffi_types[index] = CffiOp(OP_NOOP, realindex) 1331 index += 1 1332 flags = int(tp.ellipsis) 1333 if tp.abi is not None: 1334 if tp.abi == '__stdcall': 1335 flags |= 2 1336 else: 1337 raise NotImplementedError("abi=%r" % (tp.abi,)) 1338 self.cffi_types[index] = CffiOp(OP_FUNCTION_END, flags) 1339 1340 def _emit_bytecode_PointerType(self, tp, index): 1341 self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[tp.totype]) 1342 1343 _emit_bytecode_ConstPointerType = _emit_bytecode_PointerType 1344 _emit_bytecode_NamedPointerType = _emit_bytecode_PointerType 1345 1346 def _emit_bytecode_FunctionPtrType(self, tp, index): 1347 raw = tp.as_raw_function() 1348 self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[raw]) 1349 1350 def _emit_bytecode_ArrayType(self, tp, index): 1351 item_index = self._typesdict[tp.item] 1352 if tp.length is None: 1353 self.cffi_types[index] = CffiOp(OP_OPEN_ARRAY, item_index) 1354 elif tp.length == '...': 1355 raise VerificationError( 1356 "type %s badly placed: the '...' array length can only be " 1357 "used on global arrays or on fields of structures" % ( 1358 str(tp).replace('/*...*/', '...'),)) 1359 else: 1360 assert self.cffi_types[index + 1] == 'LEN' 1361 self.cffi_types[index] = CffiOp(OP_ARRAY, item_index) 1362 self.cffi_types[index + 1] = CffiOp(None, str(tp.length)) 1363 1364 def _emit_bytecode_StructType(self, tp, index): 1365 struct_index = self._struct_unions[tp] 1366 self.cffi_types[index] = CffiOp(OP_STRUCT_UNION, struct_index) 1367 _emit_bytecode_UnionType = _emit_bytecode_StructType 1368 1369 def _emit_bytecode_EnumType(self, tp, index): 1370 enum_index = self._enums[tp] 1371 self.cffi_types[index] = CffiOp(OP_ENUM, enum_index) 1372 1373 1374if sys.version_info >= (3,): 1375 NativeIO = io.StringIO 1376else: 1377 class NativeIO(io.BytesIO): 1378 def write(self, s): 1379 if isinstance(s, unicode): 1380 s = s.encode('ascii') 1381 super(NativeIO, self).write(s) 1382 1383def _make_c_or_py_source(ffi, module_name, preamble, target_file, verbose): 1384 if verbose: 1385 print("generating %s" % (target_file,)) 1386 recompiler = Recompiler(ffi, module_name, 1387 target_is_python=(preamble is None)) 1388 recompiler.collect_type_table() 1389 recompiler.collect_step_tables() 1390 f = NativeIO() 1391 recompiler.write_source_to_f(f, preamble) 1392 output = f.getvalue() 1393 try: 1394 with open(target_file, 'r') as f1: 1395 if f1.read(len(output) + 1) != output: 1396 raise IOError 1397 if verbose: 1398 print("(already up-to-date)") 1399 return False # already up-to-date 1400 except IOError: 1401 tmp_file = '%s.~%d' % (target_file, os.getpid()) 1402 with open(tmp_file, 'w') as f1: 1403 f1.write(output) 1404 try: 1405 os.rename(tmp_file, target_file) 1406 except OSError: 1407 os.unlink(target_file) 1408 os.rename(tmp_file, target_file) 1409 return True 1410 1411def make_c_source(ffi, module_name, preamble, target_c_file, verbose=False): 1412 assert preamble is not None 1413 return _make_c_or_py_source(ffi, module_name, preamble, target_c_file, 1414 verbose) 1415 1416def make_py_source(ffi, module_name, target_py_file, verbose=False): 1417 return _make_c_or_py_source(ffi, module_name, None, target_py_file, 1418 verbose) 1419 1420def _modname_to_file(outputdir, modname, extension): 1421 parts = modname.split('.') 1422 try: 1423 os.makedirs(os.path.join(outputdir, *parts[:-1])) 1424 except OSError: 1425 pass 1426 parts[-1] += extension 1427 return os.path.join(outputdir, *parts), parts 1428 1429 1430# Aaargh. Distutils is not tested at all for the purpose of compiling 1431# DLLs that are not extension modules. Here are some hacks to work 1432# around that, in the _patch_for_*() functions... 1433 1434def _patch_meth(patchlist, cls, name, new_meth): 1435 old = getattr(cls, name) 1436 patchlist.append((cls, name, old)) 1437 setattr(cls, name, new_meth) 1438 return old 1439 1440def _unpatch_meths(patchlist): 1441 for cls, name, old_meth in reversed(patchlist): 1442 setattr(cls, name, old_meth) 1443 1444def _patch_for_embedding(patchlist): 1445 if sys.platform == 'win32': 1446 # we must not remove the manifest when building for embedding! 1447 from distutils.msvc9compiler import MSVCCompiler 1448 _patch_meth(patchlist, MSVCCompiler, '_remove_visual_c_ref', 1449 lambda self, manifest_file: manifest_file) 1450 1451 if sys.platform == 'darwin': 1452 # we must not make a '-bundle', but a '-dynamiclib' instead 1453 from distutils.ccompiler import CCompiler 1454 def my_link_shared_object(self, *args, **kwds): 1455 if '-bundle' in self.linker_so: 1456 self.linker_so = list(self.linker_so) 1457 i = self.linker_so.index('-bundle') 1458 self.linker_so[i] = '-dynamiclib' 1459 return old_link_shared_object(self, *args, **kwds) 1460 old_link_shared_object = _patch_meth(patchlist, CCompiler, 1461 'link_shared_object', 1462 my_link_shared_object) 1463 1464def _patch_for_target(patchlist, target): 1465 from distutils.command.build_ext import build_ext 1466 # if 'target' is different from '*', we need to patch some internal 1467 # method to just return this 'target' value, instead of having it 1468 # built from module_name 1469 if target.endswith('.*'): 1470 target = target[:-2] 1471 if sys.platform == 'win32': 1472 target += '.dll' 1473 elif sys.platform == 'darwin': 1474 target += '.dylib' 1475 else: 1476 target += '.so' 1477 _patch_meth(patchlist, build_ext, 'get_ext_filename', 1478 lambda self, ext_name: target) 1479 1480 1481def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True, 1482 c_file=None, source_extension='.c', extradir=None, 1483 compiler_verbose=1, target=None, debug=None, **kwds): 1484 if not isinstance(module_name, str): 1485 module_name = module_name.encode('ascii') 1486 if ffi._windows_unicode: 1487 ffi._apply_windows_unicode(kwds) 1488 if preamble is not None: 1489 embedding = (ffi._embedding is not None) 1490 if embedding: 1491 ffi._apply_embedding_fix(kwds) 1492 if c_file is None: 1493 c_file, parts = _modname_to_file(tmpdir, module_name, 1494 source_extension) 1495 if extradir: 1496 parts = [extradir] + parts 1497 ext_c_file = os.path.join(*parts) 1498 else: 1499 ext_c_file = c_file 1500 # 1501 if target is None: 1502 if embedding: 1503 target = '%s.*' % module_name 1504 else: 1505 target = '*' 1506 # 1507 ext = ffiplatform.get_extension(ext_c_file, module_name, **kwds) 1508 updated = make_c_source(ffi, module_name, preamble, c_file, 1509 verbose=compiler_verbose) 1510 if call_c_compiler: 1511 patchlist = [] 1512 cwd = os.getcwd() 1513 try: 1514 if embedding: 1515 _patch_for_embedding(patchlist) 1516 if target != '*': 1517 _patch_for_target(patchlist, target) 1518 if compiler_verbose: 1519 if tmpdir == '.': 1520 msg = 'the current directory is' 1521 else: 1522 msg = 'setting the current directory to' 1523 print('%s %r' % (msg, os.path.abspath(tmpdir))) 1524 os.chdir(tmpdir) 1525 outputfilename = ffiplatform.compile('.', ext, 1526 compiler_verbose, debug) 1527 finally: 1528 os.chdir(cwd) 1529 _unpatch_meths(patchlist) 1530 return outputfilename 1531 else: 1532 return ext, updated 1533 else: 1534 if c_file is None: 1535 c_file, _ = _modname_to_file(tmpdir, module_name, '.py') 1536 updated = make_py_source(ffi, module_name, c_file, 1537 verbose=compiler_verbose) 1538 if call_c_compiler: 1539 return c_file 1540 else: 1541 return None, updated 1542 1543