5
from pypy.translator.tool.cbuild import build_executable
6
from pypy.tool.udir import udir
8
# ____________________________________________________________
10
# Helpers for simple cases
12
def getstruct(name, c_header_source, interesting_fields):
14
_header_ = c_header_source
15
STRUCT = Struct(name, interesting_fields)
16
return configure(CConfig)['STRUCT']
18
def getsimpletype(name, c_header_source, ctype_hint=ctypes.c_int):
20
_header_ = c_header_source
21
TYPE = SimpleType(name, ctype_hint)
22
return configure(CConfig)['TYPE']
24
def getconstantinteger(name, c_header_source):
26
_header_ = c_header_source
27
CONST = ConstantInteger(name)
28
return configure(CConfig)['CONST']
30
def getdefined(macro, c_header_source):
32
_header_ = c_header_source
33
DEFINED = Defined(macro)
34
return configure(CConfig)['DEFINED']
36
# ____________________________________________________________
41
def __init__(self, CConfig, info, entries):
42
self.CConfig = CConfig
45
self.entries = entries
47
def get_entry_result(self, entry):
49
return self.result[entry]
52
name = self.entries[entry]
53
info = self.info[name]
54
self.result[entry] = entry.build_result(info, self)
57
return dict([(name, self.result[entry])
58
for entry, name in self.entries.iteritems()])
60
def configure(CConfig):
61
"""Examine the local system by running the C compiler.
62
The CConfig class contains CConfigEntry attribues that describe
63
what should be inspected; configure() returns a dict mapping
67
for key in dir(CConfig):
68
value = getattr(CConfig, key)
69
if isinstance(value, CConfigEntry):
70
entries.append((key, value))
72
filepath = uniquefilepath()
73
f = filepath.open('w')
76
for path in getattr(CConfig, '_includes_', ()): # optional
77
print >> f, '#include <%s>' % (path,)
78
print >> f, getattr(CConfig, '_header_', '') # optional
80
for key, entry in entries:
81
print >> f, 'void dump_section_%s(void) {' % (key,)
82
for line in entry.prepare_code():
83
if line and line[0] != '#':
89
print >> f, 'int main(void) {'
90
for key, entry in entries:
91
print >> f, '\tprintf("-+- %s\\n");' % (key,)
92
print >> f, '\tdump_section_%s();' % (key,)
93
print >> f, '\tprintf("---\\n");'
94
print >> f, '\treturn 0;'
98
include_dirs = getattr(CConfig, '_include_dirs_', [])
99
infolist = list(run_example_code(filepath, include_dirs))
100
assert len(infolist) == len(entries)
104
for info, (key, entry) in zip(infolist, entries):
105
resultinfo[key] = info
106
resultentries[entry] = key
108
result = ConfigResult(CConfig, resultinfo, resultentries)
109
for name, entry in entries:
110
result.get_entry_result(entry)
111
return result.get_result()
113
# ____________________________________________________________
116
class CConfigEntry(object):
117
"Abstract base class."
120
class Struct(CConfigEntry):
121
"""An entry in a CConfig class that stands for an externally
124
def __init__(self, name, interesting_fields, ifdef=None):
126
self.interesting_fields = interesting_fields
129
def prepare_code(self):
130
if self.ifdef is not None:
131
yield '#ifdef %s' % (self.ifdef,)
132
yield 'dump("defined", 1);'
133
yield 'typedef %s ctypesplatcheck_t;' % (self.name,)
134
yield 'typedef struct {'
136
yield ' ctypesplatcheck_t s;'
137
yield '} ctypesplatcheck2_t;'
139
yield 'ctypesplatcheck_t s;'
140
yield 'dump("align", offsetof(ctypesplatcheck2_t, s));'
141
yield 'dump("size", sizeof(ctypesplatcheck_t));'
142
for fieldname, fieldtype in self.interesting_fields:
143
yield 'dump("fldofs %s", offsetof(ctypesplatcheck_t, %s));'%(
144
fieldname, fieldname)
145
yield 'dump("fldsize %s", sizeof(s.%s));' % (
146
fieldname, fieldname)
147
if fieldtype in integer_class:
148
yield 's.%s = 0; s.%s = ~s.%s;' % (fieldname,
151
yield 'dump("fldunsigned %s", s.%s > 0);' % (fieldname,
153
if self.ifdef is not None:
155
yield 'dump("defined", 0);'
158
def build_result(self, info, config_result):
159
if self.ifdef is not None:
160
if not info['defined']:
163
layout = [None] * info['size']
164
for fieldname, fieldtype in self.interesting_fields:
165
if isinstance(fieldtype, Struct):
166
offset = info['fldofs ' + fieldname]
167
size = info['fldsize ' + fieldname]
168
c_fieldtype = config_result.get_entry_result(fieldtype)
169
layout_addfield(layout, offset, c_fieldtype, fieldname)
170
alignment = max(alignment, ctype_alignment(c_fieldtype))
172
offset = info['fldofs ' + fieldname]
173
size = info['fldsize ' + fieldname]
174
sign = info.get('fldunsigned ' + fieldname, False)
175
if (size, sign) != size_and_sign(fieldtype):
176
fieldtype = fixup_ctype(fieldtype, fieldname, (size, sign))
177
layout_addfield(layout, offset, fieldtype, fieldname)
178
alignment = max(alignment, ctype_alignment(fieldtype))
180
# try to enforce the same alignment as the one of the original
182
if alignment < info['align']:
183
choices = [ctype for ctype in alignment_types
184
if ctype_alignment(ctype) == info['align']]
185
assert choices, "unsupported alignment %d" % (info['align'],)
186
choices = [(ctypes.sizeof(ctype), i, ctype)
187
for i, ctype in enumerate(choices)]
188
csize, _, ctype = min(choices)
189
for i in range(0, info['size'] - csize + 1, info['align']):
190
if layout[i:i+csize] == [None] * csize:
191
layout_addfield(layout, i, ctype, '_alignment')
194
raise AssertionError("unenforceable alignment %d" % (
198
for i, cell in enumerate(layout):
201
layout_addfield(layout, i, ctypes.c_char, '_pad%d' % (n,))
204
# build the ctypes Structure
210
fields.append((cell.name, cell.ctype))
213
class S(ctypes.Structure):
216
if name.startswith('struct '):
222
class SimpleType(CConfigEntry):
223
"""An entry in a CConfig class that stands for an externally
224
defined simple numeric type.
226
def __init__(self, name, ctype_hint=ctypes.c_int, ifdef=None):
228
self.ctype_hint = ctype_hint
231
def prepare_code(self):
232
if self.ifdef is not None:
233
yield '#ifdef %s' % (self.ifdef,)
234
yield 'dump("defined", 1);'
235
yield 'typedef %s ctypesplatcheck_t;' % (self.name,)
237
yield 'ctypesplatcheck_t x;'
238
yield 'dump("size", sizeof(ctypesplatcheck_t));'
239
if self.ctype_hint in integer_class:
240
yield 'x = 0; x = ~x;'
241
yield 'dump("unsigned", x > 0);'
242
if self.ifdef is not None:
244
yield 'dump("defined", 0);'
247
def build_result(self, info, config_result):
248
if self.ifdef is not None and not info['defined']:
251
sign = info.get('unsigned', False)
252
ctype = self.ctype_hint
253
if (size, sign) != size_and_sign(ctype):
254
ctype = fixup_ctype(ctype, self.name, (size, sign))
258
class ConstantInteger(CConfigEntry):
259
"""An entry in a CConfig class that stands for an externally
260
defined integer constant.
262
def __init__(self, name):
265
def prepare_code(self):
266
yield 'if ((%s) < 0) {' % (self.name,)
267
yield ' long long x = (long long)(%s);' % (self.name,)
268
yield ' printf("value: %lld\\n", x);'
270
yield ' unsigned long long x = (unsigned long long)(%s);' % (
272
yield ' printf("value: %llu\\n", x);'
275
def build_result(self, info, config_result):
278
class DefinedConstantInteger(CConfigEntry):
279
"""An entry in a CConfig class that stands for an externally
280
defined integer constant. If not #defined the value will be None.
282
def __init__(self, macro):
283
self.name = self.macro = macro
285
def prepare_code(self):
286
yield '#ifdef %s' % self.macro
287
yield 'dump("defined", 1);'
288
yield 'if ((%s) < 0) {' % (self.macro,)
289
yield ' long long x = (long long)(%s);' % (self.macro,)
290
yield ' printf("value: %lld\\n", x);'
292
yield ' unsigned long long x = (unsigned long long)(%s);' % (
294
yield ' printf("value: %llu\\n", x);'
297
yield 'dump("defined", 0);'
300
def build_result(self, info, config_result):
306
class DefinedConstantString(CConfigEntry):
309
def __init__(self, macro):
313
def prepare_code(self):
314
yield '#ifdef %s' % self.macro
316
yield 'char *p = %s;' % self.macro
317
yield 'dump("defined", 1);'
318
yield 'for (i = 0; p[i] != 0; i++ ) {'
319
yield ' printf("value_%d: %d\\n", i, (int)(unsigned char)p[i]);'
322
yield 'dump("defined", 0);'
325
def build_result(self, info, config_result):
329
while info.has_key('value_%d' % d):
330
string += chr(info['value_%d' % d])
336
class Defined(CConfigEntry):
337
"""A boolean, corresponding to an #ifdef.
339
def __init__(self, macro):
343
def prepare_code(self):
344
yield '#ifdef %s' % (self.macro,)
345
yield 'dump("defined", 1);'
347
yield 'dump("defined", 0);'
350
def build_result(self, info, config_result):
351
return bool(info['defined'])
354
class Library(CConfigEntry):
355
"""The loaded CTypes library object.
357
def __init__(self, name):
360
def prepare_code(self):
361
# XXX should check that we can link against the lib
364
def build_result(self, info, config_result):
365
from pypy.rpython.rctypes.tool import util
366
path = util.find_library(self.name)
367
mylib = ctypes.cdll.LoadLibrary(path)
369
class _FuncPtr(ctypes._CFuncPtr):
370
_flags_ = ctypes._FUNCFLAG_CDECL
371
_restype_ = ctypes.c_int # default, can be overridden in instances
372
includes = tuple(config_result.CConfig._includes_)
373
libraries = (self.name,)
375
mylib._FuncPtr = _FuncPtr
378
# ____________________________________________________________
382
def ctype_alignment(c_type):
383
if issubclass(c_type, ctypes.Structure):
384
return max([ctype_alignment(fld_type)
385
for fld_name, fld_type in c_type._fields_])
387
return ctypes.alignment(c_type)
389
def uniquefilepath(LAST=[0]):
392
return udir.join('ctypesplatcheck_%d.c' % i)
407
integer_class = [ctypes.c_byte, ctypes.c_ubyte,
408
ctypes.c_short, ctypes.c_ushort,
409
ctypes.c_int, ctypes.c_uint,
410
ctypes.c_long, ctypes.c_ulong,
411
ctypes.c_longlong, ctypes.c_ulonglong,
413
float_class = [ctypes.c_float, ctypes.c_double]
416
def __init__(self, name, ctype):
420
return '<field %s: %s>' % (self.name, self.ctype)
422
def layout_addfield(layout, offset, ctype, prefix):
423
size = ctypes.sizeof(ctype)
426
while name in layout:
428
name = '%s_%d' % (prefix, i)
429
field = Field(name, ctype)
430
for i in range(offset, offset+size):
431
assert layout[i] is None, "%s overlaps %r" % (fieldname, layout[i])
435
def size_and_sign(ctype):
436
return (ctypes.sizeof(ctype),
437
ctype in integer_class and ctype(-1).value > 0)
439
def fixup_ctype(fieldtype, fieldname, expected_size_and_sign):
440
for typeclass in [integer_class, float_class]:
441
if fieldtype in typeclass:
442
for ctype in typeclass:
443
if size_and_sign(ctype) == expected_size_and_sign:
445
if (hasattr(fieldtype, '_length_')
446
and getattr(fieldtype, '_type_', None) == ctypes.c_char):
447
# for now, assume it is an array of chars; otherwise we'd also
448
# have to check the exact integer type of the elements of the array
449
size, sign = expected_size_and_sign
450
return ctypes.c_char * size
451
if (hasattr(fieldtype, '_length_')
452
and getattr(fieldtype, '_type_', None) == ctypes.c_ubyte):
453
# grumble, fields of type 'c_char array' have automatic cast-to-
454
# Python-string behavior in ctypes, which may not be what you
455
# want, so here is the same with c_ubytes instead...
456
size, sign = expected_size_and_sign
457
return ctypes.c_ubyte * size
458
raise TypeError("conflicting field type %r for %r" % (fieldtype,
464
#include <stddef.h> /* for offsetof() */
466
void dump(char* key, int value) {
467
printf("%s: %d\\n", key, value);
471
def run_example_code(filepath, include_dirs=[]):
472
executable = build_executable([filepath], include_dirs=include_dirs)
473
output = py.process.cmdexec(executable)
475
for line in output.splitlines():
477
if line.startswith('-+- '): # start of a new section
479
elif line == '---': # section end
480
assert section is not None
484
assert section is not None
485
key, value = line.split(': ')
486
section[key] = int(value)
488
# ____________________________________________________________
490
def get_python_include_dir():
491
from distutils import sysconfig
492
gcv = sysconfig.get_config_vars()
493
return gcv['INCLUDEPY']
495
if __name__ == '__main__':
498
ctypes_platform.py -h sys/types.h -h netinet/in.h
503
opts, args = getopt.gnu_getopt(sys.argv[1:], 'h:')
505
print >> sys.stderr, doc
507
assert len(args) % 2 == 1
509
for opt, value in opts:
511
headers.append('#include <%s>' % (value,))
514
for i in range(1, len(args), 2):
515
ctype = getattr(ctypes, args[i+1])
516
fields.append((args[i], ctype))
518
S = getstruct(name, '\n'.join(headers), fields)
520
for key, value in S._fields_: