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