[pypy-commit] pypy default: merge default

NZinov pypy.commits at gmail.com
Fri Feb 12 11:34:25 EST 2016


Author: Nikolay Zinov <nzinov at gmail.com>
Branch: 
Changeset: r82187:e418c04f44ad
Date: 2016-02-12 19:28 +0300
http://bitbucket.org/pypy/pypy/changeset/e418c04f44ad/

Log:	merge default

diff too long, truncating to 2000 out of 2205 lines

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.5.0
+Version: 1.5.1
 Summary: Foreign Function Interface for Python calling C code.
 Home-page: http://cffi.readthedocs.org
 Author: Armin Rigo, Maciej Fijalkowski
diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py
--- a/lib_pypy/cffi/__init__.py
+++ b/lib_pypy/cffi/__init__.py
@@ -4,8 +4,8 @@
 from .api import FFI, CDefError, FFIError
 from .ffiplatform import VerificationError, VerificationMissing
 
-__version__ = "1.5.0"
-__version_info__ = (1, 5, 0)
+__version__ = "1.5.1"
+__version_info__ = (1, 5, 1)
 
 # 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_include.h b/lib_pypy/cffi/_cffi_include.h
--- a/lib_pypy/cffi/_cffi_include.h
+++ b/lib_pypy/cffi/_cffi_include.h
@@ -231,6 +231,12 @@
     ((got_nonpos) == (expected <= 0) &&                 \
      (got) == (unsigned long long)expected)
 
