[pypy-commit] pypy release-pypy2.7-5.x: merge default into release
mattip
pypy.commits at gmail.com
Sun Sep 24 04:51:33 EDT 2017
Author: Matti Picus <matti.picus at gmail.com>
Branch: release-pypy2.7-5.x
Changeset: r92449:c2437cf9b7f1
Date: 2017-09-24 11:42 +0300
http://bitbucket.org/pypy/pypy/changeset/c2437cf9b7f1/
Log: merge default into release
diff too long, truncating to 2000 out of 27632 lines
diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -1,6 +1,6 @@
syntax: glob
*.py[co]
-*.sw[po]
+*.sw[pon]
*~
.*.swp
.idea
@@ -8,6 +8,8 @@
.pydevproject
__pycache__
+.cache/
+.gdb_history
syntax: regexp
^testresult$
^site-packages$
@@ -23,16 +25,17 @@
^pypy/module/cpyext/test/.+\.manifest$
^pypy/module/test_lib_pypy/ctypes_tests/.+\.o$
^pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test\.o$
-^pypy/module/cppyy/src/.+\.o$
-^pypy/module/cppyy/bench/.+\.so$
-^pypy/module/cppyy/bench/.+\.root$
-^pypy/module/cppyy/bench/.+\.d$
-^pypy/module/cppyy/src/.+\.errors$
-^pypy/module/cppyy/test/.+_rflx\.cpp$
-^pypy/module/cppyy/test/.+\.so$
-^pypy/module/cppyy/test/.+\.rootmap$
-^pypy/module/cppyy/test/.+\.exe$
-^pypy/module/cppyy/test/.+_cint.h$
+^pypy/module/_cppyy/src/.+\.o$
+^pypy/module/_cppyy/bench/.+\.so$
+^pypy/module/_cppyy/bench/.+\.root$
+^pypy/module/_cppyy/bench/.+\.d$
+^pypy/module/_cppyy/src/.+\.errors$
+^pypy/module/_cppyy/test/.+_rflx\.cpp$
+^pypy/module/_cppyy/test/.+\.so$
+^pypy/module/_cppyy/test/.+\.rootmap$
+^pypy/module/_cppyy/test/.+\.exe$
+^pypy/module/_cppyy/test/.+_cint.h$
+^pypy/module/_cppyy/.+/*\.pcm$
^pypy/module/test_lib_pypy/cffi_tests/__pycache__.+$
^pypy/doc/.+\.html$
^pypy/doc/config/.+\.rst$
@@ -85,8 +88,4 @@
.hypothesis/
^release/
^rpython/_cache$
-^\.cache$
-pypy/module/cppyy/.+/*\.pcm
-
-
diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -38,3 +38,5 @@
b16a4363e930f6401bceb499b9520955504c6cb0 release-pypy3.5-v5.7.0
1aa2d8e03cdfab54b7121e93fda7e98ea88a30bf release-pypy2.7-v5.7.1
2875f328eae2216a87f3d6f335092832eb031f56 release-pypy3.5-v5.7.1
+c925e73810367cd960a32592dd7f728f436c125c release-pypy2.7-v5.8.0
+a37ecfe5f142bc971a86d17305cc5d1d70abec64 release-pypy3.5-v5.8.0
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,7 @@
RUNINTERP = $(PYPY_EXECUTABLE)
endif
-.PHONY: cffi_imports
+.PHONY: pypy-c cffi_imports
pypy-c:
@echo
@@ -32,7 +32,7 @@
@echo "===================================================================="
@echo
@sleep 5
- $(RUNINTERP) rpython/bin/rpython -Ojit pypy/goal/targetpypystandalone.py
+ cd pypy/goal && $(RUNINTERP) ../../rpython/bin/rpython -Ojit targetpypystandalone.py
# Note: the -jN option, or MAKEFLAGS=-jN, are not usable. They are
# replaced with an opaque --jobserver option by the time this Makefile
@@ -40,4 +40,4 @@
# http://lists.gnu.org/archive/html/help-make/2010-08/msg00106.html
cffi_imports: pypy-c
- PYTHONPATH=. ./pypy-c pypy/tool/build_cffi_imports.py || /bin/true
+ PYTHONPATH=. pypy/goal/pypy-c pypy/tool/build_cffi_imports.py || /bin/true
diff --git a/lib-python/2.7/ctypes/__init__.py b/lib-python/2.7/ctypes/__init__.py
--- a/lib-python/2.7/ctypes/__init__.py
+++ b/lib-python/2.7/ctypes/__init__.py
@@ -361,17 +361,20 @@
if handle is None:
if flags & _FUNCFLAG_CDECL:
- self._handle = _ffi.CDLL(name, mode)
+ pypy_dll = _ffi.CDLL(name, mode)
else:
- self._handle = _ffi.WinDLL(name, mode)
- else:
- self._handle = handle
+ pypy_dll = _ffi.WinDLL(name, mode)
+ self.__pypy_dll__ = pypy_dll
+ handle = int(pypy_dll)
+ if _sys.maxint > 2 ** 32:
+ handle = int(handle) # long -> int
+ self._handle = handle
def __repr__(self):
- return "<%s '%s', handle %r at 0x%x>" % (
- self.__class__.__name__, self._name, self._handle,
- id(self) & (_sys.maxint * 2 + 1))
-
+ return "<%s '%s', handle %x at %x>" % \
+ (self.__class__.__name__, self._name,
+ (self._handle & (_sys.maxint*2 + 1)),
+ id(self) & (_sys.maxint*2 + 1))
def __getattr__(self, name):
if name.startswith('__') and name.endswith('__'):
diff --git a/lib-python/2.7/ctypes/test/test_byteswap.py b/lib-python/2.7/ctypes/test/test_byteswap.py
--- a/lib-python/2.7/ctypes/test/test_byteswap.py
+++ b/lib-python/2.7/ctypes/test/test_byteswap.py
@@ -23,7 +23,6 @@
setattr(bits, "i%s" % i, 1)
dump(bits)
- @xfail
def test_endian_short(self):
if sys.byteorder == "little":
self.assertIs(c_short.__ctype_le__, c_short)
@@ -51,7 +50,6 @@
self.assertEqual(bin(s), "3412")
self.assertEqual(s.value, 0x1234)
- @xfail
def test_endian_int(self):
if sys.byteorder == "little":
self.assertIs(c_int.__ctype_le__, c_int)
@@ -80,7 +78,6 @@
self.assertEqual(bin(s), "78563412")
self.assertEqual(s.value, 0x12345678)
- @xfail
def test_endian_longlong(self):
if sys.byteorder == "little":
self.assertIs(c_longlong.__ctype_le__, c_longlong)
@@ -109,7 +106,6 @@
self.assertEqual(bin(s), "EFCDAB9078563412")
self.assertEqual(s.value, 0x1234567890ABCDEF)
- @xfail
def test_endian_float(self):
if sys.byteorder == "little":
self.assertIs(c_float.__ctype_le__, c_float)
@@ -128,7 +124,6 @@
self.assertAlmostEqual(s.value, math.pi, 6)
self.assertEqual(bin(struct.pack(">f", math.pi)), bin(s))
- @xfail
def test_endian_double(self):
if sys.byteorder == "little":
self.assertIs(c_double.__ctype_le__, c_double)
@@ -156,7 +151,6 @@
self.assertIs(c_char.__ctype_le__, c_char)
self.assertIs(c_char.__ctype_be__, c_char)
- @xfail
def test_struct_fields_1(self):
if sys.byteorder == "little":
base = BigEndianStructure
@@ -192,7 +186,6 @@
pass
self.assertRaises(TypeError, setattr, T, "_fields_", [("x", typ)])
- @xfail
def test_struct_struct(self):
# nested structures with different byteorders
@@ -221,7 +214,6 @@
self.assertEqual(s.point.x, 1)
self.assertEqual(s.point.y, 2)
- @xfail
def test_struct_fields_2(self):
# standard packing in struct uses no alignment.
# So, we have to align using pad bytes.
@@ -245,7 +237,6 @@
s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
self.assertEqual(bin(s1), bin(s2))
- @xfail
def test_unaligned_nonnative_struct_fields(self):
if sys.byteorder == "little":
base = BigEndianStructure
diff --git a/lib-python/2.7/ctypes/test/test_unaligned_structures.py b/lib-python/2.7/ctypes/test/test_unaligned_structures.py
--- a/lib-python/2.7/ctypes/test/test_unaligned_structures.py
+++ b/lib-python/2.7/ctypes/test/test_unaligned_structures.py
@@ -37,10 +37,7 @@
for typ in byteswapped_structures:
## print >> sys.stderr, typ.value
self.assertEqual(typ.value.offset, 1)
- try:
- o = typ()
- except NotImplementedError as e:
- self.skipTest(str(e)) # for PyPy
+ o = typ()
o.value = 4
self.assertEqual(o.value, 4)
diff --git a/lib-python/2.7/distutils/sysconfig_pypy.py b/lib-python/2.7/distutils/sysconfig_pypy.py
--- a/lib-python/2.7/distutils/sysconfig_pypy.py
+++ b/lib-python/2.7/distutils/sysconfig_pypy.py
@@ -218,6 +218,10 @@
compiler.shared_lib_extension = so_ext
+def get_config_h_filename():
+ """Returns the path of pyconfig.h."""
+ inc_dir = get_python_inc(plat_specific=1)
+ return os.path.join(inc_dir, 'pyconfig.h')
from sysconfig_cpython import (
parse_makefile, _variable_rx, expand_makefile_vars)
diff --git a/lib-python/2.7/distutils/unixccompiler.py b/lib-python/2.7/distutils/unixccompiler.py
--- a/lib-python/2.7/distutils/unixccompiler.py
+++ b/lib-python/2.7/distutils/unixccompiler.py
@@ -226,7 +226,19 @@
return "-L" + dir
def _is_gcc(self, compiler_name):
- return "gcc" in compiler_name or "g++" in compiler_name
+ # XXX PyPy workaround, look at the big comment below for more
+ # context. On CPython, the hack below works fine because
+ # `compiler_name` contains the name of the actual compiler which was
+ # used at compile time (e.g. 'x86_64-linux-gnu-gcc' on my machine).
+ # PyPy hardcodes it to 'cc', so the hack doesn't work, and the end
+ # result is that we pass the wrong option to the compiler.
+ #
+ # The workaround is to *always* pretend to be GCC if we are on Linux:
+ # this should cover the vast majority of real systems, including the
+ # ones which use clang (which understands the '-Wl,-rpath' syntax as
+ # well)
+ return (sys.platform == "linux2" or
+ "gcc" in compiler_name or "g++" in compiler_name)
def runtime_library_dir_option(self, dir):
# XXX Hackish, at the very least. See Python bug #445902:
diff --git a/lib-python/2.7/inspect.py b/lib-python/2.7/inspect.py
--- a/lib-python/2.7/inspect.py
+++ b/lib-python/2.7/inspect.py
@@ -203,7 +203,7 @@
f_locals local namespace seen by this frame
f_restricted 0 or 1 if frame is in restricted execution mode
f_trace tracing function for this frame, or None"""
- return isinstance(object, types.FrameType)
+ return isinstance(object, (types.FrameType, types.FakeFrameType))
def iscode(object):
"""Return true if the object is a code object.
diff --git a/lib-python/2.7/multiprocessing/heap.py b/lib-python/2.7/multiprocessing/heap.py
--- a/lib-python/2.7/multiprocessing/heap.py
+++ b/lib-python/2.7/multiprocessing/heap.py
@@ -62,7 +62,7 @@
self.size = size
self.name = 'pym-%d-%d' % (os.getpid(), Arena._counter.next())
self.buffer = mmap.mmap(-1, self.size, tagname=self.name)
- assert win32.GetLastError() == 0, 'tagname already in use'
+ #assert win32.GetLastError() == 0, 'tagname already in use'
self._state = (self.size, self.name)
def __getstate__(self):
@@ -72,7 +72,7 @@
def __setstate__(self, state):
self.size, self.name = self._state = state
self.buffer = mmap.mmap(-1, self.size, tagname=self.name)
- assert win32.GetLastError() == win32.ERROR_ALREADY_EXISTS
+ #assert win32.GetLastError() == win32.ERROR_ALREADY_EXISTS
else:
diff --git a/lib-python/2.7/string.py b/lib-python/2.7/string.py
--- a/lib-python/2.7/string.py
+++ b/lib-python/2.7/string.py
@@ -75,7 +75,7 @@
for i in range(256):
buf[i] = i
for i in range(n):
- buf[ord(fromstr[i])] = tostr[i]
+ buf[ord(fromstr[i])] = ord(tostr[i])
return str(buf)
diff --git a/lib-python/2.7/test/test_os.py b/lib-python/2.7/test/test_os.py
--- a/lib-python/2.7/test/test_os.py
+++ b/lib-python/2.7/test/test_os.py
@@ -580,6 +580,7 @@
"getentropy() does not use a file descriptor")
class URandomFDTests(unittest.TestCase):
@unittest.skipUnless(resource, "test requires the resource module")
+ @test_support.impl_detail(pypy=False) # on Linux, may use getrandom()
def test_urandom_failure(self):
# Check urandom() failing when it is not able to open /dev/random.
# We spawn a new process to make the test more robust (if getrlimit()
diff --git a/lib-python/2.7/types.py b/lib-python/2.7/types.py
--- a/lib-python/2.7/types.py
+++ b/lib-python/2.7/types.py
@@ -71,6 +71,12 @@
FrameType = type(tb.tb_frame)
del tb
+# PyPy extension
+try:
+ FakeFrameType = type(next(sys._current_frames().itervalues()))
+except (AttributeError, StopIteration):
+ FakeFrameType = FrameType
+
SliceType = slice
EllipsisType = type(Ellipsis)
diff --git a/lib-python/2.7/warnings.py b/lib-python/2.7/warnings.py
--- a/lib-python/2.7/warnings.py
+++ b/lib-python/2.7/warnings.py
@@ -309,9 +309,12 @@
def __init__(self, message, category, filename, lineno, file=None,
line=None):
- local_values = locals()
- for attr in self._WARNING_DETAILS:
- setattr(self, attr, local_values[attr])
+ self.message = message
+ self.category = category
+ self.filename = filename
+ self.lineno = lineno
+ self.file = file
+ self.line = line
self._category_name = category.__name__ if category else None
def __str__(self):
diff --git a/lib_pypy/_ctypes/array.py b/lib_pypy/_ctypes/array.py
--- a/lib_pypy/_ctypes/array.py
+++ b/lib_pypy/_ctypes/array.py
@@ -76,12 +76,16 @@
return self._type_._alignmentofinstances()
def _CData_output(self, resarray, base=None, index=-1):
- # this seems to be a string if we're array of char, surprise!
- from ctypes import c_char, c_wchar
- if self._type_ is c_char:
- return _rawffi.charp2string(resarray.buffer, self._length_)
- if self._type_ is c_wchar:
- return _rawffi.wcharp2unicode(resarray.buffer, self._length_)
+ from _rawffi.alt import types
+ # If a char_p or unichar_p is received, skip the string interpretation
+ if base._ffiargtype != types.Pointer(types.char_p) and \
+ base._ffiargtype != types.Pointer(types.unichar_p):
+ # this seems to be a string if we're array of char, surprise!
+ from ctypes import c_char, c_wchar
+ if self._type_ is c_char:
+ return _rawffi.charp2string(resarray.buffer, self._length_)
+ if self._type_ is c_wchar:
+ return _rawffi.wcharp2unicode(resarray.buffer, self._length_)
res = self.__new__(self)
ffiarray = self._ffiarray.fromaddress(resarray.buffer, self._length_)
res._buffer = ffiarray
diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py
--- a/lib_pypy/_ctypes/basics.py
+++ b/lib_pypy/_ctypes/basics.py
@@ -82,7 +82,7 @@
return False
def in_dll(self, dll, name):
- return self.from_address(dll._handle.getaddressindll(name))
+ return self.from_address(dll.__pypy_dll__.getaddressindll(name))
def from_buffer(self, obj, offset=0):
size = self._sizeofinstances()
diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py
--- a/lib_pypy/_ctypes/function.py
+++ b/lib_pypy/_ctypes/function.py
@@ -430,7 +430,7 @@
ffires = restype.get_ffi_argtype()
return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires, self._flags_)
- cdll = self.dll._handle
+ cdll = self.dll.__pypy_dll__
try:
ffi_argtypes = [argtype.get_ffi_argtype() for argtype in argtypes]
ffi_restype = restype.get_ffi_argtype()
diff --git a/lib_pypy/_ctypes/pointer.py b/lib_pypy/_ctypes/pointer.py
--- a/lib_pypy/_ctypes/pointer.py
+++ b/lib_pypy/_ctypes/pointer.py
@@ -142,6 +142,10 @@
ptr._buffer = tp._ffiarray(1, autofree=True)
ptr._buffer[0] = obj._buffer
result = ptr
+ elif isinstance(obj, bytes):
+ result = tp()
+ result._buffer[0] = buffer(obj)._pypy_raw_address()
+ return result
elif not (isinstance(obj, _CData) and type(obj)._is_pointer_like()):
raise TypeError("cast() argument 1 must be a pointer, not %s"
% (type(obj),))
diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py
--- a/lib_pypy/_ctypes/primitive.py
+++ b/lib_pypy/_ctypes/primitive.py
@@ -61,6 +61,54 @@
pyobj_container = GlobalPyobjContainer()
+def swap_bytes(value, sizeof, typeof, get_or_set):
+ def swap_2():
+ return ((value >> 8) & 0x00FF) | ((value << 8) & 0xFF00)
+
+ def swap_4():
+ return ((value & 0x000000FF) << 24) | \
+ ((value & 0x0000FF00) << 8) | \
+ ((value & 0x00FF0000) >> 8) | \
+ ((value >> 24) & 0xFF)
+
+ def swap_8():
+ return ((value & 0x00000000000000FFL) << 56) | \
+ ((value & 0x000000000000FF00L) << 40) | \
+ ((value & 0x0000000000FF0000L) << 24) | \
+ ((value & 0x00000000FF000000L) << 8) | \
+ ((value & 0x000000FF00000000L) >> 8) | \
+ ((value & 0x0000FF0000000000L) >> 24) | \
+ ((value & 0x00FF000000000000L) >> 40) | \
+ ((value >> 56) & 0xFF)
+
+ def swap_double_float(typ):
+ from struct import pack, unpack
+ if get_or_set == 'set':
+ if sys.byteorder == 'little':
+ st = pack(''.join(['>', typ]), value)
+ else:
+ st = pack(''.join(['<', typ]), value)
+ return unpack(typ, st)[0]
+ else:
+ packed = pack(typ, value)
+ if sys.byteorder == 'little':
+ st = unpack(''.join(['>', typ]), packed)
+ else:
+ st = unpack(''.join(['<', typ]), packed)
+ return st[0]
+
+ if typeof in ('c_float', 'c_float_le', 'c_float_be'):
+ return swap_double_float('f')
+ elif typeof in ('c_double', 'c_double_le', 'c_double_be'):
+ return swap_double_float('d')
+ else:
+ if sizeof == 2:
+ return swap_2()
+ elif sizeof == 4:
+ return swap_4()
+ elif sizeof == 8:
+ return swap_8()
+
def generic_xxx_p_from_param(cls, value):
if value is None:
return cls(None)
@@ -271,6 +319,31 @@
def _as_ffi_pointer_(self, ffitype):
return as_ffi_pointer(self, ffitype)
result._as_ffi_pointer_ = _as_ffi_pointer_
+ if name[-2:] != '_p' and name[-3:] not in ('_le', '_be') \
+ and name not in ('c_wchar', '_SimpleCData', 'c_longdouble', 'c_bool', 'py_object'):
+ from sys import byteorder
+ if byteorder == 'big':
+ name += '_le'
+ swapped = self.__new__(self, name, bases, dct)
+ result.__ctype_le__ = swapped
+ result.__ctype_be__ = result
+ swapped.__ctype_be__ = result
+ swapped.__ctype_le__ = swapped
+ else:
+ name += '_be'
+ swapped = self.__new__(self, name, bases, dct)
+ result.__ctype_be__ = swapped
+ result.__ctype_le__ = result
+ swapped.__ctype_le__ = result
+ swapped.__ctype_be__ = swapped
+ from _ctypes import sizeof
+ def _getval(self):
+ return swap_bytes(self._buffer[0], sizeof(self), name, 'get')
+ def _setval(self, value):
+ d = result()
+ d.value = value
+ self._buffer[0] = swap_bytes(d.value, sizeof(self), name, 'set')
+ swapped.value = property(_getval, _setval)
return result
diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py
--- a/lib_pypy/_ctypes/structure.py
+++ b/lib_pypy/_ctypes/structure.py
@@ -40,6 +40,22 @@
else:
rawfields.append((f[0], f[1]._ffishape_))
+ # hack for duplicate field names
+ already_seen = set()
+ names1 = names
+ names = []
+ for f in names1:
+ if f not in already_seen:
+ names.append(f)
+ already_seen.add(f)
+ already_seen = set()
+ for i in reversed(range(len(rawfields))):
+ if rawfields[i][0] in already_seen:
+ rawfields[i] = (('$DUP%d$%s' % (i, rawfields[i][0]),)
+ + rawfields[i][1:])
+ already_seen.add(rawfields[i][0])
+ # /hack
+
_set_shape(self, rawfields, self._is_union)
fields = {}
@@ -130,6 +146,7 @@
obj._buffer.__setattr__(self.name, arg)
+
def _set_shape(tp, rawfields, is_union=False):
tp._ffistruct_ = _rawffi.Structure(rawfields, is_union,
getattr(tp, '_pack_', 0))
@@ -224,19 +241,27 @@
res.__dict__['_index'] = -1
return res
-
class StructOrUnion(_CData):
__metaclass__ = StructOrUnionMeta
def __new__(cls, *args, **kwds):
from _ctypes import union
- self = super(_CData, cls).__new__(cls)
- if ('_abstract_' in cls.__dict__ or cls is Structure
+ if ('_abstract_' in cls.__dict__ or cls is Structure
or cls is union.Union):
raise TypeError("abstract class")
if hasattr(cls, '_swappedbytes_'):
- raise NotImplementedError("missing in PyPy: structure/union with "
- "swapped (non-native) byte ordering")
+ fields = [None] * len(cls._fields_)
+ for i in range(len(cls._fields_)):
+ if cls._fields_[i][1] == cls._fields_[i][1].__dict__.get('__ctype_be__', None):
+ swapped = cls._fields_[i][1].__dict__.get('__ctype_le__', cls._fields_[i][1])
+ else:
+ swapped = cls._fields_[i][1].__dict__.get('__ctype_be__', cls._fields_[i][1])
+ if len(cls._fields_[i]) < 3:
+ fields[i] = (cls._fields_[i][0], swapped)
+ else:
+ fields[i] = (cls._fields_[i][0], swapped, cls._fields_[i][2])
+ names_and_fields(cls, fields, _CData, cls.__dict__.get('_anonymous_', None))
+ self = super(_CData, cls).__new__(cls)
if hasattr(cls, '_ffistruct_'):
self.__dict__['_buffer'] = self._ffistruct_(autofree=True)
return self
diff --git a/lib_pypy/_curses.py b/lib_pypy/_curses.py
--- a/lib_pypy/_curses.py
+++ b/lib_pypy/_curses.py
@@ -8,6 +8,9 @@
from _curses_cffi import ffi, lib
+version = b"2.2"
+__version__ = b"2.2"
+
def _copy_to_globals(name):
globals()[name] = getattr(lib, name)
@@ -60,10 +63,6 @@
_setup()
-# Do we want this?
-# version = "2.2"
-# __version__ = "2.2"
-
# ____________________________________________________________
@@ -913,101 +912,29 @@
return None
-# XXX: Do something about the following?
-# /* Internal helper used for updating curses.LINES, curses.COLS, _curses.LINES
-# * and _curses.COLS */
-# #if defined(HAVE_CURSES_RESIZETERM) || defined(HAVE_CURSES_RESIZE_TERM)
-# static int
-# update_lines_cols(void)
-# {
-# PyObject *o;
-# PyObject *m = PyImport_ImportModuleNoBlock("curses");
+# Internal helper used for updating curses.LINES, curses.COLS, _curses.LINES
+# and _curses.COLS
+def update_lines_cols():
+ globals()["LINES"] = lib.LINES
+ globals()["COLS"] = lib.COLS
+ try:
+ m = sys.modules["curses"]
+ m.LINES = lib.LINES
+ m.COLS = lib.COLS
+ except (KeyError, AttributeError):
+ pass
-# if (!m)
-# return 0;
-# o = PyInt_FromLong(LINES);
-# if (!o) {
-# Py_DECREF(m);
-# return 0;
-# }
-# if (PyObject_SetAttrString(m, "LINES", o)) {
-# Py_DECREF(m);
-# Py_DECREF(o);
-# return 0;
-# }
-# if (PyDict_SetItemString(ModDict, "LINES", o)) {
-# Py_DECREF(m);
-# Py_DECREF(o);
-# return 0;
-# }
-# Py_DECREF(o);
-# o = PyInt_FromLong(COLS);
-# if (!o) {
-# Py_DECREF(m);
-# return 0;
-# }
-# if (PyObject_SetAttrString(m, "COLS", o)) {
-# Py_DECREF(m);
-# Py_DECREF(o);
-# return 0;
-# }
-# if (PyDict_SetItemString(ModDict, "COLS", o)) {
-# Py_DECREF(m);
-# Py_DECREF(o);
-# return 0;
-# }
-# Py_DECREF(o);
-# Py_DECREF(m);
-# return 1;
-# }
-# #endif
+def resizeterm(lines, columns):
+ _ensure_initialised()
+ _check_ERR(lib.resizeterm(lines, columns), "resizeterm")
+ update_lines_cols()
-# #ifdef HAVE_CURSES_RESIZETERM
-# static PyObject *
-# PyCurses_ResizeTerm(PyObject *self, PyObject *args)
-# {
-# int lines;
-# int columns;
-# PyObject *result;
-# PyCursesInitialised;
-
-# if (!PyArg_ParseTuple(args,"ii:resizeterm", &lines, &columns))
-# return NULL;
-
-# result = PyCursesCheckERR(resizeterm(lines, columns), "resizeterm");
-# if (!result)
-# return NULL;
-# if (!update_lines_cols())
-# return NULL;
-# return result;
-# }
-
-# #endif
-
-# #ifdef HAVE_CURSES_RESIZE_TERM
-# static PyObject *
-# PyCurses_Resize_Term(PyObject *self, PyObject *args)
-# {
-# int lines;
-# int columns;
-
-# PyObject *result;
-
-# PyCursesInitialised;
-
-# if (!PyArg_ParseTuple(args,"ii:resize_term", &lines, &columns))
-# return NULL;
-
-# result = PyCursesCheckERR(resize_term(lines, columns), "resize_term");
-# if (!result)
-# return NULL;
-# if (!update_lines_cols())
-# return NULL;
-# return result;
-# }
-# #endif /* HAVE_CURSES_RESIZE_TERM */
+def resize_term(lines, columns):
+ _ensure_initialised()
+ _check_ERR(lib.resize_term(lines, columns), "resize_term")
+ update_lines_cols()
def setsyx(y, x):
diff --git a/lib_pypy/_curses_build.py b/lib_pypy/_curses_build.py
--- a/lib_pypy/_curses_build.py
+++ b/lib_pypy/_curses_build.py
@@ -87,6 +87,13 @@
static const chtype A_CHARTEXT;
static const chtype A_COLOR;
+static const chtype A_HORIZONTAL;
+static const chtype A_LEFT;
+static const chtype A_LOW;
+static const chtype A_RIGHT;
+static const chtype A_TOP;
+static const chtype A_VERTICAL;
+
static const int BUTTON1_RELEASED;
static const int BUTTON1_PRESSED;
static const int BUTTON1_CLICKED;
@@ -202,6 +209,8 @@
int resetty(void);
int reset_prog_mode(void);
int reset_shell_mode(void);
+int resizeterm(int, int);
+int resize_term(int, int);
int savetty(void);
int scroll(WINDOW *);
int scrollok(WINDOW *, bool);
diff --git a/lib_pypy/_tkinter/tklib_build.py b/lib_pypy/_tkinter/tklib_build.py
--- a/lib_pypy/_tkinter/tklib_build.py
+++ b/lib_pypy/_tkinter/tklib_build.py
@@ -22,12 +22,27 @@
linklibs = ['tcl', 'tk']
libdirs = []
else:
- for _ver in ['', '8.6', '8.5', '']:
+ # On some Linux distributions, the tcl and tk libraries are
+ # stored in /usr/include, so we must check this case also
+ libdirs = []
+ found = False
+ for _ver in ['', '8.6', '8.5']:
incdirs = ['/usr/include/tcl' + _ver]
linklibs = ['tcl' + _ver, 'tk' + _ver]
- libdirs = []
if os.path.isdir(incdirs[0]):
+ found = True
break
+ if not found:
+ for _ver in ['8.6', '8.5', '']:
+ incdirs = []
+ linklibs = ['tcl' + _ver, 'tk' + _ver]
+ if os.path.isfile(''.join(['/usr/lib/lib', linklibs[1], '.so'])):
+ found = True
+ break
+ if not found:
+ sys.stderr.write("*** TCL libraries not found! Falling back...\n")
+ incdirs = []
+ linklibs = ['tcl', 'tk']
config_ffi = FFI()
config_ffi.cdef("""
diff --git a/lib_pypy/cPickle.py b/lib_pypy/cPickle.py
--- a/lib_pypy/cPickle.py
+++ b/lib_pypy/cPickle.py
@@ -116,10 +116,20 @@
@builtinify
def dump(obj, file, protocol=None):
+ if protocol > HIGHEST_PROTOCOL:
+ # use cPickle error message, not pickle.py one
+ raise ValueError("pickle protocol %d asked for; "
+ "the highest available protocol is %d" % (
+ protocol, HIGHEST_PROTOCOL))
Pickler(file, protocol).dump(obj)
@builtinify
def dumps(obj, protocol=None):
+ if protocol > HIGHEST_PROTOCOL:
+ # use cPickle error message, not pickle.py one
+ raise ValueError("pickle protocol %d asked for; "
+ "the highest available protocol is %d" % (
+ protocol, HIGHEST_PROTOCOL))
file = StringIO()
Pickler(file, protocol).dump(obj)
return file.getvalue()
@@ -431,7 +441,14 @@
self.append(obj)
def find_class(self, module, name):
- # Subclasses may override this
+ if self.find_global is None:
+ raise UnpicklingError(
+ "Global and instance pickles are not supported.")
+ return self.find_global(module, name)
+
+ def find_global(self, module, name):
+ # This can officially be patched directly in the Unpickler
+ # instance, according to the docs
__import__(module)
mod = sys.modules[module]
klass = getattr(mod, name)
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.10.1
+Version: 1.11.0
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
from .error import CDefError, FFIError, VerificationError, VerificationMissing
-__version__ = "1.10.1"
-__version_info__ = (1, 10, 1)
+__version__ = "1.11.0"
+__version_info__ = (1, 11, 0)
# 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/_cffi_errors.h b/lib_pypy/cffi/_cffi_errors.h
new file mode 100644
--- /dev/null
+++ b/lib_pypy/cffi/_cffi_errors.h
@@ -0,0 +1,145 @@
+#ifndef CFFI_MESSAGEBOX
+# ifdef _MSC_VER
+# define CFFI_MESSAGEBOX 1
+# else
+# define CFFI_MESSAGEBOX 0
+# endif
+#endif
+
+
+#if CFFI_MESSAGEBOX
+/* Windows only: logic to take the Python-CFFI embedding logic
+ initialization errors and display them in a background thread
+ with MessageBox. The idea is that if the whole program closes
+ as a result of this problem, then likely it is already a console
+ program and you can read the stderr output in the console too.
+ If it is not a console program, then it will likely show its own
+ dialog to complain, or generally not abruptly close, and for this
+ case the background thread should stay alive.
+*/
+static void *volatile _cffi_bootstrap_text;
+
+static PyObject *_cffi_start_error_capture(void)
+{
+ PyObject *result = NULL;
+ PyObject *x, *m, *bi;
+
+ if (InterlockedCompareExchangePointer(&_cffi_bootstrap_text,
+ (void *)1, NULL) != NULL)
+ return (PyObject *)1;
+
+ m = PyImport_AddModule("_cffi_error_capture");
+ if (m == NULL)
+ goto error;
+
+ result = PyModule_GetDict(m);
+ if (result == NULL)
+ goto error;
+
+#if PY_MAJOR_VERSION >= 3
+ bi = PyImport_ImportModule("builtins");
+#else
+ bi = PyImport_ImportModule("__builtin__");
+#endif
+ if (bi == NULL)
+ goto error;
+ PyDict_SetItemString(result, "__builtins__", bi);
+ Py_DECREF(bi);
+
+ x = PyRun_String(
+ "import sys\n"
+ "class FileLike:\n"
+ " def write(self, x):\n"
+ " of.write(x)\n"
+ " self.buf += x\n"
+ "fl = FileLike()\n"
+ "fl.buf = ''\n"
+ "of = sys.stderr\n"
+ "sys.stderr = fl\n"
+ "def done():\n"
+ " sys.stderr = of\n"
+ " return fl.buf\n", /* make sure the returned value stays alive */
+ Py_file_input,
+ result, result);
+ Py_XDECREF(x);
+
+ error:
+ if (PyErr_Occurred())
+ {
+ PyErr_WriteUnraisable(Py_None);
+ PyErr_Clear();
+ }
+ return result;
+}
+
+#pragma comment(lib, "user32.lib")
+
+static DWORD WINAPI _cffi_bootstrap_dialog(LPVOID ignored)
+{
+ Sleep(666); /* may be interrupted if the whole process is closing */
+#if PY_MAJOR_VERSION >= 3
+ MessageBoxW(NULL, (wchar_t *)_cffi_bootstrap_text,
+ L"Python-CFFI error",
+ MB_OK | MB_ICONERROR);
+#else
+ MessageBoxA(NULL, (char *)_cffi_bootstrap_text,
+ "Python-CFFI error",
+ MB_OK | MB_ICONERROR);
+#endif
+ _cffi_bootstrap_text = NULL;
+ return 0;
+}
+
+static void _cffi_stop_error_capture(PyObject *ecap)
+{
+ PyObject *s;
+ void *text;
+
+ if (ecap == (PyObject *)1)
+ return;
+
+ if (ecap == NULL)
+ goto error;
+
+ s = PyRun_String("done()", Py_eval_input, ecap, ecap);
+ if (s == NULL)
+ goto error;
+
+ /* Show a dialog box, but in a background thread, and
+ never show multiple dialog boxes at once. */
+#if PY_MAJOR_VERSION >= 3
+ text = PyUnicode_AsWideCharString(s, NULL);
+#else
+ text = PyString_AsString(s);
+#endif
+
+ _cffi_bootstrap_text = text;
+
+ if (text != NULL)
+ {
+ HANDLE h;
+ h = CreateThread(NULL, 0, _cffi_bootstrap_dialog,
+ NULL, 0, NULL);
+ if (h != NULL)
+ CloseHandle(h);
+ }
+ /* decref the string, but it should stay alive as 'fl.buf'
+ in the small module above. It will really be freed only if
+ we later get another similar error. So it's a leak of at
+ most one copy of the small module. That's fine for this
+ situation which is usually a "fatal error" anyway. */
+ Py_DECREF(s);
+ PyErr_Clear();
+ return;
+
+ error:
+ _cffi_bootstrap_text = NULL;
+ PyErr_Clear();
+}
+
+#else
+
+static PyObject *_cffi_start_error_capture(void) { return NULL; }
+static void _cffi_stop_error_capture(PyObject *ecap) { }
+
+#endif
diff --git a/lib_pypy/cffi/_cffi_include.h b/lib_pypy/cffi/_cffi_include.h
--- a/lib_pypy/cffi/_cffi_include.h
+++ b/lib_pypy/cffi/_cffi_include.h
@@ -95,6 +95,7 @@
#define _cffi_from_c_ulong PyLong_FromUnsignedLong
#define _cffi_from_c_longlong PyLong_FromLongLong
#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong
+#define _cffi_from_c__Bool PyBool_FromLong
#define _cffi_to_c_double PyFloat_AsDouble
#define _cffi_to_c_float PyFloat_AsDouble
@@ -159,9 +160,9 @@
#define _cffi_from_c_struct \
((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[18])
#define _cffi_to_c_wchar_t \
- ((wchar_t(*)(PyObject *))_cffi_exports[19])
+ ((_cffi_wchar_t(*)(PyObject *))_cffi_exports[19])
#define _cffi_from_c_wchar_t \
- ((PyObject *(*)(wchar_t))_cffi_exports[20])
+ ((PyObject *(*)(_cffi_wchar_t))_cffi_exports[20])
#define _cffi_to_c_long_double \
((long double(*)(PyObject *))_cffi_exports[21])
#define _cffi_to_c__Bool \
@@ -174,7 +175,11 @@
#define _CFFI_CPIDX 25
#define _cffi_call_python \
((void(*)(struct _cffi_externpy_s *, char *))_cffi_exports[_CFFI_CPIDX])
-#define _CFFI_NUM_EXPORTS 26
+#define _cffi_to_c_wchar3216_t \
+ ((int(*)(PyObject *))_cffi_exports[26])
+#define _cffi_from_c_wchar3216_t \
+ ((PyObject *(*)(int))_cffi_exports[27])
+#define _CFFI_NUM_EXPORTS 28
struct _cffi_ctypedescr;
@@ -215,6 +220,46 @@
return NULL;
}
+
+#ifdef HAVE_WCHAR_H
+typedef wchar_t _cffi_wchar_t;
+#else
+typedef uint16_t _cffi_wchar_t; /* same random pick as _cffi_backend.c */
+#endif
+
+_CFFI_UNUSED_FN static uint16_t _cffi_to_c_char16_t(PyObject *o)
+{
+ if (sizeof(_cffi_wchar_t) == 2)
+ return (uint16_t)_cffi_to_c_wchar_t(o);
+ else
+ return (uint16_t)_cffi_to_c_wchar3216_t(o);
+}
+
+_CFFI_UNUSED_FN static PyObject *_cffi_from_c_char16_t(uint16_t x)
+{
+ if (sizeof(_cffi_wchar_t) == 2)
+ return _cffi_from_c_wchar_t(x);
+ else
+ return _cffi_from_c_wchar3216_t(x);
+}
+
+_CFFI_UNUSED_FN static int _cffi_to_c_char32_t(PyObject *o)
+{
+ if (sizeof(_cffi_wchar_t) == 4)
+ return (int)_cffi_to_c_wchar_t(o);
+ else
+ return (int)_cffi_to_c_wchar3216_t(o);
+}
+
+_CFFI_UNUSED_FN static PyObject *_cffi_from_c_char32_t(int x)
+{
+ if (sizeof(_cffi_wchar_t) == 4)
+ return _cffi_from_c_wchar_t(x);
+ else
+ return _cffi_from_c_wchar3216_t(x);
+}
+
+
/********** end CPython-specific section **********/
#else
_CFFI_UNUSED_FN
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
@@ -1,7 +1,12 @@
/***** Support code for embedding *****/
-#if defined(_MSC_VER)
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#if defined(_WIN32)
# define CFFI_DLLEXPORT __declspec(dllexport)
#elif defined(__GNUC__)
# define CFFI_DLLEXPORT __attribute__((visibility("default")))
@@ -109,6 +114,8 @@
/********** CPython-specific section **********/
#ifndef PYPY_VERSION
+#include "_cffi_errors.h"
+
#define _cffi_call_python_org _cffi_exports[_CFFI_CPIDX]
@@ -220,8 +227,16 @@
/* Print as much information as potentially useful.
Debugging load-time failures with embedding is not fun
*/
+ PyObject *ecap;
PyObject *exception, *v, *tb, *f, *modules, *mod;
PyErr_Fetch(&exception, &v, &tb);
+ ecap = _cffi_start_error_capture();
+ f = PySys_GetObject((char *)"stderr");
+ if (f != NULL && f != Py_None) {
+ PyFile_WriteString(
+ "Failed to initialize the Python-CFFI embedding logic:\n\n", f);
+ }
+
if (exception != NULL) {
PyErr_NormalizeException(&exception, &v, &tb);
PyErr_Display(exception, v, tb);
@@ -230,10 +245,9 @@
Py_XDECREF(v);
Py_XDECREF(tb);
- f = PySys_GetObject((char *)"stderr");
if (f != NULL && f != Py_None) {
PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME
- "\ncompiled with cffi version: 1.10.0"
+ "\ncompiled with cffi version: 1.11.0"
"\n_cffi_backend module: ", f);
modules = PyImport_GetModuleDict();
mod = PyDict_GetItemString(modules, "_cffi_backend");
@@ -249,6 +263,7 @@
PyFile_WriteObject(PySys_GetObject((char *)"path"), f, 0);
PyFile_WriteString("\n\n", f);
}
+ _cffi_stop_error_capture(ecap);
}
result = -1;
goto done;
@@ -515,3 +530,7 @@
#undef cffi_compare_and_swap
#undef cffi_write_barrier
#undef cffi_read_barrier
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/lib_pypy/cffi/api.py b/lib_pypy/cffi/api.py
--- a/lib_pypy/cffi/api.py
+++ b/lib_pypy/cffi/api.py
@@ -75,9 +75,10 @@
self._init_once_cache = {}
self._cdef_version = None
self._embedding = None
+ self._typecache = model.get_typecache(backend)
if hasattr(backend, 'set_ffi'):
backend.set_ffi(self)
- for name in backend.__dict__:
+ for name in list(backend.__dict__):
if name.startswith('RTLD_'):
setattr(self, name, getattr(backend, name))
#
@@ -393,12 +394,17 @@
replace_with = ' ' + replace_with
return self._backend.getcname(cdecl, replace_with)
- def gc(self, cdata, destructor):
+ def gc(self, cdata, destructor, size=0):
"""Return a new cdata object that points to the same
data. Later, when this new cdata object is garbage-collected,
'destructor(old_cdata_object)' will be called.
+
+ The optional 'size' gives an estimate of the size, used to
+ trigger the garbage collection more eagerly. So far only used
+ on PyPy. It tells the GC that the returned object keeps alive
+ roughly 'size' bytes of external memory.
"""
- return self._backend.gcp(cdata, destructor)
+ return self._backend.gcp(cdata, destructor, size)
def _get_cached_btype(self, type):
assert self._lock.acquire(False) is False
@@ -764,7 +770,7 @@
if sys.platform != "win32":
return backend.load_library(None, flags)
name = "c" # Windows: load_library(None) fails, but this works
- # (backward compatibility hack only)
+ # on Python 2 (backward compatibility hack only)
first_error = None
if '.' in name or '/' in name or os.sep in name:
try:
@@ -774,6 +780,9 @@
import ctypes.util
path = ctypes.util.find_library(name)
if path is None:
+ if name == "c" and sys.platform == "win32" and sys.version_info >= (3,):
+ raise OSError("dlopen(None) cannot work on Windows for Python 3 "
+ "(see http://bugs.python.org/issue23606)")
msg = ("ctypes.util.find_library() did not manage "
"to locate a library called %r" % (name,))
if first_error is not None:
diff --git a/lib_pypy/cffi/backend_ctypes.py b/lib_pypy/cffi/backend_ctypes.py
--- a/lib_pypy/cffi/backend_ctypes.py
+++ b/lib_pypy/cffi/backend_ctypes.py
@@ -1002,7 +1002,7 @@
_weakref_cache_ref = None
- def gcp(self, cdata, destructor):
+ def gcp(self, cdata, destructor, size=0):
if self._weakref_cache_ref is None:
import weakref
class MyRef(weakref.ref):
diff --git a/lib_pypy/cffi/cffi_opcode.py b/lib_pypy/cffi/cffi_opcode.py
--- a/lib_pypy/cffi/cffi_opcode.py
+++ b/lib_pypy/cffi/cffi_opcode.py
@@ -105,8 +105,12 @@
PRIM_UINT_FAST64 = 45
PRIM_INTMAX = 46
PRIM_UINTMAX = 47
+PRIM_FLOATCOMPLEX = 48
+PRIM_DOUBLECOMPLEX = 49
+PRIM_CHAR16 = 50
+PRIM_CHAR32 = 51
-_NUM_PRIM = 48
+_NUM_PRIM = 52
_UNKNOWN_PRIM = -1
_UNKNOWN_FLOAT_PRIM = -2
_UNKNOWN_LONG_DOUBLE = -3
@@ -128,8 +132,12 @@
'float': PRIM_FLOAT,
'double': PRIM_DOUBLE,
'long double': PRIM_LONGDOUBLE,
+ 'float _Complex': PRIM_FLOATCOMPLEX,
+ 'double _Complex': PRIM_DOUBLECOMPLEX,
'_Bool': PRIM_BOOL,
'wchar_t': PRIM_WCHAR,
+ 'char16_t': PRIM_CHAR16,
+ 'char32_t': PRIM_CHAR32,
'int8_t': PRIM_INT8,
'uint8_t': PRIM_UINT8,
'int16_t': PRIM_INT16,
diff --git a/lib_pypy/cffi/model.py b/lib_pypy/cffi/model.py
--- a/lib_pypy/cffi/model.py
+++ b/lib_pypy/cffi/model.py
@@ -95,7 +95,8 @@
class BasePrimitiveType(BaseType):
- pass
+ def is_complex_type(self):
+ return False
class PrimitiveType(BasePrimitiveType):
@@ -116,9 +117,13 @@
'float': 'f',
'double': 'f',
'long double': 'f',
+ 'float _Complex': 'j',
+ 'double _Complex': 'j',
'_Bool': 'i',
# the following types are not primitive in the C sense
'wchar_t': 'c',
+ 'char16_t': 'c',
+ 'char32_t': 'c',
'int8_t': 'i',
'uint8_t': 'i',
'int16_t': 'i',
@@ -163,6 +168,8 @@
return self.ALL_PRIMITIVE_TYPES[self.name] == 'i'
def is_float_type(self):
return self.ALL_PRIMITIVE_TYPES[self.name] == 'f'
+ def is_complex_type(self):
+ return self.ALL_PRIMITIVE_TYPES[self.name] == 'j'
def build_backend_type(self, ffi, finishlist):
return global_cache(self, ffi, 'new_primitive_type', self.name)
@@ -561,22 +568,26 @@
global_lock = allocate_lock()
+_typecache_cffi_backend = weakref.WeakValueDictionary()
+
+def get_typecache(backend):
+ # returns _typecache_cffi_backend if backend is the _cffi_backend
+ # module, or type(backend).__typecache if backend is an instance of
+ # CTypesBackend (or some FakeBackend class during tests)
+ if isinstance(backend, types.ModuleType):
+ return _typecache_cffi_backend
+ with global_lock:
+ if not hasattr(type(backend), '__typecache'):
+ type(backend).__typecache = weakref.WeakValueDictionary()
+ return type(backend).__typecache
def global_cache(srctype, ffi, funcname, *args, **kwds):
key = kwds.pop('key', (funcname, args))
assert not kwds
try:
- return ffi._backend.__typecache[key]
+ return ffi._typecache[key]
except KeyError:
pass
- except AttributeError:
- # initialize the __typecache attribute, either at the module level
- # if ffi._backend is a module, or at the class level if ffi._backend
- # is some instance.
- if isinstance(ffi._backend, types.ModuleType):
- ffi._backend.__typecache = weakref.WeakValueDictionary()
- else:
- type(ffi._backend).__typecache = weakref.WeakValueDictionary()
try:
res = getattr(ffi._backend, funcname)(*args)
except NotImplementedError as e:
@@ -584,7 +595,7 @@
# note that setdefault() on WeakValueDictionary is not atomic
# and contains a rare bug (http://bugs.python.org/issue19542);
# we have to use a lock and do it ourselves
- cache = ffi._backend.__typecache
+ cache = ffi._typecache
with global_lock:
res1 = cache.get(key)
if res1 is None:
diff --git a/lib_pypy/cffi/parse_c_type.h b/lib_pypy/cffi/parse_c_type.h
--- a/lib_pypy/cffi/parse_c_type.h
+++ b/lib_pypy/cffi/parse_c_type.h
@@ -79,8 +79,12 @@
#define _CFFI_PRIM_UINT_FAST64 45
#define _CFFI_PRIM_INTMAX 46
#define _CFFI_PRIM_UINTMAX 47
+#define _CFFI_PRIM_FLOATCOMPLEX 48
+#define _CFFI_PRIM_DOUBLECOMPLEX 49
+#define _CFFI_PRIM_CHAR16 50
+#define _CFFI_PRIM_CHAR32 51
-#define _CFFI__NUM_PRIM 48
+#define _CFFI__NUM_PRIM 52
#define _CFFI__UNKNOWN_PRIM (-1)
#define _CFFI__UNKNOWN_FLOAT_PRIM (-2)
#define _CFFI__UNKNOWN_LONG_DOUBLE (-3)
diff --git a/lib_pypy/cffi/recompiler.py b/lib_pypy/cffi/recompiler.py
--- a/lib_pypy/cffi/recompiler.py
+++ b/lib_pypy/cffi/recompiler.py
@@ -3,8 +3,9 @@
from .error import VerificationError
from .cffi_opcode import *
-VERSION = "0x2601"
-VERSION_EMBEDDED = "0x2701"
+VERSION_BASE = 0x2601
+VERSION_EMBEDDED = 0x2701
+VERSION_CHAR16CHAR32 = 0x2801
class GlobalExpr:
@@ -126,6 +127,10 @@
self.ffi = ffi
self.module_name = module_name
self.target_is_python = target_is_python
+ self._version = VERSION_BASE
+
+ def needs_version(self, ver):
+ self._version = max(self._version, ver)
def collect_type_table(self):
self._typesdict = {}
@@ -303,10 +308,10 @@
base_module_name,))
prnt('#endif')
lines = self._rel_readlines('_embedding.h')
+ i = lines.index('#include "_cffi_errors.h"\n')
+ lines[i:i+1] = self._rel_readlines('_cffi_errors.h')
prnt(''.join(lines))
- version = VERSION_EMBEDDED
- else:
- version = VERSION
+ self.needs_version(VERSION_EMBEDDED)
#
# then paste the C source given by the user, verbatim.
prnt('/************************************************************/')
@@ -405,8 +410,11 @@
prnt(' _cffi_call_python_org = '
'(void(*)(struct _cffi_externpy_s *, char *))p[1];')
prnt(' }')
- prnt(' p[0] = (const void *)%s;' % version)
+ prnt(' p[0] = (const void *)0x%x;' % self._version)
prnt(' p[1] = &_cffi_type_context;')
+ prnt('#if PY_MAJOR_VERSION >= 3')
+ prnt(' return NULL;')
+ prnt('#endif')
prnt('}')
# on Windows, distutils insists on putting init_cffi_xyz in
# 'export_symbols', so instead of fighting it, just give up and
@@ -423,21 +431,22 @@
prnt('PyMODINIT_FUNC')
prnt('PyInit_%s(void)' % (base_module_name,))
prnt('{')
- prnt(' return _cffi_init("%s", %s, &_cffi_type_context);' % (
- self.module_name, version))
+ prnt(' return _cffi_init("%s", 0x%x, &_cffi_type_context);' % (
+ self.module_name, self._version))
prnt('}')
prnt('#else')
prnt('PyMODINIT_FUNC')
prnt('init%s(void)' % (base_module_name,))
prnt('{')
- prnt(' _cffi_init("%s", %s, &_cffi_type_context);' % (
- self.module_name, version))
+ prnt(' _cffi_init("%s", 0x%x, &_cffi_type_context);' % (
+ self.module_name, self._version))
prnt('}')
prnt('#endif')
prnt()
prnt('#ifdef __GNUC__')
prnt('# pragma GCC visibility pop')
prnt('#endif')
+ self._version = None
def _to_py(self, x):
if isinstance(x, str):
@@ -476,7 +485,8 @@
prnt('from %s import ffi as _ffi%d' % (included_module_name, i))
prnt()
prnt("ffi = _cffi_backend.FFI('%s'," % (self.module_name,))
- prnt(" _version = %s," % (VERSION,))
+ prnt(" _version = 0x%x," % (self._version,))
+ self._version = None
#
# the '_types' keyword argument
self.cffi_types = tuple(self.cffi_types) # don't change any more
@@ -506,7 +516,7 @@
def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode):
extraarg = ''
- if isinstance(tp, model.BasePrimitiveType):
+ if isinstance(tp, model.BasePrimitiveType) and not tp.is_complex_type():
if tp.is_integer_type() and tp.name != '_Bool':
converter = '_cffi_to_c_int'
extraarg = ', %s' % tp.name
@@ -515,8 +525,11 @@
# double' here, and _cffi_to_c_double would loose precision
converter = '(%s)_cffi_to_c_double' % (tp.get_c_name(''),)
else:
- converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''),
+ cname = tp.get_c_name('')
+ converter = '(%s)_cffi_to_c_%s' % (cname,
tp.name.replace(' ', '_'))
+ if cname in ('char16_t', 'char32_t'):
+ self.needs_version(VERSION_CHAR16CHAR32)
errvalue = '-1'
#
elif isinstance(tp, model.PointerType):
@@ -524,8 +537,10 @@
tovar, errcode)
return
#
- elif isinstance(tp, model.StructOrUnionOrEnum):
- # a struct (not a struct pointer) as a function argument
+ elif (isinstance(tp, model.StructOrUnionOrEnum) or
+ isinstance(tp, model.BasePrimitiveType)):
+ # a struct (not a struct pointer) as a function argument;
+ # or, a complex (the same code works)
self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)'
% (tovar, self._gettypenum(tp), fromvar))
self._prnt(' %s;' % errcode)
@@ -566,12 +581,15 @@
def _convert_expr_from_c(self, tp, var, context):
if isinstance(tp, model.BasePrimitiveType):
- if tp.is_integer_type():
+ if tp.is_integer_type() and tp.name != '_Bool':
return '_cffi_from_c_int(%s, %s)' % (var, tp.name)
elif isinstance(tp, model.UnknownFloatType):
return '_cffi_from_c_double(%s)' % (var,)
- elif tp.name != 'long double':
- return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var)
+ elif tp.name != 'long double' and not tp.is_complex_type():
+ cname = tp.name.replace(' ', '_')
+ if cname in ('char16_t', 'char32_t'):
+ self.needs_version(VERSION_CHAR16CHAR32)
+ return '_cffi_from_c_%s(%s)' % (cname, var)
else:
return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
var, self._gettypenum(tp))
@@ -734,21 +752,26 @@
#
# the PyPy version: need to replace struct/union arguments with
# pointers, and if the result is a struct/union, insert a first
- # arg that is a pointer to the result.
+ # arg that is a pointer to the result. We also do that for
+ # complex args and return type.
+ def need_indirection(type):
+ return (isinstance(type, model.StructOrUnion) or
+ (isinstance(type, model.PrimitiveType) and
+ type.is_complex_type()))
difference = False
arguments = []
call_arguments = []
context = 'argument of %s' % name
for i, type in enumerate(tp.args):
indirection = ''
- if isinstance(type, model.StructOrUnion):
+ if need_indirection(type):
indirection = '*'
difference = True
arg = type.get_c_name(' %sx%d' % (indirection, i), context)
arguments.append(arg)
call_arguments.append('%sx%d' % (indirection, i))
tp_result = tp.result
- if isinstance(tp_result, model.StructOrUnion):
+ if need_indirection(tp_result):
context = 'result of %s' % name
arg = tp_result.get_c_name(' *result', context)
arguments.insert(0, arg)
@@ -1180,7 +1203,7 @@
size_of_result = '(int)sizeof(%s)' % (
tp.result.get_c_name('', context),)
prnt('static struct _cffi_externpy_s _cffi_externpy__%s =' % name)
- prnt(' { "%s", %s };' % (name, size_of_result))
+ prnt(' { "%s.%s", %s };' % (self.module_name, name, size_of_result))
prnt()
#
arguments = []
diff --git a/lib_pypy/cffi/vengine_cpy.py b/lib_pypy/cffi/vengine_cpy.py
--- a/lib_pypy/cffi/vengine_cpy.py
+++ b/lib_pypy/cffi/vengine_cpy.py
@@ -296,7 +296,7 @@
def _convert_expr_from_c(self, tp, var, context):
if isinstance(tp, model.PrimitiveType):
- if tp.is_integer_type():
+ if tp.is_integer_type() and tp.name != '_Bool':
return '_cffi_from_c_int(%s, %s)' % (var, tp.name)
elif tp.name != 'long double':
return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var)
@@ -808,7 +808,8 @@
#include <stddef.h>
/* this block of #ifs should be kept exactly identical between
- c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py */
+ c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py
+ and cffi/_cffi_include.h */
#if defined(_MSC_VER)
# include <malloc.h> /* for alloca() */
# if _MSC_VER < 1600 /* MSVC < 2010 */
@@ -842,11 +843,13 @@
# include <stdint.h>
# endif
# if _MSC_VER < 1800 /* MSVC < 2013 */
- typedef unsigned char _Bool;
+# ifndef __cplusplus
+ typedef unsigned char _Bool;
+# endif
# endif
#else
# include <stdint.h>
-# if (defined (__SVR4) && defined (__sun)) || defined(_AIX)
+# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux)
# include <alloca.h>
# endif
#endif
@@ -869,6 +872,7 @@
#define _cffi_from_c_ulong PyLong_FromUnsignedLong
#define _cffi_from_c_longlong PyLong_FromLongLong
#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong
+#define _cffi_from_c__Bool PyBool_FromLong
#define _cffi_to_c_double PyFloat_AsDouble
#define _cffi_to_c_float PyFloat_AsDouble
diff --git a/lib_pypy/cffi/vengine_gen.py b/lib_pypy/cffi/vengine_gen.py
--- a/lib_pypy/cffi/vengine_gen.py
+++ b/lib_pypy/cffi/vengine_gen.py
@@ -627,7 +627,8 @@
#include <sys/types.h> /* XXX for ssize_t on some platforms */
/* this block of #ifs should be kept exactly identical between
- c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py */
+ c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py
+ and cffi/_cffi_include.h */
#if defined(_MSC_VER)
# include <malloc.h> /* for alloca() */
# if _MSC_VER < 1600 /* MSVC < 2010 */
@@ -661,11 +662,13 @@
# include <stdint.h>
# endif
# if _MSC_VER < 1800 /* MSVC < 2013 */
- typedef unsigned char _Bool;
+# ifndef __cplusplus
+ typedef unsigned char _Bool;
+# endif
# endif
#else
# include <stdint.h>
-# if (defined (__SVR4) && defined (__sun)) || defined(_AIX)
+# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux)
# include <alloca.h>
# endif
#endif
diff --git a/lib_pypy/stackless.py b/lib_pypy/stackless.py
--- a/lib_pypy/stackless.py
+++ b/lib_pypy/stackless.py
@@ -268,12 +268,22 @@
assert abs(d) == 1
source = getcurrent()
source.tempval = arg
- if d > 0:
- cando = self.balance < 0
- dir = d
- else:
- cando = self.balance > 0
- dir = 0
+ while True:
+ if d > 0:
+ cando = self.balance < 0
+ dir = d
+ else:
+ cando = self.balance > 0
+ dir = 0
+
+ if cando and self.queue[0]._tasklet_killed:
+ # issue #2595: the tasklet was killed while waiting.
+ # drop that tasklet from consideration and try again.
+ self.balance += d
+ self.queue.popleft()
+ else:
+ # normal path
+ break
if _channel_callback is not None:
_channel_callback(self, source, dir, not cando)
@@ -348,6 +358,8 @@
module.
"""
tempval = None
+ _tasklet_killed = False
+
def __new__(cls, func=None, label=''):
res = coroutine.__new__(cls)
res.label = label
@@ -395,6 +407,7 @@
If the exception passes the toplevel frame of the tasklet,
the tasklet will silently die.
"""
+ self._tasklet_killed = True
if not self.is_zombie:
# Killing the tasklet by throwing TaskletExit exception.
coroutine.kill(self)
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -36,7 +36,7 @@
"cStringIO", "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array",
"binascii", "_multiprocessing", '_warnings', "_collections",
"_multibytecodec", "micronumpy", "_continuation", "_cffi_backend",
- "_csv", "cppyy", "_pypyjson", "_jitlog"
+ "_csv", "_cppyy", "_pypyjson", "_jitlog"
])
from rpython.jit.backend import detect_cpu
@@ -67,10 +67,12 @@
if name in translation_modules:
translation_modules.remove(name)
- if "cppyy" in working_modules:
- working_modules.remove("cppyy") # not tested on win32
+ if "_cppyy" in working_modules:
+ working_modules.remove("_cppyy") # not tested on win32
if "faulthandler" in working_modules:
working_modules.remove("faulthandler") # missing details
+ if "_vmprof" in working_modules:
+ working_modules.remove("_vmprof") # FIXME: missing details
# The _locale module is needed by site.py on Windows
default_modules.add("_locale")
@@ -79,8 +81,8 @@
working_modules.remove('fcntl') # LOCK_NB not defined
working_modules.remove("_minimal_curses")
working_modules.remove("termios")
- if "cppyy" in working_modules:
- working_modules.remove("cppyy") # depends on ctypes
+ if "_cppyy" in working_modules:
+ working_modules.remove("_cppyy") # depends on ctypes
#if sys.platform.startswith("linux"):
# _mach = os.popen('uname -m', 'r').read().strip()
@@ -92,7 +94,7 @@
'_multiprocessing': [('objspace.usemodules.time', True),
('objspace.usemodules.thread', True)],
'cpyext': [('objspace.usemodules.array', True)],
- 'cppyy': [('objspace.usemodules.cpyext', True)],
+ '_cppyy': [('objspace.usemodules.cpyext', True)],
'faulthandler': [('objspace.usemodules._vmprof', True)],
}
module_suggests = {
@@ -224,11 +226,6 @@
"use specialised tuples",
default=False),
- BoolOption("withcelldict",
- "use dictionaries that are optimized for being used as module dicts",
- default=False,
- requires=[("objspace.honor__builtins__", False)]),
-
BoolOption("withliststrategies",
"enable optimized ways to store lists of primitives ",
default=True),
@@ -288,7 +285,7 @@
# extra optimizations with the JIT
if level == 'jit':
- config.objspace.std.suggest(withcelldict=True)
+ pass # none at the moment
def enable_allworkingmodules(config):
diff --git a/pypy/doc/build.rst b/pypy/doc/build.rst
--- a/pypy/doc/build.rst
+++ b/pypy/doc/build.rst
@@ -10,6 +10,18 @@
minutes on a fast machine -- and RAM-hungry. You will need **at least** 2 GB
of memory on a 32-bit machine and 4GB on a 64-bit machine.
+Before you start
+----------------
+
+Our normal development workflow avoids a full translation by using test-driven
+development. You can read more about how to develop PyPy here_, and latest
+translated (hopefully functional) binary packages are available on our
+buildbot's `nightly builds`_
+
+.. _here: getting-started-dev.html
+.. _`nightly builds`: http://buildbot.pypy.org/nightly
+
+You will need the build dependencies below to run the tests.
Clone the repository
--------------------
@@ -93,7 +105,8 @@
libsqlite3
curses
- libncurses
+ libncurses-dev (for PyPy2)
+ libncursesw-dev (for PyPy3)
gdbm
libgdbm-dev
@@ -106,12 +119,20 @@
To run untranslated tests, you need the Boehm garbage collector libgc.
-On Debian, this is the command to install all build-time dependencies::
+On recent Debian and Ubuntu (like 17.04), this is the command to install
+all build-time dependencies::
+
+ apt-get install gcc make libffi-dev pkg-config zlib1g-dev libbz2-dev \
+ libsqlite3-dev libncurses5-dev libexpat1-dev libssl-dev libgdbm-dev \
+ tk-dev libgc-dev python-cffi \
+ liblzma-dev libncursesw5-dev # these two only needed on PyPy3
+
+On older Debian and Ubuntu (12.04 to 16.04)::
apt-get install gcc make libffi-dev pkg-config libz-dev libbz2-dev \
libsqlite3-dev libncurses-dev libexpat1-dev libssl-dev libgdbm-dev \
tk-dev libgc-dev python-cffi \
- liblzma-dev # For lzma on PyPy3.
+ liblzma-dev libncursesw-dev # these two only needed on PyPy3
On Fedora::
@@ -138,22 +159,61 @@
Run the translation
-------------------
+We usually translate in the ``pypy/goal`` directory, so all the following
+commands assume your ``$pwd`` is there.
+
Translate with JIT::
- cd pypy/goal
pypy ../../rpython/bin/rpython --opt=jit
Translate without JIT::
- cd pypy/goal
pypy ../../rpython/bin/rpython --opt=2
+Note this translates pypy via the ``targetpypystandalone.py`` file, so these
+are shorthand for::
+
+ pypy ../../rpython/bin/rpython <rpython options> targetpypystandalone.py <pypy options>
+
+More help is availabe via ``--help`` at either option position, and more info
+can be found in the :doc:`config/index` section.
+
(You can use ``python`` instead of ``pypy`` here, which will take longer
but works too.)
-If everything works correctly this will create an executable ``pypy-c`` in the
-current directory. The executable behaves mostly like a normal Python
-interpreter (see :doc:`cpython_differences`).
+If everything works correctly this will:
+
+1. Run the rpython `translation chain`_, producing a database of the
+ entire pypy interpreter. This step is currently singe threaded, and RAM
+ hungry. As part of this step, the chain creates a large number of C code
+ files and a Makefile to compile them in a
+ directory controlled by the ``PYPY_USESSION_DIR`` environment variable.
+2. Create an executable ``pypy-c`` by running the Makefile. This step can
+ utilize all possible cores on the machine.
+3. Copy the needed binaries to the current directory.
+4. Generate c-extension modules for any cffi-based stdlib modules.
+
+
+The resulting executable behaves mostly like a normal Python
+interpreter (see :doc:`cpython_differences`), and is ready for testing, for
+use as a base interpreter for a new virtualenv, or for packaging into a binary
+suitable for installation on another machine running the same OS as the build
+machine.
+
+Note that step 4 is merely done as a convenience, any of the steps may be rerun
+without rerunning the previous steps.
+
+.. _`translation chain`: https://rpython.readthedocs.io/en/latest/translation.html
+
+
+Making a debug build of PyPy
+----------------------------
+
+If the Makefile is rerun with the lldebug or lldebug0 target, appropriate
+compilation flags are added to add debug info and reduce compiler optimizations
+to ``-O0`` respectively. If you stop in a debugger, you will see the
+very wordy machine-generated C code from the rpython translation step, which
+takes a little bit of reading to relate back to the rpython code.
Build cffi import libraries for the stdlib
------------------------------------------
@@ -167,14 +227,6 @@
.. _`out-of-line API mode`: http://cffi.readthedocs.org/en/latest/overview.html#real-example-api-level-out-of-line
-Translating with non-standard options
--------------------------------------
-
-It is possible to have non-standard features enabled for translation,
-but they are not really tested any more. Look, for example, at the
-:doc:`objspace proxies <objspace-proxies>` document.
-
-
Packaging (preparing for installation)
--------------------------------------
@@ -195,6 +247,31 @@
``/tmp/usession-YOURNAME/build/``. You can then either move the file
hierarchy or unpack the ``.tar.bz2`` at the correct place.
+It is recommended to use package.py because custom scripts will
+invariably become out-of-date. If you want to write custom scripts
+anyway, note an easy-to-miss point: some modules are written with CFFI,
+and require some compilation. If you install PyPy as root without
+pre-compiling them, normal users will get errors:
+
+* PyPy 2.5.1 or earlier: normal users would see permission errors.
+ Installers need to run ``pypy -c "import gdbm"`` and other similar
+ commands at install time; the exact list is in
+ :source:`pypy/tool/release/package.py <package.py>`. Users
+ seeing a broken installation of PyPy can fix it after-the-fact if they
+ have sudo rights, by running once e.g. ``sudo pypy -c "import gdbm``.
+
+* PyPy 2.6 and later: anyone would get ``ImportError: no module named
+ _gdbm_cffi``. Installers need to run ``pypy _gdbm_build.py`` in the
+ ``lib_pypy`` directory during the installation process (plus others;
+ see the exact list in :source:`pypy/tool/release/package.py <package.py>`).
+ Users seeing a broken
+ installation of PyPy can fix it after-the-fact, by running ``pypy
+ /path/to/lib_pypy/_gdbm_build.py``. This command produces a file
+ called ``_gdbm_cffi.pypy-41.so`` locally, which is a C extension
+ module for PyPy. You can move it at any place where modules are
+ normally found: e.g. in your project's main directory, or in a
+ directory that you add to the env var ``PYTHONPATH``.
+
Installation
------------
diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py
--- a/pypy/doc/conf.py
+++ b/pypy/doc/conf.py
@@ -59,16 +59,16 @@
# General information about the project.
project = u'PyPy'
-copyright = u'2016, The PyPy Project'
+copyright = u'2017, The PyPy Project'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
-version = '5.4'
+version = '5.8'
# The full version, including alpha/beta/rc tags.
-release = '5.4.0'
+release = '5.8.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/pypy/doc/config/objspace.std.withcelldict.txt b/pypy/doc/config/objspace.std.withcelldict.txt
deleted file mode 100644
--- a/pypy/doc/config/objspace.std.withcelldict.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Enable cell-dicts. This optimization is not helpful without the JIT. In the
-presence of the JIT, it greatly helps looking up globals.
diff --git a/pypy/doc/configuration.rst b/pypy/doc/configuration.rst
--- a/pypy/doc/configuration.rst
+++ b/pypy/doc/configuration.rst
@@ -188,4 +188,6 @@
can be found on the ``config`` attribute of all ``TranslationContext``
instances and are described in :source:`rpython/config/translationoption.py`. The interpreter options
are attached to the object space, also under the name ``config`` and are
-described in :source:`pypy/config/pypyoption.py`.
+described in :source:`pypy/config/pypyoption.py`. Both set of options are
+documented in the :doc:`config/index` section.
+
diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst
deleted file mode 100644
--- a/pypy/doc/cppyy.rst
+++ /dev/null
@@ -1,672 +0,0 @@
-cppyy: C++ bindings for PyPy
-============================
-
-The cppyy module delivers dynamic Python-C++ bindings.
-It is designed for automation, high performance, scale, interactivity, and
-handling all of modern C++ (11, 14, etc.).
-It is based on `Cling`_ which, through `LLVM`_/`clang`_, provides C++
-reflection and interactivity.
-Reflection information is extracted from C++ header files.
-Cppyy itself is built into PyPy (an alternative exists for CPython), but
-it requires a `backend`_, installable through pip, to interface with Cling.
-
-.. _Cling: https://root.cern.ch/cling
-.. _LLVM: http://llvm.org/
-.. _clang: http://clang.llvm.org/
-.. _backend: https://pypi.python.org/pypi/PyPy-cppyy-backend
-
-
-Installation
-------------
-
-This assumes PyPy2.7 v5.7 or later; earlier versions use a Reflex-based cppyy
-module, which is no longer supported.
-Both the tooling and user-facing Python codes are very backwards compatible,
-however.
-Further dependencies are cmake (for general build), Python2.7 (for LLVM), and
-a modern C++ compiler (one that supports at least C++11).
-
-Assuming you have a recent enough version of PyPy installed, use pip to
-complete the installation of cppyy::
-
- $ MAKE_NPROCS=4 pypy-c -m pip install --verbose PyPy-cppyy-backend
-
-Set the number of parallel builds ('4' in this example, through the MAKE_NPROCS
-environment variable) to a number appropriate for your machine.
-The building process may take quite some time as it includes a customized
-version of LLVM as part of Cling, which is why --verbose is recommended so that
-you can see the build progress.
-
-The default installation will be under
-$PYTHONHOME/site-packages/cppyy_backend/lib,
-which needs to be added to your dynamic loader path (LD_LIBRARY_PATH).
-If you need the dictionary and class map generation tools (used in the examples
-below), you need to add $PYTHONHOME/site-packages/cppyy_backend/bin to your
-executable path (PATH).
-
-
-Basic bindings example
-----------------------
-
-These examples assume that cppyy_backend is pointed to by the environment
-variable CPPYYHOME, and that CPPYYHOME/lib is added to LD_LIBRARY_PATH and
-CPPYYHOME/bin to PATH.
-
-Let's first test with a trivial example whether all packages are properly
-installed and functional.
-Create a C++ header file with some class in it (all functions are made inline
-for convenience; if you have out-of-line code, link with it as appropriate)::
-
- $ cat MyClass.h
- class MyClass {
- public:
- MyClass(int i = -99) : m_myint(i) {}
-
- int GetMyInt() { return m_myint; }
- void SetMyInt(int i) { m_myint = i; }
-
- public:
- int m_myint;
- };
-
-Then, generate the bindings using ``genreflex`` (installed under
-cppyy_backend/bin in site_packages), and compile the code::
-
- $ genreflex MyClass.h
- $ g++ -std=c++11 -fPIC -rdynamic -O2 -shared -I$CPPYYHOME/include MyClass_rflx.cpp -o libMyClassDict.so -L$CPPYYHOME/lib -lCling
-
-Next, make sure that the library can be found through the dynamic lookup path
More information about the pypy-commit
mailing list