Author: Amaury Forgeot d'Arc <[email protected]>
Branch:
Changeset: r44089:10cab42421db
Date: 2011-05-10 21:57 +0200
http://bitbucket.org/pypy/pypy/changeset/10cab42421db/
Log: Add rffi.llexternal() support to call macros that look like
functions. The generated C code was already correct, but for tests
we need to generate a real function.
diff --git a/pypy/rlib/_rsocket_rffi.py b/pypy/rlib/_rsocket_rffi.py
--- a/pypy/rlib/_rsocket_rffi.py
+++ b/pypy/rlib/_rsocket_rffi.py
@@ -90,35 +90,10 @@
COND_HEADER = ''
constants = {}
-sources = ["""
- void pypy_macro_wrapper_FD_SET(int fd, fd_set *set)
- {
- FD_SET(fd, set);
- }
- void pypy_macro_wrapper_FD_ZERO(fd_set *set)
- {
- FD_ZERO(set);
- }
- void pypy_macro_wrapper_FD_CLR(int fd, fd_set *set)
- {
- FD_CLR(fd, set);
- }
- int pypy_macro_wrapper_FD_ISSET(int fd, fd_set *set)
- {
- return FD_ISSET(fd, set);
- }
- """]
-
eci = ExternalCompilationInfo(
post_include_bits = [HEADER, COND_HEADER],
includes = includes,
libraries = libraries,
- separate_module_sources = sources,
- export_symbols = ['pypy_macro_wrapper_FD_ZERO',
- 'pypy_macro_wrapper_FD_SET',
- 'pypy_macro_wrapper_FD_CLR',
- 'pypy_macro_wrapper_FD_ISSET',
- ],
)
class CConfig:
@@ -484,9 +459,9 @@
return rffi.llexternal(name, args, result, compilation_info=eci,
calling_conv=calling_conv)
-def external_c(name, args, result):
+def external_c(name, args, result, **kwargs):
return rffi.llexternal(name, args, result, compilation_info=eci,
- calling_conv='c')
+ calling_conv='c', **kwargs)
if _POSIX:
dup = external('dup', [socketfd_type], socketfd_type)
@@ -583,10 +558,10 @@
fd_set, lltype.Ptr(timeval)],
rffi.INT)
-FD_CLR = external_c('pypy_macro_wrapper_FD_CLR', [rffi.INT, fd_set],
lltype.Void)
-FD_ISSET = external_c('pypy_macro_wrapper_FD_ISSET', [rffi.INT, fd_set],
rffi.INT)
-FD_SET = external_c('pypy_macro_wrapper_FD_SET', [rffi.INT, fd_set],
lltype.Void)
-FD_ZERO = external_c('pypy_macro_wrapper_FD_ZERO', [fd_set], lltype.Void)
+FD_CLR = external_c('FD_CLR', [rffi.INT, fd_set], lltype.Void, macro=True)
+FD_ISSET = external_c('FD_ISSET', [rffi.INT, fd_set], rffi.INT, macro=True)
+FD_SET = external_c('FD_SET', [rffi.INT, fd_set], lltype.Void, macro=True)
+FD_ZERO = external_c('FD_ZERO', [fd_set], lltype.Void, macro=True)
if _POSIX:
pollfdarray = rffi.CArray(pollfd)
diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py
b/pypy/rpython/lltypesystem/ll2ctypes.py
--- a/pypy/rpython/lltypesystem/ll2ctypes.py
+++ b/pypy/rpython/lltypesystem/ll2ctypes.py
@@ -970,13 +970,13 @@
old_eci = funcptr._obj.compilation_info
funcname = funcptr._obj._name
if hasattr(old_eci, '_with_ctypes'):
- eci = old_eci._with_ctypes
- else:
- try:
- eci = _eci_cache[old_eci]
- except KeyError:
- eci = old_eci.compile_shared_lib()
- _eci_cache[old_eci] = eci
+ old_eci = old_eci._with_ctypes
+
+ try:
+ eci = _eci_cache[old_eci]
+ except KeyError:
+ eci = old_eci.compile_shared_lib()
+ _eci_cache[old_eci] = eci
libraries = eci.testonly_libraries + eci.libraries + eci.frameworks
diff --git a/pypy/rpython/lltypesystem/rffi.py
b/pypy/rpython/lltypesystem/rffi.py
--- a/pypy/rpython/lltypesystem/rffi.py
+++ b/pypy/rpython/lltypesystem/rffi.py
@@ -54,7 +54,8 @@
compilation_info=ExternalCompilationInfo(),
sandboxsafe=False, threadsafe='auto',
_nowrapper=False, calling_conv='c',
- oo_primitive=None, pure_function=False):
+ oo_primitive=None, pure_function=False,
+ macro=None):
"""Build an external function that will invoke the C function 'name'
with the given 'args' types and 'result' type.
@@ -78,7 +79,13 @@
assert callable(_callable)
ext_type = lltype.FuncType(args, result)
if _callable is None:
- _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv)
+ if macro is not None:
+ if macro is True:
+ macro = name
+ _callable = generate_macro_wrapper(
+ name, macro, ext_type, compilation_info)
+ else:
+ _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv)
if pure_function:
_callable._pure_function_ = True
kwds = {}
@@ -314,6 +321,41 @@
compilation_info=eci, sandboxsafe=True, _nowrapper=True,
_callable=lambda: None)
+def generate_macro_wrapper(name, macro, functype, eci):
+ """Wraps a function-like macro inside a real function, and expose
+ it with llexternal."""
+
+ # Generate the function call
+ from pypy.translator.c.database import LowLevelDatabase
+ from pypy.translator.c.support import cdecl
+ wrapper_name = 'pypy_macro_wrapper_%s' % (name,)
+ argnames = ['arg%d' % (i,) for i in range(len(functype.ARGS))]
+ db = LowLevelDatabase()
+ implementationtypename = db.gettype(functype, argnames=argnames)
+ if functype.RESULT is lltype.Void:
+ pattern = '%s { %s(%s); }'
+ else:
+ pattern = '%s { return %s(%s); }'
+ source = pattern % (
+ cdecl(implementationtypename, wrapper_name),
+ macro, ', '.join(argnames))
+
+ # Now stuff this source into a "companion" eci that will be used
+ # by ll2ctypes. We replace eci._with_ctypes, so that only one
+ # shared library is actually compiled (when ll2ctypes calls the
+ # first function)
+ ctypes_eci = eci.merge(ExternalCompilationInfo(
+ separate_module_sources=[source],
+ export_symbols=[wrapper_name],
+ ))
+ if hasattr(eci, '_with_ctypes'):
+ ctypes_eci = eci._with_ctypes.merge(ctypes_eci)
+ eci._with_ctypes = ctypes_eci
+ func = llexternal(wrapper_name, functype.ARGS, functype.RESULT,
+ compilation_info=eci, _nowrapper=True)
+ # _nowrapper=True returns a pointer which is not hashable
+ return lambda *args: func(*args)
+
# ____________________________________________________________
# Few helpers for keeping callback arguments alive
# this makes passing opaque objects possible (they don't even pass
diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
--- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
+++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
@@ -787,6 +787,19 @@
res = fn()
assert res == 42
+ def test_llexternal_macro(self):
+ eci = ExternalCompilationInfo(
+ post_include_bits = ["#define fn(x) (42 + x)"],
+ )
+ fn1 = rffi.llexternal('fn', [rffi.INT], rffi.INT,
+ compilation_info=eci, macro=True)
+ fn2 = rffi.llexternal('fn2', [rffi.DOUBLE], rffi.DOUBLE,
+ compilation_info=eci, macro='fn')
+ res = fn1(10)
+ assert res == 52
+ res = fn2(10.5)
+ assert res == 52.5
+
def test_prebuilt_constant(self):
header = py.code.Source("""
#ifndef _SOME_H
@@ -1318,7 +1331,6 @@
class TestPlatform(object):
def test_lib_on_libpaths(self):
from pypy.translator.platform import platform
- from pypy.translator.tool.cbuild import ExternalCompilationInfo
tmpdir = udir.join('lib_on_libppaths')
tmpdir.ensure(dir=1)
@@ -1340,7 +1352,6 @@
py.test.skip("Not supported")
from pypy.translator.platform import platform
- from pypy.translator.tool.cbuild import ExternalCompilationInfo
tmpdir = udir.join('lib_on_libppaths_prefix')
tmpdir.ensure(dir=1)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit