[pypy-svn] r49054 - in pypy/branch/rewrite-compilation-logic: . pypy/rlib pypy/rpython/lltypesystem pypy/rpython/lltypesystem/module pypy/rpython/lltypesystem/test pypy/rpython/module pypy/rpython/tool pypy/rpython/tool/test pypy/translator/c pypy/translator/c/test pypy/translator/tool pypy/translator/tool/test

fijal at codespeak.net fijal at codespeak.net
Sat Nov 24 19:00:45 CET 2007


Author: fijal
Date: Sat Nov 24 19:00:44 2007
New Revision: 49054

Added:
   pypy/branch/rewrite-compilation-logic/
      - copied from r49053, pypy/dist/
Modified:
   pypy/branch/rewrite-compilation-logic/pypy/rlib/_rsocket_rffi.py
   pypy/branch/rewrite-compilation-logic/pypy/rlib/rposix.py
   pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/ll2ctypes.py
   pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/lltype.py
   pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/module/ll_math.py
   pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/rffi.py
   pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
   pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/test/test_rffi.py
   pypy/branch/rewrite-compilation-logic/pypy/rpython/module/ll_termios.py
   pypy/branch/rewrite-compilation-logic/pypy/rpython/tool/rffi_platform.py
   pypy/branch/rewrite-compilation-logic/pypy/rpython/tool/rfficache.py
   pypy/branch/rewrite-compilation-logic/pypy/rpython/tool/test/test_rffi_platform.py
   pypy/branch/rewrite-compilation-logic/pypy/translator/c/genc.py
   pypy/branch/rewrite-compilation-logic/pypy/translator/c/node.py
   pypy/branch/rewrite-compilation-logic/pypy/translator/c/test/test_genc.py
   pypy/branch/rewrite-compilation-logic/pypy/translator/tool/cbuild.py
   pypy/branch/rewrite-compilation-logic/pypy/translator/tool/test/test_cbuild.py
Log:
(fijal, arigo, xoraxax) In-progress checkin of rewriting compilation
logic. Tries to sort out the need of includes include_dirs, libraries
and friends.


Modified: pypy/branch/rewrite-compilation-logic/pypy/rlib/_rsocket_rffi.py
==============================================================================
--- pypy/dist/pypy/rlib/_rsocket_rffi.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/rlib/_rsocket_rffi.py	Sat Nov 24 19:00:44 2007
@@ -4,6 +4,7 @@
 from pypy.rpython.tool import rffi_platform as platform
 from pypy.rpython.lltypesystem.rffi import CCHARP
 from pypy.rlib.rposix import get_errno as geterrno
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
 
 from pypy.rlib.rarithmetic import intmask, r_uint
 import os
@@ -51,9 +52,13 @@
     COND_HEADER = ''
 constants = {}
 
+eci = ExternalCompilationInfo(
+    pre_include_lines = (HEADER + COND_HEADER).split("\n"),
+    includes = includes
+)
 
 class CConfig:
-    _header_ = HEADER + COND_HEADER
+    _compilation_info_ = eci
     # constants
     linux      = platform.Defined('linux')
     MS_WINDOWS = platform.Defined('_WIN32')
@@ -376,10 +381,10 @@
     for _name, _header in cond_includes:
         if getattr(cConfig, _name) is not None:
             includes.append(_header)
+    eci = ExternalCompilationInfo(includes=includes, libraries=libraries)
 
 def external(name, args, result):
-    return rffi.llexternal(name, args, result,
-                           includes=includes, libraries=libraries,
+    return rffi.llexternal(name, args, result, compilation_info=eci,
                            calling_conv=calling_conv)
 
 if _POSIX:

Modified: pypy/branch/rewrite-compilation-logic/pypy/rlib/rposix.py
==============================================================================
--- pypy/dist/pypy/rlib/rposix.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/rlib/rposix.py	Sat Nov 24 19:00:44 2007
@@ -1,5 +1,6 @@
 from pypy.rpython.lltypesystem.rffi import CConstant, CExternVariable
 from pypy.rpython.lltypesystem import lltype, ll2ctypes
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
 
 class CConstantErrno(CConstant):
     # these accessors are used when calling get_errno() or set_errno()
@@ -15,6 +16,10 @@
         assert index == 0
         ll2ctypes.TLS.errno = value
 
-get_errno, set_errno = CExternVariable(lltype.Signed, 'errno', CConstantErrno,
-                                       includes=['errno.h'], sandboxsafe=True)
+errno_eci = ExternalCompilationInfo(
+    includes=['errno.h']
+)
+
+get_errno, set_errno = CExternVariable(lltype.Signed, 'errno', errno_eci,
+                                       CConstantErrno, sandboxsafe=True)
 

Modified: pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/ll2ctypes.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/ll2ctypes.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/ll2ctypes.py	Sat Nov 24 19:00:44 2007
@@ -513,15 +513,6 @@
 # ____________________________________________
 
 
-def compile_c_snippet(name, source):
-    from pypy.tool.udir import udir
-    cname = udir.join(name + '.c')
-    f = cname.open('w')
-    f.write(source)
-    f.write('\n')
-    f.close()
-    return cache_c_module([cname], name)
-    
 def get_ctypes_callable(funcptr, calling_conv):
     if not ctypes:
         raise ImportError("ctypes is needed to use ll2ctypes")
@@ -534,16 +525,12 @@
         except AttributeError:
             pass
     
-    sources = getattr(funcptr._obj, 'sources', None)
-    if sources:
-        assert len(sources) == 1
-        dllname = compile_c_snippet(funcptr._obj._name, sources[0])
-        libraries = [dllname]
-    else:
-        libraries = getattr(funcptr._obj, 'libraries', None)
+    eci = funcptr._obj.compilation_info
+    libraries = list(eci.libraries)
+    funcname = funcptr._obj._name
+    eci = eci.make_shared_lib()
 
     FUNCTYPE = lltype.typeOf(funcptr).TO
-    funcname = funcptr._obj._name
     if not libraries:
         cfunc = get_on_lib(standard_c_lib, funcname)
         # XXX magic: on Windows try to load the function from 'kernel32' too

Modified: pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/lltype.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/lltype.py	Sat Nov 24 19:00:44 2007
@@ -413,9 +413,8 @@
     def __init__(self, args, result):
         for arg in args:
             assert isinstance(arg, LowLevelType)
-            # -- disable the following check for the benefits of rffi --
-            if isinstance(arg, ContainerType):
-                raise TypeError, "function arguments can only be primitives or pointers"
+            # There are external C functions eating raw structures, not
+            # pointers, don't check args not being container types
         self.ARGS = tuple(args)
         assert isinstance(result, LowLevelType)
         if isinstance(result, ContainerType):

Modified: pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/module/ll_math.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/module/ll_math.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/module/ll_math.py	Sat Nov 24 19:00:44 2007
@@ -4,6 +4,7 @@
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.tool.sourcetools import func_with_new_name
 from pypy.rlib import rposix
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
 
 math_frexp = rffi.llexternal('frexp', [rffi.DOUBLE, rffi.INTP], rffi.DOUBLE,
                              sandboxsafe=True)
@@ -55,9 +56,11 @@
         else:
             raise ValueError("math domain error")
 
+eci = ExternalCompilationInfo(libraries=['m'])
+
 def new_unary_math_function(name):
     c_func = rffi.llexternal(name, [rffi.DOUBLE], rffi.DOUBLE,
-                             sandboxsafe=True, libraries=['m'])
+                             compilation_info=eci, sandboxsafe=True)
 
     def ll_math(x):
         _error_reset()
