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.

1560 lines
62 KiB

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