+#ifdef MS_WIN32
+# define _cffi_stdcall  __stdcall
+#else
+# define _cffi_stdcall  /* nothing */
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib_pypy/cffi/_embedding.h b/lib_pypy/cffi/_embedding.h
new file mode 100644
--- /dev/null
+++ b/lib_pypy/cffi/_embedding.h
@@ -0,0 +1,517 @@
+
+/***** Support code for embedding *****/
+
+#if defined(_MSC_VER)
+#  define CFFI_DLLEXPORT  __declspec(dllexport)
+#elif defined(__GNUC__)
+#  define CFFI_DLLEXPORT  __attribute__((visibility("default")))
+#else
+#  define CFFI_DLLEXPORT  /* nothing */
+#endif
+
+
+/* There are two global variables of type _cffi_call_python_fnptr:
+
+   * _cffi_call_python, which we declare just below, is the one called
+     by ``extern "Python"`` implementations.
+
+   * _cffi_call_python_org, which on CPython is actually part of the
+     _cffi_exports[] array, is the function pointer copied from
+     _cffi_backend.
+
+   After initialization is complete, both are equal.  However, the
+   first one remains equal to &_cffi_start_and_call_python until the
+   very end of initialization, when we are (or should be) sure that
+   concurrent threads also see a completely initialized world, and
+   only then is it changed.
+*/
+#undef _cffi_call_python
+typedef void (*_cffi_call_python_fnptr)(struct _cffi_externpy_s *, char *);
+static void _cffi_start_and_call_python(struct _cffi_externpy_s *, char *);
+static _cffi_call_python_fnptr _cffi_call_python = &_cffi_start_and_call_python;
+
+
+#ifndef _MSC_VER
+   /* --- Assuming a GCC not infinitely old --- */
+# define cffi_compare_and_swap(l,o,n)  __sync_bool_compare_and_swap(l,o,n)
+# define cffi_write_barrier()          __sync_synchronize()
+# if !defined(__amd64__) && !defined(__x86_64__) &&   \
+     !defined(__i386__) && !defined(__i386)
+#   define cffi_read_barrier()         __sync_synchronize()
+# else
+#   define cffi_read_barrier()         (void)0
+# endif
+#else
+   /* --- Windows threads version --- */
+# include <Windows.h>
+# define cffi_compare_and_swap(l,o,n) \
+                               (InterlockedCompareExchangePointer(l,n,o) == (o))
+# define cffi_write_barrier()       InterlockedCompareExchange(&_cffi_dummy,0,0)
+# define cffi_read_barrier()           (void)0
+static volatile LONG _cffi_dummy;
+#endif
+
+#ifdef WITH_THREAD
+# ifndef _MSC_VER
+#  include <pthread.h>
+   static pthread_mutex_t _cffi_embed_startup_lock;
+# else
+   static CRITICAL_SECTION _cffi_embed_startup_lock;
+# endif
+  static char _cffi_embed_startup_lock_ready = 0;
+#endif
+
+static void _cffi_acquire_reentrant_mutex(void)
+{
+    static void *volatile lock = NULL;
+
+    while (!cffi_compare_and_swap(&lock, NULL, (void *)1)) {
+        /* should ideally do a spin loop instruction here, but
+           hard to do it portably and doesn't really matter I
+           think: pthread_mutex_init() should be very fast, and
+           this is only run at start-up anyway. */
+    }
+
+#ifdef WITH_THREAD
+    if (!_cffi_embed_startup_lock_ready) {
+# ifndef _MSC_VER
+        pthread_mutexattr_t attr;
+        pthread_mutexattr_init(&attr);
+        pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+        pthread_mutex_init(&_cffi_embed_startup_lock, &attr);
+# else
+        InitializeCriticalSection(&_cffi_embed_startup_lock);
+# endif
+        _cffi_embed_startup_lock_ready = 1;
+    }
+#endif
+
+    while (!cffi_compare_and_swap(&lock, (void *)1, NULL))
+        ;
+
+#ifndef _MSC_VER
+    pthread_mutex_lock(&_cffi_embed_startup_lock);
+#else
+    EnterCriticalSection(&_cffi_embed_startup_lock);
+#endif
+}
+
+static void _cffi_release_reentrant_mutex(void)
+{
+#ifndef _MSC_VER
+    pthread_mutex_unlock(&_cffi_embed_startup_lock);
+#else
+    LeaveCriticalSection(&_cffi_embed_startup_lock);
+#endif
+}
+
+
+/**********  CPython-specific section  **********/
+#ifndef PYPY_VERSION
+
+
+#define _cffi_call_python_org  _cffi_exports[_CFFI_CPIDX]
+
+PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(void);   /* forward */
+
+static void _cffi_py_initialize(void)
+{
+    /* XXX use initsigs=0, which "skips initialization registration of
+       signal handlers, which might be useful when Python is
+       embedded" according to the Python docs.  But review and think
+       if it should be a user-controllable setting.
+
+       XXX we should also give a way to write errors to a buffer
+       instead of to stderr.
+
+       XXX if importing 'site' fails, CPython (any version) calls
+       exit().  Should we try to work around this behavior here?
+    */
+    Py_InitializeEx(0);
+}
+
+static int _cffi_initialize_python(void)
+{
+    /* This initializes Python, imports _cffi_backend, and then the
+       present .dll/.so is set up as a CPython C extension module.
+    */
+    int result;
+    PyGILState_STATE state;
+    PyObject *pycode=NULL, *global_dict=NULL, *x;
+
+#if PY_MAJOR_VERSION >= 3
+    /* see comments in _cffi_carefully_make_gil() about the
+       Python2/Python3 difference 
+    */
+#else
+    /* Acquire the GIL.  We have no threadstate here.  If Python is 
+       already initialized, it is possible that there is already one
+       existing for this thread, but it is not made current now.
+    */
+    PyEval_AcquireLock();
+
+    _cffi_py_initialize();
+
+    /* The Py_InitializeEx() sometimes made a threadstate for us, but
+       not always.  Indeed Py_InitializeEx() could be called and do
+       nothing.  So do we have a threadstate, or not?  We don't know,
+       but we can replace it with NULL in all cases.
+    */
+    (void)PyThreadState_Swap(NULL);
+
+    /* Now we can release the GIL and re-acquire immediately using the
+       logic of PyGILState(), which handles making or installing the
+       correct threadstate.
+    */
+    PyEval_ReleaseLock();
+#endif
+    state = PyGILState_Ensure();
+
+    /* Call the initxxx() function from the present module.  It will
+       create and initialize us as a CPython extension module, instead
+       of letting the startup Python code do it---it might reimport
+       the same .dll/.so and get maybe confused on some platforms.
+       It might also have troubles locating the .dll/.so again for all
+       I know.
+    */
+    (void)_CFFI_PYTHON_STARTUP_FUNC();
+    if (PyErr_Occurred())
+        goto error;
+
+    /* Now run the Python code provided to ffi.embedding_init_code().
+     */
+    pycode = Py_CompileString(_CFFI_PYTHON_STARTUP_CODE,
+                              "<init code for '" _CFFI_MODULE_NAME "'>",
+                              Py_file_input);
+    if (pycode == NULL)
+        goto error;
+    global_dict = PyDict_New();
+    if (global_dict == NULL)
+        goto error;
+    if (PyDict_SetItemString(global_dict, "__builtins__",
+                             PyThreadState_GET()->interp->builtins) < 0)
+        goto error;
+    x = PyEval_EvalCode(
+#if PY_MAJOR_VERSION < 3
+                        (PyCodeObject *)
+#endif
+                        pycode, global_dict, global_dict);
+    if (x == NULL)
+        goto error;
+    Py_DECREF(x);
+
+    /* Done!  Now if we've been called from
+       _cffi_start_and_call_python() in an ``extern "Python"``, we can
+       only hope that the Python code did correctly set up the
+       corresponding @ffi.def_extern() function.  Otherwise, the
+       general logic of ``extern "Python"`` functions (inside the
+       _cffi_backend module) will find that the reference is still
+       missing and print an error.
+     */
+    result = 0;
+ done:
+    Py_XDECREF(pycode);
+    Py_XDECREF(global_dict);
+    PyGILState_Release(state);
+    return result;
+
+ error:;
+    {
+        /* Print as much information as potentially useful.
+           Debugging load-time failures with embedding is not fun
+        */
+        PyObject *exception, *v, *tb, *f, *modules, *mod;
+        PyErr_Fetch(&exception, &v, &tb);
+        if (exception != NULL) {
+            PyErr_NormalizeException(&exception, &v, &tb);
+            PyErr_Display(exception, v, tb);
+        }
+        Py_XDECREF(exception);
+        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.5.1"
+                               "\n_cffi_backend module: ", f);
+            modules = PyImport_GetModuleDict();
+            mod = PyDict_GetItemString(modules, "_cffi_backend");
+            if (mod == NULL) {
+                PyFile_WriteString("not loaded", f);
+            }
+            else {
+                v = PyObject_GetAttrString(mod, "__file__");
+                PyFile_WriteObject(v, f, 0);
+                Py_XDECREF(v);
+            }
+            PyFile_WriteString("\nsys.path: ", f);
+            PyFile_WriteObject(PySys_GetObject((char *)"path"), f, 0);
+            PyFile_WriteString("\n\n", f);
+        }
+    }
+    result = -1;
+    goto done;
+}
+
+PyAPI_DATA(char *) _PyParser_TokenNames[];  /* from CPython */
+
+static int _cffi_carefully_make_gil(void)
+{
+    /* This does the basic initialization of Python.  It can be called
+       completely concurrently from unrelated threads.  It assumes
+       that we don't hold the GIL before (if it exists), and we don't
+       hold it afterwards.
+
+       What it really does is completely different in Python 2 and 
+       Python 3.
+
+    Python 2
+    ========
+
+       Initialize the GIL, without initializing the rest of Python,
+       by calling PyEval_InitThreads().
+
+       PyEval_InitThreads() must not be called concurrently at all.
+       So we use a global variable as a simple spin lock.  This global
+       variable must be from 'libpythonX.Y.so', not from this
+       cffi-based extension module, because it must be shared from
+       different cffi-based extension modules.  We choose
+       _PyParser_TokenNames[0] as a completely arbitrary pointer value
+       that is never written to.  The default is to point to the
+       string "ENDMARKER".  We change it temporarily to point to the
+       next character in that string.  (Yes, I know it's REALLY
+       obscure.)
+
+    Python 3
+    ========
+
+       In Python 3, PyEval_InitThreads() cannot be called before
+       Py_InitializeEx() any more.  So this function calls
+       Py_InitializeEx() first.  It uses the same obscure logic to
+       make sure we never call it concurrently.
+
+       Arguably, this is less good on the spinlock, because
+       Py_InitializeEx() takes much longer to run than
+       PyEval_InitThreads().  But I didn't find a way around it.
+    */
+
+#ifdef WITH_THREAD
+    char *volatile *lock = (char *volatile *)_PyParser_TokenNames;
+    char *old_value;
+
+    while (1) {    /* spin loop */
+        old_value = *lock;
+        if (old_value[0] == 'E') {
+            assert(old_value[1] == 'N');
+            if (cffi_compare_and_swap(lock, old_value, old_value + 1))
+                break;
+        }
+        else {
+            assert(old_value[0] == 'N');
+            /* should ideally do a spin loop instruction here, but
+               hard to do it portably and doesn't really matter I
+               think: PyEval_InitThreads() should be very fast, and
+               this is only run at start-up anyway. */
+        }
+    }
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+    /* Python 3: call Py_InitializeEx() */
+    {
+        PyGILState_STATE state = PyGILState_UNLOCKED;
+        if (!Py_IsInitialized())
+            _cffi_py_initialize();
+        else
+            state = PyGILState_Ensure();
+
+        PyEval_InitThreads();
+        PyGILState_Release(state);
+    }
+#else
+    /* Python 2: call PyEval_InitThreads() */
+# ifdef WITH_THREAD
+    if (!PyEval_ThreadsInitialized()) {
+        PyEval_InitThreads();    /* makes the GIL */
+        PyEval_ReleaseLock();    /* then release it */
+    }
+    /* else: there is already a GIL, but we still needed to do the
+       spinlock dance to make sure that we see it as fully ready */
+# endif
+#endif
+
+#ifdef WITH_THREAD
+    /* release the lock */
+    while (!cffi_compare_and_swap(lock, old_value + 1, old_value))
+        ;
+#endif
+
+    return 0;
+}
+
+/**********  end CPython-specific section  **********/
+
+
+#else
+
+
+/**********  PyPy-specific section  **********/
+
+PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(const void *[]);   /* forward */
+
+static struct _cffi_pypy_init_s {
+    const char *name;
+    void (*func)(const void *[]);
+    const char *code;
+} _cffi_pypy_init = {
+    _CFFI_MODULE_NAME,
+    _CFFI_PYTHON_STARTUP_FUNC,
+    _CFFI_PYTHON_STARTUP_CODE,
+};
+
+extern int pypy_carefully_make_gil(const char *);
+extern int pypy_init_embedded_cffi_module(int, struct _cffi_pypy_init_s *);
+
+static int _cffi_carefully_make_gil(void)
+{
+    return pypy_carefully_make_gil(_CFFI_MODULE_NAME);
+}
+
+static int _cffi_initialize_python(void)
+{
+    return pypy_init_embedded_cffi_module(0xB011, &_cffi_pypy_init);
+}
+
+/**********  end PyPy-specific section  **********/
+
+
+#endif
+
+
+#ifdef __GNUC__
+__attribute__((noinline))
+#endif
+static _cffi_call_python_fnptr _cffi_start_python(void)
+{
+    /* Delicate logic to initialize Python.  This function can be
+       called multiple times concurrently, e.g. when the process calls
+       its first ``extern "Python"`` functions in multiple threads at
+       once.  It can also be called recursively, in which case we must
+       ignore it.  We also have to consider what occurs if several
+       different cffi-based extensions reach this code in parallel
+       threads---it is a different copy of the code, then, and we
+       can't have any shared global variable unless it comes from
+       'libpythonX.Y.so'.
+
+       Idea:
+
+       * _cffi_carefully_make_gil(): "carefully" call
+         PyEval_InitThreads() (possibly with Py_InitializeEx() first).
+
+       * then we use a (local) custom lock to make sure that a call to this
+         cffi-based extension will wait if another call to the *same*
+         extension is running the initialization in another thread.
+         It is reentrant, so that a recursive call will not block, but
+         only one from a different thread.
+
+       * then we grab the GIL and (Python 2) we call Py_InitializeEx().
+         At this point, concurrent calls to Py_InitializeEx() are not
+         possible: we have the GIL.
+
+       * do the rest of the specific initialization, which may
+         temporarily release the GIL but not the custom lock.
+         Only release the custom lock when we are done.
+    */
+    static char called = 0;
+
+    if (_cffi_carefully_make_gil() != 0)
+        return NULL;
+
+    _cffi_acquire_reentrant_mutex();
+
+    /* Here the GIL exists, but we don't have it.  We're only protected
+       from concurrency by the reentrant mutex. */
+
+    /* This file only initializes the embedded module once, the first
+       time this is called, even if there are subinterpreters. */
+    if (!called) {
+        called = 1;  /* invoke _cffi_initialize_python() only once,
+                        but don't set '_cffi_call_python' right now,
+                        otherwise concurrent threads won't call
+                        this function at all (we need them to wait) */
+        if (_cffi_initialize_python() == 0) {
+            /* now initialization is finished.  Switch to the fast-path. */
+
+            /* We would like nobody to see the new value of
+               '_cffi_call_python' without also seeing the rest of the
+               data initialized.  However, this is not possible.  But
+               the new value of '_cffi_call_python' is the function
+               'cffi_call_python()' from _cffi_backend.  So:  */
+            cffi_write_barrier();
+            /* ^^^ we put a write barrier here, and a corresponding
+               read barrier at the start of cffi_call_python().  This
+               ensures that after that read barrier, we see everything
+               done here before the write barrier.
+            */
+
+            assert(_cffi_call_python_org != NULL);
+            _cffi_call_python = (_cffi_call_python_fnptr)_cffi_call_python_org;
+        }
+        else {
+            /* initialization failed.  Reset this to NULL, even if it was
+               already set to some other value.  Future calls to
+               _cffi_start_python() are still forced to occur, and will
+               always return NULL from now on. */
+            _cffi_call_python_org = NULL;
+        }
+    }
+
+    _cffi_release_reentrant_mutex();
+
+    return (_cffi_call_python_fnptr)_cffi_call_python_org;
+}
+
+static
+void _cffi_start_and_call_python(struct _cffi_externpy_s *externpy, char *args)
+{
+    _cffi_call_python_fnptr fnptr;
+    int current_err = errno;
+#ifdef _MSC_VER
+    int current_lasterr = GetLastError();
+#endif
+    fnptr = _cffi_start_python();
+    if (fnptr == NULL) {
+        fprintf(stderr, "function %s() called, but initialization code "
+                        "failed.  Returning 0.\n", externpy->name);
+        memset(args, 0, externpy->size_of_result);
+    }
+#ifdef _MSC_VER
+    SetLastError(current_lasterr);
+#endif
+    errno = current_err;
+
+    if (fnptr != NULL)
+        fnptr(externpy, args);
+}
+
+
+/* The cffi_start_python() function makes sure Python is initialized
+   and our cffi module is set up.  It can be called manually from the
+   user C code.  The same effect is obtained automatically from any
+   dll-exported ``extern "Python"`` function.  This function returns
+   -1 if initialization failed, 0 if all is OK.  */
+_CFFI_UNUSED_FN
+static int cffi_start_python(void)
+{
+    if (_cffi_call_python == &_cffi_start_and_call_python) {
+        if (_cffi_start_python() == NULL)
+            return -1;
+    }
+    cffi_read_barrier();
+    return 0;
+}
+
+#undef cffi_compare_and_swap
+#undef cffi_write_barrier
+#undef cffi_read_barrier
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
@@ -1,4 +1,4 @@
-import sys, types
+import sys, sysconfig, types
 from .lock import allocate_lock
 
 try:
@@ -544,28 +544,32 @@
 
     def _apply_embedding_fix(self, kwds):
         # must include an argument like "-lpython2.7" for the compiler
+        def ensure(key, value):
+            lst = kwds.setdefault(key, [])
+            if value not in lst:
+                lst.append(value)
+        #
         if '__pypy__' in sys.builtin_module_names:
             if hasattr(sys, 'prefix'):
                 import os
-                libdir = os.path.join(sys.prefix, 'bin')
-                dirs = kwds.setdefault('library_dirs', [])
-                if libdir not in dirs:
-                    dirs.append(libdir)
+                ensure('library_dirs', os.path.join(sys.prefix, 'bin'))
             pythonlib = "pypy-c"
         else:
             if sys.platform == "win32":
                 template = "python%d%d"
-                if sys.flags.debug:
-                    template = template + '_d'
+                if hasattr(sys, 'gettotalrefcount'):
+                    template += '_d'
             else:
                 template = "python%d.%d"
+                if sysconfig.get_config_var('DEBUG_EXT'):
+                    template += sysconfig.get_config_var('DEBUG_EXT')
             pythonlib = (template %
                     (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff))
             if hasattr(sys, 'abiflags'):
                 pythonlib += sys.abiflags
-        libraries = kwds.setdefault('libraries', [])
-        if pythonlib not in libraries:
-            libraries.append(pythonlib)
+        ensure('libraries', pythonlib)
+        if sys.platform == "win32":
+            ensure('extra_link_args', '/MANIFEST')
 
     def set_source(self, module_name, source, source_extension='.c', **kwds):
         if hasattr(self, '_assigned_source'):
@@ -631,7 +635,7 @@
         compiled DLL.  Use '*' to force distutils' choice, suitable for
         regular CPython C API modules.  Use a file name ending in '.*'
         to ask for the system's default extension for dynamic libraries
-        (.so/.dll).
+        (.so/.dll/.dylib).
 
         The default is '*' when building a non-embedded C API extension,
         and (module_name + '.*') when building an embedded library.
@@ -695,6 +699,10 @@
         #
         self._embedding = pysource
 
+    def def_extern(self, *args, **kwds):
+        raise ValueError("ffi.def_extern() is only available on API-mode FFI "
+                         "objects")
+
 
 def _load_backend_lib(backend, name, flags):
     if name is None:
diff --git a/lib_pypy/cffi/cparser.py b/lib_pypy/cffi/cparser.py
--- a/lib_pypy/cffi/cparser.py
+++ b/lib_pypy/cffi/cparser.py
@@ -220,7 +220,7 @@
         self._included_declarations = set()
         self._anonymous_counter = 0
         self._structnode2type = weakref.WeakKeyDictionary()
-        self._options = None
+        self._options = {}
         self._int_constants = {}
         self._recomplete = []
         self._uses_new_feature = None
@@ -374,7 +374,7 @@
 
     def _declare_function(self, tp, quals, decl):
         tp = self._get_type_pointer(tp, quals)
-        if self._options['dllexport']:
+        if self._options.get('dllexport'):
             tag = 'dllexport_python '
         elif self._inside_extern_python:
             tag = 'extern_python '
@@ -450,7 +450,7 @@
             prevobj, prevquals = self._declarations[name]
             if prevobj is obj and prevquals == quals:
                 return
-            if not self._options['override']:
+            if not self._options.get('override'):
                 raise api.FFIError(
                     "multiple declarations of %s (for interactive usage, "
                     "try cdef(xx, override=True))" % (name,))
@@ -729,7 +729,7 @@
             if isinstance(tp, model.StructType) and tp.partial:
                 raise NotImplementedError("%s: using both bitfields and '...;'"
                                           % (tp,))
-        tp.packed = self._options['packed']
+        tp.packed = self._options.get('packed')
         if tp.completed:    # must be re-completed: it is not opaque any more
             tp.completed = 0
             self._recomplete.append(tp)
diff --git a/lib_pypy/cffi/ffiplatform.py b/lib_pypy/cffi/ffiplatform.py
--- a/lib_pypy/cffi/ffiplatform.py
+++ b/lib_pypy/cffi/ffiplatform.py
@@ -21,14 +21,12 @@
         allsources.append(os.path.normpath(src))
     return Extension(name=modname, sources=allsources, **kwds)
 
-def compile(tmpdir, ext, compiler_verbose=0, target_extension=None,
-            embedding=False):
+def compile(tmpdir, ext, compiler_verbose=0):
     """Compile a C extension module using distutils."""
 
     saved_environ = os.environ.copy()
     try:
-        outputfilename = _build(tmpdir, ext, compiler_verbose,
-                                target_extension, embedding)
+        outputfilename = _build(tmpdir, ext, compiler_verbose)
         outputfilename = os.path.abspath(outputfilename)
     finally:
         # workaround for a distutils bugs where some env vars can
@@ -38,32 +36,7 @@
                 os.environ[key] = value
     return outputfilename
 
-def _save_val(name):
-    import distutils.sysconfig
-    config_vars = distutils.sysconfig.get_config_vars()
-    return config_vars.get(name, Ellipsis)
-
-def _restore_val(name, value):
-    import distutils.sysconfig
-    config_vars = distutils.sysconfig.get_config_vars()
-    config_vars[name] = value
-    if value is Ellipsis:
-        del config_vars[name]
-
-def _win32_hack_for_embedding():
-    from distutils.msvc9compiler import MSVCCompiler
-    if not hasattr(MSVCCompiler, '_remove_visual_c_ref_CFFI_BAK'):
-        MSVCCompiler._remove_visual_c_ref_CFFI_BAK = \
-            MSVCCompiler._remove_visual_c_ref
-    MSVCCompiler._remove_visual_c_ref = lambda self,manifest_file: manifest_file
-
-def _win32_unhack_for_embedding():
-    from distutils.msvc9compiler import MSVCCompiler
-    MSVCCompiler._remove_visual_c_ref = \
-        MSVCCompiler._remove_visual_c_ref_CFFI_BAK
-
-def _build(tmpdir, ext, compiler_verbose=0, target_extension=None,
-           embedding=False):
+def _build(tmpdir, ext, compiler_verbose=0):
     # XXX compact but horrible :-(
     from distutils.core import Distribution
     import distutils.errors, distutils.log
@@ -76,25 +49,14 @@
     options['build_temp'] = ('ffiplatform', tmpdir)
     #
     try:
-        if sys.platform == 'win32' and embedding:
-            _win32_hack_for_embedding()
         old_level = distutils.log.set_threshold(0) or 0
-        old_SO = _save_val('SO')
-        old_EXT_SUFFIX = _save_val('EXT_SUFFIX')
         try:
-            if target_extension is not None:
-                _restore_val('SO', target_extension)
-                _restore_val('EXT_SUFFIX', target_extension)
             distutils.log.set_verbosity(compiler_verbose)
             dist.run_command('build_ext')
             cmd_obj = dist.get_command_obj('build_ext')
             [soname] = cmd_obj.get_outputs()
         finally:
             distutils.log.set_threshold(old_level)
-            _restore_val('SO', old_SO)
-            _restore_val('EXT_SUFFIX', old_EXT_SUFFIX)
-            if sys.platform == 'win32' and embedding:
-                _win32_unhack_for_embedding()
     except (distutils.errors.CompileError,
             distutils.errors.LinkError) as e:
         raise VerificationError('%s: %s' % (e.__class__.__name__, e))
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
@@ -1170,6 +1170,8 @@
         repr_arguments = ', '.join(arguments)
         repr_arguments = repr_arguments or 'void'
         name_and_arguments = '%s(%s)' % (name, repr_arguments)
