recompiler.py 59 KB

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