You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1553 lines
62 KiB

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

Powered by TurnKey Linux.