PageRenderTime 55ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/rpython/tool/rffi_platform.py

https://bitbucket.org/pypy/pypy/
Python | 836 lines | 749 code | 56 blank | 31 comment | 38 complexity | 02805ff07d75787046a91749012e9981 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. #! /usr/bin/env python
  2. import os
  3. import sys
  4. import struct
  5. import py
  6. from pypy.rpython.lltypesystem import lltype
  7. from pypy.rpython.lltypesystem import rffi
  8. from pypy.rpython.lltypesystem import llmemory
  9. from pypy.tool.gcc_cache import build_executable_cache, try_compile_cache
  10. from pypy.translator.tool.cbuild import ExternalCompilationInfo
  11. from pypy.translator.platform import CompilationError
  12. from pypy.tool.udir import udir
  13. from pypy.tool.autopath import pypydir
  14. from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong, intmask
  15. # ____________________________________________________________
  16. #
  17. # Helpers for simple cases
  18. def eci_from_header(c_header_source, include_dirs=None):
  19. if include_dirs is None:
  20. include_dirs = []
  21. return ExternalCompilationInfo(
  22. post_include_bits=[c_header_source],
  23. include_dirs=include_dirs
  24. )
  25. def getstruct(name, c_header_source, interesting_fields):
  26. class CConfig:
  27. _compilation_info_ = eci_from_header(c_header_source)
  28. STRUCT = Struct(name, interesting_fields)
  29. return configure(CConfig)['STRUCT']
  30. def getsimpletype(name, c_header_source, ctype_hint=rffi.INT):
  31. class CConfig:
  32. _compilation_info_ = eci_from_header(c_header_source)
  33. TYPE = SimpleType(name, ctype_hint)
  34. return configure(CConfig)['TYPE']
  35. def getconstantinteger(name, c_header_source):
  36. class CConfig:
  37. _compilation_info_ = eci_from_header(c_header_source)
  38. CONST = ConstantInteger(name)
  39. return configure(CConfig)['CONST']
  40. def getdefined(macro, c_header_source):
  41. class CConfig:
  42. _compilation_info_ = eci_from_header(c_header_source)
  43. DEFINED = Defined(macro)
  44. return configure(CConfig)['DEFINED']
  45. def getdefineddouble(macro, c_header_source):
  46. class CConfig:
  47. _compilation_info_ = eci_from_header(c_header_source)
  48. DEFINED = DefinedConstantDouble(macro)
  49. return configure(CConfig)['DEFINED']
  50. def getdefinedinteger(macro, c_header_source):
  51. class CConfig:
  52. _compilation_info_ = eci_from_header(c_header_source)
  53. DEFINED = DefinedConstantInteger(macro)
  54. return configure(CConfig)['DEFINED']
  55. def has(name, c_header_source, include_dirs=None):
  56. class CConfig:
  57. _compilation_info_ = eci_from_header(c_header_source, include_dirs)
  58. HAS = Has(name)
  59. return configure(CConfig)['HAS']
  60. def verify_eci(eci):
  61. """Check if a given ExternalCompilationInfo compiles and links.
  62. If not, raises CompilationError."""
  63. class CConfig:
  64. _compilation_info_ = eci
  65. WORKS = Works()
  66. configure(CConfig)
  67. def checkcompiles(expression, c_header_source, include_dirs=None):
  68. """Check if expression compiles. If not, returns False"""
  69. return has(expression, c_header_source, include_dirs)
  70. def sizeof(name, eci, **kwds):
  71. class CConfig:
  72. _compilation_info_ = eci
  73. SIZE = SizeOf(name)
  74. for k, v in kwds.items():
  75. setattr(CConfig, k, v)
  76. return configure(CConfig)['SIZE']
  77. def memory_alignment():
  78. """Return the alignment (in bytes) of memory allocations.
  79. This is enough to make sure a structure with pointers and 'double'
  80. fields is properly aligned."""
  81. global _memory_alignment
  82. if _memory_alignment is None:
  83. S = getstruct('struct memory_alignment_test', """
  84. struct memory_alignment_test {
  85. double d;
  86. void* p;
  87. };
  88. """, [])
  89. result = S._hints['align']
  90. assert result & (result-1) == 0, "not a power of two??"
  91. _memory_alignment = result
  92. return _memory_alignment
  93. _memory_alignment = None
  94. # ____________________________________________________________
  95. #
  96. # General interface
  97. class ConfigResult:
  98. def __init__(self, CConfig, info, entries):
  99. self.CConfig = CConfig
  100. self.result = {}
  101. self.info = info
  102. self.entries = entries
  103. def get_entry_result(self, entry):
  104. try:
  105. return self.result[entry]
  106. except KeyError:
  107. pass
  108. name = self.entries[entry]
  109. info = self.info[name]
  110. self.result[entry] = entry.build_result(info, self)
  111. return self.result[entry]
  112. def get_result(self):
  113. return dict([(name, self.result[entry])
  114. for entry, name in self.entries.iteritems()])
  115. class _CWriter(object):
  116. """ A simple class which aggregates config parts
  117. """
  118. def __init__(self, CConfig):
  119. self.path = uniquefilepath()
  120. self.f = self.path.open("w")
  121. self.config = CConfig
  122. def write_header(self):
  123. f = self.f
  124. CConfig = self.config
  125. CConfig._compilation_info_.write_c_header(f)
  126. print >> f, C_HEADER
  127. print >> f
  128. def write_entry(self, key, entry):
  129. f = self.f
  130. print >> f, 'void dump_section_%s(void) {' % (key,)
  131. for line in entry.prepare_code():
  132. if line and line[0] != '#':
  133. line = '\t' + line
  134. print >> f, line
  135. print >> f, '}'
  136. print >> f
  137. def write_entry_main(self, key):
  138. print >> self.f, '\tprintf("-+- %s\\n");' % (key,)
  139. print >> self.f, '\tdump_section_%s();' % (key,)
  140. print >> self.f, '\tprintf("---\\n");'
  141. def start_main(self):
  142. print >> self.f, 'int main(int argc, char *argv[]) {'
  143. def close(self):
  144. f = self.f
  145. print >> f, '\treturn 0;'
  146. print >> f, '}'
  147. f.close()
  148. def ask_gcc(self, question):
  149. self.start_main()
  150. self.f.write(question + "\n")
  151. self.close()
  152. eci = self.config._compilation_info_
  153. try_compile_cache([self.path], eci)
  154. def configure(CConfig, ignore_errors=False):
  155. """Examine the local system by running the C compiler.
  156. The CConfig class contains CConfigEntry attribues that describe
  157. what should be inspected; configure() returns a dict mapping
  158. names to the results.
  159. """
  160. for attr in ['_includes_', '_libraries_', '_sources_', '_library_dirs_',
  161. '_include_dirs_', '_header_']:
  162. assert not hasattr(CConfig, attr), "Found legacy attribute %s on CConfig" % (attr,)
  163. entries = []
  164. for key in dir(CConfig):
  165. value = getattr(CConfig, key)
  166. if isinstance(value, CConfigEntry):
  167. entries.append((key, value))
  168. if entries: # can be empty if there are only CConfigSingleEntries
  169. writer = _CWriter(CConfig)
  170. writer.write_header()
  171. for key, entry in entries:
  172. writer.write_entry(key, entry)
  173. f = writer.f
  174. writer.start_main()
  175. for key, entry in entries:
  176. writer.write_entry_main(key)
  177. writer.close()
  178. eci = CConfig._compilation_info_
  179. infolist = list(run_example_code(writer.path, eci,
  180. ignore_errors=ignore_errors))
  181. assert len(infolist) == len(entries)
  182. resultinfo = {}
  183. resultentries = {}
  184. for info, (key, entry) in zip(infolist, entries):
  185. resultinfo[key] = info
  186. resultentries[entry] = key
  187. result = ConfigResult(CConfig, resultinfo, resultentries)
  188. for name, entry in entries:
  189. result.get_entry_result(entry)
  190. res = result.get_result()
  191. else:
  192. res = {}
  193. for key in dir(CConfig):
  194. value = getattr(CConfig, key)
  195. if isinstance(value, CConfigSingleEntry):
  196. writer = _CWriter(CConfig)
  197. writer.write_header()
  198. res[key] = value.question(writer.ask_gcc)
  199. return res
  200. # ____________________________________________________________
  201. class CConfigEntry(object):
  202. "Abstract base class."
  203. class Struct(CConfigEntry):
  204. """An entry in a CConfig class that stands for an externally
  205. defined structure.
  206. """
  207. def __init__(self, name, interesting_fields, ifdef=None):
  208. self.name = name
  209. self.interesting_fields = interesting_fields
  210. self.ifdef = ifdef
  211. def prepare_code(self):
  212. if self.ifdef is not None:
  213. yield '#ifdef %s' % (self.ifdef,)
  214. yield 'typedef %s platcheck_t;' % (self.name,)
  215. yield 'typedef struct {'
  216. yield ' char c;'
  217. yield ' platcheck_t s;'
  218. yield '} platcheck2_t;'
  219. yield ''
  220. yield 'platcheck_t s;'
  221. if self.ifdef is not None:
  222. yield 'dump("defined", 1);'
  223. yield 'dump("align", offsetof(platcheck2_t, s));'
  224. yield 'dump("size", sizeof(platcheck_t));'
  225. for fieldname, fieldtype in self.interesting_fields:
  226. yield 'dump("fldofs %s", offsetof(platcheck_t, %s));'%(
  227. fieldname, fieldname)
  228. yield 'dump("fldsize %s", sizeof(s.%s));' % (
  229. fieldname, fieldname)
  230. if fieldtype in integer_class:
  231. yield 's.%s = 0; s.%s = ~s.%s;' % (fieldname,
  232. fieldname,
  233. fieldname)
  234. yield 'dump("fldunsigned %s", s.%s > 0);' % (fieldname,
  235. fieldname)
  236. if self.ifdef is not None:
  237. yield '#else'
  238. yield 'dump("defined", 0);'
  239. yield '#endif'
  240. def build_result(self, info, config_result):
  241. if self.ifdef is not None:
  242. if not info['defined']:
  243. return None
  244. layout = [None] * info['size']
  245. for fieldname, fieldtype in self.interesting_fields:
  246. if isinstance(fieldtype, Struct):
  247. offset = info['fldofs ' + fieldname]
  248. size = info['fldsize ' + fieldname]
  249. c_fieldtype = config_result.get_entry_result(fieldtype)
  250. layout_addfield(layout, offset, c_fieldtype, fieldname)
  251. else:
  252. offset = info['fldofs ' + fieldname]
  253. size = info['fldsize ' + fieldname]
  254. sign = info.get('fldunsigned ' + fieldname, False)
  255. if (size, sign) != rffi.size_and_sign(fieldtype):
  256. fieldtype = fixup_ctype(fieldtype, fieldname, (size, sign))
  257. layout_addfield(layout, offset, fieldtype, fieldname)
  258. n = 0
  259. padfields = []
  260. for i, cell in enumerate(layout):
  261. if cell is not None:
  262. continue
  263. name = '_pad%d' % (n,)
  264. layout_addfield(layout, i, rffi.UCHAR, name)
  265. padfields.append('c_' + name)
  266. n += 1
  267. # build the lltype Structure
  268. seen = {}
  269. fields = []
  270. fieldoffsets = []
  271. for offset, cell in enumerate(layout):
  272. if cell in seen:
  273. continue
  274. fields.append((cell.name, cell.ctype))
  275. fieldoffsets.append(offset)
  276. seen[cell] = True
  277. allfields = tuple(['c_' + name for name, _ in fields])
  278. padfields = tuple(padfields)
  279. name = self.name
  280. padding_drop = PaddingDrop(name, allfields, padfields,
  281. config_result.CConfig._compilation_info_)
  282. hints = {'align': info['align'],
  283. 'size': info['size'],
  284. 'fieldoffsets': tuple(fieldoffsets),
  285. 'padding': padfields,
  286. 'get_padding_drop': padding_drop}
  287. if name.startswith('struct '):
  288. name = name[7:]
  289. else:
  290. hints['typedef'] = True
  291. kwds = {'hints': hints}
  292. return rffi.CStruct(name, *fields, **kwds)
  293. class SimpleType(CConfigEntry):
  294. """An entry in a CConfig class that stands for an externally
  295. defined simple numeric type.
  296. """
  297. def __init__(self, name, ctype_hint=rffi.INT, ifdef=None):
  298. self.name = name
  299. self.ctype_hint = ctype_hint
  300. self.ifdef = ifdef
  301. def prepare_code(self):
  302. if self.ifdef is not None:
  303. yield '#ifdef %s' % (self.ifdef,)
  304. yield 'typedef %s platcheck_t;' % (self.name,)
  305. yield ''
  306. yield 'platcheck_t x;'
  307. if self.ifdef is not None:
  308. yield 'dump("defined", 1);'
  309. yield 'dump("size", sizeof(platcheck_t));'
  310. if self.ctype_hint in integer_class:
  311. yield 'x = 0; x = ~x;'
  312. yield 'dump("unsigned", x > 0);'
  313. if self.ifdef is not None:
  314. yield '#else'
  315. yield 'dump("defined", 0);'
  316. yield '#endif'
  317. def build_result(self, info, config_result):
  318. if self.ifdef is not None and not info['defined']:
  319. return None
  320. size = info['size']
  321. sign = info.get('unsigned', False)
  322. ctype = self.ctype_hint
  323. if (size, sign) != rffi.size_and_sign(ctype):
  324. ctype = fixup_ctype(ctype, self.name, (size, sign))
  325. return ctype
  326. class ConstantInteger(CConfigEntry):
  327. """An entry in a CConfig class that stands for an externally
  328. defined integer constant.
  329. """
  330. def __init__(self, name):
  331. self.name = name
  332. def prepare_code(self):
  333. yield 'if ((%s) < 0) {' % (self.name,)
  334. yield ' long long x = (long long)(%s);' % (self.name,)
  335. yield ' printf("value: %lld\\n", x);'
  336. yield '} else {'
  337. yield ' unsigned long long x = (unsigned long long)(%s);' % (
  338. self.name,)
  339. yield ' printf("value: %llu\\n", x);'
  340. yield '}'
  341. def build_result(self, info, config_result):
  342. return expose_value_as_rpython(info['value'])
  343. class DefinedConstantInteger(CConfigEntry):
  344. """An entry in a CConfig class that stands for an externally
  345. defined integer constant. If not #defined the value will be None.
  346. """
  347. def __init__(self, macro):
  348. self.name = self.macro = macro
  349. def prepare_code(self):
  350. yield '#ifdef %s' % self.macro
  351. yield 'dump("defined", 1);'
  352. yield 'if ((%s) < 0) {' % (self.macro,)
  353. yield ' long long x = (long long)(%s);' % (self.macro,)
  354. yield ' printf("value: %lld\\n", x);'
  355. yield '} else {'
  356. yield ' unsigned long long x = (unsigned long long)(%s);' % (
  357. self.macro,)
  358. yield ' printf("value: %llu\\n", x);'
  359. yield '}'
  360. yield '#else'
  361. yield 'dump("defined", 0);'
  362. yield '#endif'
  363. def build_result(self, info, config_result):
  364. if info["defined"]:
  365. return expose_value_as_rpython(info['value'])
  366. return None
  367. class DefinedConstantDouble(CConfigEntry):
  368. def __init__(self, macro):
  369. self.name = self.macro = macro
  370. def prepare_code(self):
  371. yield '#ifdef %s' % (self.macro,)
  372. yield 'int i;'
  373. yield 'double x = %s;' % (self.macro,)
  374. yield 'unsigned char *p = (unsigned char *)&x;'
  375. yield 'dump("defined", 1);'
  376. yield 'for (i = 0; i < 8; i++) {'
  377. yield ' printf("value_%d: %d\\n", i, p[i]);'
  378. yield '}'
  379. yield '#else'
  380. yield 'dump("defined", 0);'
  381. yield '#endif'
  382. def build_result(self, info, config_result):
  383. if info["defined"]:
  384. data = [chr(info["value_%d" % (i,)]) for i in range(8)]
  385. # N.B. This depends on IEEE 754 being implemented.
  386. return struct.unpack("d", ''.join(data))[0]
  387. return None
  388. class DefinedConstantString(CConfigEntry):
  389. """
  390. """
  391. def __init__(self, macro, name=None):
  392. self.macro = macro
  393. self.name = name or macro
  394. def prepare_code(self):
  395. yield '#ifdef %s' % self.macro
  396. yield 'int i;'
  397. yield 'char *p = %s;' % self.name
  398. yield 'dump("defined", 1);'
  399. yield 'for (i = 0; p[i] != 0; i++ ) {'
  400. yield ' printf("value_%d: %d\\n", i, (int)(unsigned char)p[i]);'
  401. yield '}'
  402. yield '#else'
  403. yield 'dump("defined", 0);'
  404. yield '#endif'
  405. def build_result(self, info, config_result):
  406. if info["defined"]:
  407. string = ''
  408. d = 0
  409. while info.has_key('value_%d' % d):
  410. string += chr(info['value_%d' % d])
  411. d += 1
  412. return string
  413. return None
  414. class Defined(CConfigEntry):
  415. """A boolean, corresponding to an #ifdef.
  416. """
  417. def __init__(self, macro):
  418. self.macro = macro
  419. self.name = macro
  420. def prepare_code(self):
  421. yield '#ifdef %s' % (self.macro,)
  422. yield 'dump("defined", 1);'
  423. yield '#else'
  424. yield 'dump("defined", 0);'
  425. yield '#endif'
  426. def build_result(self, info, config_result):
  427. return bool(info['defined'])
  428. class CConfigSingleEntry(object):
  429. """ An abstract class of type which requires
  430. gcc succeeding/failing instead of only asking
  431. """
  432. pass
  433. class Has(CConfigSingleEntry):
  434. def __init__(self, name):
  435. self.name = name
  436. def question(self, ask_gcc):
  437. try:
  438. ask_gcc(self.name + ';')
  439. return True
  440. except CompilationError:
  441. return False
  442. class Works(CConfigSingleEntry):
  443. def question(self, ask_gcc):
  444. ask_gcc("")
  445. class SizeOf(CConfigEntry):
  446. """An entry in a CConfig class that stands for
  447. some external opaque type
  448. """
  449. def __init__(self, name):
  450. self.name = name
  451. def prepare_code(self):
  452. yield 'dump("size", sizeof(%s));' % self.name
  453. def build_result(self, info, config_result):
  454. return info['size']
  455. # ____________________________________________________________
  456. class PaddingDrop(object):
  457. # Compute (lazily) the padding_drop for a structure.
  458. # See test_generate_padding for more information.
  459. cache = None
  460. def __init__(self, name, allfields, padfields, eci):
  461. self.name = name
  462. self.allfields = allfields
  463. self.padfields = padfields
  464. self.eci = eci
  465. def __call__(self, types):
  466. if self.cache is None:
  467. self.compute_now(types)
  468. return self.cache
  469. def compute_now(self, types):
  470. # Some simplifying assumptions there. We assume that all fields
  471. # are either integers or pointers, so can be written in C as '0'.
  472. # We also assume that the C backend gives us in 'types' a dictionary
  473. # mapping non-padding field names to their C type (without '@').
  474. drops = []
  475. staticfields = []
  476. consecutive_pads = []
  477. for fieldname in self.allfields:
  478. if fieldname in self.padfields:
  479. consecutive_pads.append(fieldname)
  480. continue
  481. staticfields.append(types[fieldname])
  482. if consecutive_pads:
  483. # In that case we have to ask: how many of these pads are
  484. # really needed? The correct answer might be between none
  485. # and all of the pads listed in 'consecutive_pads'.
  486. for i in range(len(consecutive_pads)+1):
  487. class CConfig:
  488. _compilation_info_ = self.eci
  489. FIELDLOOKUP = _PaddingDropFieldLookup(self.name,
  490. staticfields,
  491. fieldname)
  492. try:
  493. got = configure(CConfig)['FIELDLOOKUP']
  494. if got == 1:
  495. break # found
  496. except CompilationError:
  497. pass
  498. staticfields.insert(-1, None)
  499. else:
  500. raise Exception("could not determine the detailed field"
  501. " layout of %r" % (self.name,))
  502. # succeeded with 'i' pads. Drop all pads beyond that.
  503. drops += consecutive_pads[i:]
  504. consecutive_pads = []
  505. drops += consecutive_pads # drop the final pads too
  506. self.cache = drops
  507. class _PaddingDropFieldLookup(CConfigEntry):
  508. def __init__(self, name, staticfields, fieldname):
  509. self.name = name
  510. self.staticfields = staticfields
  511. self.fieldname = fieldname
  512. def prepare_code(self):
  513. yield 'typedef %s platcheck_t;' % (self.name,)
  514. yield 'static platcheck_t s = {'
  515. for i, type in enumerate(self.staticfields):
  516. if i == len(self.staticfields)-1:
  517. value = -1
  518. else:
  519. value = 0
  520. if type:
  521. yield '\t(%s)%s,' % (type, value)
  522. else:
  523. yield '\t%s,' % (value,)
  524. yield '};'
  525. fieldname = self.fieldname
  526. assert fieldname.startswith('c_')
  527. yield 'dump("fieldlookup", s.%s != 0);' % (fieldname[2:],)
  528. def build_result(self, info, config_result):
  529. return info['fieldlookup']
  530. # ____________________________________________________________
  531. #
  532. # internal helpers
  533. def uniquefilepath(LAST=[0]):
  534. i = LAST[0]
  535. LAST[0] += 1
  536. return udir.join('platcheck_%d.c' % i)
  537. integer_class = [rffi.SIGNEDCHAR, rffi.UCHAR, rffi.CHAR,
  538. rffi.SHORT, rffi.USHORT,
  539. rffi.INT, rffi.UINT,
  540. rffi.LONG, rffi.ULONG,
  541. rffi.LONGLONG, rffi.ULONGLONG]
  542. # XXX SIZE_T?
  543. float_class = [rffi.DOUBLE]
  544. def _sizeof(tp):
  545. # XXX don't use this! internal purpose only, not really a sane logic
  546. if isinstance(tp, lltype.Struct):
  547. return sum([_sizeof(i) for i in tp._flds.values()])
  548. return rffi.sizeof(tp)
  549. class Field(object):
  550. def __init__(self, name, ctype):
  551. self.name = name
  552. self.ctype = ctype
  553. def __repr__(self):
  554. return '<field %s: %s>' % (self.name, self.ctype)
  555. def layout_addfield(layout, offset, ctype, prefix):
  556. size = _sizeof(ctype)
  557. name = prefix
  558. i = 0
  559. while name in layout:
  560. i += 1
  561. name = '%s_%d' % (prefix, i)
  562. field = Field(name, ctype)
  563. for i in range(offset, offset+size):
  564. assert layout[i] is None, "%s overlaps %r" % (name, layout[i])
  565. layout[i] = field
  566. return field
  567. def fixup_ctype(fieldtype, fieldname, expected_size_and_sign):
  568. for typeclass in [integer_class, float_class]:
  569. if fieldtype in typeclass:
  570. for ctype in typeclass:
  571. if rffi.size_and_sign(ctype) == expected_size_and_sign:
  572. return ctype
  573. if isinstance(fieldtype, lltype.FixedSizeArray):
  574. size, _ = expected_size_and_sign
  575. return lltype.FixedSizeArray(fieldtype.OF, size/_sizeof(fieldtype.OF))
  576. raise TypeError("conflicting field type %r for %r" % (fieldtype,
  577. fieldname))
  578. def expose_value_as_rpython(value):
  579. if intmask(value) == value:
  580. return value
  581. if r_uint(value) == value:
  582. return r_uint(value)
  583. try:
  584. if r_longlong(value) == value:
  585. return r_longlong(value)
  586. except OverflowError:
  587. pass
  588. if r_ulonglong(value) == value:
  589. return r_ulonglong(value)
  590. raise OverflowError("value %d does not fit into any RPython integer type"
  591. % (value,))
  592. C_HEADER = """
  593. #include <stdio.h>
  594. #include <stddef.h> /* for offsetof() */
  595. void dump(char* key, int value) {
  596. printf("%s: %d\\n", key, value);
  597. }
  598. """
  599. def run_example_code(filepath, eci, ignore_errors=False):
  600. eci = eci.convert_sources_to_files(being_main=True)
  601. files = [filepath]
  602. output = build_executable_cache(files, eci, ignore_errors=ignore_errors)
  603. section = None
  604. for line in output.splitlines():
  605. line = line.strip()
  606. if line.startswith('-+- '): # start of a new section
  607. section = {}
  608. elif line == '---': # section end
  609. assert section is not None
  610. yield section
  611. section = None
  612. elif line:
  613. assert section is not None
  614. key, value = line.split(': ')
  615. section[key] = int(value)
  616. # ____________________________________________________________
  617. PYPY_EXTERNAL_DIR = py.path.local(pypydir).join('..', '..')
  618. # XXX make this configurable
  619. if sys.platform == 'win32':
  620. libdir = py.path.local('c:/buildslave/support') # on the bigboard buildbot
  621. if libdir.check():
  622. PYPY_EXTERNAL_DIR = libdir
  623. def configure_external_library(name, eci, configurations,
  624. symbol=None, _cache={}):
  625. """try to find the external library.
  626. On Unix, this simply tests and returns the given eci.
  627. On Windows, various configurations may be tried to compile the
  628. given eci object. These configurations are a list of dicts,
  629. containing:
  630. - prefix: if an absolute path, will prefix each include and
  631. library directories. If a relative path, the external
  632. directory is searched for directories which names start
  633. with the prefix. The last one in alphabetical order
  634. chosen, and becomes the prefix.
  635. - include_dir: prefix + include_dir is added to the include directories
  636. - library_dir: prefix + library_dir is added to the library directories
  637. """
  638. if sys.platform != 'win32':
  639. configurations = []
  640. key = (name, eci)
  641. try:
  642. return _cache[key]
  643. except KeyError:
  644. last_error = None
  645. # Always try the default configuration
  646. if {} not in configurations:
  647. configurations.append({})
  648. for configuration in configurations:
  649. prefix = configuration.get('prefix', '')
  650. include_dir = configuration.get('include_dir', '')
  651. library_dir = configuration.get('library_dir', '')
  652. if prefix and not os.path.isabs(prefix):
  653. import glob
  654. entries = glob.glob(str(PYPY_EXTERNAL_DIR.join(prefix + '*')))
  655. if entries:
  656. # Get last version
  657. prefix = sorted(entries)[-1]
  658. else:
  659. continue
  660. include_dir = os.path.join(prefix, include_dir)
  661. library_dir = os.path.join(prefix, library_dir)
  662. eci_lib = ExternalCompilationInfo(
  663. include_dirs=include_dir and [include_dir] or [],
  664. library_dirs=library_dir and [library_dir] or [],
  665. )
  666. eci_lib = eci_lib.merge(eci)
  667. # verify that this eci can be compiled
  668. try:
  669. verify_eci(eci_lib)
  670. except CompilationError, e:
  671. last_error = e
  672. else:
  673. _cache[key] = eci_lib
  674. return eci_lib
  675. # Nothing found
  676. if last_error:
  677. raise last_error
  678. else:
  679. raise CompilationError("Library %s is not installed" % (name,))
  680. def configure_boehm(platform=None):
  681. if platform is None:
  682. from pypy.translator.platform import platform
  683. if sys.platform == 'win32':
  684. library_dir = 'Release'
  685. libraries = ['gc']
  686. includes=['gc.h']
  687. else:
  688. library_dir = ''
  689. libraries = ['gc', 'dl']
  690. includes=['gc/gc.h']
  691. eci = ExternalCompilationInfo(
  692. platform=platform,
  693. includes=includes,
  694. libraries=libraries,
  695. )
  696. return configure_external_library(
  697. 'gc', eci,
  698. [dict(prefix='gc-', include_dir='include', library_dir=library_dir)],
  699. symbol='GC_init')
  700. if __name__ == '__main__':
  701. doc = """Example:
  702. rffi_platform.py -h sys/types.h -h netinet/in.h
  703. 'struct sockaddr_in'
  704. sin_port INT
  705. """
  706. import getopt
  707. opts, args = getopt.gnu_getopt(sys.argv[1:], 'h:')
  708. if not args:
  709. print >> sys.stderr, doc
  710. else:
  711. assert len(args) % 2 == 1
  712. headers = []
  713. for opt, value in opts:
  714. if opt == '-h':
  715. headers.append('#include <%s>' % (value,))
  716. name = args[0]
  717. fields = []
  718. for i in range(1, len(args), 2):
  719. ctype = getattr(rffi, args[i+1])
  720. fields.append((args[i], ctype))
  721. S = getstruct(name, '\n'.join(headers), fields)
  722. for name in S._names:
  723. print name, getattr(S, name)