@@ -69,7 +72,7 @@
 
 def new_binary_math_function(name):
     c_func = rffi.llexternal(name, [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE,
-                             sandboxsafe=True, libraries=['m'])
+                             compilation_info=eci, sandboxsafe=True)
 
     def ll_math(x, y):
         _error_reset()

Modified: pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/rffi.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/rffi.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/rffi.py	Sat Nov 24 19:00:44 2007
@@ -10,6 +10,7 @@
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.tool.sourcetools import func_with_new_name
 from pypy.rpython.tool.rfficache import platform
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
 import os
 
 class CConstant(Symbolic):
@@ -25,8 +26,8 @@
     def lltype(self):
         return self.TP
 
-def llexternal(name, args, result, _callable=None, sources=[], includes=[],
-               libraries=[], include_dirs=[], library_dirs=[],
+def llexternal(name, args, result, _callable=None,
+               compilation_info=ExternalCompilationInfo(),
                sandboxsafe=False, threadsafe='auto',
                canraise=False, _nowrapper=False, calling_conv='c'):
     """Build an external function that will invoke the C function 'name'
@@ -48,11 +49,7 @@
     if _callable is None:
         _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv)
     funcptr = lltype.functionptr(ext_type, name, external='C',
-                                 sources=tuple(sources),
-                                 includes=tuple(includes),
-                                 libraries=tuple(libraries),
-                                 include_dirs=tuple(include_dirs),
-                                 library_dirs=tuple(library_dirs),
+                                 compilation_info=compilation_info,
                                  _callable=_callable,
                                  _safe_not_sandboxed=sandboxsafe,
                                  _debugexc=True, # on top of llinterp
@@ -220,7 +217,9 @@
     return lltype.Ptr(CArray(tp))
 CArray._annspecialcase_ = 'specialize:memo'
 
-def COpaque(name, hints=None, **kwds):
+def COpaque(name, hints=None, compilation_info=None):
+    if compilation_info is None:
+        compilation_info = ExternalCompilationInfo()
     if hints is None:
         hints = {}
     else:
@@ -230,11 +229,7 @@
     def lazy_getsize():
         from pypy.rpython.tool import rffi_platform
         k = {}
-        for _name, value in kwds.items():
-            if _name in ['includes', 'include_dirs', 'libraries',
-                         'library_dirs']:
-                k['_%s_' % _name] = value
-        return rffi_platform.sizeof(name, '', **k)
+        return rffi_platform.sizeof(name, compilation_info)
     
     hints['getsize'] = lazy_getsize
     return lltype.OpaqueType(name, hints)
@@ -242,12 +237,13 @@
 def COpaquePtr(*args, **kwds):
     return lltype.Ptr(COpaque(*args, **kwds))
 
-def CExternVariable(TYPE, name, _CConstantClass=CConstant, includes=[],
-                    include_dirs=[], sandboxsafe=False):
+def CExternVariable(TYPE, name, eci, _CConstantClass=CConstant,
+                    sandboxsafe=False):
     """Return a pair of functions - a getter and a setter - to access
     the given global C variable.
     """
     from pypy.translator.c.primitive import PrimitiveType
+    from pypy.translator.tool.cbuild import ExternalCompilationInfo
     # XXX we cannot really enumerate all C types here, do it on a case-by-case
     #     basis
     if TYPE == CCHARPP:
@@ -264,15 +260,18 @@
     c_getter = "%(c_type)s %(getter_name)s () { return %(name)s; }" % locals()
     c_setter = "void %(setter_name)s (%(c_type)s v) { %(name)s = v; }" % locals()
 
-    lines = ["#include <%s>" % i for i in includes]
+    lines = ["#include <%s>" % i for i in eci.includes]
     lines.append(c_getter)
     lines.append(c_setter)
     sources = ('\n'.join(lines),)
-
-    kwds = {'includes': includes, 'sources':sources,
-            'include_dirs':include_dirs, 'sandboxsafe': sandboxsafe}
-    getter = llexternal(getter_name, [], TYPE, **kwds)
-    setter = llexternal(setter_name, [TYPE], lltype.Void, **kwds)
+    new_eci = eci.merge(ExternalCompilationInfo(
+        separate_module_sources = sources
+    ))
+
+    getter = llexternal(getter_name, [], TYPE, compilation_info=new_eci,
+                        sandboxsafe=sandboxsafe)
+    setter = llexternal(setter_name, [TYPE], lltype.Void,
+                        compilation_info=new_eci, sandboxsafe=sandboxsafe)
     return getter, setter
     
 ##    # XXX THIS IS ONLY A QUICK HACK TO MAKE IT WORK

Modified: pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/test/test_ll2ctypes.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/test/test_ll2ctypes.py	Sat Nov 24 19:00:44 2007
@@ -9,6 +9,7 @@
 from pypy.rpython.lltypesystem.ll2ctypes import ALLOCATED
 from pypy.rpython.annlowlevel import llhelper
 from pypy.rlib import rposix
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
 
 class TestLL2Ctypes(object):
 
@@ -139,8 +140,9 @@
         assert not ALLOCATED     # detects memory leaks in the test
 
     def test_strlen(self):
+        eci = ExternalCompilationInfo(includes=['string.h'])
         strlen = rffi.llexternal('strlen', [rffi.CCHARP], rffi.SIZE_T,
-                                 includes=['string.h'])
+                                 compilation_info=eci)
         s = rffi.str2charp("xxx")
         res = strlen(s)
         rffi.free_charp(s)
@@ -152,19 +154,22 @@
         assert not ALLOCATED     # detects memory leaks in the test
 
     def test_func_not_in_clib(self):
+        eci = ExternalCompilationInfo(libraries=['m'])
         foobar = rffi.llexternal('I_really_dont_exist', [], lltype.Signed)
         py.test.raises(NotImplementedError, foobar)
 
         foobar = rffi.llexternal('I_really_dont_exist', [], lltype.Signed,
-                                 libraries=['m'])    # math library
+                                 compilation_info=eci)    # math library
         py.test.raises(NotImplementedError, foobar)
 
+        eci = ExternalCompilationInfo(libraries=['m', 'z'])
         foobar = rffi.llexternal('I_really_dont_exist', [], lltype.Signed,
-                                 libraries=['m', 'z'])  # math and zlib
+                                 compilation_info=eci)  # math and zlib
         py.test.raises(NotImplementedError, foobar)
 
+        eci = ExternalCompilationInfo(libraries=['I_really_dont_exist_either'])
         foobar = rffi.llexternal('I_really_dont_exist', [], lltype.Signed,
-                                 libraries=['I_really_dont_exist_either'])
+                                 compilation_info=eci)
         py.test.raises(NotImplementedError, foobar)
         assert not ALLOCATED     # detects memory leaks in the test
 
@@ -229,9 +234,9 @@
         assert not ALLOCATED     # detects memory leaks in the test
 
     def test_strchr(self):
+        eci = ExternalCompilationInfo(includes=['string.h'])
         strchr = rffi.llexternal('strchr', [rffi.CCHARP, rffi.INT],
-                                 rffi.CCHARP,
-                                 includes=['string.h'])
+                                 rffi.CCHARP, compilation_info=eci)
         s = rffi.str2charp("hello world")
         res = strchr(s, ord('r'))
         assert res[0] == 'r'
@@ -243,11 +248,11 @@
         assert not ALLOCATED     # detects memory leaks in the test
 
     def test_frexp(self):
+        eci = ExternalCompilationInfo(includes=['math.h'],
+                                      libraries=['m'])
         A = lltype.FixedSizeArray(rffi.INT, 1)
         frexp = rffi.llexternal('frexp', [rffi.DOUBLE, lltype.Ptr(A)],
-                                rffi.DOUBLE,
-                                includes=['math.h'],
-                                libraries=['m'])
+                                rffi.DOUBLE, compilation_info=eci)
         p = lltype.malloc(A, flavor='raw')
         res = frexp(2.5, p)
         assert res == 0.625
@@ -256,10 +261,11 @@
         assert not ALLOCATED     # detects memory leaks in the test
 
     def test_rand(self):
+        eci = ExternalCompilationInfo(includes=['stdlib.h'])
         rand = rffi.llexternal('rand', [], rffi.INT,
-                               includes=['stdlib.h'])
+                               compilation_info=eci)
         srand = rffi.llexternal('srand', [rffi.UINT], lltype.Void,
-                                includes=['stdlib.h'])
+                                compilation_info=eci)
         srand(rffi.r_uint(123))
         res1 = rand()
         res2 = rand()
@@ -274,11 +280,13 @@
         assert not ALLOCATED     # detects memory leaks in the test
 
     def test_opaque_obj(self):
-        includes = ['sys/time.h', 'time.h']
-        TIMEVALP = rffi.COpaquePtr('struct timeval', includes=includes)
-        TIMEZONEP = rffi.COpaquePtr('struct timezone', includes=includes)
+        eci = ExternalCompilationInfo(
+            includes = ['sys/time.h', 'time.h']
+        )
+        TIMEVALP = rffi.COpaquePtr('struct timeval', compilation_info=eci)
+        TIMEZONEP = rffi.COpaquePtr('struct timezone', compilation_info=eci)
         gettimeofday = rffi.llexternal('gettimeofday', [TIMEVALP, TIMEZONEP],
-                                       rffi.INT, includes=includes)
+                                       rffi.INT, compilation_info=eci)
         ll_timevalp = lltype.malloc(TIMEVALP.TO, flavor='raw')
         ll_timezonep = lltype.malloc(TIMEZONEP.TO, flavor='raw')
         res = gettimeofday(ll_timevalp, ll_timezonep)
@@ -582,12 +590,13 @@
         assert not ALLOCATED     # detects memory leaks in the test
 
     def test_get_errno(self):
+        eci = ExternalCompilationInfo(includes=['string.h'])
         if sys.platform.startswith('win'):
             underscore_on_windows = '_'
         else:
             underscore_on_windows = ''
         strlen = rffi.llexternal('strlen', [rffi.CCHARP], rffi.SIZE_T,
-                                 includes=['string.h'])
+                                 compilation_info=eci)
         os_write = rffi.llexternal(underscore_on_windows+'write',
                                    [rffi.INT, rffi.CCHARP, rffi.SIZE_T],
                                    rffi.SIZE_T)
@@ -650,23 +659,6 @@
         assert isinstance(b[2], rffi.r_singlefloat)
         assert abs(float(b[2]) - 2.2) < 1E-6
 
-    def test_cfunc_returning_newly_allocated(self):
-        py.test.skip("complains about a double free")
-        from crypt import crypt as pycrypt
-        crypt = rffi.llexternal('crypt', [rffi.CCHARP, rffi.CCHARP],
-                                rffi.CCHARP,
-                                libraries=['crypt'])
-
-        s1 = rffi.str2charp("pass")
-        s2 = rffi.str2charp("ab")
-        r = crypt(s1, s2)
-        rffi.free_charp(s1)
-        rffi.free_charp(s2)
-        res = rffi.charp2str(r)
-        assert res == pycrypt("pass", "ab")
-        rffi.free_charp(r)
-        assert not ALLOCATED
-
     def test_different_signatures(self):
         fcntl_int = rffi.llexternal('fcntl', [rffi.INT, rffi.INT, rffi.INT],
                                     rffi.INT)
@@ -677,7 +669,36 @@
         fcntl_int(12345, 1, 0)
 
     def test_llexternal_source(self):
-        fn = rffi.llexternal('fn', [], rffi.INT, sources = ["int fn() { return 42; }"])
+        eci = ExternalCompilationInfo(
+            separate_module_sources = ["int fn() { return 42; }"]
+        )
+        fn = rffi.llexternal('fn', [], rffi.INT, compilation_info=eci)
         res = fn()
         assert res == 42
 
+    def test_prebuilt_constant(self):
+        source = py.code.Source("""
+        int x = 3;
+        char** z = NULL;
+        """)
+
+        eci = ExternalCompilationInfo(post_include_lines=source.lines)
+        
+        get_x, set_x = rffi.CExternVariable(lltype.Signed, 'x', eci)
+        get_z, set_z = rffi.CExternVariable(rffi.CCHARPP, 'z', eci)
+
+        def f():
+            one = get_x()
+            set_x(13)
+            return one + get_x()
+
+        def g():
+            l = rffi.liststr2charpp(["a", "b", "c"])
+            try:
+                set_z(l)
+                return rffi.charp2str(get_z()[2])
+            finally:
+                rffi.free_charpp(l)
+
+        assert f() == 16
+        assert g() == "c"

Modified: pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/test/test_rffi.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/test/test_rffi.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/test/test_rffi.py	Sat Nov 24 19:00:44 2007
@@ -13,6 +13,7 @@
 from pypy.translator.translator import graphof
 from pypy.conftest import option
 from pypy.objspace.flow.model import summary
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
 
 def test_basic():
     c_source = py.code.Source("""
@@ -21,7 +22,9 @@
         return (x + 3);
     }
     """)
-    z = llexternal('z', [Signed], Signed, sources=[c_source])
+
+    eci = ExternalCompilationInfo(separate_module_sources=[c_source])
+    z = llexternal('z', [Signed], Signed, eci)
 
     def f():
         return z(8)

Modified: pypy/branch/rewrite-compilation-logic/pypy/rpython/module/ll_termios.py
==============================================================================
--- pypy/dist/pypy/rpython/module/ll_termios.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/rpython/module/ll_termios.py	Sat Nov 24 19:00:44 2007
@@ -15,11 +15,14 @@
 from pypy.rpython import rclass
 from pypy.rlib import rtermios
 from pypy.rpython.tool import rffi_platform
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
 
-includes = ['termios.h', 'unistd.h']
+eci = ExternalCompilationInfo(
+    includes = ['termios.h', 'unistd.h']
+)
 
 class CConfig:
-    _includes_ = includes
+    _compilation_info_ = eci
     NCCS = rffi_platform.DefinedConstantInteger('NCCS')
 
 NCCS = rffi_platform.configure(CConfig)['NCCS']
@@ -39,7 +42,7 @@
                            ('c_cc', lltype.FixedSizeArray(CC_T, NCCS)))
 
 def c_external(name, args, result):
-    return rffi.llexternal(name, args, result, includes=includes)
+    return rffi.llexternal(name, args, result, compilation_info=eci)
 
 c_tcsetattr = c_external('tcsetattr', [INT, INT, TERMIOSP], INT)
 c_cfgetispeed = c_external('cfgetispeed', [TERMIOSP], SPEED_T)

Modified: pypy/branch/rewrite-compilation-logic/pypy/rpython/tool/rffi_platform.py
==============================================================================
--- pypy/dist/pypy/rpython/tool/rffi_platform.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/rpython/tool/rffi_platform.py	Sat Nov 24 19:00:44 2007
@@ -5,6 +5,7 @@
 from pypy.rpython.lltypesystem import rffi
 from pypy.rpython.lltypesystem import llmemory
 from pypy.tool.gcc_cache import build_executable_cache, try_compile_cache
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from pypy.tool.udir import udir
 import distutils
 
@@ -12,39 +13,44 @@
 #
 # Helpers for simple cases
 
+def eci_from_header(c_header_source):
+    return ExternalCompilationInfo(
+        pre_include_lines=c_header_source.split("\n")
+    )
+
 def getstruct(name, c_header_source, interesting_fields):
     class CConfig:
-        _header_ = c_header_source
+        _compilation_info_ = eci_from_header(c_header_source)
         STRUCT = Struct(name, interesting_fields)
     return configure(CConfig)['STRUCT']
 
 def getsimpletype(name, c_header_source, ctype_hint=rffi.INT):
     class CConfig:
-        _header_ = c_header_source
+        _compilation_info_ = eci_from_header(c_header_source)
         TYPE = SimpleType(name, ctype_hint)
     return configure(CConfig)['TYPE']
 
 def getconstantinteger(name, c_header_source):
     class CConfig:
-        _header_ = c_header_source
+        _compilation_info_ = eci_from_header(c_header_source)
         CONST = ConstantInteger(name)
     return configure(CConfig)['CONST']
 
 def getdefined(macro, c_header_source):
     class CConfig:
-        _header_ = c_header_source
+        _compilation_info_ = eci_from_header(c_header_source)
         DEFINED = Defined(macro)
     return configure(CConfig)['DEFINED']
 
 def has(name, c_header_source):
     class CConfig:
-        _header_ = c_header_source
+        _compilation_info_ = eci_from_header(c_header_source)
         HAS = Has(name)
     return configure(CConfig)['HAS']
 
-def sizeof(name, c_header_source, **kwds):
+def sizeof(name, eci, **kwds):
     class CConfig:
-        _header_ = c_header_source
+        _compilation_info_ = eci
         SIZE = SizeOf(name)
     for k, v in kwds.items():
         setattr(CConfig, k, v)
@@ -85,12 +91,7 @@
     def write_header(self):
         f = self.f
         CConfig = self.config
-        # NB: the _header_ must be printed before everything else,
-        # because it might contain #defines that need to appear before
-        # any system #include.
-        print >> f, getattr(CConfig, '_header_', '')      # optional
-        for path in getattr(CConfig, '_includes_', ()):   # optional
-            print >> f, '#include <%s>' % (path,)
+        CConfig._compilation_info_.write_c_header(f)
         print >> f, C_HEADER
         print >> f
 
@@ -122,12 +123,8 @@
         self.start_main()
         self.f.write(question + "\n")
         self.close()
-        include_dirs = getattr(self.config, '_include_dirs_', [])
-        libraries = getattr(self.config, '_libraries_', [])
-        library_dirs = getattr(self.config, '_library_dirs_', [])
-        return try_compile_cache([self.path], include_dirs=include_dirs,
-                                 libraries=libraries,
-                                 library_dirs=library_dirs)
+        eci = self.config._compilation_info_
+        return try_compile_cache([self.path], eci)
         
 def configure(CConfig):
     """Examine the local system by running the C compiler.
