recompiler.py 64 KB

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