+        if tp.abi == "__stdcall":
+            name_and_arguments = '_cffi_stdcall ' + name_and_arguments
         #
         def may_need_128_bits(tp):
             return (isinstance(tp, model.PrimitiveType) and
@@ -1357,6 +1359,58 @@
     parts[-1] += extension
     return os.path.join(outputdir, *parts), parts
 
+
+# Aaargh.  Distutils is not tested at all for the purpose of compiling
+# DLLs that are not extension modules.  Here are some hacks to work
+# around that, in the _patch_for_*() functions...
+
+def _patch_meth(patchlist, cls, name, new_meth):
+    old = getattr(cls, name)
+    patchlist.append((cls, name, old))
+    setattr(cls, name, new_meth)
+    return old
+
+def _unpatch_meths(patchlist):
+    for cls, name, old_meth in reversed(patchlist):
+        setattr(cls, name, old_meth)
+
+def _patch_for_embedding(patchlist):
+    if sys.platform == 'win32':
+        # we must not remove the manifest when building for embedding!
+        from distutils.msvc9compiler import MSVCCompiler
+        _patch_meth(patchlist, MSVCCompiler, '_remove_visual_c_ref',
+                    lambda self, manifest_file: manifest_file)
+
+    if sys.platform == 'darwin':
+        # we must not make a '-bundle', but a '-dynamiclib' instead
+        from distutils.ccompiler import CCompiler
+        def my_link_shared_object(self, *args, **kwds):
+            if '-bundle' in self.linker_so:
+                self.linker_so = list(self.linker_so)
+                i = self.linker_so.index('-bundle')
+                self.linker_so[i] = '-dynamiclib'
+            return old_link_shared_object(self, *args, **kwds)
+        old_link_shared_object = _patch_meth(patchlist, CCompiler,
+                                             'link_shared_object',
+                                             my_link_shared_object)
+
+def _patch_for_target(patchlist, target):
+    from distutils.command.build_ext import build_ext
+    # if 'target' is different from '*', we need to patch some internal
+    # method to just return this 'target' value, instead of having it
+    # built from module_name
+    if target.endswith('.*'):
+        target = target[:-2]
+        if sys.platform == 'win32':
+            target += '.dll'
+        elif sys.platform == 'darwin':
+            target += '.dylib'
+        else:
+            target += '.so'
+    _patch_meth(patchlist, build_ext, 'get_ext_filename',
+                lambda self, ext_name: target)
+
+
 def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True,
               c_file=None, source_extension='.c', extradir=None,
               compiler_verbose=1, target=None, **kwds):
@@ -1382,36 +1436,22 @@
                 target = '%s.*' % module_name
             else:
                 target = '*'
-        if target == '*':
-            target_module_name = module_name
-            target_extension = None      # use default
-        else:
-            if target.endswith('.*'):
-                target = target[:-2]
-                if sys.platform == 'win32':
-                    target += '.dll'
-                else:
-                    target += '.so'
-            # split along the first '.' (not the last one, otherwise the
-            # preceeding dots are interpreted as splitting package names)
-            index = target.find('.')
-            if index < 0:
-                raise ValueError("target argument %r should be a file name "
-                                 "containing a '.'" % (target,))
-            target_module_name = target[:index]
-            target_extension = target[index:]
         #
-        ext = ffiplatform.get_extension(ext_c_file, target_module_name, **kwds)
+        ext = ffiplatform.get_extension(ext_c_file, module_name, **kwds)
         updated = make_c_source(ffi, module_name, preamble, c_file)
         if call_c_compiler:
+            patchlist = []
             cwd = os.getcwd()
             try:
+                if embedding:
+                    _patch_for_embedding(patchlist)
+                if target != '*':
+                    _patch_for_target(patchlist, target)
                 os.chdir(tmpdir)
-                outputfilename = ffiplatform.compile('.', ext, compiler_verbose,
-                                                     target_extension,
-                                                     embedding=embedding)
+                outputfilename = ffiplatform.compile('.', ext, compiler_verbose)
             finally:
                 os.chdir(cwd)
+                _unpatch_meths(patchlist)
             return outputfilename
         else:
             return ext, updated
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -142,4 +142,9 @@
 
 .. branch: vmprof-newstack
 
-Refactor vmprof to work cross-operating-system.
\ No newline at end of file
+Refactor vmprof to work cross-operating-system.
+
+.. branch: seperate-strucmember_h
+
+Seperate structmember.h from Python.h Also enhance creating api functions
+to specify which header file they appear in (previously only pypy_decl.h) 
diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py
--- a/pypy/module/_cffi_backend/__init__.py
+++ b/pypy/module/_cffi_backend/__init__.py
@@ -3,7 +3,7 @@
 from rpython.rlib import rdynload, clibffi, entrypoint
 from rpython.rtyper.lltypesystem import rffi
 
-VERSION = "1.5.0"
+VERSION = "1.5.1"
 
 FFI_DEFAULT_ABI = clibffi.FFI_DEFAULT_ABI
 try:
@@ -69,6 +69,7 @@
     def startup(self, space):
         from pypy.module._cffi_backend import embedding
         embedding.glob.space = space
+        embedding.glob.patched_sys = False
 
 
 def get_dict_rtld_constants():
diff --git a/pypy/module/_cffi_backend/embedding.py b/pypy/module/_cffi_backend/embedding.py
--- a/pypy/module/_cffi_backend/embedding.py
+++ b/pypy/module/_cffi_backend/embedding.py
@@ -45,6 +45,26 @@
     pass
 glob = Global()
 
+def patch_sys(space):
+    # Annoying: CPython would just use the C-level std{in,out,err} as
+    # configured by the main application, for example in binary mode
+    # on Windows or with buffering turned off.  We can't easily do the
+    # same.  Instead, go for the safest bet (but possibly bad for
+    # performance) and open sys.std{in,out,err} unbuffered.  On
+    # Windows I guess binary mode is a better default choice.
+    #
+    # XXX if needed, we could add support for a flag passed to
+    # pypy_init_embedded_cffi_module().
+    if not glob.patched_sys:
+        space.appexec([], """():
+            import os
+            sys.stdin  = sys.__stdin__  = os.fdopen(0, 'rb', 0)
+            sys.stdout = sys.__stdout__ = os.fdopen(1, 'wb', 0)
+            sys.stderr = sys.__stderr__ = os.fdopen(2, 'wb', 0)
+        """)
+        glob.patched_sys = True
+
+
 def pypy_init_embedded_cffi_module(version, init_struct):
     # called from __init__.py
     name = "?"
@@ -56,6 +76,7 @@
         must_leave = False
         try:
             must_leave = space.threadlocals.try_enter_thread(space)
+            patch_sys(space)
             load_embedded_cffi_module(space, version, init_struct)
             res = 0
         except OperationError, operr:
@@ -84,72 +105,87 @@
     return rffi.cast(rffi.INT, res)
 
 # ____________________________________________________________
+
 if os.name == 'nt':
-    do_startup = r'''
-#include <stdio.h>
-#define WIN32_LEAN_AND_MEAN
+
+    do_includes = r"""
+#define _WIN32_WINNT 0x0501
 #include <windows.h>
-RPY_EXPORTED void rpython_startup_code(void);
-RPY_EXPORTED int pypy_setup_home(char *, int);
 
-static unsigned char _cffi_ready = 0;
-static const char *volatile _cffi_module_name;
+#define CFFI_INIT_HOME_PATH_MAX  _MAX_PATH
+static void _cffi_init(void);
+static void _cffi_init_error(const char *msg, const char *extra);
 
-static void _cffi_init_error(const char *msg, const char *extra)
+static int _cffi_init_home(char *output_home_path)
 {
-    fprintf(stderr,
-            "\nPyPy initialization failure when loading module '%s':\n%s%s\n",
-            _cffi_module_name, msg, extra);
-}
-
-BOOL CALLBACK _cffi_init(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContex)
-{
-
-    HMODULE hModule;
-    TCHAR home[_MAX_PATH];
-    rpython_startup_code();
-    RPyGilAllocate();
+    HMODULE hModule = 0;
+    DWORD res;
 
     GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | 
                        GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
                        (LPCTSTR)&_cffi_init, &hModule);
+
     if (hModule == 0 ) {
-        /* TODO turn the int into a string with FormatMessage */
-        
-        _cffi_init_error("dladdr() failed: ", "");
-        return TRUE;
+        _cffi_init_error("GetModuleHandleEx() failed", "");
+        return -1;
     }
-    GetModuleFileName(hModule, home, _MAX_PATH);
-    if (pypy_setup_home(home, 1) != 0) {
-        _cffi_init_error("pypy_setup_home() failed", "");
-        return TRUE;
+    res = GetModuleFileName(hModule, output_home_path, CFFI_INIT_HOME_PATH_MAX);
+    if (res >= CFFI_INIT_HOME_PATH_MAX) {
+        return -1;
     }
-    _cffi_ready = 1;
-    fprintf(stderr, "startup succeeded, home %s\n", home);
-    return TRUE;
+    return 0;
 }
 
-RPY_EXPORTED
-int pypy_carefully_make_gil(const char *name)
+static void _cffi_init_once(void)
 {
-    /* For CFFI: this initializes the GIL and loads the home path.
-       It can be called completely concurrently from unrelated threads.
-       It assumes that we don't hold the GIL before (if it exists), and we
-       don't hold it afterwards.
-    */
-    static INIT_ONCE s_init_once;
+    static LONG volatile lock = 0;
+    static int _init_called = 0;
 
-    _cffi_module_name = name;    /* not really thread-safe, but better than
-                                    nothing */
-    InitOnceExecuteOnce(&s_init_once, _cffi_init, NULL, NULL);
-    return (int)_cffi_ready - 1;
-}'''
+    while (InterlockedCompareExchange(&lock, 1, 0) != 0) {
+         SwitchToThread();        /* spin loop */
+    }
+    if (!_init_called) {
+        _cffi_init();
+        _init_called = 1;
+    }
+    InterlockedCompareExchange(&lock, 0, 1);
+}
+"""
+
 else:
-    do_startup = r"""
-#include <stdio.h>
+
+    do_includes = r"""
 #include <dlfcn.h>
 #include <pthread.h>
 
+#define CFFI_INIT_HOME_PATH_MAX  PATH_MAX
+static void _cffi_init(void);
+static void _cffi_init_error(const char *msg, const char *extra);
+
+static int _cffi_init_home(char *output_home_path)
+{
+    Dl_info info;
+    dlerror();   /* reset */
+    if (dladdr(&_cffi_init, &info) == 0) {
+        _cffi_init_error("dladdr() failed: ", dlerror());
+        return -1;
+    }
+    if (realpath(info.dli_fname, output_home_path) == NULL) {
+        perror("realpath() failed");
+        _cffi_init_error("realpath() failed", "");
+        return -1;
+    }
+    return 0;
+}
+
+static void _cffi_init_once(void)
+{
+    static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+    pthread_once(&once_control, _cffi_init);
+}
+"""
+
+do_startup = do_includes + r"""
 RPY_EXPORTED void rpython_startup_code(void);
 RPY_EXPORTED int pypy_setup_home(char *, int);
 
@@ -165,17 +201,13 @@
 
 static void _cffi_init(void)
 {
-    Dl_info info;
-    char *home;
+    char home[CFFI_INIT_HOME_PATH_MAX + 1];
 
     rpython_startup_code();
     RPyGilAllocate();
 
-    if (dladdr(&_cffi_init, &info) == 0) {
-        _cffi_init_error("dladdr() failed: ", dlerror());
+    if (_cffi_init_home(home) != 0)
         return;
-    }
-    home = realpath(info.dli_fname, NULL);
     if (pypy_setup_home(home, 1) != 0) {
         _cffi_init_error("pypy_setup_home() failed", "");
         return;
@@ -191,11 +223,9 @@
        It assumes that we don't hold the GIL before (if it exists), and we
        don't hold it afterwards.
     */
-    static pthread_once_t once_control = PTHREAD_ONCE_INIT;
-
     _cffi_module_name = name;    /* not really thread-safe, but better than
                                     nothing */
-    pthread_once(&once_control, _cffi_init);
+    _cffi_init_once();
     return (int)_cffi_ready - 1;
 }
 """
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -1,7 +1,7 @@
 # ____________________________________________________________
 
 import sys