@@ -135,6 +132,9 @@
     what should be inspected; configure() returns a dict mapping
     names to the results.
     """
+    for attr in ['_includes_', '_libraries_', '_sources_', '_library_dirs_',
+                 '_include_dirs_', '_header_']:
+        assert not hasattr(CConfig, attr), "Found legacy attribut %s on CConfig" % (attr,)
     entries = []
     for key in dir(CConfig):
         value = getattr(CConfig, key)
@@ -153,11 +153,8 @@
             writer.write_entry_main(key)
         writer.close()
 
-        include_dirs = getattr(CConfig, '_include_dirs_', [])
-        libraries = getattr(CConfig, '_libraries_', [])
-        library_dirs = getattr(CConfig, '_library_dirs_', [])
-        infolist = list(run_example_code(writer.path, include_dirs,
-                                         libraries, library_dirs))
+        eci = CConfig._compilation_info_
+        infolist = list(run_example_code(writer.path, eci))
         assert len(infolist) == len(entries)
 
         resultinfo = {}
@@ -503,10 +500,8 @@
 }
 """
 
-def run_example_code(filepath, include_dirs=[], libraries=[], library_dirs=[]):
-    output = build_executable_cache([filepath], include_dirs=include_dirs,
-                                    libraries=libraries,
-                                    library_dirs=library_dirs)
+def run_example_code(filepath, eci):
+    output = build_executable_cache([filepath], eci)
     section = None
     for line in output.splitlines():
         line = line.strip()

Modified: pypy/branch/rewrite-compilation-logic/pypy/rpython/tool/rfficache.py
==============================================================================
--- pypy/dist/pypy/rpython/tool/rfficache.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/rpython/tool/rfficache.py	Sat Nov 24 19:00:44 2007
@@ -1,12 +1,12 @@
 
-""" This file creates and maintains _cache/stdtypes.py, which
-keeps information about C type sizes
-"""
+# XXX This is completely outdated file, kept here only for bootstrapping
+#     reasons. If you touch it, try removing it
 
 import py
 import os
 import distutils
-from pypy.translator.tool.cbuild import build_executable
+from pypy.translator.tool.cbuild import build_executable, \
+     ExternalCompilationInfo
 from pypy.tool.udir import udir
 from pypy.tool.autopath import pypydir
 from pypy.rlib import rarithmetic
@@ -31,7 +31,8 @@
     ''' % (include_string, add_source, str(question)))
     c_file = udir.join("gcctest.c")
     c_file.write(c_source)
-    return build_executable_cache([c_file], compiler_exe=compiler_exe)
+    eci = ExternalCompilationInfo()
+    return build_executable_cache([c_file], eci, compiler_exe=compiler_exe)
 
 def sizeof_c_type(c_typename, **kwds):
     question = 'printf("%%d", sizeof(%s));' % (c_typename,);

Modified: pypy/branch/rewrite-compilation-logic/pypy/rpython/tool/test/test_rffi_platform.py
==============================================================================
--- pypy/dist/pypy/rpython/tool/test/test_rffi_platform.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/rpython/tool/test/test_rffi_platform.py	Sat Nov 24 19:00:44 2007
@@ -3,6 +3,7 @@
 from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.lltypesystem import rffi
 from pypy.tool.udir import udir
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
 
 def import_ctypes():
     try:
@@ -109,11 +110,12 @@
     test_h.write('#define XYZZY 42\n')
 
     class CConfig:
-        _header_ = """ /* a C comment */
-                       #include <stdio.h>
-                       #include <test_ctypes_platform.h>
-                   """
-        _include_dirs_ = [str(udir)]
+        _compilation_info_ = ExternalCompilationInfo(
+            pre_include_lines = ["/* a C comment */",
+                                 "#include <stdio.h>",
+                                 "#include <test_ctypes_platform.h>"],
+            include_dirs = [str(udir)]
+        )
 
         FILE = rffi_platform.Struct('FILE', [])
         ushort = rffi_platform.SimpleType('unsigned short')
@@ -127,14 +129,14 @@
 
 def test_ifdef():
     class CConfig:
-        _header_ = """ /* a C comment */
-#define XYZZY 42
-typedef int foo;
-struct s {
-    int i;
-    double f;
-};
-"""
+        _compilation_info_ = ExternalCompilationInfo(
+            post_include_lines = ['/* a C comment */',
+                                  '#define XYZZY 42',
+                                  'typedef int foo;',
+                                  'struct s {',
+                                  'int i;',
+                                  'double f;'
+                                  '};'])
 
         s = rffi_platform.Struct('struct s', [('i', rffi.INT)],
                                    ifdef='XYZZY')
@@ -152,16 +154,17 @@
 
 def test_nested_structs():
     class CConfig:
-        _header_ = """
-struct x {
-    int foo;
-    unsigned long bar;
-    };
-struct y {
-    char c;
-    struct x x;
-    };
-"""
+        _compilation_info_ = ExternalCompilationInfo(
+            post_include_lines="""
+            struct x {
+            int foo;
+            unsigned long bar;
+            };
+            struct y {
+            char c;
+            struct x x;
+            };
+            """.split("\n"))
         x = rffi_platform.Struct("struct x", [("bar", rffi.SHORT)])
         y = rffi_platform.Struct("struct y", [("x", x)])
 
@@ -193,4 +196,4 @@
     assert not rffi_platform.has("x", "#include <some/path/which/cannot/exist>")
 
 def test_sizeof():
-    assert rffi_platform.sizeof("char", "") == 1
+    assert rffi_platform.sizeof("char", ExternalCompilationInfo()) == 1

Modified: pypy/branch/rewrite-compilation-logic/pypy/translator/c/genc.py
==============================================================================
--- pypy/dist/pypy/translator/c/genc.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/translator/c/genc.py	Sat Nov 24 19:00:44 2007
@@ -6,7 +6,7 @@
 from pypy.translator.c.extfunc import pre_include_code_lines
 from pypy.translator.llsupport.wrapper import new_wrapper
 from pypy.translator.gensupp import uniquemodulename, NameManager
-from pypy.translator.tool.cbuild import so_ext
+from pypy.translator.tool.cbuild import so_ext, ExternalCompilationInfo
 from pypy.translator.tool.cbuild import compile_c_module
 from pypy.translator.tool.cbuild import build_executable, CCompiler, ProfOpt
 from pypy.translator.tool.cbuild import import_module_from_directory
@@ -24,8 +24,8 @@
     _compiled = False
     modulename = None
     
-    def __init__(self, translator, entrypoint, config, libraries=None,
-                 gcpolicy=None):
+    def __init__(self, translator, entrypoint, config,
+                 eci=ExternalCompilationInfo(), gcpolicy=None):
         self.translator = translator
         self.entrypoint = entrypoint
         self.entrypoint_name = self.entrypoint.func_name
@@ -34,11 +34,8 @@
         if gcpolicy is not None and gcpolicy.requires_stackless:
             config.translation.stackless = True
         self.config = config
-
-        if libraries is None:
-            libraries = []
-        self.libraries = libraries
         self.exports = {}
+        self.eci = eci
 
     def build_database(self):
         translator = self.translator
@@ -65,7 +62,8 @@
         self.db = db
 
         # we need a concrete gcpolicy to do this
-        self.libraries += db.gcpolicy.gc_libraries()
+        self.eci = self.eci.merge(ExternalCompilationInfo(
+            libraries=db.gcpolicy.gc_libraries()))
 
         # give the gc a chance to register interest in the start-up functions it
         # need (we call this for its side-effects of db.get())
@@ -77,19 +75,19 @@
         self.exports[self.entrypoint_name] = pf
         self.c_entrypoint_name = pfname
         db.complete()
-
-        # add library dependencies
-        seen = dict.fromkeys(self.libraries)
-        for node in db.globalcontainers():
-            if hasattr(node, 'libraries'):
-                for library in node.libraries:
-                    if library not in seen:
-                        self.libraries.append(library)
-                        seen[library] = True
+        
+        self.collect_compilation_info()
         return db
 
     have___thread = None
 
+    def collect_compilation_info(self):
+        all = []
+        for node in self.db.globalcontainers():
+            eci = getattr(node, 'compilation_info', None)
+            if eci:
+                all.append(eci)
+        self.eci = self.eci.merge(*all)
 
     def get_gcpolicyclass(self):
         if self.gcpolicy is None:
@@ -112,7 +110,6 @@
             db = self.build_database()
         pf = self.getentrypointptr()
         pfname = db.get(pf)
-        extra_info = extra_information(db)
         if self.modulename is None:
             self.modulename = uniquemodulename('testing')
         modulename = self.modulename
@@ -128,27 +125,21 @@
             CBuilder.have___thread = check_under_under_thread()
         if not self.standalone:
             assert not self.config.translation.instrument
-            cfile, extra, include_dirs, library_dirs = \
-                   gen_source(db, modulename, targetdir,
-                              defines = defines,
-                              exports = self.exports,
-                              libraries = self.libraries,
-                              extra_info = extra_info)
+            cfile, extra = gen_source(db, modulename, targetdir, self.eci,
+                                      defines = defines,
+                                      exports = self.exports)
         else:
             if self.config.translation.instrument:
                 defines['INSTRUMENT'] = 1
             if CBuilder.have___thread:
                 if not self.config.translation.no__thread:
                     defines['USE___THREAD'] = 1
-            cfile, extra, include_dirs, library_dirs = \
-                   gen_source_standalone(db, modulename, targetdir,
-                                         entrypointname = pfname,
-                                         defines = defines,
-                                         extra_info = extra_info)
+            cfile, extra = gen_source_standalone(db, modulename, targetdir,
+                                                 self.eci,
+                                                 entrypointname = pfname,
+                                                 defines = defines)
         self.c_source_filename = py.path.local(cfile)
         self.extrafiles = extra
-        self.include_dirs = include_dirs.keys()
-        self.library_dirs = library_dirs.keys()
         if self.standalone:
             self.gen_makefile(targetdir)
         return cfile
@@ -636,23 +627,8 @@
     print >> f, '\treturn error;'
     print >> f, '}'
 
-def extra_information(database):
-    includes = {}
-    sources = {}
-    include_dirs = {}
-    library_dirs = {}
-    for node in database.globalcontainers():
-        for attrname in ['includes', 'sources', 'include_dirs', 'library_dirs']:
-            if hasattr(node, attrname):
-                for elem in getattr(node, attrname):
-                    locals()[attrname][elem] = True
-    includes = includes.keys()
-    includes.sort()
-    return {'includes':includes, 'sources':sources,
-            'include_dirs':include_dirs, 'library_dirs':library_dirs}
-
-def gen_source_standalone(database, modulename, targetdir, 
-                          entrypointname, defines={}, extra_info={}): 
+def gen_source_standalone(database, modulename, targetdir, eci,
+                          entrypointname, defines={}): 
     assert database.standalone
     if isinstance(targetdir, str):
         targetdir = py.path.local(targetdir)
@@ -710,12 +686,10 @@
         print >>fi, "#define INSTRUMENT_NCOUNTER %d" % n
         fi.close()
 
-    return filename, sg.getextrafiles(), extra_info.get('include_dirs', None),\
-           extra_info.get('library_dirs', None)
+    return filename, sg.getextrafiles()
 
 
-def gen_source(database, modulename, targetdir, defines={}, exports={},
-               libraries=[], extra_info={}):
+def gen_source(database, modulename, targetdir, eci, defines={}, exports={}):
     assert not database.standalone
     if isinstance(targetdir, str):
         targetdir = py.path.local(targetdir)
@@ -741,11 +715,11 @@
     for line in database.gcpolicy.pre_gc_code():
         print >> fi, line
 
-    for include in extra_info.get('includes', []):
-        print >> fi, '#include <%s>' % (include,)
+    eci.write_c_header(fi)
+    fi.close()
+
     for source in extra_info.get('sources', []):
         print >> f, source
-    fi.close()
 
     if database.translator is None or database.translator.rtyper is None:
         preimplementationlines = []
@@ -769,13 +743,10 @@
     #
     pypy_include_dir = autopath.this_dir
     f = targetdir.join('setup.py').open('w')
-    include_dirs = extra_info.get('include_dirs', [])
-    library_dirs = extra_info.get('library_dirs', [])
     f.write(SETUP_PY % locals())
     f.close()
 
-    return filename, sg.getextrafiles(), include_dirs,\
-           library_dirs
+    return filename, sg.getextrafiles()
 
 
 SETUP_PY = '''

