PageRenderTime 75ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/rtyper/tool/test/test_rffi_platform.py

https://bitbucket.org/pypy/pypy/
Python | 473 lines | 451 code | 10 blank | 12 comment | 4 complexity | 2b53ae05226c09bfe23306b83fb53755 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import py, sys, struct
  2. from rpython.rtyper.tool import rffi_platform
  3. from rpython.rtyper.lltypesystem import lltype
  4. from rpython.rtyper.lltypesystem import rffi
  5. from rpython.tool.udir import udir
  6. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  7. from rpython.translator.platform import platform
  8. from rpython.translator import cdir
  9. from rpython.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong
  10. from rpython.rlib.rfloat import isnan
  11. def import_ctypes():
  12. try:
  13. import ctypes
  14. except ImportError:
  15. py.test.skip("this test requires ctypes")
  16. return ctypes
  17. def test_dirent():
  18. dirent = rffi_platform.getstruct("struct dirent",
  19. """
  20. struct dirent /* for this example only, not the exact dirent */
  21. {
  22. long d_ino;
  23. int d_off;
  24. unsigned short d_reclen;
  25. char d_name[32];
  26. };
  27. """,
  28. [("d_reclen", rffi.USHORT)])
  29. assert isinstance(dirent, lltype.Struct)
  30. # check that we have the desired field
  31. assert dirent.c_d_reclen is rffi.USHORT
  32. ctypes = import_ctypes()
  33. class CTypesDirent(ctypes.Structure):
  34. _fields_ = [('d_ino', ctypes.c_long),
  35. ('d_off', ctypes.c_int),
  36. ('d_reclen', ctypes.c_ushort),
  37. ('d_name', ctypes.c_char * 32)]
  38. assert dirent._hints['size'] == ctypes.sizeof(CTypesDirent)
  39. def test_fit_type():
  40. S = rffi_platform.getstruct("struct S",
  41. """
  42. struct S {
  43. signed char c;
  44. unsigned char uc;
  45. short s;
  46. unsigned short us;
  47. int i;
  48. unsigned int ui;
  49. long l;
  50. unsigned long ul;
  51. long long ll;
  52. unsigned long long ull;
  53. double d;
  54. };
  55. """,
  56. [("c", rffi.INT),
  57. ("uc", rffi.INT),
  58. ("s", rffi.UINT),
  59. ("us", rffi.INT),
  60. ("i", rffi.INT),
  61. ("ui", rffi.INT),
  62. ("l", rffi.INT),
  63. ("ul", rffi.INT),
  64. ("ll", rffi.INT),
  65. ("ull", rffi.INT),
  66. ("d", rffi.DOUBLE)])
  67. # XXX we need to have a float here as well as soon as we'll
  68. # have support
  69. assert isinstance(S, lltype.Struct)
  70. assert S.c_c == rffi.SIGNEDCHAR
  71. assert S.c_uc == rffi.UCHAR
  72. assert S.c_s == rffi.SHORT
  73. assert S.c_us == rffi.USHORT
  74. assert S.c_i == rffi.INT
  75. assert S.c_ui == rffi.UINT
  76. assert S.c_l == rffi.LONG
  77. assert S.c_ul == rffi.ULONG
  78. assert S.c_ll == rffi.LONGLONG
  79. assert S.c_ull == rffi.ULONGLONG
  80. assert S.c_d == rffi.DOUBLE
  81. def test_simple_type():
  82. ctype = rffi_platform.getsimpletype('test_t',
  83. 'typedef unsigned short test_t;',
  84. rffi.INT)
  85. assert ctype == rffi.USHORT
  86. def test_constant_integer():
  87. value = rffi_platform.getconstantinteger('BLAH',
  88. '#define BLAH (6*7)')
  89. assert value == 42
  90. value = rffi_platform.getconstantinteger('BLAH',
  91. '#define BLAH (-2147483648LL)')
  92. assert value == -2147483648
  93. value = rffi_platform.getconstantinteger('BLAH',
  94. '#define BLAH (3333333333ULL)')
  95. assert value == 3333333333
  96. def test_defined():
  97. res = rffi_platform.getdefined('ALFKJLKJFLKJFKLEJDLKEWMECEE', '')
  98. assert not res
  99. res = rffi_platform.getdefined('ALFKJLKJFLKJFKLEJDLKEWMECEE',
  100. '#define ALFKJLKJFLKJFKLEJDLKEWMECEE')
  101. assert res
  102. def test_defined_constant():
  103. res = rffi_platform.getdefineddouble('ABCDFGH', '#define ABCDFGH 2.0')
  104. assert res == 2.0
  105. res = rffi_platform.getdefinedinteger('ABCDFGH', '#define ABCDFGH 2')
  106. assert res == 2
  107. def test_defined_constant_float():
  108. value = rffi_platform.getdefineddouble('BLAH', '#define BLAH 1.0')
  109. assert value == 1.0
  110. value = rffi_platform.getdefineddouble('BLAH', '#define BLAH 1.5')
  111. assert value == 1.5
  112. value = rffi_platform.getdefineddouble('BLAH', '#define BLAH 1.0e20')
  113. assert value == 1.0e20
  114. if platform.name != 'msvc':
  115. value = rffi_platform.getdefineddouble('BLAH', '#define BLAH 1.0e50000')
  116. assert value == float("inf")
  117. value = rffi_platform.getdefineddouble('BLAH', '#define BLAH (double)0/0')
  118. assert isnan(value)
  119. def test_defined_constant_string():
  120. value = rffi_platform.getdefinedstring('MCDONC', '')
  121. assert value is None
  122. value = rffi_platform.getdefinedstring('RAYDEO',
  123. '#define RAYDEO "Michael Merickel"')
  124. assert value == 'Michael Merickel'
  125. def test_getintegerfunctionresult():
  126. func = 'RPY_EXPORTED int sum(int a, int b) {return a + b;}'
  127. value = rffi_platform.getintegerfunctionresult('sum', [6, 7], func)
  128. assert value == 13
  129. if not platform.name == 'msvc':
  130. # MSVC gets lround in VS2013!
  131. value = rffi_platform.getintegerfunctionresult('lround', [6.7],
  132. '#include <math.h>')
  133. assert value == 7
  134. value = rffi_platform.getintegerfunctionresult('lround', [9.1],
  135. includes=['math.h'])
  136. assert value == 9
  137. def test_configure():
  138. test_h = udir.join('test_ctypes_platform.h')
  139. test_h.write('#define XYZZY 42\n')
  140. class CConfig:
  141. _compilation_info_ = ExternalCompilationInfo(
  142. pre_include_bits = ["/* a C comment */",
  143. "#include <stdio.h>",
  144. "#include <test_ctypes_platform.h>"],
  145. include_dirs = [str(udir)]
  146. )
  147. FILE = rffi_platform.Struct('FILE', [])
  148. ushort = rffi_platform.SimpleType('unsigned short')
  149. XYZZY = rffi_platform.ConstantInteger('XYZZY')
  150. res = rffi_platform.configure(CConfig)
  151. assert isinstance(res['FILE'], lltype.Struct)
  152. assert res == {'FILE': res['FILE'],
  153. 'ushort': rffi.USHORT,
  154. 'XYZZY': 42}
  155. def test_integer_function_result():
  156. class CConfig:
  157. _compilation_info_ = ExternalCompilationInfo(
  158. pre_include_bits = ["""int sum(int a, int b){ return a+b;}"""],
  159. )
  160. SUM = rffi_platform.IntegerFunctionResult('sum', [12, 34])
  161. SUM2 = rffi_platform.IntegerFunctionResult('sum', [-12, -34])
  162. res = rffi_platform.configure(CConfig)
  163. assert res['SUM'] == 46
  164. assert res['SUM2'] == -46
  165. def test_ifdef():
  166. class CConfig:
  167. _compilation_info_ = ExternalCompilationInfo(
  168. post_include_bits = ['/* a C comment */',
  169. '#define XYZZY 42',
  170. 'typedef int foo;',
  171. '''
  172. struct s {
  173. int i;
  174. double f;
  175. };
  176. '''])
  177. s = rffi_platform.Struct('struct s', [('i', rffi.INT)],
  178. ifdef='XYZZY')
  179. z = rffi_platform.Struct('struct z', [('i', rffi.INT)],
  180. ifdef='FOOBAR')
  181. foo = rffi_platform.SimpleType('foo', ifdef='XYZZY')
  182. bar = rffi_platform.SimpleType('bar', ifdef='FOOBAR')
  183. res = rffi_platform.configure(CConfig)
  184. assert res['s'] is not None
  185. assert res['z'] is None
  186. assert res['foo'] is not None
  187. assert res['bar'] is None
  188. def test_nested_structs():
  189. class CConfig:
  190. _compilation_info_ = ExternalCompilationInfo(
  191. post_include_bits=["""
  192. struct x {
  193. int foo;
  194. unsigned long bar;
  195. };
  196. struct y {
  197. char c;
  198. struct x x;
  199. };
  200. """])
  201. x = rffi_platform.Struct("struct x", [("bar", rffi.SHORT)])
  202. y = rffi_platform.Struct("struct y", [("x", x)])
  203. res = rffi_platform.configure(CConfig)
  204. c_x = res["x"]
  205. c_y = res["y"]
  206. assert isinstance(c_x, lltype.Struct)
  207. assert isinstance(c_y, lltype.Struct)
  208. assert c_y.c_x is c_x
  209. def test_nested_structs_in_the_opposite_order():
  210. class CConfig:
  211. _compilation_info_ = ExternalCompilationInfo(
  212. post_include_bits=["""
  213. struct y {
  214. int foo;
  215. unsigned long bar;
  216. };
  217. struct x {
  218. char c;
  219. struct y y;
  220. };
  221. """])
  222. y = rffi_platform.Struct("struct y", [("bar", rffi.SHORT)])
  223. x = rffi_platform.Struct("struct x", [("y", y)])
  224. res = rffi_platform.configure(CConfig)
  225. c_x = res["x"]
  226. c_y = res["y"]
  227. assert isinstance(c_x, lltype.Struct)
  228. assert isinstance(c_y, lltype.Struct)
  229. assert c_x.c_y is c_y
  230. def test_array():
  231. dirent = rffi_platform.getstruct("struct dirent",
  232. """
  233. struct dirent /* for this example only, not the exact dirent */
  234. {
  235. long d_ino;
  236. int d_off;
  237. unsigned short d_reclen;
  238. char d_name[32];
  239. };
  240. """,
  241. [("d_name", lltype.FixedSizeArray(rffi.CHAR, 1))])
  242. assert dirent.c_d_name.length == 32
  243. def test_array_varsized_struct():
  244. dirent = rffi_platform.getstruct("struct dirent",
  245. """
  246. struct dirent /* for this example only, not the exact dirent */
  247. {
  248. int d_off;
  249. char d_name[1];
  250. };
  251. """,
  252. [("d_name", rffi.CArray(rffi.CHAR))])
  253. assert rffi.offsetof(dirent, 'c_d_name') == 4
  254. assert dirent.c_d_name == rffi.CArray(rffi.CHAR)
  255. def test_has_0001():
  256. assert rffi_platform.has("x", "int x = 3;")
  257. assert not rffi_platform.has("x", "")
  258. # has() should also not crash if it is given an invalid #include
  259. assert not rffi_platform.has("x", "#include <some/path/which/cannot/exist>")
  260. def test_has_0002():
  261. if platform.name == 'msvc':
  262. py.test.skip('no m.lib in msvc')
  263. assert rffi_platform.has("pow", "#include <math.h>", libraries=["m"])
  264. def test_has_0003():
  265. """multiple libraries"""
  266. if platform.name == 'msvc':
  267. py.test.skip('no m.lib in msvc')
  268. assert rffi_platform.has("pow", "#include <math.h>", libraries=["m", "c"])
  269. def test_has_0004():
  270. """bogus symbol name"""
  271. assert not rffi_platform.has("pow", "#include <math.h>",
  272. libraries=["boguslibname"])
  273. def test_has_0005():
  274. """bogus symbol name and lib name"""
  275. assert not rffi_platform.has("bogus_symbol_name", "#include <math.h>",
  276. libraries=["boguslibname"])
  277. def test_has_0006():
  278. """missing include"""
  279. assert not rffi_platform.has("pow", "", libraries=["m"])
  280. def test_verify_eci():
  281. eci = ExternalCompilationInfo()
  282. rffi_platform.verify_eci(eci)
  283. eci = ExternalCompilationInfo(libraries=['some_name_that_doesnt_exist_'])
  284. py.test.raises(rffi_platform.CompilationError,
  285. rffi_platform.verify_eci, eci)
  286. def test_sizeof():
  287. assert rffi_platform.sizeof("char", ExternalCompilationInfo()) == 1
  288. def test_memory_alignment():
  289. a = rffi_platform.memory_alignment()
  290. print a
  291. assert a % struct.calcsize("P") == 0
  292. def test_external_lib():
  293. eci = ExternalCompilationInfo(include_dirs = [cdir])
  294. c_source = """
  295. #include "src/precommondefs.h"
  296. RPY_EXPORTED
  297. int f(int a, int b)
  298. {
  299. return (a + b);
  300. }
  301. """
  302. if platform.name == 'msvc':
  303. libname = 'libc_lib'
  304. else:
  305. libname = 'c_lib'
  306. tmpdir = udir.join('external_lib').ensure(dir=1)
  307. c_file = tmpdir.join('libc_lib.c')
  308. c_file.write(c_source)
  309. l = platform.compile([c_file], eci, standalone=False)
  310. eci = ExternalCompilationInfo(
  311. libraries = [libname],
  312. library_dirs = [str(tmpdir)]
  313. )
  314. rffi_platform.verify_eci(eci)
  315. def test_generate_padding():
  316. # 'padding_drop' is a bit strange, but is what we need to write C code
  317. # that defines prebuilt structures of that type. Normally, the C
  318. # backend would generate '0' entries for every field c__pad#. That's
  319. # usually much more than the number of real fields in the real structure
  320. # definition. So 'padding_drop' allows a quick fix: it lists fields
  321. # that should be ignored by the C backend. It should only be used in
  322. # that situation because it lists some of the c__pad# fields a bit
  323. # randomly -- to the effect that writing '0' for the other fields gives
  324. # the right amount of '0's.
  325. S = rffi_platform.getstruct("foobar_t", """
  326. typedef struct {
  327. char c1; /* followed by one byte of padding */
  328. short s1;
  329. } foobar_t;
  330. """, [("c1", lltype.Signed),
  331. ("s1", lltype.Signed)])
  332. assert S._hints['padding'] == ('c__pad0',)
  333. d = {'c_c1': 'char', 'c_s1': 'short'}
  334. assert S._hints['get_padding_drop'](d) == ['c__pad0']
  335. #
  336. S = rffi_platform.getstruct("foobar_t", """
  337. typedef struct {
  338. char c1;
  339. char c2; /* _pad0 */
  340. short s1;
  341. } foobar_t;
  342. """, [("c1", lltype.Signed),
  343. ("s1", lltype.Signed)])
  344. assert S._hints['padding'] == ('c__pad0',)
  345. d = {'c_c1': 'char', 'c_s1': 'short'}
  346. assert S._hints['get_padding_drop'](d) == []
  347. #
  348. S = rffi_platform.getstruct("foobar_t", """
  349. typedef struct {
  350. char c1;
  351. char c2; /* _pad0 */
  352. /* _pad1, _pad2 */
  353. int i1;
  354. } foobar_t;
  355. """, [("c1", lltype.Signed),
  356. ("i1", lltype.Signed)])
  357. assert S._hints['padding'] == ('c__pad0', 'c__pad1', 'c__pad2')
  358. d = {'c_c1': 'char', 'c_i1': 'int'}
  359. assert S._hints['get_padding_drop'](d) == ['c__pad1', 'c__pad2']
  360. #
  361. S = rffi_platform.getstruct("foobar_t", """
  362. typedef struct {
  363. char c1;
  364. char c2; /* _pad0 */
  365. char c3; /* _pad1 */
  366. /* _pad2 */
  367. int i1;
  368. } foobar_t;
  369. """, [("c1", lltype.Signed),
  370. ("i1", lltype.Signed)])
  371. assert S._hints['padding'] == ('c__pad0', 'c__pad1', 'c__pad2')
  372. d = {'c_c1': 'char', 'c_i1': 'int'}
  373. assert S._hints['get_padding_drop'](d) == ['c__pad2']
  374. #
  375. S = rffi_platform.getstruct("foobar_t", """
  376. typedef struct {
  377. char c1;
  378. /* _pad0 */
  379. short s1; /* _pad1, _pad2 */
  380. int i1;
  381. } foobar_t;
  382. """, [("c1", lltype.Signed),
  383. ("i1", lltype.Signed)])
  384. assert S._hints['padding'] == ('c__pad0', 'c__pad1', 'c__pad2')
  385. d = {'c_c1': 'char', 'c_i1': 'int'}
  386. assert S._hints['get_padding_drop'](d) == ['c__pad1', 'c__pad2']
  387. #
  388. S = rffi_platform.getstruct("foobar_t", """
  389. typedef struct {
  390. char c1;
  391. char c2; /* _pad0 */
  392. /* _pad1, _pad2 */
  393. int i1;
  394. char c3; /* _pad3 */
  395. /* _pad4 */
  396. short s1;
  397. } foobar_t;
  398. """, [("c1", lltype.Signed),
  399. ("i1", lltype.Signed),
  400. ("s1", lltype.Signed)])
  401. assert S._hints['padding'] == ('c__pad0', 'c__pad1', 'c__pad2',
  402. 'c__pad3', 'c__pad4')
  403. d = {'c_c1': 'char', 'c_i1': 'int', 'c_s1': 'short'}
  404. assert S._hints['get_padding_drop'](d) == ['c__pad1', 'c__pad2', 'c__pad4']
  405. #
  406. S = rffi_platform.getstruct("foobar_t", """
  407. typedef struct {
  408. char c1;
  409. long l2; /* some number of _pads */
  410. } foobar_t;
  411. """, [("c1", lltype.Signed)])
  412. padding = list(S._hints['padding'])
  413. d = {'c_c1': 'char'}
  414. assert S._hints['get_padding_drop'](d) == padding
  415. def test_expose_value_as_rpython():
  416. def get(x):
  417. x = rffi_platform.expose_value_as_rpython(x)
  418. return (x, type(x))
  419. assert get(5) == (5, int)
  420. assert get(-82) == (-82, int)
  421. assert get(sys.maxint) == (sys.maxint, int)
  422. assert get(sys.maxint+1) == (sys.maxint+1, r_uint)
  423. if sys.maxint == 2147483647:
  424. assert get(9999999999) == (9999999999, r_longlong)
  425. assert get(-9999999999) == (-9999999999, r_longlong)
  426. assert get(2**63) == (2**63, r_ulonglong)
  427. assert get(-2**63) == (-2**63, r_longlong)
  428. py.test.raises(OverflowError, get, -2**63-1)
  429. py.test.raises(OverflowError, get, 2**64)