Author: Armin Rigo <ar...@tunes.org>
Branch: 
Changeset: r82164:450c1a29e5d3
Date: 2016-02-11 16:09 +0100
http://bitbucket.org/pypy/pypy/changeset/450c1a29e5d3/

Log:    hg merge cffi-embedding-win32

        Support for cffi embedding on Windows. Thanks matti for the initial
        work

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
@@ -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:
@@ -85,14 +106,86 @@
 
 # ____________________________________________________________
 
+if os.name == 'nt':
 
-eci = ExternalCompilationInfo(separate_module_sources=[
-r"""
-/* XXX Windows missing */
-#include <stdio.h>
+    do_includes = r"""
+#define _WIN32_WINNT 0x0501
+#include <windows.h>
+
+#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 int _cffi_init_home(char *output_home_path)
+{
+    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 ) {
+        _cffi_init_error("GetModuleHandleEx() failed", "");
+        return -1;
+    }
+    res = GetModuleFileName(hModule, output_home_path, 
CFFI_INIT_HOME_PATH_MAX);
+    if (res >= CFFI_INIT_HOME_PATH_MAX) {
+        return -1;
+    }
+    return 0;
+}
+
+static void _cffi_init_once(void)
+{
+    static LONG volatile lock = 0;
+    static int _init_called = 0;
+
+    while (InterlockedCompareExchange(&lock, 1, 0) != 0) {
+         SwitchToThread();        /* spin loop */
+    }
+    if (!_init_called) {
+        _cffi_init();
+        _init_called = 1;
+    }
+    InterlockedCompareExchange(&lock, 0, 1);
+}
+"""
+
+else:
+
+    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);
 
@@ -108,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;
@@ -134,13 +223,12 @@
        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;
 }
-"""])
+"""
+eci = ExternalCompilationInfo(separate_module_sources=[do_startup])
 
 declare_c_function = rffi.llexternal_use_eci(eci)
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 cffi1_module, 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/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py
--- a/pypy/objspace/fake/objspace.py
+++ b/pypy/objspace/fake/objspace.py
@@ -397,9 +397,14 @@
             space.wrap(value)
 
 class FakeCompiler(object):
-    pass
+    def compile(self, code, name, mode, flags):
+        return FakePyCode()
 FakeObjSpace.default_compiler = FakeCompiler()
 
+class FakePyCode(W_Root):
+    def exec_code(self, space, w_globals, w_locals):
+        return W_Root()
+
 
 class FakeModule(W_Root):
     def __init__(self):
diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py
--- a/pypy/tool/release/package.py
+++ b/pypy/tool/release/package.py
@@ -129,6 +129,9 @@
         win_extras = ['libpypy-c.dll', 'sqlite3.dll']
         if not options.no_tk:
             win_extras += ['tcl85.dll', 'tk85.dll']
+        # add the .lib too, which is convenient to compile other programs
+        # that use the .dll (and for cffi's embedding mode)
+        win_extras.append('libpypy-c.lib')
 
         for extra in win_extras:
             p = pypy_c.dirpath().join(extra)
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to