Modified: pypy/branch/rewrite-compilation-logic/pypy/translator/c/node.py
==============================================================================
--- pypy/dist/pypy/translator/c/node.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/translator/c/node.py	Sat Nov 24 19:00:44 2007
@@ -13,7 +13,7 @@
 from pypy.translator.c.primitive import PrimitiveType
 from pypy.rlib.rarithmetic import isinf, isnan
 from pypy.translator.c import extfunc
-
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
 
 def needs_gcheader(T):
     if not isinstance(T, ContainerType):
@@ -698,9 +698,8 @@
         else:
             self.name = (forcename or
                          db.namespace.uniquename('g_' + self.basename()))
-        for attrname in 'libraries', 'include_dirs', 'includes', 'sources', 'library_dirs':
-            if hasattr(obj, attrname):
-                setattr(self, attrname, getattr(obj, attrname))
+        self.compilation_info = getattr(obj, 'compilation_info',
+                                        ExternalCompilationInfo())
         self.make_funcgens()
         #self.dependencies = {}
         self.typename = db.gettype(T)  #, who_asks=self)

Modified: pypy/branch/rewrite-compilation-logic/pypy/translator/c/test/test_genc.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_genc.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/translator/c/test/test_genc.py	Sat Nov 24 19:00:44 2007
@@ -10,6 +10,7 @@
 from pypy.objspace.flow.model import Block, Link, FunctionGraph
 from pypy.tool.udir import udir
 from pypy.translator.tool.cbuild import make_module_from_c
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from pypy.translator.gensupp import uniquemodulename
 from pypy.translator.backendopt.all import backend_optimizations
 from pypy.translator.interactive import Translation

Modified: pypy/branch/rewrite-compilation-logic/pypy/translator/tool/cbuild.py
==============================================================================
--- pypy/dist/pypy/translator/tool/cbuild.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/translator/tool/cbuild.py	Sat Nov 24 19:00:44 2007
@@ -8,6 +8,7 @@
 from pypy.tool.ansi_print import ansi_log
 log = py.log.Producer("cbuild")
 py.log.setconsumer("cbuild", ansi_log)
+from pypy.tool.udir import udir
 
 debug = 0
 
@@ -16,6 +17,8 @@
     _ATTRIBUTES = ['pre_include_lines', 'includes', 'include_dirs',
                    'post_include_lines', 'libraries', 'library_dirs',
                    'separate_module_sources', 'separate_module_files']
+    _AVOID_DUPLICATES = ['separate_module_files', 'libraries', 'includes',
+                         'include_dirs', 'library_dirs']
 
     def __init__(self,
                  pre_include_lines       = [],
@@ -60,6 +63,54 @@
         # XXX custom hash and eq functions, they should be compared
         #     by contents
 
+    def merge(self, *others):
+        others = list(others)
+        attrs = {}
+        for name in self._ATTRIBUTES:
+            if name not in self._AVOID_DUPLICATES:
+                s = []
+                for i in [self] + others:
+                    s += getattr(i, name)
+                attrs[name] = s
+            else:
+                s = set()
+                attr = []
+                for one in [self] + others:
+                    for elem in getattr(one, name):
+                        if elem not in s:
+                            s.add(elem)
+                            attr.append(elem)
+                attrs[name] = attr
+        return ExternalCompilationInfo(**attrs)
+
+    def write_c_header(self, fileobj):
+        for line in self.pre_include_lines:
+            print >> fileobj, line
+        for path in self.includes:
+            print >> fileobj, '#include <%s>' % (path,)
+        for line in self.post_include_lines:
+            print >> fileobj, line
+
+    def convert_sources_to_files(self, cache_dir=None):
+        if cache_dir is None:
+            cache_dir = udir.join('module_cache').ensure(dir=1)
+        num = 0
+        files = []
+        for source in self.separate_module_sources:
+            while 1:
+                filename = cache_dir.join('module_%d.c' % num)
+                num += 1
+                if not filename.check():
+                    break
+            filename.write(source)
+            files.append(str(filename))
+        d = {}
+        for attr in self._ATTRIBUTES:
+            d[attr] = getattr(self, attr)
+        d['separate_module_sources'] = ()
+        d['separate_module_files'] += tuple(files)
+        return ExternalCompilationInfo(**d)
+
 if sys.platform == 'win32':
     so_ext = '.dll'
 else:
@@ -94,17 +145,24 @@
         opt += '/Op'
     gcv['OPT'] = opt
 
-def compile_c_module(cfiles, modname, include_dirs=[], libraries=[],
-                     library_dirs=[]):
+def compile_c_module(cfiles, modname, eci):
     #try:
     #    from distutils.log import set_threshold
     #    set_threshold(10000)
     #except ImportError:
     #    print "ERROR IMPORTING"
     #    pass
-    include_dirs = list(include_dirs)
+    cfiles = [py.path.local(f) for f in cfiles]
+    tmpdir = udir.join("modcache").ensure(dir=1)
+    num = 0
+    for source in eci.separate_module_sources:
+        c_file = tmpdir.join('mod_%d.c' % num)
+        c_file.write(source)
+        cfiles.append(c_file)
+    cfiles += eci.separate_module_files
+    include_dirs = list(eci.include_dirs)
     include_dirs.append(py.path.local(pypydir).join('translator', 'c'))
-    library_dirs = list(library_dirs)
+    library_dirs = list(eci.library_dirs)
     if sys.platform == 'darwin':    # support Fink & Darwinports
         for s in ('/sw/', '/opt/local/'):
             if s + 'include' not in include_dirs and \
@@ -114,8 +172,9 @@
                os.path.exists(s + 'lib'):
                 library_dirs.append(s + 'lib')
 
-    dirpath = cfiles[0].dirpath()
+    dirpath = py.path.local(modname).dirpath()
     lastdir = dirpath.chdir()
+    libraries = eci.libraries
     ensure_correct_math()
     try:
         if debug: print "modname", modname
@@ -195,9 +254,9 @@
             raise
     finally:
         lastdir.chdir()
+    return modname + so_ext
 
-def cache_c_module(cfiles, modname, cache_dir=None,
-                   include_dirs=[], libraries=[]):
+def cache_c_module(cfiles, modname, eci, cache_dir=None):
     """ Same as build c module, but instead caches results.
     XXX currently there is no way to force a recompile, so this is pretty
     useless as soon as the sources (or headers they depend on) change :-/
@@ -210,14 +269,12 @@
         cache_dir = py.path.local(cache_dir)
     assert cache_dir.check(dir=1)   # XXX
     modname = str(cache_dir.join(modname))
-    compile_c_module(cfiles, modname, include_dirs=include_dirs,
-                     libraries=libraries)
-    return modname + so_ext
+    return compile_c_module(cfiles, modname, eci)
 
-def make_module_from_c(cfile, include_dirs=None, libraries=[]):
+def make_module_from_c(cfile, eci):
     cfile = py.path.local(cfile)
     modname = cfile.purebasename
-    compile_c_module([cfile], modname, include_dirs, libraries)
+    compile_c_module([cfile], modname, eci)
     return import_module_from_directory(cfile.dirpath(), modname)
 
 def import_module_from_directory(dir, modname):
@@ -267,16 +324,15 @@
             
 class CCompiler:
 
-    def __init__(self, cfilenames, outputfilename=None, include_dirs=[],
-                 libraries=[], library_dirs=[], compiler_exe=None,
-                 profbased=None):
+    def __init__(self, cfilenames, eci, outputfilename=None,
+                 compiler_exe=None, profbased=None):
         self.cfilenames = cfilenames
         ext = ''
         self.compile_extra = []
         self.link_extra = []
-        self.libraries = list(libraries)
-        self.include_dirs = list(include_dirs)
-        self.library_dirs = list(library_dirs)
+        self.libraries = list(eci.libraries)
+        self.include_dirs = list(eci.include_dirs)
+        self.library_dirs = list(eci.library_dirs)
         self.compiler_exe = compiler_exe
         self.profbased = profbased
         if not sys.platform in ('win32', 'darwin'): # xxx

Modified: pypy/branch/rewrite-compilation-logic/pypy/translator/tool/test/test_cbuild.py
==============================================================================
--- pypy/dist/pypy/translator/tool/test/test_cbuild.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/translator/tool/test/test_cbuild.py	Sat Nov 24 19:00:44 2007
@@ -1,7 +1,9 @@
 import py, sys
 
 from pypy.tool.udir import udir 
-from pypy.translator.tool.cbuild import build_executable, cache_c_module
+from pypy.translator.tool.cbuild import build_executable, cache_c_module,\
+     ExternalCompilationInfo
+from subprocess import Popen, PIPE, STDOUT
 
 def test_simple_executable(): 
     print udir
@@ -14,7 +16,8 @@
             return 0;
         }
 """)
-    testexec = build_executable([t])
+    eci = ExternalCompilationInfo()
+    testexec = build_executable([t], eci)
     out = py.process.cmdexec(testexec)
     assert out.startswith('hello world')
     
@@ -30,8 +33,81 @@
     csourcedir = pypydir.join('translator', 'c', 'src')
     include_dirs = [str(csourcedir.dirpath())]
     files = [csourcedir.join('thread.c')]
-    cache_c_module(files, '_thread', cache_dir=udir, include_dirs=include_dirs,
-                   libraries=['pthread'])
+    eci = ExternalCompilationInfo(
+        include_dirs=include_dirs,
+        libraries=['pthread']
+    )
+    cache_c_module(files, '_thread', eci, cache_dir=udir)
     cdll = ctypes.CDLL(str(udir.join('_thread.so')))
     assert hasattr(cdll, 'RPyThreadLockInit')
 
+
+class TestEci:
+    def setup_class(cls):
+        tmpdir = udir.ensure('testeci', dir=1)
+        c_file = tmpdir.join('module.c')
+        c_file.write(py.code.Source('''
+        int sum(int x, int y)
+        {
+            return x + y;
+        }
+        '''))
+        cls.modfile = c_file
+        cls.tmpdir = tmpdir
+
+    def test_standalone(self):
+        tmpdir = self.tmpdir
+        c_file = tmpdir.join('stand1.c')
+        c_file.write('''
+        #include <math.h>
+        #include <stdio.h>
+        
+        int main()
+        {
+            printf("%f\\n", pow(2.0, 2.0));
+        }''')
+        eci = ExternalCompilationInfo(
+            libraries = ['m'],
+        )
+        output = build_executable([c_file], eci)
+        p = Popen(output, stdout=PIPE, stderr=STDOUT)
+        p.wait()
+        assert p.stdout.readline().startswith('4.0')
+    
+    def test_merge(self):
+        e1 = ExternalCompilationInfo(
+            pre_include_lines  = ['1'],
+            includes           = ['x.h'],
+            post_include_lines = ['p1']
+        )
+        e2 = ExternalCompilationInfo(
+            pre_include_lines  = ['2'],
+            includes           = ['x.h', 'y.h'],
+            post_include_lines = ['p2'],
+        )
+        e3 = ExternalCompilationInfo(
+            pre_include_lines  = ['3'],
+            includes           = ['y.h', 'z.h'],
+            post_include_lines = ['p3']
+        )
+        e = e1.merge(e2, e3)
+        assert e.pre_include_lines == ('1', '2', '3')
+        assert e.includes == ('x.h', 'y.h', 'z.h')
+        assert e.post_include_lines == ('p1', 'p2', 'p3')
+
+    def test_convert_sources_to_c_files(self):
+        eci = ExternalCompilationInfo(
+            separate_module_sources = ['xxx'],
+            separate_module_files = ['x.c'],
+        )
+        cache_dir = udir.join('test_convert_sources').ensure(dir=1)
+        neweci = eci.convert_sources_to_files(cache_dir)
+        assert not neweci.separate_module_sources
+        res = neweci.separate_module_files
+        assert len(res) == 2
+        assert res[0] == 'x.c'
+        assert str(res[1]).startswith(str(cache_dir))
+
+    def test_compile_c_files_to_ofiles(self):
+        pass
+



More information about the Pypy-commit mailing list