[pypy-svn] r26136 - in pypy/dist/pypy/rpython/rctypes/tool: . test
arigo at codespeak.net
arigo at codespeak.net
Sat Apr 22 13:31:36 CEST 2006
Author: arigo
Date: Sat Apr 22 13:31:35 2006
New Revision: 26136
Modified:
pypy/dist/pypy/rpython/rctypes/tool/ctypes_platform.py
pypy/dist/pypy/rpython/rctypes/tool/test/test_ctypes_platform.py
Log:
An easy refactoring of ctypes_platform.py to allow many queries -- a
whole configuration -- to be performed in a single pass through the C
compiler. This also gives a natural place to put some new general
settings, like _include_dirs_ for a list of include dirs to pass to the
compiler.
Modified: pypy/dist/pypy/rpython/rctypes/tool/ctypes_platform.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/tool/ctypes_platform.py (original)
+++ pypy/dist/pypy/rpython/rctypes/tool/ctypes_platform.py Sat Apr 22 13:31:35 2006
@@ -5,6 +5,241 @@
from pypy.translator.tool.cbuild import build_executable
from pypy.tool.udir import udir
+# ____________________________________________________________
+#
+# Helpers for simple cases
+
+def getstruct(name, c_header_source, interesting_fields):
+ class CConfig:
+ _header_ = c_header_source
+ STRUCT = Struct(name, interesting_fields)
+ return configure(CConfig)['STRUCT']
+
+def getsimpletype(name, c_header_source, ctype_hint=ctypes.c_int):
+ class CConfig:
+ _header_ = c_header_source
+ TYPE = SimpleType(name, ctype_hint)
+ return configure(CConfig)['TYPE']
+
+def getconstantinteger(name, c_header_source):
+ class CConfig:
+ _header_ = c_header_source
+ CONST = ConstantInteger(name)
+ return configure(CConfig)['CONST']
+
+def getdefined(macro, c_header_source):
+ class CConfig:
+ _header_ = c_header_source
+ DEFINED = Defined(macro)
+ return configure(CConfig)['DEFINED']
+
+# ____________________________________________________________
+#
+# General interface
+
+def configure(CConfig):
+ """Examine the local system by running the C compiler.
+ The CConfig class contains CConfigEntry attribues that describe
+ what should be inspected; configure() returns a dict mapping
+ names to the results.
+ """
+ entries = []
+ for key in dir(CConfig):
+ value = getattr(CConfig, key)
+ if isinstance(value, CConfigEntry):
+ entries.append((key, value))
+
+ filepath = uniquefilepath()
+ f = filepath.open('w')
+ print >> f, C_HEADER
+ print >> f
+ print >> f, CConfig._header_ # mandatory
+ print >> f
+ for key, entry in entries:
+ print >> f, 'void dump_section_%s(void) {' % (key,)
+ print >> f, '\tprintf("-+- %s\\n");' % (key,)
+ for line in entry.prepare_code():
+ if line and line[0] != '#':
+ line = '\t' + line
+ print >> f, line
+ print >> f, '\tprintf("---\\n");'
+ print >> f, '}'
+ print >> f
+
+ print >> f, 'int main(void) {'
+ for key, entry in entries:
+ print >> f, '\tdump_section_%s();' % (key,)
+ print >> f, '\treturn 0;'
+ print >> f, '}'
+ f.close()
+
+ include_dirs = getattr(CConfig, '_include_dirs_', [])
+ infolist = list(run_example_code(filepath, include_dirs))
+ assert len(infolist) == len(entries)
+
+ result = {}
+ for info, (key, entry) in zip(infolist, entries):
+ result[key] = entry.build_result(info)
+ return result
+
+# ____________________________________________________________
+
+
+class CConfigEntry(object):
+ "Abstract base class."
+
+
+class Struct(CConfigEntry):
+ """An entry in a CConfig class that stands for an externally
+ defined structure.
+ """
+ def __init__(self, name, interesting_fields):
+ self.name = name
+ self.interesting_fields = interesting_fields
+
+ def prepare_code(self):
+ yield 'typedef %s ctypesplatcheck_t;' % (self.name,)
+ yield 'typedef struct {'
+ yield ' char c;'
+ yield ' ctypesplatcheck_t s;'
+ yield '} ctypesplatcheck2_t;'
+ yield ''
+ yield 'ctypesplatcheck_t s;'
+ yield 'dump("align", offsetof(ctypesplatcheck2_t, s));'
+ yield 'dump("size", sizeof(ctypesplatcheck_t));'
+ for fieldname, fieldtype in self.interesting_fields:
+ yield 'dump("fldofs %s", offsetof(ctypesplatcheck_t, %s));'%(
+ fieldname, fieldname)
+ yield 'dump("fldsize %s", sizeof(s.%s));' % (
+ fieldname, fieldname)
+ if fieldtype in integer_class:
+ yield 's.%s = 0; s.%s = ~s.%s;' % (fieldname,
+ fieldname,
+ fieldname)
+ yield 'dump("fldunsigned %s", s.%s > 0);' % (fieldname,
+ fieldname)
+
+ def build_result(self, info):
+ alignment = 1
+ layout = [None] * info['size']
+ for fieldname, fieldtype in self.interesting_fields:
+ offset = info['fldofs ' + fieldname]
+ size = info['fldsize ' + fieldname]
+ sign = info.get('fldunsigned ' + fieldname, False)
+ if (size, sign) != size_and_sign(fieldtype):
+ fieldtype = fixup_ctype(fieldtype, fieldname, (size, sign))
+ layout_addfield(layout, offset, fieldtype, fieldname)
+ alignment = max(alignment, ctypes.alignment(fieldtype))
+
+ # try to enforce the same alignment as the one of the original
+ # structure
+ if alignment < info['align']:
+ choices = [ctype for ctype in alignment_types
+ if ctypes.alignment(ctype) == info['align']]
+ assert choices, "unsupported alignment %d" % (info['align'],)
+ choices = [(ctypes.sizeof(ctype), i, ctype)
+ for i, ctype in enumerate(choices)]
+ csize, _, ctype = min(choices)
+ for i in range(0, info['size'] - csize + 1, info['align']):
+ if layout[i:i+csize] == [None] * csize:
+ layout_addfield(layout, i, ctype, '_alignment')
+ break
+ else:
+ raise AssertionError("unenforceable alignment %d" % (
+ info['align'],))
+
+ n = 0
+ for i, cell in enumerate(layout):
+ if cell is not None:
+ continue
+ layout_addfield(layout, i, ctypes.c_char, '_pad%d' % (n,))
+ n += 1
+
+ # build the ctypes Structure
+ seen = {}
+ fields = []
+ for cell in layout:
+ if cell in seen:
+ continue
+ fields.append((cell.name, cell.ctype))
+ seen[cell] = True
+
+ class S(ctypes.Structure):
+ _fields_ = fields
+ name = self.name
+ if name.startswith('struct '):
+ name = name[7:]
+ S.__name__ = name
+ return S
+
+
+class SimpleType(CConfigEntry):
+ """An entry in a CConfig class that stands for an externally
+ defined simple numeric type.
+ """
+ def __init__(self, name, ctype_hint=ctypes.c_int):
+ self.name = name
+ self.ctype_hint = ctype_hint
+
+ def prepare_code(self):
+ yield 'typedef %s ctypesplatcheck_t;' % (self.name,)
+ yield ''
+ yield 'ctypesplatcheck_t x;'
+ yield 'dump("size", sizeof(ctypesplatcheck_t));'
+ if self.ctype_hint in integer_class:
+ yield 'x = 0; x = ~x;'
+ yield 'dump("unsigned", x > 0);'
+
+ def build_result(self, info):
+ size = info['size']
+ sign = info.get('unsigned', False)
+ ctype = self.ctype_hint
+ if (size, sign) != size_and_sign(ctype):
+ ctype = fixup_ctype(ctype, self.name, (size, sign))
+ return ctype
+
+
+class ConstantInteger(CConfigEntry):
+ """An entry in a CConfig class that stands for an externally
+ defined integer constant.
+ """
+ def __init__(self, name):
+ self.name = name
+
+ def prepare_code(self):
+ yield ' if ((%s) < 0) {' % (self.name,)
+ yield ' long long x = (long long)(%s);' % (self.name,)
+ yield ' printf("value: %lld\\n", x);'
+ yield ' } else {'
+ yield ' unsigned long long x = (unsigned long long)(%s);' % (
+ self.name,)
+ yield ' printf("value: %llu\\n", x);'
+ yield ' }'
+
+ def build_result(self, info):
+ return info['value']
+
+
+class Defined(CConfigEntry):
+ """A boolean, corresponding to an #ifdef.
+ """
+ def __init__(self, macro):
+ self.macro = macro
+ self.name = macro
+
+ def prepare_code(self):
+ yield '#ifdef %s' % (self.macro,)
+ yield 'dump("defined", 1);'
+ yield '#else'
+ yield 'dump("defined", 0);'
+ yield '#endif'
+
+ def build_result(self, info):
+ return bool(info['defined'])
+
+# ____________________________________________________________
+#
+# internal helpers
def uniquefilepath(LAST=[0]):
i = LAST[0]
@@ -75,157 +310,24 @@
}
"""
-def run_example_code(filepath):
- executable = build_executable([filepath])
+def run_example_code(filepath, include_dirs=[]):
+ executable = build_executable([filepath], include_dirs=include_dirs)
output = py.process.cmdexec(executable)
- info = {}
+ section = None
for line in output.splitlines():
- key, value = line.strip().split(': ')
- info[key] = int(value)
- return info
-
-def getstruct(name, c_header_source, interesting_fields):
- filepath = uniquefilepath()
- f = filepath.open('w')
- print >> f, C_HEADER
- print >> f
- print >> f, c_header_source
- print >> f
- print >> f, 'typedef %s ctypesplatcheck_t;' % (name,)
- print >> f, 'typedef struct {'
- print >> f, ' char c;'
- print >> f, ' ctypesplatcheck_t s;'
- print >> f, '} ctypesplatcheck2_t;'
- print >> f
- print >> f, 'int main(void) {'
- print >> f, ' ctypesplatcheck_t s;'
- print >> f, ' dump("align", offsetof(ctypesplatcheck2_t, s));'
- print >> f, ' dump("size", sizeof(ctypesplatcheck_t));'
- for fieldname, fieldtype in interesting_fields:
- print >> f, ' dump("fldofs %s", offsetof(ctypesplatcheck_t, %s));'%(
- fieldname, fieldname)
- print >> f, ' dump("fldsize %s", sizeof(s.%s));' % (
- fieldname, fieldname)
- if fieldtype in integer_class:
- print >> f, ' s.%s = 0; s.%s = ~s.%s;' % (fieldname,
- fieldname,
- fieldname)
- print >> f, ' dump("fldunsigned %s", s.%s > 0);' % (fieldname,
- fieldname)
- print >> f, ' return 0;'
- print >> f, '}'
- f.close()
-
- info = run_example_code(filepath)
-
- alignment = 1
- layout = [None] * info['size']
- for fieldname, fieldtype in interesting_fields:
- offset = info['fldofs ' + fieldname]
- size = info['fldsize ' + fieldname]
- sign = info.get('fldunsigned ' + fieldname, False)
- if (size, sign) != size_and_sign(fieldtype):
- fieldtype = fixup_ctype(fieldtype, fieldname, (size, sign))
- layout_addfield(layout, offset, fieldtype, fieldname)
- alignment = max(alignment, ctypes.alignment(fieldtype))
-
- # try to enforce the same alignment as the one of the original structure
- if alignment < info['align']:
- choices = [ctype for ctype in alignment_types
- if ctypes.alignment(ctype) == info['align']]
- assert choices, "unsupported alignment %d" % (info['align'],)
- choices = [(ctypes.sizeof(ctype), i, ctype)
- for i, ctype in enumerate(choices)]
- csize, _, ctype = min(choices)
- for i in range(0, info['size'] - csize + 1, info['align']):
- if layout[i:i+csize] == [None] * csize:
- layout_addfield(layout, i, ctype, '_alignment')
- break
- else:
- raise AssertionError("unenforceable alignment %d" % (
- info['align'],))
-
- n = 0
- for i, cell in enumerate(layout):
- if cell is not None:
- continue
- layout_addfield(layout, i, ctypes.c_char, '_pad%d' % (n,))
- n += 1
-
- # build the ctypes Structure
- seen = {}
- fields = []
- for cell in layout:
- if cell in seen:
- continue
- fields.append((cell.name, cell.ctype))
- seen[cell] = True
-
- class S(ctypes.Structure):
- _fields_ = fields
- if name.startswith('struct '):
- name = name[7:]
- S.__name__ = name
- return S
-
-
-def getsimpletype(name, c_header_source, ctype_hint):
- filepath = uniquefilepath()
- f = filepath.open('w')
- print >> f, C_HEADER
- print >> f
- print >> f, c_header_source
- print >> f
- print >> f, 'typedef %s ctypesplatcheck_t;' % (name,)
- print >> f
- print >> f, 'int main(void) {'
- print >> f, ' ctypesplatcheck_t x;'
- print >> f, ' dump("size", sizeof(ctypesplatcheck_t));'
- if ctype_hint in integer_class:
- print >> f, ' x = 0; x = ~x;'
- print >> f, ' dump("unsigned", x > 0);'
- print >> f, ' return 0;'
- print >> f, '}'
- f.close()
-
- info = run_example_code(filepath)
-
- size = info['size']
- sign = info.get('unsigned', False)
- if (size, sign) != size_and_sign(ctype_hint):
- ctype_hint = fixup_ctype(ctype_hint, name, (size, sign))
- return ctype_hint
-
-
-def getconstantinteger(name, c_header_source):
- filepath = uniquefilepath()
- f = filepath.open('w')
- print >> f, C_HEADER
- print >> f
- print >> f, c_header_source
- print >> f
- print >> f, 'int main(void) {'
- print >> f, ' if ((%s) < 0) {' % (name,)
- print >> f, ' long long x = (long long)(%s);' % (name,)
- print >> f, ' printf("value: %lld\\n", x);'
- print >> f, ' } else {'
- print >> f, ' unsigned long long x = (unsigned long long)(%s);' % (
- name,)
- print >> f, ' printf("value: %llu\\n", x);'
- print >> f, ' }'
- print >> f, ' return 0;'
- print >> f, '}'
- f.close()
-
- info = run_example_code(filepath)
-
- return info['value']
-
-
-def getdefined(name, c_header_source):
- return getconstantinteger('\n#ifdef %s\n1\n#else\n0\n#endif\n' % (name),
- c_header_source)
+ line = line.strip()
+ if line.startswith('-+- '): # start of a new section
+ section = {}
+ elif line == '---': # section end
+ assert section is not None
+ yield section
+ section = None
+ elif line:
+ assert section is not None
+ key, value = line.split(': ')
+ section[key] = int(value)
+# ____________________________________________________________
if __name__ == '__main__':
doc = """Example:
Modified: pypy/dist/pypy/rpython/rctypes/tool/test/test_ctypes_platform.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/tool/test/test_ctypes_platform.py (original)
+++ pypy/dist/pypy/rpython/rctypes/tool/test/test_ctypes_platform.py Sat Apr 22 13:31:35 2006
@@ -1,5 +1,6 @@
import py, sys, struct
from pypy.rpython.rctypes.tool import ctypes_platform
+from pypy.tool.udir import udir
import ctypes
@@ -102,3 +103,24 @@
res = ctypes_platform.getdefined('ALFKJLKJFLKJFKLEJDLKEWMECEE',
'#define ALFKJLKJFLKJFKLEJDLKEWMECEE')
assert res
+
+def test_configure():
+ test_h = udir.join('test_ctypes_platform.h')
+ test_h.write('#define XYZZY 42\n')
+
+ class CConfig:
+ _header_ = """ /* a C comment */
+ #include <stdio.h>
+ #include <test_ctypes_platform.h>
+ """
+ _include_dirs_ = [str(udir)]
+
+ FILE = ctypes_platform.Struct('FILE', [])
+ ushort = ctypes_platform.SimpleType('unsigned short')
+ XYZZY = ctypes_platform.ConstantInteger('XYZZY')
+
+ res = ctypes_platform.configure(CConfig)
+ assert issubclass(res['FILE'], ctypes.Structure)
+ assert res == {'FILE': res['FILE'],
+ 'ushort': ctypes.c_ushort,
+ 'XYZZY': 42}
More information about the Pypy-commit
mailing list