Author: Armin Rigo <ar...@tunes.org> Branch: py3.5 Changeset: r89312:020911d610d9 Date: 2017-01-02 19:42 +0100 http://bitbucket.org/pypy/pypy/changeset/020911d610d9/
Log: hg merge default diff too long, truncating to 2000 out of 4555 lines diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -28,7 +28,7 @@ DEALINGS IN THE SOFTWARE. -PyPy Copyright holders 2003-2016 +PyPy Copyright holders 2003-2017 ----------------------------------- Except when otherwise stated (look for LICENSE files or information at diff --git a/ctypes_configure/__init__.py b/ctypes_configure/__init__.py deleted file mode 100644 diff --git a/ctypes_configure/cbuild.py b/ctypes_configure/cbuild.py deleted file mode 100644 --- a/ctypes_configure/cbuild.py +++ /dev/null @@ -1,456 +0,0 @@ - -import os, sys, inspect, re, imp, py -from ctypes_configure import stdoutcapture -import distutils - -debug = 0 - -configdir = py.path.local.make_numbered_dir(prefix='ctypes_configure-') - -class ExternalCompilationInfo(object): - - _ATTRIBUTES = ['pre_include_lines', 'includes', 'include_dirs', - 'post_include_lines', 'libraries', 'library_dirs', - 'separate_module_sources', 'separate_module_files'] - _AVOID_DUPLICATES = ['separate_module_files', 'libraries', 'includes', - 'include_dirs', 'library_dirs', 'separate_module_sources'] - - def __init__(self, - pre_include_lines = [], - includes = [], - include_dirs = [], - post_include_lines = [], - libraries = [], - library_dirs = [], - separate_module_sources = [], - separate_module_files = []): - """ - pre_include_lines: list of lines that should be put at the top - of the generated .c files, before any #include. They shouldn't - contain an #include themselves. - - includes: list of .h file names to be #include'd from the - generated .c files. - - include_dirs: list of dir names that is passed to the C compiler - - post_include_lines: list of lines that should be put at the top - of the generated .c files, after the #includes. - - libraries: list of library names that is passed to the linker - - library_dirs: list of dir names that is passed to the linker - - separate_module_sources: list of multiline strings that are - each written to a .c file and compiled separately and linked - later on. (If function prototypes are needed for other .c files - to access this, they can be put in post_include_lines.) - - separate_module_files: list of .c file names that are compiled - separately and linked later on. (If an .h file is needed for - other .c files to access this, it can be put in includes.) - """ - for name in self._ATTRIBUTES: - value = locals()[name] - assert isinstance(value, (list, tuple)) - setattr(self, name, tuple(value)) - - def _value(self): - return tuple([getattr(self, x) for x in self._ATTRIBUTES]) - - def __hash__(self): - return hash(self._value()) - - def __eq__(self, other): - return self.__class__ is other.__class__ and \ - self._value() == other._value() - - def __ne__(self, other): - return not self == other - - def __repr__(self): - info = [] - for attr in self._ATTRIBUTES: - val = getattr(self, attr) - info.append("%s=%s" % (attr, repr(val))) - return "<ExternalCompilationInfo (%s)>" % ", ".join(info) - - def merge(self, *others): - others = list(others) - attrs = {} - for name in self._ATTRIBUTES: - if name not in self._AVOID_DUPLICATES: - s = [] - for i in [self] + others: - s += getattr(i, name) - attrs[name] = s - else: - s = set() - attr = [] - for one in [self] + others: - for elem in getattr(one, name): - if elem not in s: - s.add(elem) - attr.append(elem) - attrs[name] = attr - return ExternalCompilationInfo(**attrs) - - def write_c_header(self, fileobj): - for line in self.pre_include_lines: - print >> fileobj, line - for path in self.includes: - print >> fileobj, '#include <%s>' % (path,) - for line in self.post_include_lines: - print >> fileobj, line - - def _copy_attributes(self): - d = {} - for attr in self._ATTRIBUTES: - d[attr] = getattr(self, attr) - return d - - def convert_sources_to_files(self, cache_dir=None, being_main=False): - if not self.separate_module_sources: - return self - if cache_dir is None: - cache_dir = configdir.join('module_cache').ensure(dir=1) - num = 0 - files = [] - for source in self.separate_module_sources: - while 1: - filename = cache_dir.join('module_%d.c' % num) - num += 1 - if not filename.check(): - break - f = filename.open("w") - if being_main: - f.write("#define PYPY_NOT_MAIN_FILE\n") - self.write_c_header(f) - source = str(source) - f.write(source) - if not source.endswith('\n'): - f.write('\n') - f.close() - files.append(str(filename)) - d = self._copy_attributes() - d['separate_module_sources'] = () - d['separate_module_files'] += tuple(files) - return ExternalCompilationInfo(**d) - - def compile_shared_lib(self): - self = self.convert_sources_to_files() - if not self.separate_module_files: - return self - lib = compile_c_module([], 'externmod', self) - d = self._copy_attributes() - d['libraries'] += (lib,) - d['separate_module_files'] = () - d['separate_module_sources'] = () - return ExternalCompilationInfo(**d) - -if sys.platform == 'win32': - so_ext = '.dll' -else: - so_ext = '.so' - -def compiler_command(): - # e.g. for tcc, you might set this to - # "tcc -shared -o %s.so %s.c" - return os.getenv('PYPY_CC') - -def enable_fast_compilation(): - if sys.platform == 'win32': - dash = '/' - else: - dash = '-' - from distutils import sysconfig - gcv = sysconfig.get_config_vars() - opt = gcv.get('OPT') # not always existent - if opt: - opt = re.sub('%sO\d+' % dash, '%sO0' % dash, opt) - else: - opt = '%sO0' % dash - gcv['OPT'] = opt - -def ensure_correct_math(): - if sys.platform != 'win32': - return # so far - from distutils import sysconfig - gcv = sysconfig.get_config_vars() - opt = gcv.get('OPT') # not always existent - if opt and '/Op' not in opt: - opt += '/Op' - gcv['OPT'] = opt - - -def try_compile(c_files, eci): - try: - build_executable(c_files, eci) - result = True - except (distutils.errors.CompileError, - distutils.errors.LinkError): - result = False - return result - -def compile_c_module(cfiles, modbasename, eci, tmpdir=None): - #try: - # from distutils.log import set_threshold - # set_threshold(10000) - #except ImportError: - # print "ERROR IMPORTING" - # pass - cfiles = [py.path.local(f) for f in cfiles] - if tmpdir is None: - tmpdir = configdir.join("module_cache").ensure(dir=1) - num = 0 - cfiles += eci.separate_module_files - include_dirs = list(eci.include_dirs) - library_dirs = list(eci.library_dirs) - if (sys.platform == 'darwin' or # support Fink & Darwinports - sys.platform.startswith('freebsd')): - for s in ('/sw/', '/opt/local/', '/usr/local/'): - if s + 'include' not in include_dirs and \ - os.path.exists(s + 'include'): - include_dirs.append(s + 'include') - if s + 'lib' not in library_dirs and \ - os.path.exists(s + 'lib'): - library_dirs.append(s + 'lib') - - num = 0 - modname = modbasename - while 1: - if not tmpdir.join(modname + so_ext).check(): - break - num += 1 - modname = '%s_%d' % (modbasename, num) - - lastdir = tmpdir.chdir() - libraries = eci.libraries - ensure_correct_math() - try: - if debug: print "modname", modname - c = stdoutcapture.Capture(mixed_out_err = True) - try: - try: - if compiler_command(): - # GCC-ish options only - from distutils import sysconfig - gcv = sysconfig.get_config_vars() - cmd = compiler_command().replace('%s', - str(tmpdir.join(modname))) - for dir in [gcv['INCLUDEPY']] + list(include_dirs): - cmd += ' -I%s' % dir - for dir in library_dirs: - cmd += ' -L%s' % dir - os.system(cmd) - else: - from distutils.dist import Distribution - from distutils.extension import Extension - from distutils.ccompiler import get_default_compiler - saved_environ = os.environ.items() - try: - # distutils.core.setup() is really meant for end-user - # interactive usage, because it eats most exceptions and - # turn them into SystemExits. Instead, we directly - # instantiate a Distribution, which also allows us to - # ignore unwanted features like config files. - extra_compile_args = [] - # ensure correct math on windows - if sys.platform == 'win32': - extra_compile_args.append('/Op') # get extra precision - if get_default_compiler() == 'unix': - old_version = False - try: - g = os.popen('gcc --version', 'r') - verinfo = g.read() - g.close() - except (OSError, IOError): - pass - else: - old_version = verinfo.startswith('2') - if not old_version: - extra_compile_args.extend(["-Wno-unused-label", - "-Wno-unused-variable"]) - attrs = { - 'name': "testmodule", - 'ext_modules': [ - Extension(modname, [str(cfile) for cfile in cfiles], - include_dirs=include_dirs, - library_dirs=library_dirs, - extra_compile_args=extra_compile_args, - libraries=list(libraries),) - ], - 'script_name': 'setup.py', - 'script_args': ['-q', 'build_ext', '--inplace', '--force'], - } - dist = Distribution(attrs) - if not dist.parse_command_line(): - raise ValueError, "distutils cmdline parse error" - dist.run_commands() - finally: - for key, value in saved_environ: - if os.environ.get(key) != value: - os.environ[key] = value - finally: - foutput, foutput = c.done() - data = foutput.read() - if data: - fdump = open("%s.errors" % modname, "w") - fdump.write(data) - fdump.close() - # XXX do we need to do some check on fout/ferr? - # XXX not a nice way to import a module - except: - print >>sys.stderr, data - raise - finally: - lastdir.chdir() - return str(tmpdir.join(modname) + so_ext) - -def make_module_from_c(cfile, eci): - cfile = py.path.local(cfile) - modname = cfile.purebasename - compile_c_module([cfile], modname, eci) - return import_module_from_directory(cfile.dirpath(), modname) - -def import_module_from_directory(dir, modname): - file, pathname, description = imp.find_module(modname, [str(dir)]) - try: - mod = imp.load_module(modname, file, pathname, description) - finally: - if file: - file.close() - return mod - - -def log_spawned_cmd(spawn): - def spawn_and_log(cmd, *args, **kwds): - if debug: - print ' '.join(cmd) - return spawn(cmd, *args, **kwds) - return spawn_and_log - - -class ProfOpt(object): - #XXX assuming gcc style flags for now - name = "profopt" - - def __init__(self, compiler): - self.compiler = compiler - - def first(self): - self.build('-fprofile-generate') - - def probe(self, exe, args): - # 'args' is a single string typically containing spaces - # and quotes, which represents several arguments. - os.system("'%s' %s" % (exe, args)) - - def after(self): - self.build('-fprofile-use') - - def build(self, option): - compiler = self.compiler - compiler.compile_extra.append(option) - compiler.link_extra.append(option) - try: - compiler._build() - finally: - compiler.compile_extra.pop() - compiler.link_extra.pop() - -class CCompiler: - - def __init__(self, cfilenames, eci, outputfilename=None, - compiler_exe=None, profbased=None): - self.cfilenames = cfilenames - ext = '' - self.compile_extra = [] - self.link_extra = [] - self.libraries = list(eci.libraries) - self.include_dirs = list(eci.include_dirs) - self.library_dirs = list(eci.library_dirs) - self.compiler_exe = compiler_exe - self.profbased = profbased - if not sys.platform in ('win32', 'darwin', 'cygwin'): # xxx - if 'm' not in self.libraries: - self.libraries.append('m') - if 'pthread' not in self.libraries: - self.libraries.append('pthread') - self.compile_extra += ['-O3', '-fomit-frame-pointer', '-pthread'] - self.link_extra += ['-pthread'] - if sys.platform == 'win32': - self.link_extra += ['/DEBUG'] # generate .pdb file - if (sys.platform == 'darwin' or # support Fink & Darwinports - sys.platform.startswith('freebsd')): - for s in ('/sw/', '/opt/local/', '/usr/local/'): - if s + 'include' not in self.include_dirs and \ - os.path.exists(s + 'include'): - self.include_dirs.append(s + 'include') - if s + 'lib' not in self.library_dirs and \ - os.path.exists(s + 'lib'): - self.library_dirs.append(s + 'lib') - self.compile_extra += ['-O3', '-fomit-frame-pointer'] - - if outputfilename is None: - self.outputfilename = py.path.local(cfilenames[0]).new(ext=ext) - else: - self.outputfilename = py.path.local(outputfilename) - - def build(self, noerr=False): - basename = self.outputfilename.new(ext='') - data = '' - try: - saved_environ = os.environ.copy() - c = stdoutcapture.Capture(mixed_out_err = True) - try: - self._build() - finally: - # workaround for a distutils bugs where some env vars can - # become longer and longer every time it is used - for key, value in saved_environ.items(): - if os.environ.get(key) != value: - os.environ[key] = value - foutput, foutput = c.done() - data = foutput.read() - if data: - fdump = basename.new(ext='errors').open("w") - fdump.write(data) - fdump.close() - except: - if not noerr: - print >>sys.stderr, data - raise - - def _build(self): - from distutils.ccompiler import new_compiler - compiler = new_compiler(force=1) - if self.compiler_exe is not None: - for c in '''compiler compiler_so compiler_cxx - linker_exe linker_so'''.split(): - compiler.executables[c][0] = self.compiler_exe - compiler.spawn = log_spawned_cmd(compiler.spawn) - objects = [] - for cfile in self.cfilenames: - cfile = py.path.local(cfile) - old = cfile.dirpath().chdir() - try: - res = compiler.compile([cfile.basename], - include_dirs=self.include_dirs, - extra_preargs=self.compile_extra) - assert len(res) == 1 - cobjfile = py.path.local(res[0]) - assert cobjfile.check() - objects.append(str(cobjfile)) - finally: - old.chdir() - compiler.link_executable(objects, str(self.outputfilename), - libraries=self.libraries, - extra_preargs=self.link_extra, - library_dirs=self.library_dirs) - -def build_executable(*args, **kwds): - noerr = kwds.pop('noerr', False) - compiler = CCompiler(*args, **kwds) - compiler.build(noerr=noerr) - return str(compiler.outputfilename) diff --git a/ctypes_configure/configure.py b/ctypes_configure/configure.py deleted file mode 100755 --- a/ctypes_configure/configure.py +++ /dev/null @@ -1,621 +0,0 @@ -#! /usr/bin/env python - -import os, py, sys -import ctypes -from ctypes_configure.cbuild import build_executable, configdir, try_compile -from ctypes_configure.cbuild import ExternalCompilationInfo -import distutils - -# ____________________________________________________________ -# -# Helpers for simple cases - -def eci_from_header(c_header_source): - return ExternalCompilationInfo( - pre_include_lines=c_header_source.split("\n") - ) - - -def getstruct(name, c_header_source, interesting_fields): - class CConfig: - _compilation_info_ = eci_from_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: - _compilation_info_ = eci_from_header(c_header_source) - TYPE = SimpleType(name, ctype_hint) - return configure(CConfig)['TYPE'] - -def getconstantinteger(name, c_header_source): - class CConfig: - _compilation_info_ = eci_from_header(c_header_source) - CONST = ConstantInteger(name) - return configure(CConfig)['CONST'] - -def getdefined(macro, c_header_source): - class CConfig: - _compilation_info_ = eci_from_header(c_header_source) - DEFINED = Defined(macro) - return configure(CConfig)['DEFINED'] - -def has(name, c_header_source): - class CConfig: - _compilation_info_ = eci_from_header(c_header_source) - HAS = Has(name) - return configure(CConfig)['HAS'] - -def check_eci(eci): - """Check if a given ExternalCompilationInfo compiles and links.""" - class CConfig: - _compilation_info_ = eci - WORKS = Works() - return configure(CConfig)['WORKS'] - -def sizeof(name, eci, **kwds): - class CConfig: - _compilation_info_ = eci - SIZE = SizeOf(name) - for k, v in kwds.items(): - setattr(CConfig, k, v) - return configure(CConfig)['SIZE'] - -def memory_alignment(): - """Return the alignment (in bytes) of memory allocations. - This is enough to make sure a structure with pointers and 'double' - fields is properly aligned.""" - global _memory_alignment - if _memory_alignment is None: - S = getstruct('struct memory_alignment_test', """ - struct memory_alignment_test { - double d; - void* p; - }; - """, []) - result = ctypes.alignment(S) - assert result & (result-1) == 0, "not a power of two??" - _memory_alignment = result - return _memory_alignment -_memory_alignment = None - -# ____________________________________________________________ -# -# General interface - -class ConfigResult: - def __init__(self, CConfig, info, entries): - self.CConfig = CConfig - self.result = {} - self.info = info - self.entries = entries - - def get_entry_result(self, entry): - try: - return self.result[entry] - except KeyError: - pass - name = self.entries[entry] - info = self.info[name] - self.result[entry] = entry.build_result(info, self) - - def get_result(self): - return dict([(name, self.result[entry]) - for entry, name in self.entries.iteritems()]) - - -class _CWriter(object): - """ A simple class which aggregates config parts - """ - def __init__(self, CConfig): - self.path = uniquefilepath() - self.f = self.path.open("w") - self.config = CConfig - - def write_header(self): - f = self.f - CConfig = self.config - CConfig._compilation_info_.write_c_header(f) - print >> f, C_HEADER - print >> f - - def write_entry(self, key, entry): - f = self.f - print >> f, 'void dump_section_%s(void) {' % (key,) - for line in entry.prepare_code(): - if line and line[0] != '#': - line = '\t' + line - print >> f, line - print >> f, '}' - print >> f - - def write_entry_main(self, key): - print >> self.f, '\tprintf("-+- %s\\n");' % (key,) - print >> self.f, '\tdump_section_%s();' % (key,) - print >> self.f, '\tprintf("---\\n");' - - def start_main(self): - print >> self.f, 'int main(int argc, char *argv[]) {' - - def close(self): - f = self.f - print >> f, '\treturn 0;' - print >> f, '}' - f.close() - - def ask_gcc(self, question): - self.start_main() - self.f.write(question + "\n") - self.close() - eci = self.config._compilation_info_ - return try_compile([self.path], eci) - - -def configure(CConfig, noerr=False): - """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. - """ - for attr in ['_includes_', '_libraries_', '_sources_', '_library_dirs_', - '_include_dirs_', '_header_']: - assert not hasattr(CConfig, attr), "Found legacy attribut %s on CConfig" % (attr,) - entries = [] - for key in dir(CConfig): - value = getattr(CConfig, key) - if isinstance(value, CConfigEntry): - entries.append((key, value)) - - if entries: # can be empty if there are only CConfigSingleEntries - writer = _CWriter(CConfig) - writer.write_header() - for key, entry in entries: - writer.write_entry(key, entry) - - f = writer.f - writer.start_main() - for key, entry in entries: - writer.write_entry_main(key) - writer.close() - - eci = CConfig._compilation_info_ - infolist = list(run_example_code(writer.path, eci, noerr=noerr)) - assert len(infolist) == len(entries) - - resultinfo = {} - resultentries = {} - for info, (key, entry) in zip(infolist, entries): - resultinfo[key] = info - resultentries[entry] = key - - result = ConfigResult(CConfig, resultinfo, resultentries) - for name, entry in entries: - result.get_entry_result(entry) - res = result.get_result() - else: - res = {} - - for key in dir(CConfig): - value = getattr(CConfig, key) - if isinstance(value, CConfigSingleEntry): - writer = _CWriter(CConfig) - writer.write_header() - res[key] = value.question(writer.ask_gcc) - return res - -# ____________________________________________________________ - - -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, ifdef=None): - self.name = name - self.interesting_fields = interesting_fields - self.ifdef = ifdef - - def prepare_code(self): - if self.ifdef is not None: - yield '#ifdef %s' % (self.ifdef,) - 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;' - if self.ifdef is not None: - yield 'dump("defined", 1);' - 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) - if self.ifdef is not None: - yield '#else' - yield 'dump("defined", 0);' - yield '#endif' - - def build_result(self, info, config_result): - if self.ifdef is not None: - if not info['defined']: - return None - alignment = 1 - layout = [None] * info['size'] - for fieldname, fieldtype in self.interesting_fields: - if isinstance(fieldtype, Struct): - offset = info['fldofs ' + fieldname] - size = info['fldsize ' + fieldname] - c_fieldtype = config_result.get_entry_result(fieldtype) - layout_addfield(layout, offset, c_fieldtype, fieldname) - alignment = max(alignment, ctype_alignment(c_fieldtype)) - else: - 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, ctype_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 ctype_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, ifdef=None): - self.name = name - self.ctype_hint = ctype_hint - self.ifdef = ifdef - - def prepare_code(self): - if self.ifdef is not None: - yield '#ifdef %s' % (self.ifdef,) - yield 'typedef %s ctypesplatcheck_t;' % (self.name,) - yield '' - yield 'ctypesplatcheck_t x;' - if self.ifdef is not None: - yield 'dump("defined", 1);' - yield 'dump("size", sizeof(ctypesplatcheck_t));' - if self.ctype_hint in integer_class: - yield 'x = 0; x = ~x;' - yield 'dump("unsigned", x > 0);' - if self.ifdef is not None: - yield '#else' - yield 'dump("defined", 0);' - yield '#endif' - - def build_result(self, info, config_result): - if self.ifdef is not None and not info['defined']: - return None - 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, config_result): - return info['value'] - -class DefinedConstantInteger(CConfigEntry): - """An entry in a CConfig class that stands for an externally - defined integer constant. If not #defined the value will be None. - """ - def __init__(self, macro): - self.name = self.macro = macro - - def prepare_code(self): - yield '#ifdef %s' % self.macro - yield 'dump("defined", 1);' - yield 'if ((%s) < 0) {' % (self.macro,) - yield ' long long x = (long long)(%s);' % (self.macro,) - yield ' printf("value: %lld\\n", x);' - yield '} else {' - yield ' unsigned long long x = (unsigned long long)(%s);' % ( - self.macro,) - yield ' printf("value: %llu\\n", x);' - yield '}' - yield '#else' - yield 'dump("defined", 0);' - yield '#endif' - - def build_result(self, info, config_result): - if info["defined"]: - return info['value'] - return None - - -class DefinedConstantString(CConfigEntry): - """ - """ - def __init__(self, macro): - self.macro = macro - self.name = macro - - def prepare_code(self): - yield '#ifdef %s' % self.macro - yield 'int i;' - yield 'char *p = %s;' % self.macro - yield 'dump("defined", 1);' - yield 'for (i = 0; p[i] != 0; i++ ) {' - yield ' printf("value_%d: %d\\n", i, (int)(unsigned char)p[i]);' - yield '}' - yield '#else' - yield 'dump("defined", 0);' - yield '#endif' - - def build_result(self, info, config_result): - if info["defined"]: - string = '' - d = 0 - while info.has_key('value_%d' % d): - string += chr(info['value_%d' % d]) - d += 1 - return string - return None - - -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, config_result): - return bool(info['defined']) - -class CConfigSingleEntry(object): - """ An abstract class of type which requires - gcc succeeding/failing instead of only asking - """ - pass - -class Has(CConfigSingleEntry): - def __init__(self, name): - self.name = name - - def question(self, ask_gcc): - return ask_gcc(self.name + ';') - -class Works(CConfigSingleEntry): - def question(self, ask_gcc): - return ask_gcc("") - -class SizeOf(CConfigEntry): - """An entry in a CConfig class that stands for - some external opaque type - """ - def __init__(self, name): - self.name = name - - def prepare_code(self): - yield 'dump("size", sizeof(%s));' % self.name - - def build_result(self, info, config_result): - return info['size'] - -# ____________________________________________________________ -# -# internal helpers - -def ctype_alignment(c_type): - if issubclass(c_type, ctypes.Structure): - return max([ctype_alignment(fld_type) - for fld_name, fld_type in c_type._fields_]) - - return ctypes.alignment(c_type) - -def uniquefilepath(LAST=[0]): - i = LAST[0] - LAST[0] += 1 - return configdir.join('ctypesplatcheck_%d.c' % i) - -alignment_types = [ - ctypes.c_short, - ctypes.c_int, - ctypes.c_long, - ctypes.c_float, - ctypes.c_double, - ctypes.c_char_p, - ctypes.c_void_p, - ctypes.c_longlong, - ctypes.c_wchar, - ctypes.c_wchar_p, - ] - -integer_class = [ctypes.c_byte, ctypes.c_ubyte, - ctypes.c_short, ctypes.c_ushort, - ctypes.c_int, ctypes.c_uint, - ctypes.c_long, ctypes.c_ulong, - ctypes.c_longlong, ctypes.c_ulonglong, - ] -float_class = [ctypes.c_float, ctypes.c_double] - -class Field(object): - def __init__(self, name, ctype): - self.name = name - self.ctype = ctype - def __repr__(self): - return '<field %s: %s>' % (self.name, self.ctype) - -def layout_addfield(layout, offset, ctype, prefix): - size = ctypes.sizeof(ctype) - name = prefix - i = 0 - while name in layout: - i += 1 - name = '%s_%d' % (prefix, i) - field = Field(name, ctype) - for i in range(offset, offset+size): - assert layout[i] is None, "%s overlaps %r" % (fieldname, layout[i]) - layout[i] = field - return field - -def size_and_sign(ctype): - return (ctypes.sizeof(ctype), - ctype in integer_class and ctype(-1).value > 0) - -def fixup_ctype(fieldtype, fieldname, expected_size_and_sign): - for typeclass in [integer_class, float_class]: - if fieldtype in typeclass: - for ctype in typeclass: - if size_and_sign(ctype) == expected_size_and_sign: - return ctype - if (hasattr(fieldtype, '_length_') - and getattr(fieldtype, '_type_', None) == ctypes.c_char): - # for now, assume it is an array of chars; otherwise we'd also - # have to check the exact integer type of the elements of the array - size, sign = expected_size_and_sign - return ctypes.c_char * size - if (hasattr(fieldtype, '_length_') - and getattr(fieldtype, '_type_', None) == ctypes.c_ubyte): - # grumble, fields of type 'c_char array' have automatic cast-to- - # Python-string behavior in ctypes, which may not be what you - # want, so here is the same with c_ubytes instead... - size, sign = expected_size_and_sign - return ctypes.c_ubyte * size - raise TypeError("conflicting field type %r for %r" % (fieldtype, - fieldname)) - - -C_HEADER = """ -#include <stdio.h> -#include <stddef.h> /* for offsetof() */ -#ifndef _WIN32 -# include <stdint.h> /* FreeBSD: for uint64_t */ -#endif - -void dump(char* key, int value) { - printf("%s: %d\\n", key, value); -} -""" - -def run_example_code(filepath, eci, noerr=False): - executable = build_executable([filepath], eci, noerr=noerr) - output = py.process.cmdexec(executable) - section = None - for line in output.splitlines(): - 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) - -# ____________________________________________________________ - -def get_python_include_dir(): - from distutils import sysconfig - gcv = sysconfig.get_config_vars() - return gcv['INCLUDEPY'] - -if __name__ == '__main__': - doc = """Example: - - ctypes_platform.py -h sys/types.h -h netinet/in.h - 'struct sockaddr_in' - sin_port c_int - """ - import sys, getopt - opts, args = getopt.gnu_getopt(sys.argv[1:], 'h:') - if not args: - print >> sys.stderr, doc - else: - assert len(args) % 2 == 1 - headers = [] - for opt, value in opts: - if opt == '-h': - headers.append('#include <%s>' % (value,)) - name = args[0] - fields = [] - for i in range(1, len(args), 2): - ctype = getattr(ctypes, args[i+1]) - fields.append((args[i], ctype)) - - S = getstruct(name, '\n'.join(headers), fields) - - for key, value in S._fields_: - print key, value diff --git a/ctypes_configure/doc/configure.html b/ctypes_configure/doc/configure.html deleted file mode 100644 --- a/ctypes_configure/doc/configure.html +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head> -<meta http-equiv="Content-Type" content="text/html; charset=latin1" /> -<meta name="generator" content="Docutils 0.4.1: http://docutils.sourceforge.net/" /> -<title>ctypes configure</title> -</head> -<body> -<div class="document" id="ctypes-configure"> -<h1 class="title">ctypes configure</h1> -<div class="section"> -<h1><a id="idea" name="idea">idea</a></h1> -<p>One of ctypes problems is that ctypes programs are usually not very -platform-independent. We created ctypes_configure, which invokes gcc -for various platform-dependent details like -exact sizes of types (for example size_t), #defines, exact outline -of structures etc. It replaces in this regard code generator (h2py).</p> -</div> -<div class="section"> -<h1><a id="installation" name="installation">installation</a></h1> -<p><tt class="docutils literal"><span class="pre">easy_install</span> <span class="pre">ctypes_configure</span></tt></p> -</div> -<div class="section"> -<h1><a id="usage" name="usage">usage</a></h1> -<p><a class="reference" href="http://codespeak.net/svn/pypy/dist/ctypes_configure/doc/sample.py">sample.py</a> explains in details how to use it.</p> -</div> -</div> -</body> -</html> diff --git a/ctypes_configure/doc/configure.txt b/ctypes_configure/doc/configure.txt deleted file mode 100644 --- a/ctypes_configure/doc/configure.txt +++ /dev/null @@ -1,22 +0,0 @@ -================= -ctypes configure -================= - -idea -==== - -One of ctypes problems is that ctypes programs are usually not very -platform-independent. We created ctypes_configure, which invokes gcc -for various platform-dependent details like -exact sizes of types (for example size\_t), #defines, exact outline -of structures etc. It replaces in this regard code generator (h2py). - -installation -============ - -``easy_install ctypes_configure`` - -usage -===== - -:source:`sample.py <ctypes_configure/doc/sample.py>` explains in details how to use it. diff --git a/ctypes_configure/doc/sample.py b/ctypes_configure/doc/sample.py deleted file mode 100644 --- a/ctypes_configure/doc/sample.py +++ /dev/null @@ -1,72 +0,0 @@ - -from ctypes_configure import configure -import ctypes - -class CConfigure: - _compilation_info_ = configure.ExternalCompilationInfo( - - # all lines landing in C header before includes - pre_include_lines = [], - - # list of .h files to include - includes = ['time.h', 'sys/time.h', 'unistd.h'], - - # list of directories to search for include files - include_dirs = [], - - # all lines landing in C header after includes - post_include_lines = [], - - # libraries to link with - libraries = [], - - # library directories - library_dirs = [], - - # additional C sources to compile with (that go to - # created .c files) - separate_module_sources = [], - - # additional existing C source file names - separate_module_files = [], - ) - - # get real int type out of hint and name - size_t = configure.SimpleType('size_t', ctypes.c_int) - - # grab value of numerical #define - NULL = configure.ConstantInteger('NULL') - - # grab #define, whether it's defined or not - EXISTANT = configure.Defined('NULL') - NOT_EXISTANT = configure.Defined('XXXNOTNULL') - - # check for existance of C functions - has_write = configure.Has('write') - no_xxxwrite = configure.Has('xxxwrite') - - # check for size of type - sizeof_size_t = configure.SizeOf('size_t') - - # structure, with given hints for interesting fields, - # types does not need to be too specific. - # all interesting fields would end up with right offset - # size and order - struct_timeval = configure.Struct('struct timeval',[ - ('tv_sec', ctypes.c_int), - ('tv_usec', ctypes.c_int)]) - -info = configure.configure(CConfigure) - -assert info['has_write'] -assert not info['no_xxxwrite'] -assert info['NULL'] == 0 -size_t = info['size_t'] -print "size_t in ctypes is ", size_t -assert ctypes.sizeof(size_t) == info['sizeof_size_t'] -assert info['EXISTANT'] -assert not info['NOT_EXISTANT'] -print -print "fields of struct timeval are " -for name, value in info['struct_timeval']._fields_: - print " ", name, " ", value diff --git a/ctypes_configure/dumpcache.py b/ctypes_configure/dumpcache.py deleted file mode 100644 --- a/ctypes_configure/dumpcache.py +++ /dev/null @@ -1,46 +0,0 @@ -import os, sys -import ctypes - - -def dumpcache(referencefilename, filename, config): - dirname = os.path.dirname(referencefilename) - filename = os.path.join(dirname, filename) - f = open(filename, 'w') - print >> f, 'import ctypes' - print >> f - names = config.keys() - names.sort() - print >> f, '__all__ = %r' % (tuple(names),) - print >> f - for key in names: - val = config[key] - if isinstance(val, (int, long)): - f.write("%s = %d\n" % (key, val)) - elif val is None: - f.write("%s = None\n" % key) - elif isinstance(val, ctypes.Structure.__class__): - f.write("class %s(ctypes.Structure):\n" % key) - f.write(" _fields_ = [\n") - for k, v in val._fields_: - f.write(" ('%s', %s),\n" % (k, ctypes_repr(v))) - f.write(" ]\n") - elif isinstance(val, (tuple, list)): - for x in val: - assert isinstance(x, (int, long, str)), \ - "lists of integers or strings only" - f.write("%s = %r\n" % (key, val)) - else: - # a simple type, hopefully - f.write("%s = %s\n" % (key, ctypes_repr(val))) - f.close() - print 'Wrote %s.' % (filename,) - sys.stdout.flush() - -def ctypes_repr(cls): - # ctypes_configure does not support nested structs so far - # so let's ignore it - if isinstance(cls, ctypes._SimpleCData.__class__): - return "ctypes." + cls.__name__ - if hasattr(cls, '_length_') and hasattr(cls, '_type_'): # assume an array - return '%s*%d' % (ctypes_repr(cls._type_), cls._length_) - raise NotImplementedError("saving of object with type %r" % type(cls)) diff --git a/ctypes_configure/stdoutcapture.py b/ctypes_configure/stdoutcapture.py deleted file mode 100644 --- a/ctypes_configure/stdoutcapture.py +++ /dev/null @@ -1,77 +0,0 @@ -""" -A quick hack to capture stdout/stderr. -""" - -import os, sys - - -class Capture: - - def __init__(self, mixed_out_err = False): - "Start capture of the Unix-level stdout and stderr." - if (not hasattr(os, 'tmpfile') or - not hasattr(os, 'dup') or - not hasattr(os, 'dup2') or - not hasattr(os, 'fdopen')): - self.dummy = 1 - else: - try: - self.tmpout = os.tmpfile() - if mixed_out_err: - self.tmperr = self.tmpout - else: - self.tmperr = os.tmpfile() - except OSError: # bah? on at least one Windows box - self.dummy = 1 - return - self.dummy = 0 - # make new stdout/stderr files if needed - self.localoutfd = os.dup(1) - self.localerrfd = os.dup(2) - if hasattr(sys.stdout, 'fileno') and sys.stdout.fileno() == 1: - self.saved_stdout = sys.stdout - sys.stdout = os.fdopen(self.localoutfd, 'w', 1) - else: - self.saved_stdout = None - if hasattr(sys.stderr, 'fileno') and sys.stderr.fileno() == 2: - self.saved_stderr = sys.stderr - sys.stderr = os.fdopen(self.localerrfd, 'w', 0) - else: - self.saved_stderr = None - os.dup2(self.tmpout.fileno(), 1) - os.dup2(self.tmperr.fileno(), 2) - - def done(self): - "End capture and return the captured text (stdoutfile, stderrfile)." - if self.dummy: - import cStringIO - return cStringIO.StringIO(), cStringIO.StringIO() - else: - os.dup2(self.localoutfd, 1) - os.dup2(self.localerrfd, 2) - if self.saved_stdout is not None: - f = sys.stdout - sys.stdout = self.saved_stdout - f.close() - else: - os.close(self.localoutfd) - if self.saved_stderr is not None: - f = sys.stderr - sys.stderr = self.saved_stderr - f.close() - else: - os.close(self.localerrfd) - self.tmpout.seek(0) - self.tmperr.seek(0) - return self.tmpout, self.tmperr - - -if __name__ == '__main__': - # test - c = Capture() - try: - os.system('echo hello') - finally: - fout, ferr = c.done() - print 'Output:', `fout.read()` - print 'Error:', `ferr.read()` diff --git a/ctypes_configure/test/__init__.py b/ctypes_configure/test/__init__.py deleted file mode 100644 diff --git a/ctypes_configure/test/test_configure.py b/ctypes_configure/test/test_configure.py deleted file mode 100644 --- a/ctypes_configure/test/test_configure.py +++ /dev/null @@ -1,212 +0,0 @@ -import py, sys, struct -from ctypes_configure import configure -from ctypes_configure.cbuild import ExternalCompilationInfo -import ctypes - -def test_dirent(): - dirent = configure.getstruct("struct dirent", - """ - struct dirent /* for this example only, not the exact dirent */ - { - long d_ino; - int d_off; - unsigned short d_reclen; - char d_name[32]; - }; - """, - [("d_reclen", ctypes.c_ushort)]) - assert issubclass(dirent, ctypes.Structure) - ssize = (ctypes.sizeof(ctypes.c_long) + - ctypes.sizeof(ctypes.c_int) + - ctypes.sizeof(ctypes.c_ushort) + - 32) - extra_padding = (-ssize) % ctypes.alignment(ctypes.c_long) - - assert dirent._fields_ == [('_alignment', ctypes.c_long), - ('_pad0', ctypes.c_char), - ('_pad1', ctypes.c_char), - ('_pad2', ctypes.c_char), - ('_pad3', ctypes.c_char), - ('d_reclen', ctypes.c_ushort), - ] + [ - ('_pad%d' % n, ctypes.c_char) - for n in range(4, 4+32+extra_padding)] - assert ctypes.sizeof(dirent) == ssize + extra_padding - assert ctypes.alignment(dirent) == ctypes.alignment(ctypes.c_long) - -def test_fit_type(): - S = configure.getstruct("struct S", - """ - struct S { - signed char c; - unsigned char uc; - short s; - unsigned short us; - int i; - unsigned int ui; - long l; - unsigned long ul; - long long ll; - unsigned long long ull; - float f; - double d; - }; - """, - [("c", ctypes.c_int), - ("uc", ctypes.c_int), - ("s", ctypes.c_uint), - ("us", ctypes.c_int), - ("i", ctypes.c_int), - ("ui", ctypes.c_int), - ("l", ctypes.c_int), - ("ul", ctypes.c_int), - ("ll", ctypes.c_int), - ("ull", ctypes.c_int), - ("f", ctypes.c_double), - ("d", ctypes.c_float)]) - assert issubclass(S, ctypes.Structure) - fields = dict(S._fields_) - assert fields["c"] == ctypes.c_byte - assert fields["uc"] == ctypes.c_ubyte - assert fields["s"] == ctypes.c_short - assert fields["us"] == ctypes.c_ushort - assert fields["i"] == ctypes.c_int - assert fields["ui"] == ctypes.c_uint - assert fields["l"] == ctypes.c_long - assert fields["ul"] == ctypes.c_ulong - assert fields["ll"] == ctypes.c_longlong - assert fields["ull"] == ctypes.c_ulonglong - assert fields["f"] == ctypes.c_float - assert fields["d"] == ctypes.c_double - -def test_simple_type(): - ctype = configure.getsimpletype('test_t', - 'typedef unsigned short test_t;', - ctypes.c_int) - assert ctype == ctypes.c_ushort - -def test_constant_integer(): - value = configure.getconstantinteger('BLAH', - '#define BLAH (6*7)') - assert value == 42 - value = configure.getconstantinteger('BLAH', - '#define BLAH (-2147483648LL)') - assert value == -2147483648 - value = configure.getconstantinteger('BLAH', - '#define BLAH (3333333333ULL)') - assert value == 3333333333 - -def test_defined(): - res = configure.getdefined('ALFKJLKJFLKJFKLEJDLKEWMECEE', '') - assert not res - res = configure.getdefined('ALFKJLKJFLKJFKLEJDLKEWMECEE', - '#define ALFKJLKJFLKJFKLEJDLKEWMECEE') - assert res - -def test_configure(): - configdir = configure.configdir - test_h = configdir.join('test_ctypes_platform.h') - test_h.write('#define XYZZY 42\n') - - class CConfig: - _compilation_info_ = ExternalCompilationInfo( - pre_include_lines = ["/* a C comment */", - "#include <stdio.h>", - "#include <test_ctypes_platform.h>"], - include_dirs = [str(configdir)] - ) - - FILE = configure.Struct('FILE', []) - ushort = configure.SimpleType('unsigned short') - XYZZY = configure.ConstantInteger('XYZZY') - - res = configure.configure(CConfig) - assert issubclass(res['FILE'], ctypes.Structure) - assert res == {'FILE': res['FILE'], - 'ushort': ctypes.c_ushort, - 'XYZZY': 42} - -def test_ifdef(): - class CConfig: - _compilation_info_ = ExternalCompilationInfo( - post_include_lines = ['/* a C comment */', - '#define XYZZY 42', - 'typedef int foo;', - 'struct s {', - 'int i;', - 'double f;' - '};']) - - - s = configure.Struct('struct s', [('i', ctypes.c_int)], - ifdef='XYZZY') - z = configure.Struct('struct z', [('i', ctypes.c_int)], - ifdef='FOOBAR') - - foo = configure.SimpleType('foo', ifdef='XYZZY') - bar = configure.SimpleType('bar', ifdef='FOOBAR') - - res = configure.configure(CConfig) - assert res['s'] is not None - assert res['z'] is None - assert res['foo'] is not None - assert res['bar'] is None - -def test_nested_structs(): - class CConfig: - _compilation_info_ = ExternalCompilationInfo( - post_include_lines=""" - struct x { - int foo; - unsigned long bar; - }; - struct y { - char c; - struct x x; - }; - """.split("\n")) - - x = configure.Struct("struct x", [("bar", ctypes.c_short)]) - y = configure.Struct("struct y", [("x", x)]) - - res = configure.configure(CConfig) - c_x = res["x"] - c_y = res["y"] - c_y_fields = dict(c_y._fields_) - assert issubclass(c_x , ctypes.Structure) - assert issubclass(c_y, ctypes.Structure) - assert c_y_fields["x"] is c_x - -def test_array(): - dirent = configure.getstruct("struct dirent", - """ - struct dirent /* for this example only, not the exact dirent */ - { - long d_ino; - int d_off; - unsigned short d_reclen; - char d_name[32]; - }; - """, - [("d_name", ctypes.c_char * 0)]) - assert dirent.d_name.size == 32 - -def test_has(): - assert configure.has("x", "int x = 3;") - assert not configure.has("x", "") - # has() should also not crash if it is given an invalid #include - assert not configure.has("x", "#include <some/path/which/cannot/exist>") - -def test_check_eci(): - eci = ExternalCompilationInfo() - assert configure.check_eci(eci) - eci = ExternalCompilationInfo(libraries=['some_name_that_doesnt_exist_']) - assert not configure.check_eci(eci) - -def test_sizeof(): - assert configure.sizeof("char", ExternalCompilationInfo()) == 1 - -def test_memory_alignment(): - a = configure.memory_alignment() - print a - assert a % struct.calcsize("P") == 0 diff --git a/ctypes_configure/test/test_dumpcache.py b/ctypes_configure/test/test_dumpcache.py deleted file mode 100644 --- a/ctypes_configure/test/test_dumpcache.py +++ /dev/null @@ -1,61 +0,0 @@ -import ctypes -from ctypes_configure import configure, dumpcache -from ctypes_configure.cbuild import ExternalCompilationInfo - - -def test_cache(): - configdir = configure.configdir - test_h = configdir.join('test_ctypes_platform2.h') - test_h.write('#define XYZZY 42\n' - "#define large 2147483648L\n") - - class CConfig: - _compilation_info_ = ExternalCompilationInfo( - pre_include_lines = ["/* a C comment */", - "#include <stdio.h>", - "#include <test_ctypes_platform2.h>"], - include_dirs = [str(configdir)] - ) - - FILE = configure.Struct('FILE', []) - ushort = configure.SimpleType('unsigned short') - XYZZY = configure.ConstantInteger('XYZZY') - XUZ = configure.Has('XUZ') - large = configure.DefinedConstantInteger('large') - undef = configure.Defined('really_undefined') - - res = configure.configure(CConfig) - - cachefile = configdir.join('cache') - dumpcache.dumpcache('', str(cachefile), res) - - d = {} - execfile(str(cachefile), d) - assert d['XYZZY'] == res['XYZZY'] - assert d['ushort'] == res['ushort'] - assert d['FILE']._fields_ == res['FILE']._fields_ - assert d['FILE'].__mro__[1:] == res['FILE'].__mro__[1:] - assert d['undef'] == res['undef'] - assert d['large'] == res['large'] - assert d['XUZ'] == res['XUZ'] - - -def test_cache_array(): - configdir = configure.configdir - res = {'foo': ctypes.c_short * 27} - cachefile = configdir.join('cache_array') - dumpcache.dumpcache('', str(cachefile), res) - # - d = {} - execfile(str(cachefile), d) - assert d['foo'] == res['foo'] - -def test_cache_array_array(): - configdir = configure.configdir - res = {'foo': (ctypes.c_int * 2) * 3} - cachefile = configdir.join('cache_array_array') - dumpcache.dumpcache('', str(cachefile), res) - # - d = {} - execfile(str(cachefile), d) - assert d['foo'] == res['foo'] diff --git a/lib-python/2.7/sqlite3/test/regression.py b/lib-python/2.7/sqlite3/test/regression.py --- a/lib-python/2.7/sqlite3/test/regression.py +++ b/lib-python/2.7/sqlite3/test/regression.py @@ -351,7 +351,10 @@ self.assertRaises(ValueError, cur.execute, " \0select 2") self.assertRaises(ValueError, cur.execute, "select 2\0") + @test_support.impl_detail(pypy=False) def CheckCommitCursorReset(self): + # This test is for logic added in 2.7.13 which PyPy doesn't + # implement. See http://bugs.python.org/issue29006 """ Connection.commit() did reset cursors, which made sqlite3 to return rows multiple times when fetched from cursors diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py --- a/lib_pypy/_sqlite3.py +++ b/lib_pypy/_sqlite3.py @@ -374,12 +374,6 @@ if cursor is not None: cursor._reset = True - def _reset_other_statements(self, excepted): - for weakref in self.__statements: - statement = weakref() - if statement is not None and statement is not excepted: - statement._reset() - @_check_thread_wrap @_check_closed_wrap def __call__(self, sql): @@ -435,6 +429,16 @@ if not self._in_transaction: return + # The following line is a KNOWN DIFFERENCE with CPython 2.7.13. + # More precisely, the corresponding line was removed in the + # version 2.7.13 of CPython, but this is causing troubles for + # PyPy (and potentially for CPython too): + # + # http://bugs.python.org/issue29006 + # + # So for now, we keep this line. + self.__do_all_statements(Statement._reset, False) + statement_star = _ffi.new('sqlite3_stmt **') ret = _lib.sqlite3_prepare_v2(self._db, b"COMMIT", -1, statement_star, _ffi.NULL) @@ -862,24 +866,7 @@ self.__statement._set_params(params) # Actually execute the SQL statement - - # NOTE: if we get SQLITE_LOCKED, it's probably because - # one of the cursors created previously is still alive - # and not reset and the operation we're trying to do - # makes Sqlite unhappy about that. In that case, we - # automatically reset all cursors and try again. This - # is not what CPython does! It is a workaround for a - # new feature of 2.7.13. Previously, all cursors would - # be reset at commit(), which makes it unlikely to have - # cursors lingering around. Since 2.7.13, cursors stay - # around instead. This causes problems here---at least: - # this is the only place shown by pysqlite tests, and I - # can only hope there is no other. - ret = _lib.sqlite3_step(self.__statement._statement) - if ret == _lib.SQLITE_LOCKED: - self.__connection._reset_other_statements(self.__statement) - ret = _lib.sqlite3_step(self.__statement._statement) if ret == _lib.SQLITE_ROW: if multiple: diff --git a/lib_pypy/cffi.egg-info/PKG-INFO b/lib_pypy/cffi.egg-info/PKG-INFO --- a/lib_pypy/cffi.egg-info/PKG-INFO +++ b/lib_pypy/cffi.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: cffi -Version: 1.9.1 +Version: 1.9.2 Summary: Foreign Function Interface for Python calling C code. Home-page: http://cffi.readthedocs.org Author: Armin Rigo, Maciej Fijalkowski diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py --- a/lib_pypy/cffi/__init__.py +++ b/lib_pypy/cffi/__init__.py @@ -4,8 +4,8 @@ from .api import FFI, CDefError, FFIError from .ffiplatform import VerificationError, VerificationMissing -__version__ = "1.9.1" -__version_info__ = (1, 9, 1) +__version__ = "1.9.2" +__version_info__ = (1, 9, 2) # The verifier module file names are based on the CRC32 of a string that # contains the following version number. It may be older than __version__ diff --git a/lib_pypy/cffi/_embedding.h b/lib_pypy/cffi/_embedding.h --- a/lib_pypy/cffi/_embedding.h +++ b/lib_pypy/cffi/_embedding.h @@ -233,7 +233,7 @@ f = PySys_GetObject((char *)"stderr"); if (f != NULL && f != Py_None) { PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME - "\ncompiled with cffi version: 1.9.1" + "\ncompiled with cffi version: 1.9.2" "\n_cffi_backend module: ", f); modules = PyImport_GetModuleDict(); mod = PyDict_GetItemString(modules, "_cffi_backend"); diff --git a/py/_io/saferepr.py b/py/_io/saferepr.py --- a/py/_io/saferepr.py +++ b/py/_io/saferepr.py @@ -21,6 +21,11 @@ return py.builtin._totext('"%s"') % u else: return py.builtin._totext("'%s'") % u.replace("'", r"\'") + + repr = builtin_repr + # ^^^ it's very annoying to display 'xx' instead of u'xx' when + # the difference can be essential, particularly in PyPy + s = repr(x[:self.maxstring]) if len(s) > self.maxstring: i = max(0, (self.maxstring-3)//2) diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -494,6 +494,11 @@ the rest is kept. If you return an unexpected string from ``__hex__()`` you get an exception (or a crash before CPython 2.7.13). +* The ``sqlite`` module was updated on 2.7.13 to no longer reset all + cursors when there is a commit. This causes troubles for PyPy (and + potentially for CPython too), and so for now we didn't port this change: + see http://bugs.python.org/issue29006. + .. _`is ignored in PyPy`: http://bugs.python.org/issue14621 .. _`little point`: http://events.ccc.de/congress/2012/Fahrplan/events/5152.en.html .. _`#2072`: https://bitbucket.org/pypy/pypy/issue/2072/ diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -77,3 +77,16 @@ .. branch: stdlib-2.7.13 Updated the implementation to match CPython 2.7.13 instead of 2.7.13. + +.. branch: issue2444 + +Fix ``PyObject_GetBuffer`` and ``PyMemoryView_GET_BUFFER``, which leaked +memory and held references. Add a finalizer to CPyBuffer, add a +PyMemoryViewObject with a PyBuffer attached so that the call to +``PyMemoryView_GET_BUFFER`` does not leak a PyBuffer-sized piece of memory. +Properly call ``bf_releasebuffer`` when not ``NULL``. + +.. branch: boehm-rawrefcount + +Support translations of cpyext with the Boehm GC (for special cases like +revdb). diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -309,9 +309,9 @@ config.translation.jit = True if config.objspace.usemodules.cpyext: - if config.translation.gc != 'incminimark': + if config.translation.gc not in ('incminimark', 'boehm'): raise Exception("The 'cpyext' module requires the 'incminimark'" - " GC. You need either 'targetpypystandalone.py" + " 'boehm' GC. You need either 'targetpypystandalone.py" " --withoutmod-cpyext' or '--gc=incminimark'") config.translating = True diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py --- a/pypy/module/_cffi_backend/__init__.py +++ b/pypy/module/_cffi_backend/__init__.py @@ -3,7 +3,7 @@ from rpython.rlib import rdynload, clibffi from rpython.rtyper.lltypesystem import rffi -VERSION = "1.9.1" +VERSION = "1.9.2" FFI_DEFAULT_ABI = clibffi.FFI_DEFAULT_ABI try: diff --git a/pypy/module/_cffi_backend/ctypefunc.py b/pypy/module/_cffi_backend/ctypefunc.py --- a/pypy/module/_cffi_backend/ctypefunc.py +++ b/pypy/module/_cffi_backend/ctypefunc.py @@ -17,7 +17,7 @@ from pypy.module._cffi_backend.ctypeobj import W_CType from pypy.module._cffi_backend.ctypeptr import W_CTypePtrBase, W_CTypePointer from pypy.module._cffi_backend.ctypevoid import W_CTypeVoid -from pypy.module._cffi_backend.ctypestruct import W_CTypeStruct +from pypy.module._cffi_backend.ctypestruct import W_CTypeStruct, W_CTypeUnion from pypy.module._cffi_backend.ctypeprim import (W_CTypePrimitiveSigned, W_CTypePrimitiveUnsigned, W_CTypePrimitiveCharOrUniChar, W_CTypePrimitiveFloat, W_CTypePrimitiveLongDouble) @@ -231,6 +231,11 @@ return cifbuilder.fb_struct_ffi_type(self, is_result_type) return _missing_ffi_type(self, cifbuilder, is_result_type) +def _union_ffi_type(self, cifbuilder, is_result_type): + if self.size >= 0: # only for a better error message + return cifbuilder.fb_union_ffi_type(self, is_result_type) + return _missing_ffi_type(self, cifbuilder, is_result_type) + def _primsigned_ffi_type(self, cifbuilder, is_result_type): size = self.size if size == 1: return clibffi.ffi_type_sint8 @@ -266,6 +271,7 @@ W_CType._get_ffi_type = _missing_ffi_type W_CTypeStruct._get_ffi_type = _struct_ffi_type +W_CTypeUnion._get_ffi_type = _union_ffi_type W_CTypePrimitiveSigned._get_ffi_type = _primsigned_ffi_type W_CTypePrimitiveCharOrUniChar._get_ffi_type = _primunsigned_ffi_type W_CTypePrimitiveUnsigned._get_ffi_type = _primunsigned_ffi_type @@ -276,6 +282,12 @@ # ---------- +_SUPPORTED_IN_API_MODE = ( + " are only supported as %s if the function is " + "'API mode' and non-variadic (i.e. declared inside ffibuilder" + ".cdef()+ffibuilder.set_source() and not taking a final '...' " + "argument)") + class CifDescrBuilder(object): rawmem = lltype.nullptr(rffi.CCHARP.TO) @@ -297,6 +309,20 @@ def fb_fill_type(self, ctype, is_result_type): return ctype._get_ffi_type(self, is_result_type) + def fb_unsupported(self, ctype, is_result_type, detail): + place = "return value" if is_result_type else "argument" + raise oefmt(self.space.w_NotImplementedError, + "ctype '%s' not supported as %s. %s. " + "Such structs" + _SUPPORTED_IN_API_MODE, + ctype.name, place, detail, place) + + def fb_union_ffi_type(self, ctype, is_result_type=False): + place = "return value" if is_result_type else "argument" + raise oefmt(self.space.w_NotImplementedError, + "ctype '%s' not supported as %s by libffi. " + "Unions" + _SUPPORTED_IN_API_MODE, + ctype.name, place, place) + def fb_struct_ffi_type(self, ctype, is_result_type=False): # We can't pass a struct that was completed by verify(). # Issue: assume verify() is given "struct { long b; ...; }". @@ -309,37 +335,40 @@ # Another reason for 'custom_field_pos' would be anonymous # nested structures: we lost the information about having it # here, so better safe (and forbid it) than sorry (and maybe - # crash). + # crash). Note: it seems we only get in this case with + # ffi.verify(). space = self.space ctype.force_lazy_struct() if ctype._custom_field_pos: # these NotImplementedErrors may be caught and ignored until # a real call is made to a function of this type - place = "return value" if is_result_type else "argument" - raise oefmt(space.w_NotImplementedError, - "ctype '%s' not supported as %s (it is a struct declared " - "with \"...;\", but the C calling convention may depend " - "on the missing fields)", ctype.name, place) + raise self.fb_unsupported(ctype, is_result_type, + "It is a struct declared with \"...;\", but the C " + "calling convention may depend on the missing fields; " + "or, it contains anonymous struct/unions") + # Another reason: __attribute__((packed)) is not supported by libffi. + if ctype._with_packed_change: + raise self.fb_unsupported(ctype, is_result_type, + "It is a 'packed' structure, with a different layout than " + "expected by libffi") # walk the fields, expanding arrays into repetitions; first, # only count how many flattened fields there are nflat = 0 for i, cf in enumerate(ctype._fields_list): if cf.is_bitfield(): - place = "return value" if is_result_type else "argument" - raise oefmt(space.w_NotImplementedError, - "ctype '%s' not supported as %s" - " (it is a struct with bit fields)", ctype.name, place) + raise self.fb_unsupported(ctype, is_result_type, + "It is a struct with bit fields, which libffi does not " + "support") flat = 1 ct = cf.ctype while isinstance(ct, ctypearray.W_CTypeArray): flat *= ct.length ct = ct.ctitem if flat <= 0: - place = "return value" if is_result_type else "argument" - raise oefmt(space.w_NotImplementedError, - "ctype '%s' not supported as %s (it is a struct" - " with a zero-length array)", ctype.name, place) + raise self.fb_unsupported(ctype, is_result_type, + "It is a struct with a zero-length array, which libffi " + "does not support") nflat += flat if USE_C_LIBFFI_MSVC and is_result_type: diff --git a/pypy/module/_cffi_backend/ctypestruct.py b/pypy/module/_cffi_backend/ctypestruct.py --- a/pypy/module/_cffi_backend/ctypestruct.py +++ b/pypy/module/_cffi_backend/ctypestruct.py @@ -34,6 +34,7 @@ _fields_dict = None _custom_field_pos = False _with_var_array = False + _with_packed_changed = False def __init__(self, space, name): W_CType.__init__(self, space, -1, name, len(name)) diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py --- a/pypy/module/_cffi_backend/newtype.py +++ b/pypy/module/_cffi_backend/newtype.py @@ -303,6 +303,7 @@ fields_dict = {} w_ctype._custom_field_pos = False with_var_array = False + with_packed_change = False for i in range(len(fields_w)): w_field = fields_w[i] @@ -333,7 +334,8 @@ # # update the total alignment requirement, but skip it if the # field is an anonymous bitfield or if SF_PACKED - falign = 1 if sflags & SF_PACKED else ftype.alignof() + falignorg = ftype.alignof() + falign = 1 if sflags & SF_PACKED else falignorg do_align = True if (sflags & SF_GCC_ARM_BITFIELDS) == 0 and fbitsize >= 0: if (sflags & SF_MSVC_BITFIELDS) == 0: @@ -359,7 +361,10 @@ bs_flag = ctypestruct.W_CField.BS_REGULAR _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit