[pypy-commit] pypy fix-result-types: hg merge default

rlamy noreply at buildbot.pypy.org
Fri May 29 16:17:59 CEST 2015


Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: fix-result-types
Changeset: r77691:af369ce9b273
Date: 2015-05-29 15:17 +0100
http://bitbucket.org/pypy/pypy/changeset/af369ce9b273/

Log:	hg merge default

diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -11,3 +11,5 @@
 10f1b29a2bd21f837090286174a9ca030b8680b2 release-2.5.0
 9c4588d731b7fe0b08669bd732c2b676cb0a8233 release-2.5.1
 fcdb941565156385cbac04cfb891f8f4c7a92ef6 release-2.6.0
+fcdb941565156385cbac04cfb891f8f4c7a92ef6 release-2.6.0
+e03971291f3a0729ecd3ee7fae7ddb0bb82d476c release-2.6.0
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
@@ -505,7 +505,7 @@
                             "modules")
         mkpath(tmpdir)
         ext, updated = recompile(self, module_name,
-                                 source, tmpdir=tmpdir,
+                                 source, tmpdir=tmpdir, extradir=tmpdir,
                                  source_extension=source_extension,
                                  call_c_compiler=False, **kwds)
         if verbose:
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
@@ -52,6 +52,7 @@
 OP_CONSTANT_INT    = 31
 OP_GLOBAL_VAR      = 33
 OP_DLOPEN_FUNC     = 35
+OP_DLOPEN_CONST    = 37
 
 PRIM_VOID          = 0
 PRIM_BOOL          = 1
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
@@ -25,6 +25,7 @@
 #define _CFFI_OP_CONSTANT_INT   31
 #define _CFFI_OP_GLOBAL_VAR     33
 #define _CFFI_OP_DLOPEN_FUNC    35
+#define _CFFI_OP_DLOPEN_CONST   37
 
 #define _CFFI_PRIM_VOID          0
 #define _CFFI_PRIM_BOOL          1
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
@@ -11,7 +11,7 @@
 
 
 class GlobalExpr:
-    def __init__(self, name, address, type_op, size=0, check_value=None):
+    def __init__(self, name, address, type_op, size=0, check_value=0):
         self.name = name
         self.address = address
         self.type_op = type_op
@@ -23,11 +23,6 @@
             self.name, self.address, self.type_op.as_c_expr(), self.size)
 
     def as_python_expr(self):
-        if not isinstance(self.check_value, int_type):
-            raise ffiplatform.VerificationError(
-                "ffi.dlopen() will not be able to figure out the value of "
-                "constant %r (only integer constants are supported, and only "
-                "if their value are specified in the cdef)" % (self.name,))
         return "b'%s%s',%d" % (self.type_op.as_python_bytes(), self.name,
                                self.check_value)
 
@@ -747,7 +742,7 @@
             meth_kind = OP_CPYTHON_BLTN_V   # 'METH_VARARGS'
         self._lsts["global"].append(
             GlobalExpr(name, '_cffi_f_%s' % name,
-                       CffiOp(meth_kind, type_index), check_value=0,
+                       CffiOp(meth_kind, type_index),
                        size='_cffi_d_%s' % name))
 
     # ----------
@@ -971,7 +966,7 @@
 
     def _generate_cpy_constant_collecttype(self, tp, name):
         is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type()
-        if not is_int:
+        if not is_int or self.target_is_python:
             self._do_collect_type(tp)
 
     def _generate_cpy_constant_decl(self, tp, name):
@@ -979,11 +974,20 @@
         self._generate_cpy_const(is_int, name, tp)
 
     def _generate_cpy_constant_ctx(self, tp, name):
-        if isinstance(tp, model.PrimitiveType) and tp.is_integer_type():
+        if (not self.target_is_python and
+                isinstance(tp, model.PrimitiveType) and tp.is_integer_type()):
             type_op = CffiOp(OP_CONSTANT_INT, -1)
         else:
+            if not tp.sizeof_enabled():
+                raise ffiplatform.VerificationError(
+                    "constant '%s' is of type '%s', whose size is not known"
+                    % (name, tp._get_c_name()))
+            if self.target_is_python:
+                const_kind = OP_DLOPEN_CONST
+            else:
+                const_kind = OP_CONSTANT
             type_index = self._typesdict[tp]
-            type_op = CffiOp(OP_CONSTANT, type_index)
+            type_op = CffiOp(const_kind, type_index)
         self._lsts["global"].append(
             GlobalExpr(name, '_cffi_const_%s' % name, type_op))
 
@@ -1034,6 +1038,10 @@
 
     def _generate_cpy_macro_ctx(self, tp, name):
         if tp == '...':
+            if self.target_is_python:
+                raise ffiplatform.VerificationError(
+                    "cannot use the syntax '...' in '#define %s ...' when "
+                    "using the ABI mode" % (name,))
             check_value = None
         else:
             check_value = tp     # an integer
@@ -1066,7 +1074,7 @@
         else:
             size = 0
         self._lsts["global"].append(
-            GlobalExpr(name, '&%s' % name, type_op, size, 0))
+            GlobalExpr(name, '&%s' % name, type_op, size))
 
     # ----------
     # emitting the opcodes for individual types
@@ -1148,8 +1156,14 @@
                 raise IOError
         return False     # already up-to-date
     except IOError:
-        with open(target_file, 'w') as f1:
+        tmp_file = '%s.~%d' % (target_file, os.getpid())
+        with open(tmp_file, 'w') as f1:
             f1.write(output)
+        try:
+            os.rename(tmp_file, target_file)
+        except OSError:
+            os.unlink(target_file)
+            os.rename(tmp_file, target_file)
         return True
 
 def make_c_source(ffi, module_name, preamble, target_c_file):
@@ -1159,29 +1173,45 @@
 def make_py_source(ffi, module_name, target_py_file):
     return _make_c_or_py_source(ffi, module_name, None, target_py_file)
 
-def _get_extension(module_name, c_file, kwds):
-    source_name = ffiplatform.maybe_relative_path(c_file)
-    return ffiplatform.get_extension(source_name, module_name, **kwds)
+def _modname_to_file(outputdir, modname, extension):
+    parts = modname.split('.')
+    try:
+        os.makedirs(os.path.join(outputdir, *parts[:-1]))
+    except OSError:
+        pass
+    parts[-1] += extension
+    return os.path.join(outputdir, *parts), parts
 
 def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True,
-              c_file=None, source_extension='.c', **kwds):
+              c_file=None, source_extension='.c', extradir=None, **kwds):
     if not isinstance(module_name, str):
         module_name = module_name.encode('ascii')
     if ffi._windows_unicode:
         ffi._apply_windows_unicode(kwds)
     if preamble is not None:
         if c_file is None:
-            c_file = os.path.join(tmpdir, module_name + source_extension)
-        ext = _get_extension(module_name, c_file, kwds)
+            c_file, parts = _modname_to_file(tmpdir, module_name,
+                                             source_extension)
+            if extradir:
+                parts = [extradir] + parts
+            ext_c_file = os.path.join(*parts)
+        else:
+            ext_c_file = c_file
+        ext = ffiplatform.get_extension(ext_c_file, module_name, **kwds)
         updated = make_c_source(ffi, module_name, preamble, c_file)
         if call_c_compiler:
-            outputfilename = ffiplatform.compile(tmpdir, ext)
+            cwd = os.getcwd()
+            try:
+                os.chdir(tmpdir)
+                outputfilename = ffiplatform.compile('.', ext)
+            finally:
+                os.chdir(cwd)
             return outputfilename
         else:
             return ext, updated
     else:
         if c_file is None:
-            c_file = os.path.join(tmpdir, module_name + '.py')
+            c_file, _ = _modname_to_file(tmpdir, module_name, '.py')
         updated = make_py_source(ffi, module_name, c_file)
         if call_c_compiler:
             return c_file
diff --git a/lib_pypy/cffi/setuptools_ext.py b/lib_pypy/cffi/setuptools_ext.py
--- a/lib_pypy/cffi/setuptools_ext.py
+++ b/lib_pypy/cffi/setuptools_ext.py
@@ -108,13 +108,11 @@
 def _add_py_module(dist, ffi, module_name):
     from distutils.dir_util import mkpath
     from distutils.command.build_py import build_py
+    from distutils.command.build_ext import build_ext
     from distutils import log
     from cffi import recompiler
 
-    def make_mod(tmpdir):
-        module_path = module_name.split('.')
-        module_path[-1] += '.py'
-        py_file = os.path.join(tmpdir, *module_path)
+    def generate_mod(py_file):
         log.info("generating cffi module %r" % py_file)
         mkpath(os.path.dirname(py_file))
         updated = recompiler.make_py_source(ffi, module_name, py_file)
@@ -125,9 +123,25 @@
     class build_py_make_mod(base_class):
         def run(self):
             base_class.run(self)
-            make_mod(self.build_lib)
+            module_path = module_name.split('.')
+            module_path[-1] += '.py'
+            generate_mod(os.path.join(self.build_lib, *module_path))
     dist.cmdclass['build_py'] = build_py_make_mod
 
+    # the following is only for "build_ext -i"
+    base_class_2 = dist.cmdclass.get('build_ext', build_ext)
+    class build_ext_make_mod(base_class_2):
+        def run(self):
+            base_class_2.run(self)
+            if self.inplace:
+                # from get_ext_fullpath() in distutils/command/build_ext.py
+                module_path = module_name.split('.')
+                package = '.'.join(module_path[:-1])
+                build_py = self.get_finalized_command('build_py')
+                package_dir = build_py.get_package_dir(package)
+                file_name = module_path[-1] + '.py'
+                generate_mod(os.path.join(package_dir, file_name))
+    dist.cmdclass['build_ext'] = build_ext_make_mod
 
 def cffi_modules(dist, attr, value):
     assert attr == 'cffi_modules'
diff --git a/lib_pypy/datetime.py b/lib_pypy/datetime.py
--- a/lib_pypy/datetime.py
+++ b/lib_pypy/datetime.py
@@ -816,9 +816,9 @@
             _MONTHNAMES[self._month],
             self._day, self._year)
 
-    def strftime(self, fmt):
+    def strftime(self, format):
         "Format using strftime()."
-        return _wrap_strftime(self, fmt, self.timetuple())
+        return _wrap_strftime(self, format, self.timetuple())
 
     def __format__(self, fmt):
         if not isinstance(fmt, (str, unicode)):
@@ -1308,7 +1308,7 @@
 
     __str__ = isoformat
 
-    def strftime(self, fmt):
+    def strftime(self, format):
         """Format using strftime().  The date part of the timestamp passed
         to underlying strftime should not be used.
         """
@@ -1317,7 +1317,7 @@
         timetuple = (1900, 1, 1,
                      self._hour, self._minute, self._second,
                      0, 1, -1)
-        return _wrap_strftime(self, fmt, timetuple)
+        return _wrap_strftime(self, format, timetuple)
 
     def __format__(self, fmt):
         if not isinstance(fmt, (str, unicode)):
@@ -1497,7 +1497,7 @@
         return self._tzinfo
 
     @classmethod
