Author: Armin Rigo <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit