[pypy-svn] r49060 - in pypy/branch/rewrite-compilation-logic/pypy: rpython/lltypesystem rpython/lltypesystem/test translator/tool translator/tool/test

fijal at codespeak.net fijal at codespeak.net
Sat Nov 24 23:14:19 CET 2007


Author: fijal
Date: Sat Nov 24 23:14:18 2007
New Revision: 49060

Modified:
   pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/ll2ctypes.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/translator/tool/cbuild.py
   pypy/branch/rewrite-compilation-logic/pypy/translator/tool/test/test_cbuild.py
Log:
* A bit of cleanups
* Extremely smart hack to make tests work. I fear this hack would be too
  smart or become dependant on caching on different level or sth.
* Add extern keyword next to external variables


Modified: pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/ll2ctypes.py
==============================================================================
--- pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/ll2ctypes.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/ll2ctypes.py	Sat Nov 24 23:14:18 2007
@@ -14,14 +14,13 @@
 from pypy.tool.tls import tlsobject
 from pypy.rlib.rarithmetic import r_uint, r_singlefloat
 from pypy.annotation import model as annmodel
-from pypy.translator.tool.cbuild import cache_c_module
-
 
 def uaddressof(obj):
     return fixid(ctypes.addressof(obj))
 
 
 _ctypes_cache = {}
+_eci_cache = {}
 
 def _setup_ctypes_cache():
     from pypy.rpython.lltypesystem import rffi
@@ -525,10 +524,15 @@
         except AttributeError:
             pass
     
-    eci = funcptr._obj.compilation_info
-    libraries = list(eci.libraries)
+    old_eci = funcptr._obj.compilation_info
     funcname = funcptr._obj._name
-    eci = eci.make_shared_lib()
+    try:
+        eci = _eci_cache[old_eci]
+    except KeyError:
+        eci = old_eci.compile_shared_lib()
+        _eci_cache[old_eci] = eci
+
+    libraries = list(eci.libraries)
 
     FUNCTYPE = lltype.typeOf(funcptr).TO
     if not libraries:

Modified: pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/rffi.py
==============================================================================
--- pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/rffi.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/rffi.py	Sat Nov 24 23:14:18 2007
@@ -250,6 +250,8 @@
         c_type = 'char **'
     elif TYPE == CCHARP:
         c_type = 'char *'
+    elif TYPE == INT:
+        c_type = 'int'
     else:
         c_type = PrimitiveType[TYPE]
         assert c_type.endswith(' @')
@@ -261,6 +263,7 @@
     c_setter = "void %(setter_name)s (%(c_type)s v) { %(name)s = v; }" % locals()
 
     lines = ["#include <%s>" % i for i in eci.includes]
+    lines.append('extern %s %s;' % (c_type, name))
     lines.append(c_getter)
     lines.append(c_setter)
     sources = ('\n'.join(lines),)

Modified: pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
==============================================================================
--- pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/test/test_ll2ctypes.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/rpython/lltypesystem/test/test_ll2ctypes.py	Sat Nov 24 23:14:18 2007
@@ -10,6 +10,7 @@
 from pypy.rpython.annlowlevel import llhelper
 from pypy.rlib import rposix
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
+from pypy.tool.udir import udir
 
 class TestLL2Ctypes(object):
 
@@ -677,14 +678,19 @@
         assert res == 42
 
     def test_prebuilt_constant(self):
-        source = py.code.Source("""
-        int x = 3;
-        char** z = NULL;
+        header = py.code.Source("""
+        #include <stdlib.h>
+        
+        static int x = 3;
+        char **z = NULL;
         """)
-
-        eci = ExternalCompilationInfo(post_include_lines=source.lines)
+        h_file = udir.join("some_h.h")
+        h_file.write(header)
+        
+        eci = ExternalCompilationInfo(includes=['stdio.h', str(h_file.basename)],
+                                      include_dirs=[str(udir)])
         
-        get_x, set_x = rffi.CExternVariable(lltype.Signed, 'x', eci)
+        get_x, set_x = rffi.CExternVariable(rffi.LONG, 'x', eci)
         get_z, set_z = rffi.CExternVariable(rffi.CCHARPP, 'z', eci)
 
         def f():
@@ -700,5 +706,6 @@
             finally:
                 rffi.free_charpp(l)
 
-        assert f() == 16
+        res = f()
+        assert res == 16
         assert g() == "c"

Modified: pypy/branch/rewrite-compilation-logic/pypy/translator/tool/cbuild.py
==============================================================================
--- pypy/branch/rewrite-compilation-logic/pypy/translator/tool/cbuild.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/translator/tool/cbuild.py	Sat Nov 24 23:14:18 2007
@@ -60,8 +60,25 @@
             assert isinstance(value, (list, tuple))
             setattr(self, name, tuple(value))
 
-        # XXX custom hash and eq functions, they should be compared
-        #     by contents
+    def _value(self):
+        return tuple([getattr(self, x) for x in self._ATTRIBUTES])
+
+    def __hash__(self):
+        return hash(self._value())
+
+    def __eq__(self, other):
+        return self.__class__ is other.__class__ and \
+               self._value() == other._value()
+
+    def __ne__(self, other):
+        return not self == other
+
+    def __repr__(self):
+        info = []
+        for attr in self._ATTRIBUTES:
+            val = getattr(self, attr)
+            info.append("%s=%s" % (attr, repr(val)))
+        return "<ExternalCompilationInfo (%s)>" % ", ".join(info)
 
     def merge(self, *others):
         others = list(others)
@@ -91,7 +108,15 @@
         for line in self.post_include_lines:
             print >> fileobj, line
 
+    def _copy_attributes(self):
+        d = {}
+        for attr in self._ATTRIBUTES:
+            d[attr] = getattr(self, attr)
+        return d
+
     def convert_sources_to_files(self, cache_dir=None):
+        if not self.separate_module_sources:
+            return self
         if cache_dir is None:
             cache_dir = udir.join('module_cache').ensure(dir=1)
         num = 0
@@ -104,13 +129,22 @@
                     break
             filename.write(source)
             files.append(str(filename))
-        d = {}
-        for attr in self._ATTRIBUTES:
-            d[attr] = getattr(self, attr)
+        d = self._copy_attributes()
         d['separate_module_sources'] = ()
         d['separate_module_files'] += tuple(files)
         return ExternalCompilationInfo(**d)
 
+    def compile_shared_lib(self):
+        self = self.convert_sources_to_files()
+        if not self.separate_module_files:
+            return self
+        lib = compile_c_module([], 'externmod', self)
+        d = self._copy_attributes()
+        d['libraries'] += (lib,)
+        d['separate_module_files'] = ()
+        d['separate_module_sources'] = ()
+        return ExternalCompilationInfo(**d)
+
 if sys.platform == 'win32':
     so_ext = '.dll'
 else:
@@ -145,7 +179,7 @@
         opt += '/Op'
     gcv['OPT'] = opt
 
-def compile_c_module(cfiles, modname, eci):
+def compile_c_module(cfiles, modbasename, eci):
     #try:
     #    from distutils.log import set_threshold
     #    set_threshold(10000)
@@ -153,12 +187,8 @@
     #    print "ERROR IMPORTING"
     #    pass
     cfiles = [py.path.local(f) for f in cfiles]
-    tmpdir = udir.join("modcache").ensure(dir=1)
+    tmpdir = udir.join("module_cache").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'))
@@ -172,8 +202,15 @@
                os.path.exists(s + 'lib'):
                 library_dirs.append(s + 'lib')
 
-    dirpath = py.path.local(modname).dirpath()
-    lastdir = dirpath.chdir()
+    num = 0
+    modname = modbasename
+    while 1:
+        if not tmpdir.join(modname + so_ext).check():
+            break
+        num += 1
+        modname = '%s_%d' % (modbasename, num)
+
+    lastdir = tmpdir.chdir()
     libraries = eci.libraries
     ensure_correct_math()
     try:
@@ -186,7 +223,7 @@
                     from distutils import sysconfig
                     gcv = sysconfig.get_config_vars()
                     cmd = compiler_command().replace('%s',
-                                                     str(dirpath.join(modname)))
+                                                     str(tmpdir.join(modname)))
                     for dir in [gcv['INCLUDEPY']] + list(include_dirs):
                         cmd += ' -I%s' % dir
                     for dir in library_dirs:
@@ -254,22 +291,7 @@
             raise
     finally:
         lastdir.chdir()
-    return modname + so_ext
-
-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 :-/
-    XXX for now I'm forcing a recompilation all the time.  Better than not...
-    """
-    from pypy.tool.autopath import pypydir
-    if cache_dir is None:
-        cache_dir = py.path.local(pypydir).join('_cache')
-    else:
-        cache_dir = py.path.local(cache_dir)
-    assert cache_dir.check(dir=1)   # XXX
-    modname = str(cache_dir.join(modname))
-    return compile_c_module(cfiles, modname, eci)
+    return str(tmpdir.join(modname) + so_ext)
 
 def make_module_from_c(cfile, eci):
     cfile = py.path.local(cfile)

Modified: pypy/branch/rewrite-compilation-logic/pypy/translator/tool/test/test_cbuild.py
==============================================================================
--- pypy/branch/rewrite-compilation-logic/pypy/translator/tool/test/test_cbuild.py	(original)
+++ pypy/branch/rewrite-compilation-logic/pypy/translator/tool/test/test_cbuild.py	Sat Nov 24 23:14:18 2007
@@ -1,8 +1,8 @@
 import py, sys
 
 from pypy.tool.udir import udir 
-from pypy.translator.tool.cbuild import build_executable, cache_c_module,\
-     ExternalCompilationInfo
+from pypy.translator.tool.cbuild import build_executable, \
+     ExternalCompilationInfo, compile_c_module
 from subprocess import Popen, PIPE, STDOUT
 
 def test_simple_executable(): 
@@ -37,11 +37,10 @@
         include_dirs=include_dirs,
         libraries=['pthread']
     )
-    cache_c_module(files, '_thread', eci, cache_dir=udir)
-    cdll = ctypes.CDLL(str(udir.join('_thread.so')))
+    mod = compile_c_module(files, '_thread', eci)
+    cdll = ctypes.CDLL(mod)
     assert hasattr(cdll, 'RPyThreadLockInit')
 
-
 class TestEci:
     def setup_class(cls):
         tmpdir = udir.ensure('testeci', dir=1)
@@ -107,7 +106,23 @@
         assert len(res) == 2
         assert res[0] == 'x.c'
         assert str(res[1]).startswith(str(cache_dir))
+        e = ExternalCompilationInfo()
+        assert e.convert_sources_to_files() is e
 
-    def test_compile_c_files_to_ofiles(self):
-        pass
-
+    def test_make_shared_lib(self):
+        eci = ExternalCompilationInfo(
+            separate_module_sources = ['''
+            int get()
+            {
+                return 42;
+            }''']
+        )
+        neweci = eci.compile_shared_lib()
+        assert len(neweci.libraries) == 1
+        try:
+            import ctypes
+        except ImportError:
+            py.test.skip("Need ctypes for that test")
+        assert ctypes.CDLL(neweci.libraries[0]).get() == 42
+        assert not neweci.separate_module_sources
+        assert not neweci.separate_module_files



More information about the Pypy-commit mailing list