-    def fromtimestamp(cls, t, tz=None):
+    def fromtimestamp(cls, timestamp, tz=None):
         """Construct a datetime from a POSIX timestamp (like time.time()).
 
         A timezone info object may be passed in as well.
@@ -1507,12 +1507,12 @@
 
         converter = _time.localtime if tz is None else _time.gmtime
 
-        if isinstance(t, int):
+        if isinstance(timestamp, int):
             us = 0
         else:
-            t_full = t
-            t = int(_math.floor(t))
-            frac = t_full - t
+            t_full = timestamp
+            timestamp = int(_math.floor(timestamp))
+            frac = t_full - timestamp
             us = _round(frac * 1e6)
 
         # If timestamp is less than one microsecond smaller than a
@@ -1520,9 +1520,9 @@
         # roll over to seconds, otherwise, ValueError is raised
         # by the constructor.
         if us == 1000000:
-            t += 1
+            timestamp += 1
             us = 0
-        y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
+        y, m, d, hh, mm, ss, weekday, jday, dst = converter(timestamp)
         ss = min(ss, 59)    # clamp out leap seconds if the platform has them
         result = cls(y, m, d, hh, mm, ss, us, tz)
         if tz is not None:
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -321,7 +321,7 @@
 
 
 def enable_allworkingmodules(config):
-    modules = working_modules
+    modules = working_modules.copy()
     if config.translation.sandbox:
         modules = default_modules
     # ignore names from 'essential_modules', notably 'exceptions', which
diff --git a/pypy/doc/config/objspace.usemodules._vmprof.txt b/pypy/doc/config/objspace.usemodules._vmprof.txt
new file mode 100644
diff --git a/pypy/doc/config/translation.icon.txt b/pypy/doc/config/translation.icon.txt
new file mode 100644
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
@@ -364,6 +364,18 @@
   wrappers.  On PyPy we can't tell the difference, so
   ``ismethod([].__add__) == ismethod(list.__add__) == True``.
 
+* in pure Python, if you write ``class A(object): def f(self): pass``
+  and have a subclass ``B`` which doesn't override ``f()``, then
+  ``B.f(x)`` still checks that ``x`` is an instance of ``B``.  In
+  CPython, types written in C use a different rule.  If ``A`` is
+  written in C, any instance of ``A`` will be accepted by ``B.f(x)``
+  (and actually, ``B.f is A.f`` in this case).  Some code that could
+  work on CPython but not on PyPy includes:
+  ``datetime.datetime.strftime(datetime.date.today(), ...)`` (here,
+  ``datetime.date`` is the superclass of ``datetime.datetime``).
+  Anyway, the proper fix is arguably to use a regular method call in
+  the first place: ``datetime.date.today().strftime(...)``
+
 * the ``__dict__`` attribute of new-style classes returns a normal dict, as
   opposed to a dict proxy like in CPython. Mutating the dict will change the
   type and vice versa. For builtin types, a dictionary will be returned that
diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst
--- a/pypy/doc/how-to-release.rst
+++ b/pypy/doc/how-to-release.rst
@@ -16,40 +16,44 @@
 -------------
 
 * At code freeze make a release branch using release-x.x.x in mercurial
-  Bump the
+  and add a release-specific tag
+* Bump the
   pypy version number in module/sys/version.py and in
-  module/cpyext/include/patchlevel.h. The branch
+  module/cpyext/include/patchlevel.h and . The branch
   will capture the revision number of this change for the release.
+
   Some of the next updates may be done before or after branching; make
   sure things are ported back to the trunk and to the branch as
-  necessary; also update the version number in pypy/doc/conf.py.
+  necessary.
 * update pypy/doc/contributor.rst (and possibly LICENSE)
   pypy/doc/tool/makecontributor.py generates the list of contributors
 * rename pypy/doc/whatsnew_head.rst to whatsnew_VERSION.rst
   create a fresh whatsnew_head.rst after the release
   and add the new file to  pypy/doc/index-of-whatsnew.rst
-* go to pypy/tool/release and run:
-  force-builds.py <release branch>
-
-  The following binaries should be built, however, we need more buildbots:
-    JIT: windows, linux, os/x, armhf, armel
-    no JIT: windows, linux, os/x
-    sandbox: linux, os/x
+* go to pypy/tool/release and run
+  ``force-builds.py <release branch>``
+  The following binaries should be built, however, we need more buildbots
+ - JIT: windows, linux, os/x, armhf, armel
+ - no JIT: windows, linux, os/x
+ - sandbox: linux, os/x
 
 * wait for builds to complete, make sure there are no failures
 * download the builds, repackage binaries. Tag the release version
   and download and repackage source from bitbucket. You may find it
-  convenient to use the repackage.sh script in pypy/tools to do this. 
-  Otherwise, repackage and upload source "-src.tar.bz2" to bitbucket
+  convenient to use the ``repackage.sh`` script in pypy/tools to do this. 
+
+  Otherwise repackage and upload source "-src.tar.bz2" to bitbucket
   and to cobra, as some packagers prefer a clearly labeled source package
- (download e.g.  https://bitbucket.org/pypy/pypy/get/release-2.5.x.tar.bz2,
+  ( download e.g.  https://bitbucket.org/pypy/pypy/get/release-2.5.x.tar.bz2,
   unpack, rename the top-level directory to "pypy-2.5.0-src", repack, and upload)
 
 * Upload binaries to https://bitbucket.org/pypy/pypy/downloads
 
 * write release announcement pypy/doc/release-x.y(.z).txt
-  the release announcement should contain a direct link to the download page
-  and add new files to  pypy/doc/index-of-release-notes.rst
+
+  The release announcement should contain a direct link to the download page
+
+* Add the new files to  pypy/doc/index-of-{whatsnew,release-notes}.rst
 
 * update pypy.org (under extradoc/pypy.org), rebuild and commit
 
@@ -59,4 +63,5 @@
 
 * add a tag on the pypy/jitviewer repo that corresponds to pypy release
 * add a tag on the codespeed web site that corresponds to pypy release
+* update the version number in {rpython,pypy}/doc/conf.py.
 * revise versioning at https://readthedocs.org/projects/pypy
diff --git a/pypy/module/_cffi_backend/cffi_opcode.py b/pypy/module/_cffi_backend/cffi_opcode.py
--- a/pypy/module/_cffi_backend/cffi_opcode.py
+++ b/pypy/module/_cffi_backend/cffi_opcode.py
@@ -52,6 +52,7 @@
 OP_CONSTANT_INT    = 31
 OP_GLOBAL_VAR      = 33
 OP_DLOPEN_FUNC     = 35
+OP_DLOPEN_CONST    = 37
 
 PRIM_VOID          = 0
 PRIM_BOOL          = 1
diff --git a/pypy/module/_cffi_backend/lib_obj.py b/pypy/module/_cffi_backend/lib_obj.py
--- a/pypy/module/_cffi_backend/lib_obj.py
+++ b/pypy/module/_cffi_backend/lib_obj.py
@@ -122,18 +122,26 @@
                 w_result = realize_c_type.realize_global_int(self.ffi, g,
                                                              index)
                 #
-            elif op == cffi_opcode.OP_CONSTANT:
+            elif (op == cffi_opcode.OP_CONSTANT or
+                  op == cffi_opcode.OP_DLOPEN_CONST):
                 # A constant which is not of integer type
                 w_ct = realize_c_type.realize_c_type(
                     self.ffi, self.ctx.c_types, getarg(g.c_type_op))
                 fetch_funcptr = rffi.cast(
                     realize_c_type.FUNCPTR_FETCH_CHARP,
                     g.c_address)
-                assert fetch_funcptr
-                assert w_ct.size > 0
-                with lltype.scoped_alloc(rffi.CCHARP.TO, w_ct.size) as ptr:
+                if w_ct.size <= 0:
+                    raise oefmt(space.w_SystemError,
+                                "constant has no known size")
+                if not fetch_funcptr:   # for dlopen() style
+                    assert op == cffi_opcode.OP_DLOPEN_CONST
+                    ptr = self.cdlopen_fetch(attr)
+                else:
+                    assert op == cffi_opcode.OP_CONSTANT
+                    ptr = lltype.malloc(rffi.CCHARP.TO, w_ct.size, flavor='raw')
+                    self.ffi._finalizer.free_mems.append(ptr)
                     fetch_funcptr(ptr)
-                    w_result = w_ct.convert_to_object(ptr)
+                w_result = w_ct.convert_to_object(ptr)
                 #
             elif op == cffi_opcode.OP_DLOPEN_FUNC:
                 # For dlopen(): the function of the given 'name'.  We use
diff --git a/pypy/module/_cffi_backend/test/test_re_python.py b/pypy/module/_cffi_backend/test/test_re_python.py
--- a/pypy/module/_cffi_backend/test/test_re_python.py
+++ b/pypy/module/_cffi_backend/test/test_re_python.py
@@ -22,6 +22,8 @@
         #define BIGNEG -420000000000L
         int add42(int x) { return x + 42; }
         int globalvar42 = 1234;
+        const int globalconst42 = 4321;
+        const char *const globalconsthello = "hello";
         struct foo_s;
         typedef struct bar_s { int x; signed char a[]; } bar_t;
         enum foo_e { AA, BB, CC };
@@ -34,7 +36,8 @@
         c_file = tmpdir.join('_test_re_python.c')
         c_file.write(SRC)
         ext = ffiplatform.get_extension(str(c_file), '_test_re_python',
-                                        export_symbols=['add42', 'globalvar42'])
+            export_symbols=['add42', 'globalvar42',
+                            'globalconst42', 'globalconsthello'])
         outputfilename = ffiplatform.compile(str(tmpdir), ext)
         cls.w_extmod = space.wrap(outputfilename)
         #mod.tmpdir = tmpdir
@@ -47,6 +50,8 @@
         #define BIGNEG -420000000000L
         int add42(int);
         int globalvar42;
+        const int globalconst42;
+        const char *const globalconsthello = "hello";
         int no_such_function(int);
         int no_such_globalvar;
         struct foo_s;
@@ -157,6 +162,18 @@
         p[0] -= 1
         assert lib.globalvar42 == 1238
 
+    def test_global_const_int(self):
+        from re_python_pysrc import ffi
+        lib = ffi.dlopen(self.extmod)
+        assert lib.globalconst42 == 4321
+        raises(AttributeError, ffi.addressof, lib, 'globalconst42')
+
+    def test_global_const_nonint(self):
+        from re_python_pysrc import ffi
+        lib = ffi.dlopen(self.extmod)
+        assert ffi.string(lib.globalconsthello, 8) == "hello"
+        raises(AttributeError, ffi.addressof, lib, 'globalconsthello')
+
     def test_rtld_constants(self):
         from re_python_pysrc import ffi
         ffi.RTLD_NOW    # check that we have the attributes
diff --git a/pypy/module/_cffi_backend/test/test_recompiler.py b/pypy/module/_cffi_backend/test/test_recompiler.py
--- a/pypy/module/_cffi_backend/test/test_recompiler.py
+++ b/pypy/module/_cffi_backend/test/test_recompiler.py
@@ -7,7 +7,8 @@
 
 
 @unwrap_spec(cdef=str, module_name=str, source=str)
-def prepare(space, cdef, module_name, source, w_includes=None):
+def prepare(space, cdef, module_name, source, w_includes=None,
+            w_extra_source=None):
     try:
         import cffi
         from cffi import FFI            # <== the system one, which
@@ -45,9 +46,13 @@
     ffi.emit_c_code(c_file)
 
     base_module_name = module_name.split('.')[-1]
+    sources = []
+    if w_extra_source is not None:
+        sources.append(space.str_w(w_extra_source))
     ext = ffiplatform.get_extension(c_file, module_name,
             include_dirs=[str(rdir)],
-            export_symbols=['_cffi_pypyinit_' + base_module_name])
+            export_symbols=['_cffi_pypyinit_' + base_module_name],
+            sources=sources)
     ffiplatform.compile(str(rdir), ext)
 
     for extension in ['so', 'pyd', 'dylib']:
@@ -66,6 +71,9 @@
     """)
     ffiobject = space.getitem(w_res, space.wrap(0))
     ffiobject._test_recompiler_source_ffi = ffi
+    if not hasattr(space, '_cleanup_ffi'):
+        space._cleanup_ffi = []
+    space._cleanup_ffi.append(ffiobject)
     return w_res
 
 
@@ -76,6 +84,8 @@
         if cls.runappdirect:
             py.test.skip("not a test for -A")
         cls.w_prepare = cls.space.wrap(interp2app(prepare))
+        cls.w_udir = cls.space.wrap(str(udir))
+        cls.w_os_sep = cls.space.wrap(os.sep)
 
     def setup_method(self, meth):
         self._w_modules = self.space.appexec([], """():
@@ -84,6 +94,10 @@
         """)
 
     def teardown_method(self, meth):
+        if hasattr(self.space, '_cleanup_ffi'):
+            for ffi in self.space._cleanup_ffi:
+                del ffi.cached_types     # try to prevent cycles
+            del self.space._cleanup_ffi
         self.space.appexec([self._w_modules], """(old_modules):
             import sys
             for key in sys.modules.keys():
@@ -799,3 +813,73 @@
         assert addr(0xABC05) == 47
         assert isinstance(addr, ffi.CData)
         assert ffi.typeof(addr) == ffi.typeof("long(*)(long)")
+
+    def test_issue198(self):
+        ffi, lib = self.prepare("""
+            typedef struct{...;} opaque_t;
+            const opaque_t CONSTANT;
+            int toint(opaque_t);
+        """, 'test_issue198', """
+            typedef int opaque_t;
+            #define CONSTANT ((opaque_t)42)
+            static int toint(opaque_t o) { return o; }
+        """)
+        def random_stuff():
+            pass
+        assert lib.toint(lib.CONSTANT) == 42
+        random_stuff()
+        assert lib.toint(lib.CONSTANT) == 42
+
+    def test_constant_is_not_a_compiler_constant(self):
+        ffi, lib = self.prepare(
+            "static const float almost_forty_two;",
+            'test_constant_is_not_a_compiler_constant', """
+                static float f(void) { return 42.25; }
+                #define almost_forty_two (f())
+            """)
+        assert lib.almost_forty_two == 42.25
+
+    def test_variable_of_unknown_size(self):
+        ffi, lib = self.prepare("""
+            typedef ... opaque_t;
+            opaque_t globvar;
+        """, 'test_constant_of_unknown_size', """
+            typedef char opaque_t[6];
+            opaque_t globvar = "hello";
+        """)
+        # can't read or write it at all
+        e = raises(TypeError, getattr, lib, 'globvar')
+        assert str(e.value) == "'opaque_t' is opaque or not completed yet"
+        e = raises(TypeError, setattr, lib, 'globvar', [])
+        assert str(e.value) == "'opaque_t' is opaque or not completed yet"
+        # but we can get its address
+        p = ffi.addressof(lib, 'globvar')
+        assert ffi.typeof(p) == ffi.typeof('opaque_t *')
+        assert ffi.string(ffi.cast("char *", p), 8) == "hello"
+
+    def test_constant_of_value_unknown_to_the_compiler(self):
+        extra_c_source = self.udir + self.os_sep + (
+            'extra_test_constant_of_value_unknown_to_the_compiler.c')
+        with open(extra_c_source, 'w') as f:
+            f.write('const int external_foo = 42;\n')
+        ffi, lib = self.prepare(
+            "const int external_foo;",
+            'test_constant_of_value_unknown_to_the_compiler',
+            "extern const int external_foo;",
+            extra_source=extra_c_source)
+        assert lib.external_foo == 42
+
+    def test_call_with_incomplete_structs(self):
+        ffi, lib = self.prepare(
+            "typedef struct {...;} foo_t; "
+            "foo_t myglob; "
+            "foo_t increment(foo_t s); "
+            "double getx(foo_t s);",
+            'test_call_with_incomplete_structs', """
+            typedef double foo_t;
+            double myglob = 42.5;
+            double getx(double x) { return x; }
+            double increment(double x) { return x + 1; }
+        """)
+        assert lib.getx(lib.myglob) == 42.5
+        assert lib.getx(lib.increment(lib.myglob)) == 43.5
diff --git a/pypy/module/_vmprof/src/fake_pypy_api.c b/pypy/module/_vmprof/src/fake_pypy_api.c
--- a/pypy/module/_vmprof/src/fake_pypy_api.c
+++ b/pypy/module/_vmprof/src/fake_pypy_api.c
@@ -1,21 +1,4 @@
-
-long pypy_jit_stack_depth_at_loc(long x)
-{
-	return 0;
-}
-
-void *pypy_find_codemap_at_addr(long x)
-{
-	return (void *)0;
-}
-
-long pypy_yield_codemap_at_addr(void *x, long y, long *a)
-{
-	return 0;
-}
 
 void pypy_pyframe_execute_frame(void)
 {
 }
-
-volatile int pypy_codemap_currently_invalid = 0;
diff --git a/pypy/module/_vmprof/src/get_custom_offset.c b/pypy/module/_vmprof/src/get_custom_offset.c
--- a/pypy/module/_vmprof/src/get_custom_offset.c
+++ b/pypy/module/_vmprof/src/get_custom_offset.c
@@ -1,3 +1,5 @@
+
+#ifdef PYPY_JIT_CODEMAP
 
 extern volatile int pypy_codemap_currently_invalid;
 
@@ -6,6 +8,8 @@
                                 long *current_pos_addr);
 long pypy_jit_stack_depth_at_loc(long loc);
 
+#endif
+
 
 void vmprof_set_tramp_range(void* start, void* end)
 {
@@ -13,17 +17,26 @@
 
 int custom_sanity_check()
 {
+#ifdef PYPY_JIT_CODEMAP
     return !pypy_codemap_currently_invalid;
+#else
+    return 1;
+#endif
 }
 
 static ptrdiff_t vmprof_unw_get_custom_offset(void* ip, void *cp) {
+#ifdef PYPY_JIT_CODEMAP
     intptr_t ip_l = (intptr_t)ip;
     return pypy_jit_stack_depth_at_loc(ip_l);
+#else
+    return 0;
+#endif
 }
 
 static long vmprof_write_header_for_jit_addr(void **result, long n,
                                              void *ip, int max_depth)
 {
+#ifdef PYPY_JIT_CODEMAP
     void *codemap;
     long current_pos = 0;
     intptr_t id;
@@ -62,5 +75,6 @@
     if (n < max_depth) {
         result[n++] = (void*)3;
     }
+#endif
     return n;
 }
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_dlopen.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_dlopen.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_dlopen.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_dlopen.py
@@ -20,27 +20,20 @@
 )
 """
 
-def test_invalid_global_constant():
+def test_global_constant():
     ffi = FFI()
-    ffi.cdef("static const int BB;")
-    target = udir.join('test_invalid_global_constants.py')
-    e = py.test.raises(VerificationError, make_py_source, ffi,
-                       'test_invalid_global_constants', str(target))
-    assert str(e.value) == (
-        "ffi.dlopen() will not be able to figure out "
-        "the value of constant 'BB' (only integer constants are "
-        "supported, and only if their value are specified in the cdef)")
+    ffi.cdef("static const long BB; static const float BF = 12;")
+    target = udir.join('test_valid_global_constant.py')
+    make_py_source(ffi, 'test_valid_global_constant', str(target))
+    assert target.read() == r"""# auto-generated file
+import _cffi_backend
 
-def test_invalid_global_constant_2():
-    ffi = FFI()
-    ffi.cdef("static const float BB = 12;")
-    target = udir.join('test_invalid_global_constants_2.py')
-    e = py.test.raises(VerificationError, make_py_source, ffi,
-                       'test_invalid_global_constants_2', str(target))
-    assert str(e.value) == (
-        "ffi.dlopen() will not be able to figure out "
-        "the value of constant 'BB' (only integer constants are "
-        "supported, and only if their value are specified in the cdef)")
+ffi = _cffi_backend.FFI('test_valid_global_constant',
+    _version = 0x2601,
+    _types = b'\x00\x00\x0D\x01\x00\x00\x09\x01',
+    _globals = (b'\x00\x00\x01\x25BB',0,b'\x00\x00\x00\x25BF',0),
+)
+"""
 
 def test_invalid_global_constant_3():
     ffi = FFI()
@@ -54,10 +47,8 @@
     target = udir.join('test_invalid_dotdotdot_in_macro.py')
     e = py.test.raises(VerificationError, make_py_source, ffi,
                        'test_invalid_dotdotdot_in_macro', str(target))
-    assert str(e.value) == (
-        "ffi.dlopen() will not be able to figure out "
-        "the value of constant 'FOO' (only integer constants are "
-        "supported, and only if their value are specified in the cdef)")
+    assert str(e.value) == ("macro FOO: cannot use the syntax '...' in "
+                            "'#define FOO ...' when using the ABI mode")
 
 def test_typename():
     ffi = FFI()
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_re_python.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_re_python.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_re_python.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_re_python.py
@@ -15,6 +15,8 @@
     int add42(int x) { return x + 42; }
     int add43(int x, ...) { return x; }
     int globalvar42 = 1234;
+    const int globalconst42 = 4321;
+    const char *const globalconsthello = "hello";
     struct foo_s;
     typedef struct bar_s { int x; signed char a[]; } bar_t;
     enum foo_e { AA, BB, CC };
@@ -29,7 +31,8 @@
     ext = ffiplatform.get_extension(
         str(c_file),
         '_test_re_python',
-        export_symbols=['add42', 'add43', 'globalvar42']
+        export_symbols=['add42', 'add43', 'globalvar42',
+                        'globalconst42', 'globalconsthello']
     )
     outputfilename = ffiplatform.compile(str(tmpdir), ext)
     mod.extmod = outputfilename
@@ -44,6 +47,8 @@
     int add42(int);
     int add43(int, ...);
     int globalvar42;
+    const int globalconst42;
+    const char *const globalconsthello = "hello";
     int no_such_function(int);
     int no_such_globalvar;
     struct foo_s;
@@ -127,6 +132,10 @@
     sub_ffi.set_source('re_python_pysrc', None)
     sub_ffi.emit_python_code(str(tmpdir.join('_re_include_1.py')))
     #
+    if sys.version_info[:2] >= (3, 3):
+        import importlib
+        importlib.invalidate_caches()  # issue 197 (but can't reproduce myself)
+    #
     from _re_include_1 import ffi
     assert ffi.integer_const('FOOBAR') == -42
     assert ffi.integer_const('FOOBAZ') == -43
@@ -149,6 +158,18 @@
     p[0] -= 1
     assert lib.globalvar42 == 1238
 
+def test_global_const_int():
+    from re_python_pysrc import ffi
+    lib = ffi.dlopen(extmod)
+    assert lib.globalconst42 == 4321
+    py.test.raises(AttributeError, ffi.addressof, lib, 'globalconst42')
+
+def test_global_const_nonint():
+    from re_python_pysrc import ffi
+    lib = ffi.dlopen(extmod)
+    assert ffi.string(lib.globalconsthello, 8) == b"hello"
+    py.test.raises(AttributeError, ffi.addressof, lib, 'globalconsthello')
+
 def test_rtld_constants():
     from re_python_pysrc import ffi
     ffi.RTLD_NOW    # check that we have the attributes
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
@@ -479,8 +479,11 @@
     old_sys_path = sys.path[:]
     try:
         package_dir = udir.join('test_module_name_in_package')
+        for name in os.listdir(str(udir)):
+            assert not name.startswith('test_module_name_in_package.')
         assert os.path.isdir(str(package_dir))
         assert len(os.listdir(str(package_dir))) > 0
+        assert os.path.exists(str(package_dir.join('mymod.c')))
         package_dir.join('__init__.py').write('')
         #
         sys.path.insert(0, str(udir))
@@ -821,3 +824,87 @@
     assert addr(0xABC05) == 47
     assert isinstance(addr, ffi.CData)
     assert ffi.typeof(addr) == ffi.typeof("long(*)(long)")
+
+def test_issue198():
+    ffi = FFI()
+    ffi.cdef("""
+        typedef struct{...;} opaque_t;
+        const opaque_t CONSTANT;
+        int toint(opaque_t);
+    """)
+    lib = verify(ffi, 'test_issue198', """
+        typedef int opaque_t;
+        #define CONSTANT ((opaque_t)42)
+        static int toint(opaque_t o) { return o; }
+    """)
+    def random_stuff():
+        pass
+    assert lib.toint(lib.CONSTANT) == 42
+    random_stuff()
+    assert lib.toint(lib.CONSTANT) == 42
+
+def test_constant_is_not_a_compiler_constant():
+    ffi = FFI()
+    ffi.cdef("static const float almost_forty_two;")
+    lib = verify(ffi, 'test_constant_is_not_a_compiler_constant', """
+        static float f(void) { return 42.25; }
+        #define almost_forty_two (f())
+    """)
+    assert lib.almost_forty_two == 42.25
+
+def test_constant_of_unknown_size():
+    ffi = FFI()
+    ffi.cdef("""
+        typedef ... opaque_t;
+        const opaque_t CONSTANT;
+    """)
+    e = py.test.raises(VerificationError, verify, ffi,
+                       'test_constant_of_unknown_size', "stuff")
+    assert str(e.value) == ("constant CONSTANT: constant 'CONSTANT' is of "
+                            "type 'opaque_t', whose size is not known")
+
+def test_variable_of_unknown_size():
+    ffi = FFI()
+    ffi.cdef("""
+        typedef ... opaque_t;
+        opaque_t globvar;
+    """)
+    lib = verify(ffi, 'test_constant_of_unknown_size', """
+        typedef char opaque_t[6];
+        opaque_t globvar = "hello";
+    """)
+    # can't read or write it at all
+    e = py.test.raises(TypeError, getattr, lib, 'globvar')
+    assert str(e.value) == "cdata 'opaque_t' is opaque"
+    e = py.test.raises(TypeError, setattr, lib, 'globvar', [])
+    assert str(e.value) == "'opaque_t' is opaque"
+    # but we can get its address
+    p = ffi.addressof(lib, 'globvar')
+    assert ffi.typeof(p) == ffi.typeof('opaque_t *')
+    assert ffi.string(ffi.cast("char *", p), 8) == b"hello"
+
+def test_constant_of_value_unknown_to_the_compiler():
+    extra_c_source = udir.join(
+        'extra_test_constant_of_value_unknown_to_the_compiler.c')
+    extra_c_source.write('const int external_foo = 42;\n')
+    ffi = FFI()
+    ffi.cdef("const int external_foo;")
+    lib = verify(ffi, 'test_constant_of_value_unknown_to_the_compiler', """
+        extern const int external_foo;
+    """, sources=[str(extra_c_source)])
+    assert lib.external_foo == 42
+
+def test_call_with_incomplete_structs():
+    ffi = FFI()
+    ffi.cdef("typedef struct {...;} foo_t; "
+             "foo_t myglob; "
+             "foo_t increment(foo_t s); "
+             "double getx(foo_t s);")
+    lib = verify(ffi, 'test_call_with_incomplete_structs', """
+        typedef double foo_t;
+        double myglob = 42.5;
+        double getx(double x) { return x; }
+        double increment(double x) { return x + 1; }
+    """)
+    assert lib.getx(lib.myglob) == 42.5
+    assert lib.getx(lib.increment(lib.myglob)) == 43.5
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_zdist.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_zdist.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_zdist.py
@@ -0,0 +1,339 @@
+# Generated by pypy/tool/import_cffi.py
+import sys, os, py
+import subprocess
+import cffi
+from pypy.module.test_lib_pypy.cffi_tests.udir import udir
+
+
+def chdir_to_tmp(f):
+    f.chdir_to_tmp = True
+    return f
+
+def from_outside(f):
+    f.chdir_to_tmp = False
+    return f
+
+
+class TestDist(object):
+
+    def setup_method(self, meth):
+        self.executable = os.path.abspath(sys.executable)
+        self.rootdir = os.path.abspath(os.path.dirname(os.path.dirname(
+            cffi.__file__)))
+        self.udir = udir.join(meth.__name__)
+        os.mkdir(str(self.udir))
+        if meth.chdir_to_tmp:
+            self.saved_cwd = os.getcwd()
+            os.chdir(str(self.udir))
+
+    def teardown_method(self, meth):
+        if hasattr(self, 'saved_cwd'):
+            os.chdir(self.saved_cwd)
+
+    def run(self, args):
+        env = os.environ.copy()
+        newpath = self.rootdir
+        if 'PYTHONPATH' in env:
+            newpath += os.pathsep + env['PYTHONPATH']
+        env['PYTHONPATH'] = newpath
+        subprocess.check_call([self.executable] + args, env=env)
+
+    def _prepare_setuptools(self):
+        if hasattr(TestDist, '_setuptools_ready'):
+            return
+        try:
+            import setuptools
+        except ImportError:
+            py.test.skip("setuptools not found")
+        subprocess.check_call([self.executable, 'setup.py', 'egg_info'],
+                              cwd=self.rootdir)
+        TestDist._setuptools_ready = True
+
+    def check_produced_files(self, content, curdir=None):
+        if curdir is None:
+            curdir = str(self.udir)
+        found_so = None
+        for name in os.listdir(curdir):
+            if (name.endswith('.so') or name.endswith('.pyd') or
+                name.endswith('.dylib')):
+                found_so = os.path.join(curdir, name)
+                name = name.split('.')[0] + '.SO' # foo.cpython-34m.so => foo.SO
+            if name.startswith('pycparser') and name.endswith('.egg'):
+                continue    # no clue why this shows up sometimes and not others
+            assert name in content, "found unexpected file %r" % (
+                os.path.join(curdir, name),)
+            value = content.pop(name)
+            if value is None:
+                assert name.endswith('.SO') or (
+                    os.path.isfile(os.path.join(curdir, name)))
+            else:
+                subdir = os.path.join(curdir, name)
+                assert os.path.isdir(subdir)
+                if value == '?':
+                    continue
+                found_so = self.check_produced_files(value, subdir) or found_so
+        assert content == {}, "files or dirs not produced in %r: %r" % (
+            curdir, content.keys())
+        return found_so
+
+    @chdir_to_tmp
+    def test_empty(self):
+        self.check_produced_files({})
+
+    @chdir_to_tmp
+    def test_abi_emit_python_code_1(self):
+        ffi = cffi.FFI()
+        ffi.set_source("package_name_1.mymod", None)
+        ffi.emit_python_code('xyz.py')
+        self.check_produced_files({'xyz.py': None})
+
+    @chdir_to_tmp
+    def test_abi_emit_python_code_2(self):
+        ffi = cffi.FFI()
+        ffi.set_source("package_name_1.mymod", None)
+        py.test.raises(IOError, ffi.emit_python_code, 'unexisting/xyz.py')
+
+    @from_outside
+    def test_abi_emit_python_code_3(self):
+        ffi = cffi.FFI()
+        ffi.set_source("package_name_1.mymod", None)
+        ffi.emit_python_code(str(self.udir.join('xyt.py')))
+        self.check_produced_files({'xyt.py': None})
+
+    @chdir_to_tmp
+    def test_abi_compile_1(self):
+        ffi = cffi.FFI()
+        ffi.set_source("mod_name_in_package.mymod", None)
+        x = ffi.compile()
+        self.check_produced_files({'mod_name_in_package': {'mymod.py': None}})
+        assert x == os.path.join('.', 'mod_name_in_package', 'mymod.py')
+
+    @chdir_to_tmp
+    def test_abi_compile_2(self):
+        ffi = cffi.FFI()
+        ffi.set_source("mod_name_in_package.mymod", None)
+        x = ffi.compile('build2')
+        self.check_produced_files({'build2': {
+            'mod_name_in_package': {'mymod.py': None}}})
+        assert x == os.path.join('build2', 'mod_name_in_package', 'mymod.py')
+
+    @from_outside
+    def test_abi_compile_3(self):
+        ffi = cffi.FFI()
+        ffi.set_source("mod_name_in_package.mymod", None)
+        tmpdir = str(self.udir.join('build3'))
+        x = ffi.compile(tmpdir)
+        self.check_produced_files({'build3': {
+            'mod_name_in_package': {'mymod.py': None}}})
+        assert x == os.path.join(tmpdir, 'mod_name_in_package', 'mymod.py')
+
+    @chdir_to_tmp
+    def test_api_emit_c_code_1(self):
+        ffi = cffi.FFI()
+        ffi.set_source("package_name_1.mymod", "/*code would be here*/")
+        ffi.emit_c_code('xyz.c')
+        self.check_produced_files({'xyz.c': None})
+
+    @chdir_to_tmp
+    def test_api_emit_c_code_2(self):
+        ffi = cffi.FFI()
+        ffi.set_source("package_name_1.mymod", "/*code would be here*/")
+        py.test.raises(IOError, ffi.emit_c_code, 'unexisting/xyz.c')
+
+    @from_outside
+    def test_api_emit_c_code_3(self):
+        ffi = cffi.FFI()
+        ffi.set_source("package_name_1.mymod", "/*code would be here*/")
+        ffi.emit_c_code(str(self.udir.join('xyu.c')))
+        self.check_produced_files({'xyu.c': None})
+
+    @chdir_to_tmp
+    def test_api_compile_1(self):
+        ffi = cffi.FFI()
+        ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
+        x = ffi.compile()
+        if sys.platform != 'win32':
+            sofile = self.check_produced_files({
+                'mod_name_in_package': {'mymod.SO': None,
+                                        'mymod.c': None,
+                                        'mymod.o': None}})
+            assert os.path.isabs(x) and os.path.samefile(x, sofile)
+        else:
+            self.check_produced_files({
+                'mod_name_in_package': {'mymod.SO': None,
+                                        'mymod.c': None},
+                'Release': '?'})
+
+    @chdir_to_tmp
+    def test_api_compile_2(self):
+        ffi = cffi.FFI()
+        ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
+        x = ffi.compile('output')
+        if sys.platform != 'win32':
+            sofile = self.check_produced_files({
+                'output': {'mod_name_in_package': {'mymod.SO': None,
+                                                   'mymod.c': None,
+                                                   'mymod.o': None}}})
+            assert os.path.isabs(x) and os.path.samefile(x, sofile)
+        else:
+            self.check_produced_files({
+                'output': {'mod_name_in_package': {'mymod.SO': None,
+                                                   'mymod.c': None},
+                           'Release': '?'}})
+
+    @from_outside
+    def test_api_compile_3(self):
+        ffi = cffi.FFI()
+        ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
+        x = ffi.compile(str(self.udir.join('foo')))
+        if sys.platform != 'win32':
+            sofile = self.check_produced_files({
+                'foo': {'mod_name_in_package': {'mymod.SO': None,
+                                                'mymod.c': None,
+                                                'mymod.o': None}}})
+            assert os.path.isabs(x) and os.path.samefile(x, sofile)
+        else:
+            self.check_produced_files({
+                'foo': {'mod_name_in_package': {'mymod.SO': None,
+                                                'mymod.c': None},
+                        'Release': '?'}})
+
+    @chdir_to_tmp
+    def test_api_distutils_extension_1(self):
+        ffi = cffi.FFI()
+        ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
+        ext = ffi.distutils_extension()
+        self.check_produced_files({'build': {
+            'mod_name_in_package': {'mymod.c': None}}})
+        if hasattr(os.path, 'samefile'):
+            assert os.path.samefile(ext.sources[0],
+                                    'build/mod_name_in_package/mymod.c')
+
+    @from_outside
+    def test_api_distutils_extension_2(self):
+        ffi = cffi.FFI()
+        ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
+        ext = ffi.distutils_extension(str(self.udir.join('foo')))
+        self.check_produced_files({'foo': {
+            'mod_name_in_package': {'mymod.c': None}}})
+        if hasattr(os.path, 'samefile'):
+            assert os.path.samefile(ext.sources[0],
+                str(self.udir.join('foo/mod_name_in_package/mymod.c')))
+
+
+    def _make_distutils_api(self):
+        os.mkdir("src")
+        os.mkdir(os.path.join("src", "pack1"))
+        with open(os.path.join("src", "pack1", "__init__.py"), "w") as f:
+            pass
+        with open("setup.py", "w") as f:
+            f.write("""if 1:
+                import cffi
+                ffi = cffi.FFI()
+                ffi.set_source("pack1.mymod", "/*code would be here*/")
+
+                from distutils.core import setup
+                setup(name='example1',
+                      version='0.1',
+                      packages=['pack1'],
+                      package_dir={'': 'src'},
+                      ext_modules=[ffi.distutils_extension()])
+            """)
+
+    @chdir_to_tmp
+    def test_distutils_api_1(self):
+        self._make_distutils_api()
+        self.run(["setup.py", "build"])
+        self.check_produced_files({'setup.py': None,
+                                   'build': '?',
+                                   'src': {'pack1': {'__init__.py': None}}})
+
+    @chdir_to_tmp
+    def test_distutils_api_2(self):
+        self._make_distutils_api()
+        self.run(["setup.py", "build_ext", "-i"])
+        self.check_produced_files({'setup.py': None,
+                                   'build': '?',
+                                   'src': {'pack1': {'__init__.py': None,
+                                                     'mymod.SO': None}}})
+
+    def _make_setuptools_abi(self):
+        self._prepare_setuptools()
+        os.mkdir("src0")
+        os.mkdir(os.path.join("src0", "pack2"))
+        with open(os.path.join("src0", "pack2", "__init__.py"), "w") as f:
+            pass
+        with open(os.path.join("src0", "pack2", "_build.py"), "w") as f:
+            f.write("""if 1:
+                import cffi
+                ffi = cffi.FFI()
+                ffi.set_source("pack2.mymod", None)
+            """)
+        with open("setup.py", "w") as f:
+            f.write("""if 1:
+                from setuptools import setup
+                setup(name='example1',
+                      version='0.1',
+                      packages=['pack2'],
+                      package_dir={'': 'src0'},
+                      cffi_modules=["src0/pack2/_build.py:ffi"])
+            """)
+
+    @chdir_to_tmp
+    def test_setuptools_abi_1(self):
+        self._make_setuptools_abi()
+        self.run(["setup.py", "build"])
+        self.check_produced_files({'setup.py': None,
+                                   'build': '?',
+                                   'src0': {'pack2': {'__init__.py': None,
+                                                      '_build.py': None}}})
+
+    @chdir_to_tmp
+    def test_setuptools_abi_2(self):
+        self._make_setuptools_abi()
+        self.run(["setup.py", "build_ext", "-i"])
+        self.check_produced_files({'setup.py': None,
+                                   'src0': {'pack2': {'__init__.py': None,
+                                                      '_build.py': None,
+                                                      'mymod.py': None}}})
+
+    def _make_setuptools_api(self):
+        self._prepare_setuptools()
+        os.mkdir("src1")
+        os.mkdir(os.path.join("src1", "pack3"))
+        with open(os.path.join("src1", "pack3", "__init__.py"), "w") as f:
+            pass
+        with open(os.path.join("src1", "pack3", "_build.py"), "w") as f:
+            f.write("""if 1:
+                import cffi
+                ffi = cffi.FFI()
+                ffi.set_source("pack3.mymod", "/*code would be here*/")
+            """)
+        with open("setup.py", "w") as f:
+            f.write("""if 1:
+                from setuptools import setup
+                setup(name='example1',
+                      version='0.1',
+                      packages=['pack3'],
+                      package_dir={'': 'src1'},
+                      cffi_modules=["src1/pack3/_build.py:ffi"])
+            """)
+
+    @chdir_to_tmp
+    def test_setuptools_api_1(self):
+        self._make_setuptools_api()
+        self.run(["setup.py", "build"])
+        self.check_produced_files({'setup.py': None,
+                                   'build': '?',
+                                   'src1': {'pack3': {'__init__.py': None,
+                                                      '_build.py': None}}})
+
+    @chdir_to_tmp
+    def test_setuptools_api_2(self):
+        self._make_setuptools_api()
+        self.run(["setup.py", "build_ext", "-i"])
+        self.check_produced_files({'setup.py': None,
+                                   'build': '?',
+                                   'src1': {'pack3': {'__init__.py': None,
+                                                      '_build.py': None,
+                                                      'mymod.SO': None}}})
diff --git a/rpython/doc/conf.py b/rpython/doc/conf.py
--- a/rpython/doc/conf.py
+++ b/rpython/doc/conf.py
@@ -66,9 +66,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = '2.5'
+version = '2.6'
 # The full version, including alpha/beta/rc tags.
-release = '2.5.0'
+release = '2.6.0'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/rpython/jit/backend/llsupport/codemap.py b/rpython/jit/backend/llsupport/codemap.py
--- a/rpython/jit/backend/llsupport/codemap.py
+++ b/rpython/jit/backend/llsupport/codemap.py
@@ -30,6 +30,7 @@
     libraries.append('Kernel32')
 
 eci = ExternalCompilationInfo(post_include_bits=["""
+
 RPY_EXTERN long pypy_jit_codemap_add(unsigned long addr,
                                      unsigned int machine_code_size,
                                      long *bytecode_info,
@@ -47,7 +48,8 @@
 """], separate_module_sources=[
     open(os.path.join(srcdir, 'skiplist.c'), 'r').read() +
     open(os.path.join(srcdir, 'codemap.c'), 'r').read()
-], include_dirs=[cdir], libraries=libraries)
+], include_dirs=[cdir], libraries=libraries,
+compile_extra=['-DPYPY_JIT_CODEMAP'])
 
 def llexternal(name, args, res):
     return rffi.llexternal(name, args, res, compilation_info=eci,
diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -560,6 +560,7 @@
     'debug_start':          LLOp(canrun=True),
     'debug_stop':           LLOp(canrun=True),
     'have_debug_prints':    LLOp(canrun=True),
+    'have_debug_prints_for':LLOp(canrun=True),
     'debug_offset':         LLOp(canrun=True),
     'debug_flush':          LLOp(canrun=True),
     'debug_assert':         LLOp(tryfold=True),
@@ -573,6 +574,7 @@
     'debug_reraise_traceback': LLOp(),
     'debug_print_traceback':   LLOp(),
     'debug_nonnull_pointer':   LLOp(canrun=True),
+    'debug_forked':            LLOp(),
 
     # __________ instrumentation _________
     'instrument_count':     LLOp(),
diff --git a/rpython/rtyper/lltypesystem/opimpl.py b/rpython/rtyper/lltypesystem/opimpl.py
--- a/rpython/rtyper/lltypesystem/opimpl.py
+++ b/rpython/rtyper/lltypesystem/opimpl.py
@@ -597,6 +597,9 @@
 def op_have_debug_prints():
     return debug.have_debug_prints()
 
+def op_have_debug_prints_for(prefix):
+    return True
+
 def op_debug_nonnull_pointer(x):
     assert x
 


More information about the pypy-commit mailing list