-assert __version__ == "1.5.0", ("This test_c.py file is for testing a version"
+assert __version__ == "1.5.1", ("This test_c.py file is for testing a version"
                                 " of cffi that differs from the one that we"
                                 " get from 'import _cffi_backend'")
 if sys.version_info < (3,):
diff --git a/pypy/module/_cffi_backend/test/test_ztranslation.py b/pypy/module/_cffi_backend/test/test_ztranslation.py
--- a/pypy/module/_cffi_backend/test/test_ztranslation.py
+++ b/pypy/module/_cffi_backend/test/test_ztranslation.py
@@ -4,15 +4,18 @@
 
 # side-effect: FORMAT_LONGDOUBLE must be built before test_checkmodule()
 from pypy.module._cffi_backend import misc
-from pypy.module._cffi_backend import cffi1_module
+from pypy.module._cffi_backend import embedding
 
 
 def test_checkmodule():
     # prepare_file_argument() is not working without translating the _file
     # module too
     def dummy_prepare_file_argument(space, fileobj):
-        # call load_cffi1_module() too, from a random place like here
-        cffi1_module.load_cffi1_module(space, "foo", "foo", 42)
+        # call pypy_init_embedded_cffi_module() from a random place like here
+        # --- this calls load_cffi1_module(), too
+        embedding.pypy_init_embedded_cffi_module(
+            rffi.cast(rffi.INT, embedding.EMBED_VERSION_MIN),
+            42)
         return lltype.nullptr(rffi.CCHARP.TO)
     old = ctypeptr.prepare_file_argument
     try:
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -59,7 +59,7 @@
 class CConfig:
     _compilation_info_ = ExternalCompilationInfo(
         include_dirs=include_dirs,
-        includes=['Python.h', 'stdarg.h'],
+        includes=['Python.h', 'stdarg.h', 'structmember.h'],
         compile_extra=['-DPy_BUILD_CORE'],
         )
 
@@ -129,6 +129,7 @@
 for name in constant_names:
     setattr(CConfig_constants, name, rffi_platform.ConstantInteger(name))
 udir.join('pypy_decl.h').write("/* Will be filled later */\n")
+udir.join('pypy_structmember_decl.h').write("/* Will be filled later */\n")
 udir.join('pypy_macros.h').write("/* Will be filled later */\n")
 globals().update(rffi_platform.configure(CConfig_constants))
 
@@ -147,7 +148,7 @@
     # XXX: 20 lines of code to recursively copy a directory, really??
     assert dstdir.check(dir=True)
     headers = include_dir.listdir('*.h') + include_dir.listdir('*.inl')
-    for name in ("pypy_decl.h", "pypy_macros.h"):
+    for name in ("pypy_decl.h", "pypy_macros.h", "pypy_structmember_decl.h"):
         headers.append(udir.join(name))
     _copy_header_files(headers, dstdir)
 
@@ -232,7 +233,7 @@
                 wrapper.c_name = cpyext_namespace.uniquename(self.c_name)
         return wrapper
 
-def cpython_api(argtypes, restype, error=_NOT_SPECIFIED, external=True,
+def cpython_api(argtypes, restype, error=_NOT_SPECIFIED, header='pypy_decl.h',
                 gil=None):
     """
     Declares a function to be exported.
@@ -241,8 +242,8 @@
       special value 'CANNOT_FAIL' (also when restype is Void) turns an eventual
       exception into a wrapped SystemError.  Unwrapped exceptions also cause a
       SytemError.
-    - set `external` to False to get a C function pointer, but not exported by
-      the API headers.
+    - `header` is the header file to export the function in, Set to None to get
+      a C function pointer, but not exported by the API headers.
     - set `gil` to "acquire", "release" or "around" to acquire the GIL,
       release the GIL, or both
     """
@@ -263,7 +264,7 @@
 
     def decorate(func):
         func_name = func.func_name
-        if external:
+        if header is not None:
             c_name = None
         else:
             c_name = func_name
@@ -271,7 +272,7 @@
                                    c_name=c_name, gil=gil)
         func.api_func = api_function
 
-        if external:
+        if header is not None:
             assert func_name not in FUNCTIONS, (
                 "%s already registered" % func_name)
 
@@ -363,8 +364,9 @@
 
         unwrapper_catch = make_unwrapper(True)
         unwrapper_raise = make_unwrapper(False)
-        if external:
+        if header is not None:
             FUNCTIONS[func_name] = api_function
+            FUNCTIONS_BY_HEADER.setdefault(header, {})[func_name] = api_function
         INTERPLEVEL_API[func_name] = unwrapper_catch # used in tests
         return unwrapper_raise # used in 'normal' RPython code.
     return decorate
@@ -383,6 +385,7 @@
 
 INTERPLEVEL_API = {}
 FUNCTIONS = {}
+FUNCTIONS_BY_HEADER = {}
 
 # These are C symbols which cpyext will export, but which are defined in .c
 # files somewhere in the implementation of cpyext (rather than being defined in
@@ -811,6 +814,7 @@
     global_code = '\n'.join(global_objects)
 
     prologue = ("#include <Python.h>\n"
+                "#include <structmember.h>\n"
                 "#include <src/thread.c>\n")
     code = (prologue +
             struct_declaration_code +
@@ -960,7 +964,8 @@
     "NOT_RPYTHON"
     # implement function callbacks and generate function decls
     functions = []
-    pypy_decls = []
+    decls = {}
+    pypy_decls = decls['pypy_decl.h'] = []
     pypy_decls.append("#ifndef _PYPY_PYPY_DECL_H\n")
     pypy_decls.append("#define _PYPY_PYPY_DECL_H\n")
     pypy_decls.append("#ifndef PYPY_STANDALONE\n")
@@ -973,17 +978,23 @@
     for decl in FORWARD_DECLS:
         pypy_decls.append("%s;" % (decl,))
 
-    for name, func in sorted(FUNCTIONS.iteritems()):
-        restype, args = c_function_signature(db, func)
-        pypy_decls.append("PyAPI_FUNC(%s) %s(%s);" % (restype, name, args))
-        if api_struct:
-            callargs = ', '.join('arg%d' % (i,)
-                                 for i in range(len(func.argtypes)))
-            if func.restype is lltype.Void:
-                body = "{ _pypyAPI.%s(%s); }" % (name, callargs)
-            else:
-                body = "{ return _pypyAPI.%s(%s); }" % (name, callargs)
-            functions.append('%s %s(%s)\n%s' % (restype, name, args, body))
+    for header_name, header_functions in FUNCTIONS_BY_HEADER.iteritems():
+        if header_name not in decls:
+            header = decls[header_name] = []
+        else:
+            header = decls[header_name]
+
+        for name, func in sorted(header_functions.iteritems()):
+            restype, args = c_function_signature(db, func)
+            header.append("PyAPI_FUNC(%s) %s(%s);" % (restype, name, args))
+            if api_struct:
+                callargs = ', '.join('arg%d' % (i,)
+                                    for i in range(len(func.argtypes)))
+                if func.restype is lltype.Void:
+                    body = "{ _pypyAPI.%s(%s); }" % (name, callargs)
+                else:
+                    body = "{ return _pypyAPI.%s(%s); }" % (name, callargs)
+                functions.append('%s %s(%s)\n%s' % (restype, name, args, body))
     for name in VA_TP_LIST:
         name_no_star = process_va_name(name)
         header = ('%s pypy_va_get_%s(va_list* vp)' %
@@ -1007,8 +1018,9 @@
     pypy_decls.append("#endif /*PYPY_STANDALONE*/\n")
     pypy_decls.append("#endif /*_PYPY_PYPY_DECL_H*/\n")
 
-    pypy_decl_h = udir.join('pypy_decl.h')
-    pypy_decl_h.write('\n'.join(pypy_decls))
+    for header_name, header_decls in decls.iteritems():
+        decl_h = udir.join(header_name)
+        decl_h.write('\n'.join(header_decls))
     return functions
 
 separate_module_files = [source_dir / "varargwrapper.c",
diff --git a/pypy/module/cpyext/bufferobject.py b/pypy/module/cpyext/bufferobject.py
--- a/pypy/module/cpyext/bufferobject.py
+++ b/pypy/module/cpyext/bufferobject.py
@@ -73,7 +73,7 @@
         "Don't know how to realize a buffer"))
 
 
- at cpython_api([PyObject], lltype.Void, external=False)
+ at cpython_api([PyObject], lltype.Void, header=None)
 def buffer_dealloc(space, py_obj):
     py_buf = rffi.cast(PyBufferObject, py_obj)
     if py_buf.c_b_base:
diff --git a/pypy/module/cpyext/frameobject.py b/pypy/module/cpyext/frameobject.py
--- a/pypy/module/cpyext/frameobject.py
+++ b/pypy/module/cpyext/frameobject.py
@@ -39,7 +39,7 @@
     py_frame.c_f_locals = make_ref(space, frame.get_w_locals())
     rffi.setintfield(py_frame, 'c_f_lineno', frame.getorcreatedebug().f_lineno)
 
- at cpython_api([PyObject], lltype.Void, external=False)
+ at cpython_api([PyObject], lltype.Void, header=None)
 def frame_dealloc(space, py_obj):
     py_frame = rffi.cast(PyFrameObject, py_obj)
     py_code = rffi.cast(PyObject, py_frame.c_f_code)
diff --git a/pypy/module/cpyext/funcobject.py b/pypy/module/cpyext/funcobject.py
--- a/pypy/module/cpyext/funcobject.py
+++ b/pypy/module/cpyext/funcobject.py
@@ -56,7 +56,7 @@
     assert isinstance(w_obj, Function)
     py_func.c_func_name = make_ref(space, space.wrap(w_obj.name))
 
- at cpython_api([PyObject], lltype.Void, external=False)
+ at cpython_api([PyObject], lltype.Void, header=None)
 def function_dealloc(space, py_obj):
     py_func = rffi.cast(PyFunctionObject, py_obj)
     Py_DecRef(space, py_func.c_func_name)
@@ -75,7 +75,7 @@
     rffi.setintfield(py_code, 'c_co_flags', co_flags)
     rffi.setintfield(py_code, 'c_co_argcount', w_obj.co_argcount)
 
- at cpython_api([PyObject], lltype.Void, external=False)
+ at cpython_api([PyObject], lltype.Void, header=None)
 def code_dealloc(space, py_obj):
     py_code = rffi.cast(PyCodeObject, py_obj)
     Py_DecRef(space, py_code.c_co_name)
diff --git a/pypy/module/cpyext/include/Python.h b/pypy/module/cpyext/include/Python.h
--- a/pypy/module/cpyext/include/Python.h
+++ b/pypy/module/cpyext/include/Python.h
@@ -84,6 +84,7 @@
 #include "pyconfig.h"
 
 #include "object.h"
+#include "pymath.h"
 #include "pyport.h"
 #include "warnings.h"
 
@@ -115,7 +116,6 @@
 #include "compile.h"
 #include "frameobject.h"
 #include "eval.h"
-#include "pymath.h"
 #include "pymem.h"
 #include "pycobject.h"
 #include "pycapsule.h"
@@ -132,9 +132,6 @@
 /* Missing definitions */
 #include "missing.h"
 
-// XXX This shouldn't be included here
-#include "structmember.h"
-
 #include <pypy_decl.h>
 
 /* Define macros for inline documentation. */
diff --git a/pypy/module/cpyext/include/floatobject.h b/pypy/module/cpyext/include/floatobject.h
--- a/pypy/module/cpyext/include/floatobject.h
+++ b/pypy/module/cpyext/include/floatobject.h
@@ -7,6 +7,18 @@
 extern "C" {
 #endif
 
+#define PyFloat_STR_PRECISION 12
+
+#ifdef Py_NAN
+#define Py_RETURN_NAN return PyFloat_FromDouble(Py_NAN)
+#endif
+
+#define Py_RETURN_INF(sign) do                                  \
+        if (copysign(1., sign) == 1.) {                         \
+                return PyFloat_FromDouble(Py_HUGE_VAL); \
+        } else {                                                \
+                return PyFloat_FromDouble(-Py_HUGE_VAL);        \
+        } while(0)
 
 #ifdef __cplusplus
 }
diff --git a/pypy/module/cpyext/include/pymath.h b/pypy/module/cpyext/include/pymath.h
--- a/pypy/module/cpyext/include/pymath.h
+++ b/pypy/module/cpyext/include/pymath.h
@@ -17,4 +17,35 @@
 #define Py_HUGE_VAL HUGE_VAL
 #endif
 
+/* Py_NAN
+ * A value that evaluates to a NaN. On IEEE 754 platforms INF*0 or
+ * INF/INF works. Define Py_NO_NAN in pyconfig.h if your platform
+ * doesn't support NaNs.
+ */
+#if !defined(Py_NAN) && !defined(Py_NO_NAN)
+#if !defined(__INTEL_COMPILER)
+    #define Py_NAN (Py_HUGE_VAL * 0.)
+#else /* __INTEL_COMPILER */
+    #if defined(ICC_NAN_STRICT)
+        #pragma float_control(push)
+        #pragma float_control(precise, on)
+        #pragma float_control(except,  on)
+        #if defined(_MSC_VER)
+            __declspec(noinline)
+        #else /* Linux */
+            __attribute__((noinline))
+        #endif /* _MSC_VER */
+        static double __icc_nan()
+        {
+            return sqrt(-1.0);
+        }
+        #pragma float_control (pop)
+        #define Py_NAN __icc_nan()
+    #else /* ICC_NAN_RELAXED as default for Intel Compiler */
+        static union { unsigned char buf[8]; double __icc_nan; } __nan_store = {0,0,0,0,0,0,0xf8,0x7f};
+        #define Py_NAN (__nan_store.__icc_nan)
+    #endif /* ICC_NAN_STRICT */
+#endif /* __INTEL_COMPILER */
+#endif
+
 #endif /* Py_PYMATH_H */
diff --git a/pypy/module/cpyext/include/structmember.h b/pypy/module/cpyext/include/structmember.h
--- a/pypy/module/cpyext/include/structmember.h
+++ b/pypy/module/cpyext/include/structmember.h
@@ -4,54 +4,85 @@
 extern "C" {
 #endif
 
+
+/* Interface to map C struct members to Python object attributes */
+
 #include <stddef.h> /* For offsetof */
+
+/* The offsetof() macro calculates the offset of a structure member
+   in its structure.  Unfortunately this cannot be written down
+   portably, hence it is provided by a Standard C header file.
+   For pre-Standard C compilers, here is a version that usually works
+   (but watch out!): */
+
 #ifndef offsetof
 #define offsetof(type, member) ( (int) & ((type*)0) -> member )
 #endif
 
+/* An array of memberlist structures defines the name, type and offset
+   of selected members of a C structure.  These can be read by
+   PyMember_Get() and set by PyMember_Set() (except if their READONLY flag
+   is set).  The array must be terminated with an entry whose name
+   pointer is NULL. */
+
+
 
 typedef struct PyMemberDef {
-	/* Current version, use this */
-	char *name;
-	int type;
-	Py_ssize_t offset;
-	int flags;
-	char *doc;
+    /* Current version, use this */
+    char *name;
+    int type;
+    Py_ssize_t offset;
+    int flags;
+    char *doc;
 } PyMemberDef;
 
+/* Types */
+#define T_SHORT         0
+#define T_INT           1
+#define T_LONG          2
+#define T_FLOAT         3
+#define T_DOUBLE        4
+#define T_STRING        5
+#define T_OBJECT        6
+/* XXX the ordering here is weird for binary compatibility */
+#define T_CHAR          7       /* 1-character string */
+#define T_BYTE          8       /* 8-bit signed int */
+/* unsigned variants: */
+#define T_UBYTE         9
+#define T_USHORT        10
+#define T_UINT          11
+#define T_ULONG         12
 
-/* Types. These constants are also in structmemberdefs.py. */
-#define T_SHORT		0
-#define T_INT		1
-#define T_LONG		2
-#define T_FLOAT		3
-#define T_DOUBLE	4
-#define T_STRING	5
-#define T_OBJECT	6
-#define T_CHAR		7	/* 1-character string */
-#define T_BYTE		8	/* 8-bit signed int */
-#define T_UBYTE		9
-#define T_USHORT	10
-#define T_UINT		11
-#define T_ULONG		12
-#define T_STRING_INPLACE 13	/* Strings contained in the structure */
-#define T_BOOL		14
-#define T_OBJECT_EX	16	/* Like T_OBJECT, but raises AttributeError
-				   when the value is NULL, instead of
-				   converting to None. */
-#define T_LONGLONG	17
-#define T_ULONGLONG	18
-#define T_PYSSIZET	19
+/* Added by Jack: strings contained in the structure */
+#define T_STRING_INPLACE        13
+
+/* Added by Lillo: bools contained in the structure (assumed char) */
+#define T_BOOL          14
+
+#define T_OBJECT_EX     16      /* Like T_OBJECT, but raises AttributeError
+                   when the value is NULL, instead of
+                   converting to None. */
+#ifdef HAVE_LONG_LONG
+#define T_LONGLONG      17
+#define T_ULONGLONG      18
+#endif /* HAVE_LONG_LONG */
+
+#define T_PYSSIZET       19 /* Py_ssize_t */
 
 /* Flags. These constants are also in structmemberdefs.py. */
-#define READONLY      1
-#define RO            READONLY                /* Shorthand */
+#define READONLY        1
+#define RO              READONLY                /* Shorthand */
 #define READ_RESTRICTED 2
 #define PY_WRITE_RESTRICTED 4
-#define RESTRICTED    (READ_RESTRICTED | PY_WRITE_RESTRICTED)
+#define RESTRICTED      (READ_RESTRICTED | PY_WRITE_RESTRICTED)
+
+
+/* API functions. */
+#include "pypy_structmember_decl.h"
 
 
 #ifdef __cplusplus
 }
 #endif
 #endif /* !Py_STRUCTMEMBER_H */
+
diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py
--- a/pypy/module/cpyext/methodobject.py
+++ b/pypy/module/cpyext/methodobject.py
@@ -50,7 +50,7 @@
     py_func.c_m_self = make_ref(space, w_obj.w_self)
     py_func.c_m_module = make_ref(space, w_obj.w_module)
 
- at cpython_api([PyObject], lltype.Void, external=False)
+ at cpython_api([PyObject], lltype.Void, header=None)
 def cfunction_dealloc(space, py_obj):
     py_func = rffi.cast(PyCFunctionObject, py_obj)
     Py_DecRef(space, py_func.c_m_self)
diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py
--- a/pypy/module/cpyext/pyobject.py
+++ b/pypy/module/cpyext/pyobject.py
@@ -70,7 +70,7 @@
     alloc     : allocate and basic initialization of a raw PyObject
     attach    : Function called to tie a raw structure to a pypy object
     realize   : Function called to create a pypy object from a raw struct
-    dealloc   : a cpython_api(external=False), similar to PyObject_dealloc
+    dealloc   : a cpython_api(header=None), similar to PyObject_dealloc
     """
 
     tp_basestruct = kw.pop('basestruct', PyObject.TO)
diff --git a/pypy/module/cpyext/pytraceback.py b/pypy/module/cpyext/pytraceback.py
--- a/pypy/module/cpyext/pytraceback.py
+++ b/pypy/module/cpyext/pytraceback.py
@@ -41,7 +41,7 @@
     rffi.setintfield(py_traceback, 'c_tb_lasti', traceback.lasti)
     rffi.setintfield(py_traceback, 'c_tb_lineno',traceback.get_lineno())
 
- at cpython_api([PyObject], lltype.Void, external=False)
+ at cpython_api([PyObject], lltype.Void, header=None)
 def traceback_dealloc(space, py_obj):
     py_traceback = rffi.cast(PyTracebackObject, py_obj)
     Py_DecRef(space, rffi.cast(PyObject, py_traceback.c_tb_next))
diff --git a/pypy/module/cpyext/sliceobject.py b/pypy/module/cpyext/sliceobject.py
--- a/pypy/module/cpyext/sliceobject.py
+++ b/pypy/module/cpyext/sliceobject.py
@@ -36,7 +36,7 @@
     py_slice.c_stop = make_ref(space, w_obj.w_stop)
     py_slice.c_step = make_ref(space, w_obj.w_step)
 
- at cpython_api([PyObject], lltype.Void, external=False)
+ at cpython_api([PyObject], lltype.Void, header=None)
 def slice_dealloc(space, py_obj):
     """Frees allocated PyStringObject resources.
     """
diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py
--- a/pypy/module/cpyext/slotdefs.py
+++ b/pypy/module/cpyext/slotdefs.py
@@ -309,7 +309,7 @@
 
     return space.wrap(generic_cpy_call(space, func_target, w_self, w_other))
 
- at cpython_api([PyTypeObjectPtr, PyObject, PyObject], PyObject, external=False)
+ at cpython_api([PyTypeObjectPtr, PyObject, PyObject], PyObject, header=None)
 def slot_tp_new(space, type, w_args, w_kwds):
     from pypy.module.cpyext.tupleobject import PyTuple_Check
     pyo = rffi.cast(PyObject, type)
@@ -320,30 +320,30 @@
     w_args_new = space.newtuple(args_w)
     return space.call(w_func, w_args_new, w_kwds)
 
- at cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, error=-1, external=False)
+ at cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, error=-1, header=None)
 def slot_tp_init(space, w_self, w_args, w_kwds):
     w_descr = space.lookup(w_self, '__init__')
     args = Arguments.frompacked(space, w_args, w_kwds)
     space.get_and_call_args(w_descr, w_self, args)
     return 0
 
- at cpython_api([PyObject, PyObject, PyObject], PyObject, external=False)
+ at cpython_api([PyObject, PyObject, PyObject], PyObject, header=None)
 def slot_tp_call(space, w_self, w_args, w_kwds):
     return space.call(w_self, w_args, w_kwds)
 
- at cpython_api([PyObject], PyObject, external=False)
+ at cpython_api([PyObject], PyObject, header=None)
 def slot_tp_str(space, w_self):
     return space.str(w_self)
 
- at cpython_api([PyObject], PyObject, external=False)
+ at cpython_api([PyObject], PyObject, header=None)
 def slot_nb_int(space, w_self):
     return space.int(w_self)
 
- at cpython_api([PyObject], PyObject, external=False)
+ at cpython_api([PyObject], PyObject, header=None)
 def slot_tp_iter(space, w_self):
     return space.iter(w_self)
 
- at cpython_api([PyObject], PyObject, external=False)
+ at cpython_api([PyObject], PyObject, header=None)
 def slot_tp_iternext(space, w_self):
     return space.next(w_self)
 
@@ -371,7 +371,7 @@
             return
 
         @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real,
-                     error=-1, external=True) # XXX should not be exported
+                     error=-1) # XXX should be header=None
         @func_renamer("cpyext_tp_setattro_%s" % (typedef.name,))
         def slot_tp_setattro(space, w_self, w_name, w_value):
             if w_value is not None:
@@ -385,8 +385,7 @@
         if getattr_fn is None:
             return
 
-        @cpython_api([PyObject, PyObject], PyObject,
-                     external=True)
+        @cpython_api([PyObject, PyObject], PyObject)
         @func_renamer("cpyext_tp_getattro_%s" % (typedef.name,))
         def slot_tp_getattro(space, w_self, w_name):
             return space.call_function(getattr_fn, w_self, w_name)
diff --git a/pypy/module/cpyext/stringobject.py b/pypy/module/cpyext/stringobject.py
--- a/pypy/module/cpyext/stringobject.py
+++ b/pypy/module/cpyext/stringobject.py
@@ -103,7 +103,7 @@
     track_reference(space, py_obj, w_obj)
     return w_obj
 
- at cpython_api([PyObject], lltype.Void, external=False)
+ at cpython_api([PyObject], lltype.Void, header=None)
 def string_dealloc(space, py_obj):
     """Frees allocated PyStringObject resources.
     """
diff --git a/pypy/module/cpyext/structmember.py b/pypy/module/cpyext/structmember.py
--- a/pypy/module/cpyext/structmember.py
+++ b/pypy/module/cpyext/structmember.py
@@ -31,8 +31,10 @@
     (T_PYSSIZET, rffi.SSIZE_T, PyLong_AsSsize_t),
     ])
 
+_HEADER = 'pypy_structmember_decl.h'
 
- at cpython_api([PyObject, lltype.Ptr(PyMemberDef)], PyObject)
+
+ at cpython_api([PyObject, lltype.Ptr(PyMemberDef)], PyObject, header=_HEADER)
 def PyMember_GetOne(space, obj, w_member):
     addr = rffi.cast(ADDR, obj)
     addr += w_member.c_offset
@@ -83,7 +85,8 @@
     return w_result
 
 
- at cpython_api([PyObject, lltype.Ptr(PyMemberDef), PyObject], rffi.INT_real, error=-1)
+ at cpython_api([PyObject, lltype.Ptr(PyMemberDef), PyObject], rffi.INT_real,
+             error=-1, header=_HEADER)
 def PyMember_SetOne(space, obj, w_member, w_value):
     addr = rffi.cast(ADDR, obj)
     addr += w_member.c_offset
diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -863,3 +863,15 @@
                 os.unlink('_imported_already')
             except OSError:
                 pass
+
+    def test_no_structmember(self):
+        """structmember.h should not be included by default."""
+        mod = self.import_extension('foo', [
+            ('bar', 'METH_NOARGS',
+             '''
+             /* reuse a name that is #defined in structmember.h */
+             int RO;
+             Py_RETURN_NONE;
+             '''
+             ),
+        ])
diff --git a/pypy/module/cpyext/test/test_floatobject.py b/pypy/module/cpyext/test/test_floatobject.py
--- a/pypy/module/cpyext/test/test_floatobject.py
+++ b/pypy/module/cpyext/test/test_floatobject.py
@@ -45,3 +45,35 @@
             ])
         assert module.from_string() == 1234.56
         assert type(module.from_string()) is float
+
+class AppTestFloatMacros(AppTestCpythonExtensionBase):
+    def test_return_nan(self):
+        import math
+
+        module = self.import_extension('foo', [
+            ("return_nan", "METH_NOARGS",
+             "Py_RETURN_NAN;"),
+            ])
+        assert math.isnan(module.return_nan())
+
+    def test_return_inf(self):
+        import math
+
+        module = self.import_extension('foo', [
+            ("return_inf", "METH_NOARGS",
+             "Py_RETURN_INF(10);"),
+            ])
+        inf = module.return_inf()
+        assert inf > 0
+        assert math.isinf(inf)
+
+    def test_return_inf_negative(self):
+        import math
+
+        module = self.import_extension('foo', [
+            ("return_neginf", "METH_NOARGS",
+             "Py_RETURN_INF(-10);"),
+            ])
+        neginf = module.return_neginf()
+        assert neginf < 0
+        assert math.isinf(neginf)
diff --git a/pypy/module/cpyext/test/test_intobject.py b/pypy/module/cpyext/test/test_intobject.py
--- a/pypy/module/cpyext/test/test_intobject.py
+++ b/pypy/module/cpyext/test/test_intobject.py
@@ -99,6 +99,7 @@
              """),
             ],
             prologue="""
+            #include "structmember.h"
             typedef struct
             {
                 PyObject_HEAD
diff --git a/pypy/module/cpyext/test/test_translate.py b/pypy/module/cpyext/test/test_translate.py
--- a/pypy/module/cpyext/test/test_translate.py
+++ b/pypy/module/cpyext/test/test_translate.py
@@ -19,7 +19,7 @@
 
     @specialize.memo()
     def get_tp_function(space, typedef):
-        @cpython_api([], lltype.Signed, error=-1, external=False)
+        @cpython_api([], lltype.Signed, error=-1, header=None)
         def slot_tp_function(space):
             return typedef.value
 
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -183,7 +183,7 @@
     if pto.c_tp_new:
         add_tp_new_wrapper(space, dict_w, pto)
 
- at cpython_api([PyObject, PyObject, PyObject], PyObject, external=False)
+ at cpython_api([PyObject, PyObject, PyObject], PyObject, header=None)
 def tp_new_wrapper(space, self, w_args, w_kwds):
     tp_new = rffi.cast(PyTypeObjectPtr, self).c_tp_new
 
@@ -311,7 +311,7 @@
                    dealloc=type_dealloc)
 
 
- at cpython_api([PyObject], lltype.Void, external=False)
+ at cpython_api([PyObject], lltype.Void, header=None)
 def subtype_dealloc(space, obj):
     pto = obj.c_ob_type
     base = pto
@@ -327,7 +327,7 @@
     # hopefully this does not clash with the memory model assumed in
     # extension modules
 
- at cpython_api([PyObject, Py_ssize_tP], lltype.Signed, external=False,
+ at cpython_api([PyObject, Py_ssize_tP], lltype.Signed, header=None,
              error=CANNOT_FAIL)
 def str_segcount(space, w_obj, ref):
     if ref:
@@ -335,7 +335,7 @@
     return 1
 
 @cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
-             external=False, error=-1)
+             header=None, error=-1)
 def str_getreadbuffer(space, w_str, segment, ref):
     from pypy.module.cpyext.stringobject import PyString_AsString
     if segment != 0:
@@ -348,7 +348,7 @@
     return space.len_w(w_str)
 
 @cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed,
-             external=False, error=-1)
+             header=None, error=-1)
 def str_getcharbuffer(space, w_str, segment, ref):
     from pypy.module.cpyext.stringobject import PyString_AsString
     if segment != 0:
@@ -361,7 +361,7 @@
     return space.len_w(w_str)
 
 @cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
-             external=False, error=-1)
+             header=None, error=-1)
 def buf_getreadbuffer(space, pyref, segment, ref):
     from pypy.module.cpyext.bufferobject import PyBufferObject
     if segment != 0:
@@ -393,7 +393,7 @@
                                  buf_getreadbuffer.api_func.get_wrapper(space))
     pto.c_tp_as_buffer = c_buf
 
- at cpython_api([PyObject], lltype.Void, external=False)
+ at cpython_api([PyObject], lltype.Void, header=None)
 def type_dealloc(space, obj):
     from pypy.module.cpyext.object import PyObject_dealloc
     obj_pto = rffi.cast(PyTypeObjectPtr, obj)
diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py
--- a/pypy/module/cpyext/unicodeobject.py
+++ b/pypy/module/cpyext/unicodeobject.py
@@ -75,7 +75,7 @@
     track_reference(space, py_obj, w_obj)
     return w_obj
 
- at cpython_api([PyObject], lltype.Void, external=False)
+ at cpython_api([PyObject], lltype.Void, header=None)
 def unicode_dealloc(space, py_obj):
     py_unicode = rffi.cast(PyUnicodeObject, py_obj)
     if py_unicode.c_buffer:
diff --git a/pypy/module/sys/interp_encoding.py b/pypy/module/sys/interp_encoding.py
--- a/pypy/module/sys/interp_encoding.py
+++ b/pypy/module/sys/interp_encoding.py
@@ -34,7 +34,11 @@
 elif sys.platform == "darwin":
     base_encoding = "utf-8"
 else:
-    base_encoding = None
+    # In CPython, the default base encoding is NULL. This is paired with a
+    # comment that says "If non-NULL, this is different than the default
+    # encoding for strings". Therefore, the default filesystem encoding is the
+    # default encoding for strings, which is ASCII.
+    base_encoding = "ascii"
 
 def _getfilesystemencoding(space):
     encoding = base_encoding
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
@@ -1847,3 +1847,8 @@
             thread.start_new_thread(f, ())
         time.sleep(1.5)
         assert seen == ['init!', 'init done'] + 6 * [7]
+
+    def test_sizeof_struct_directly(self):
+        # only works with the Python FFI instances
+        ffi = FFI(backend=self.Backend())
+        assert ffi.sizeof("struct{int a;}") == ffi.sizeof("int")
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ffi_backend.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ffi_backend.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ffi_backend.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ffi_backend.py
@@ -420,3 +420,7 @@
             ]:
             x = ffi.sizeof(name)
             assert 1 <= x <= 16
+
+    def test_ffi_def_extern(self):
+        ffi = FFI()
+        py.test.raises(ValueError, ffi.def_extern)
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py
@@ -92,8 +92,8 @@
     assert lib.sin(1.23) == math.sin(1.23)
 
 def _Wconversion(cdef, source, **kargs):
-    if sys.platform == 'win32':
-        py.test.skip("needs GCC or Clang")
+    if sys.platform in ('win32', 'darwin'):
+        py.test.skip("needs GCC")
     ffi = FFI()
     ffi.cdef(cdef)
     py.test.raises(VerificationError, ffi.verify, source, **kargs)
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
@@ -1714,3 +1714,33 @@
     # a case where 'onerror' is not callable
     py.test.raises(TypeError, ffi.def_extern(name='bar', onerror=42),
                    lambda x: x)
+
+def test_extern_python_stdcall():
+    ffi = FFI()
+    ffi.cdef("""
+        extern "Python" int __stdcall foo(int);
+        extern "Python" int WINAPI bar(int);
+        int (__stdcall * mycb1)(int);
+        int indirect_call(int);
+    """)
+    lib = verify(ffi, 'test_extern_python_stdcall', """
+        #ifndef _MSC_VER
+        #  define __stdcall
+        #endif
+        static int (__stdcall * mycb1)(int);
+        static int indirect_call(int x) {
+            return mycb1(x);
+        }
+    """)
+    #
+    @ffi.def_extern()
+    def foo(x):
+        return x + 42
+    @ffi.def_extern()
+    def bar(x):
+        return x + 43
+    assert lib.foo(100) == 142
+    assert lib.bar(100) == 143
+    lib.mycb1 = lib.foo
+    assert lib.mycb1(200) == 242
+    assert lib.indirect_call(300) == 342
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py
@@ -72,8 +72,8 @@
     assert lib.sin(1.23) == math.sin(1.23)
 
 def _Wconversion(cdef, source, **kargs):
-    if sys.platform == 'win32':
-        py.test.skip("needs GCC or Clang")
+    if sys.platform in ('win32', 'darwin'):
+        py.test.skip("needs GCC")
     ffi = FFI()
     ffi.cdef(cdef)
     py.test.raises(VerificationError, ffi.verify, source, **kargs)
@@ -2092,20 +2092,20 @@
     old = sys.getdlopenflags()
     try:
         ffi1 = FFI()
-        ffi1.cdef("int foo_verify_dlopen_flags;")
+        ffi1.cdef("int foo_verify_dlopen_flags_1;")
         sys.setdlopenflags(ffi1.RTLD_GLOBAL | ffi1.RTLD_NOW)
-        lib1 = ffi1.verify("int foo_verify_dlopen_flags;")
+        lib1 = ffi1.verify("int foo_verify_dlopen_flags_1;")
     finally:
         sys.setdlopenflags(old)
 
     ffi2 = FFI()
     ffi2.cdef("int *getptr(void);")
     lib2 = ffi2.verify("""
-        extern int foo_verify_dlopen_flags;
-        static int *getptr(void) { return &foo_verify_dlopen_flags; }
+        extern int foo_verify_dlopen_flags_1;
+        static int *getptr(void) { return &foo_verify_dlopen_flags_1; }
     """)
     p = lib2.getptr()
-    assert ffi1.addressof(lib1, 'foo_verify_dlopen_flags') == p
+    assert ffi1.addressof(lib1, 'foo_verify_dlopen_flags_1') == p
 
 def test_consider_not_implemented_function_type():
     ffi = FFI()
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
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_zdist.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_zdist.py
@@ -49,7 +49,8 @@
             import setuptools
         except ImportError:


More information about the pypy-commit mailing list