Author: Armin Rigo <[email protected]>
Branch: win32-stdcall
Changeset: r2305:91834f9534f8
Date: 2015-10-05 20:05 +0200
http://bitbucket.org/cffi/cffi/changeset/91834f9534f8/
Log: Starting, with exactly two function types: no-abi (i.e. cdecl on
windows), or stdcall.
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -4661,7 +4661,7 @@
}
static int fb_build_name(struct funcbuilder_s *fb, PyObject *fargs,
- CTypeDescrObject *fresult, int ellipsis)
+ CTypeDescrObject *fresult, int ellipsis, int fabi)
{
Py_ssize_t i, nargs = PyTuple_GET_SIZE(fargs);
fb->nargs = nargs;
@@ -4672,9 +4672,17 @@
RESULT_TYPE_HEAD (*)(ARG_1_TYPE, ARG_2_TYPE, etc) RESULT_TYPE_TAIL
*/
fb_cat_name(fb, fresult->ct_name, fresult->ct_name_position);
- fb_cat_name(fb, "(*)(", 4);
+ fb_cat_name(fb, "(", 1);
+ i = 2;
+#if defined(MS_WIN32) && !defined(_WIN64)
+ if (fabi == FFI_STDCALL) {
+ fb_cat_name(fb, "__stdcall ", 10);
+ i += 10;
+ }
+#endif
+ fb_cat_name(fb, "*)(", 3);
if (fb->fct) {
- i = fresult->ct_name_position + 2; /* between '(*' and ')(' */
+ i = fresult->ct_name_position + i; /* between '(*' and ')(' */
fb->fct->ct_name_position = i;
}
@@ -4710,7 +4718,7 @@
static CTypeDescrObject *fb_prepare_ctype(struct funcbuilder_s *fb,
PyObject *fargs,
CTypeDescrObject *fresult,
- int ellipsis)
+ int ellipsis, int fabi)
{
CTypeDescrObject *fct;
@@ -4719,7 +4727,7 @@
fb->fct = NULL;
/* compute the total size needed for the name */
- if (fb_build_name(fb, fargs, fresult, ellipsis) < 0)
+ if (fb_build_name(fb, fargs, fresult, ellipsis, fabi) < 0)
return NULL;
/* allocate the function type */
@@ -4730,7 +4738,7 @@
/* call again fb_build_name() to really build the ct_name */
fb->bufferp = fct->ct_name;
- if (fb_build_name(fb, fargs, fresult, ellipsis) < 0)
+ if (fb_build_name(fb, fargs, fresult, ellipsis, fabi) < 0)
goto error;
assert(fb->bufferp == fct->ct_name + fb->nb_bytes);
@@ -4807,7 +4815,7 @@
return NULL;
}
- fct = fb_prepare_ctype(&funcbuilder, fargs, fresult, ellipsis);
+ fct = fb_prepare_ctype(&funcbuilder, fargs, fresult, ellipsis, fabi);
if (fct == NULL)
return NULL;
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -91,7 +91,7 @@
self.NULL = self.cast(self.BVoidP, 0)
self.CData, self.CType = backend._get_types()
- def cdef(self, csource, override=False, packed=False):
+ def cdef(self, csource, override=False, packed=False, calling_conv=None):
"""Parse the given C source. This registers all declared functions,
types, and global variables. The functions and global variables can
then be accessed via either 'ffi.dlopen()' or 'ffi.verify()'.
@@ -104,7 +104,8 @@
raise TypeError("cdef() argument must be a string")
csource = csource.encode('ascii')
with self._lock:
- self._parser.parse(csource, override=override, packed=packed)
+ self._parser.parse(csource, override=override, packed=packed,
+ calling_conv=calling_conv)
self._cdefsources.append(csource)
if override:
for cache in self._function_caches:
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -103,6 +103,7 @@
self._structnode2type = weakref.WeakKeyDictionary()
self._override = False
self._packed = False
+ self._abi = None
self._int_constants = {}
self._recomplete = []
self._uses_new_feature = None
@@ -162,16 +163,26 @@
msg = 'parse error\n%s' % (msg,)
raise api.CDefError(msg)
- def parse(self, csource, override=False, packed=False):
+ def parse(self, csource, override=False, packed=False, calling_conv=None):
+ if calling_conv is None or calling_conv == "cdecl":
+ abi = None
+ elif calling_conv == "stdcall":
+ abi = "stdcall"
+ else:
+ raise api.CDefError("calling_conv must be 'cdecl' or 'stdcall';"
+ " got %r" % (calling_conv,))
prev_override = self._override
prev_packed = self._packed
+ prev_abi = self._abi
try:
self._override = override
self._packed = packed
+ self._abi = abi
self._internal_parse(csource)
finally:
self._override = prev_override
self._packed = prev_packed
+ self._abi = prev_abi
def _internal_parse(self, csource):
ast, macros, csource = self._parse(csource)
@@ -449,7 +460,7 @@
if not ellipsis and args == [model.void_type]:
args = []
result, quals = self._get_type_and_quals(typenode.type)
- return model.RawFunctionType(tuple(args), result, ellipsis)
+ return model.RawFunctionType(tuple(args), result, ellipsis, self._abi)
def _as_func_arg(self, type, quals):
if isinstance(type, model.ArrayType):
diff --git a/cffi/model.py b/cffi/model.py
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -193,18 +193,21 @@
class BaseFunctionType(BaseType):
- _attrs_ = ('args', 'result', 'ellipsis')
+ _attrs_ = ('args', 'result', 'ellipsis', 'abi')
- def __init__(self, args, result, ellipsis):
+ def __init__(self, args, result, ellipsis, abi=None):
self.args = args
self.result = result
self.ellipsis = ellipsis
+ self.abi = abi
#
reprargs = [arg._get_c_name() for arg in self.args]
if self.ellipsis:
reprargs.append('...')
reprargs = reprargs or ['void']
replace_with = self._base_pattern % (', '.join(reprargs),)
+ if abi is not None:
+ replace_with = replace_with[:1] + abi + ' ' + replace_with[1:]
self.c_name_with_marker = (
self.result.c_name_with_marker.replace('&', replace_with))
@@ -222,7 +225,7 @@
"type, not a pointer-to-function type" % (self,))
def as_function_pointer(self):
- return FunctionPtrType(self.args, self.result, self.ellipsis)
+ return FunctionPtrType(self.args, self.result, self.ellipsis, self.abi)
class FunctionPtrType(BaseFunctionType):
@@ -233,11 +236,25 @@
args = []
for tp in self.args:
args.append(tp.get_cached_btype(ffi, finishlist))
+ if self.abi is None:
+ abi_args = ()
+ elif self.abi == "stdcall":
+ try:
+ abi_args = (ffi._backend.FFI_STDCALL,)
+ except AttributeError:
+ if sys.platform == "win32":
+ raise NotImplementedError("%r: stdcall with ctypes
backend")
+ else:
+ from . import api
+ raise api.CDefError("%r: '__stdcall' only for Windows")
+ import pdb;pdb.set_trace()
+ else:
+ raise NotImplementedError("abi=%r" % (self.abi,))
return global_cache(self, ffi, 'new_function_type',
- tuple(args), result, self.ellipsis)
+ tuple(args), result, self.ellipsis, *abi_args)
def as_raw_function(self):
- return RawFunctionType(self.args, self.result, self.ellipsis)
+ return RawFunctionType(self.args, self.result, self.ellipsis, self.abi)
class PointerType(BaseType):
diff --git a/testing/cffi0/test_function.py b/testing/cffi0/test_function.py
--- a/testing/cffi0/test_function.py
+++ b/testing/cffi0/test_function.py
@@ -440,9 +440,7 @@
""")
m = ffi.dlopen("Kernel32.dll")
tp = ffi.typeof(m.QueryPerformanceFrequency)
- assert 'stdcall' not in str(tp) and 'cdecl' not in str(tp)
- assert tp is (
- ffi.typeof(ffi.addressof(m, 'QueryPerformanceFrequency')).item)
+ assert str(tp) == "<ctype 'int(*)(long long *)'>"
#
ffi = FFI(backend=self.Backend())
ffi.cdef("""
@@ -451,8 +449,6 @@
m = ffi.dlopen("Kernel32.dll")
tpc = ffi.typeof(m.QueryPerformanceFrequency)
assert tpc is tp
- assert tpc is (
- ffi.typeof(ffi.addressof(m, 'QueryPerformanceFrequency')).item)
#
ffi = FFI(backend=self.Backend())
ffi.cdef("""
@@ -461,9 +457,7 @@
m = ffi.dlopen("Kernel32.dll")
tps = ffi.typeof(m.QueryPerformanceFrequency)
assert tps is not tpc
- assert '__stdcall' in str(tps) and 'cdecl' not in str(tps)
- assert tps is (
- ffi.typeof(ffi.addressof(m, 'QueryPerformanceFrequency')).item)
+ assert str(tps) == "<ctype 'int(__stdcall *)(long long *)'>"
#
ffi = FFI(backend=self.Backend())
ffi.cdef("typedef int (*fnc_t)(int);", calling_conv="cdecl")
@@ -472,3 +466,13 @@
tps = ffi.typeof("fns_t")
assert str(tpc) == "<ctype 'int(*)(int)'>"
assert str(tps) == "<ctype 'int(__stdcall *)(int)'>"
+
+ def test_stdcall_only_on_windows(self):
+ if sys.platform == 'win32':
+ py.test.skip("not-Windows-only test")
+ ffi = FFI(backend=self.Backend())
+ e = py.test.raises(CDefError, ffi.cdef, """
+ BOOL QueryPerformanceFrequency(LONGLONG *lpFrequency);
+ """, calling_conv="stdcall")
+ assert str(e.value) == (
+ "<int(__stdcall *)(int)>: '__stdcall' only for Windows")
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit