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

Reply via email to