[pypy-svn] r73508 - in pypy/branch/cpython-extension/pypy: config doc/config translator translator/c translator/c/src translator/c/test

afa at codespeak.net afa at codespeak.net
Wed Apr 7 16:27:51 CEST 2010


Author: afa
Date: Wed Apr  7 16:27:49 2010
New Revision: 73508

Added:
   pypy/branch/cpython-extension/pypy/doc/config/translation.shared.txt   (contents, props changed)
Modified:
   pypy/branch/cpython-extension/pypy/config/pypyoption.py
   pypy/branch/cpython-extension/pypy/config/translationoption.py
   pypy/branch/cpython-extension/pypy/translator/c/genc.py
   pypy/branch/cpython-extension/pypy/translator/c/src/main.h
   pypy/branch/cpython-extension/pypy/translator/c/test/test_standalone.py
   pypy/branch/cpython-extension/pypy/translator/driver.py
Log:
Add the --shared option to translation.
This allows to build pypy as a shared library, which can thus export the C API provided by cpyext.

On windows, this builds two files:
- pypy-c.exe.dll is the shared library containing all pypy
- pypy-c.exe is a tiny executable that calls the main function in the dll.


Modified: pypy/branch/cpython-extension/pypy/config/pypyoption.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/config/pypyoption.py	(original)
+++ pypy/branch/cpython-extension/pypy/config/pypyoption.py	Wed Apr  7 16:27:49 2010
@@ -62,12 +62,14 @@
 
 
 module_dependencies = {}
-module_suggests = {    # the reason you want _rawffi is for ctypes, which
-                       # itself needs the interp-level struct module
-                       # because 'P' is missing from the app-level one
-                       '_rawffi': [("objspace.usemodules.struct", True)],
-                       'cpyext': [("translation.secondaryentrypoints", "cpyext")],
-                       }
+module_suggests = {
+    # the reason you want _rawffi is for ctypes, which
+    # itself needs the interp-level struct module
+    # because 'P' is missing from the app-level one
+    "_rawffi": [("objspace.usemodules.struct", True)],
+    "cpyext": [("translation.secondaryentrypoints", "cpyext"),
+               ("translation.shared", sys.platform == "win32")],
+    }
 
 module_import_dependencies = {
     # no _rawffi if importing pypy.rlib.libffi raises ImportError

Modified: pypy/branch/cpython-extension/pypy/config/translationoption.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/config/translationoption.py	(original)
+++ pypy/branch/cpython-extension/pypy/config/translationoption.py	Wed Apr  7 16:27:49 2010
@@ -42,6 +42,9 @@
                      },
                  cmdline="-b --backend"),
 
+    BoolOption("shared", "Build as a shared library",
+               default=False, cmdline="--shared"),
+
     BoolOption("log", "Include debug prints in the translation (PYPYLOG=...)",
                default=True, cmdline="--log"),
 

Added: pypy/branch/cpython-extension/pypy/doc/config/translation.shared.txt
==============================================================================
--- (empty file)
+++ pypy/branch/cpython-extension/pypy/doc/config/translation.shared.txt	Wed Apr  7 16:27:49 2010
@@ -0,0 +1,2 @@
+Build pypy as a shared library or a DLL, with a small executable to run it.
+This is necessary on Windows to expose the C API provided by the cpyext module.

Modified: pypy/branch/cpython-extension/pypy/translator/c/genc.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/translator/c/genc.py	(original)
+++ pypy/branch/cpython-extension/pypy/translator/c/genc.py	Wed Apr  7 16:27:49 2010
@@ -78,14 +78,15 @@
         self.outputfilename = outputfilename
         self.profbased = profbased
 
-    def _build(self, eci=ExternalCompilationInfo()):
+    def _build(self, eci=ExternalCompilationInfo(), shared=False):
         return self.platform.compile(self.cfiles, self.eci.merge(eci),
-                                     outputfilename=self.outputfilename)
+                                     outputfilename=self.outputfilename,
+                                     standalone=not shared)
 
-    def build(self):
+    def build(self, shared=False):
         if self.profbased:
             return self._do_profbased()
-        return self._build()
+        return self._build(shared=shared)
 
     def _do_profbased(self):
         ProfDriver, args = self.profbased
@@ -252,6 +253,10 @@
             if CBuilder.have___thread:
                 if not self.config.translation.no__thread:
                     defines['USE___THREAD'] = 1
+            if self.config.translation.shared:
+                defines['PYPY_MAIN_FUNCTION'] = "pypy_main_startup"
+                self.eci = self.eci.merge(ExternalCompilationInfo(
+                    export_symbols=["pypy_main_startup"]))
             self.eci, cfile, extra = gen_source_standalone(db, modulename,
                                                  targetdir,
                                                  self.eci,
@@ -422,6 +427,7 @@
 class CStandaloneBuilder(CBuilder):
     standalone = True
     executable_name = None
+    shared_library_name = None
 
     def getprofbased(self):
         profbased = None
@@ -462,9 +468,33 @@
             return res.out, res.err
         return res.out
 
-    def compile(self):
+    def build_main_for_shared(self, shared_library_name, entrypoint):
+        self.shared_library_name = shared_library_name
+        # build main program
+        eci = self.get_eci()
+        eci = eci.merge(ExternalCompilationInfo(
+            separate_module_sources=['''
+                int %s(argc, argv);
+
+                int main(int argc, char* argv[])
+                { %s(argc, argv); }
+                ''' % (entrypoint, entrypoint)
+                ],
+            libraries=[self.shared_library_name.new(ext='')]
+            ))
+        eci = eci.convert_sources_to_files(
+            cache_dir=self.targetdir)
+        outfilename = self.shared_library_name.new(ext='')
+        return self.translator.platform.compile(
+            [], eci,
+            outputfilename=str(outfilename))
+
+    def compile(self, exe_name=None):
         assert self.c_source_filename
         assert not self._compiled
+
+        shared = self.config.translation.shared
+
         if (self.config.translation.gcrootfinder == "asmgcc" or
             self.config.translation.force_make):
             extra_opts = []
@@ -475,16 +505,21 @@
         else:
             compiler = CCompilerDriver(self.translator.platform,
                                        [self.c_source_filename] + self.extrafiles,
-                                       self.eci, profbased=self.getprofbased())
-            self.executable_name = compiler.build()
+                                       self.eci, profbased=self.getprofbased(),
+                                       outputfilename=exe_name)
+            self.executable_name = compiler.build(shared=shared)
+            if shared:
+                self.executable_name = self.build_main_for_shared(
+                    self.executable_name, "pypy_main_startup")
             assert self.executable_name
         self._compiled = True
         return self.executable_name
 
-    def gen_makefile(self, targetdir):
+    def gen_makefile(self, targetdir, exe_name=None):
         cfiles = [self.c_source_filename] + self.extrafiles
         mk = self.translator.platform.gen_makefile(cfiles, self.eci,
-                                                   path=targetdir)
+                                                   path=targetdir,
+                                                   exe_name=exe_name)
         if self.has_profopt():
             profopt = self.config.translation.profopt
             mk.definition('ABS_TARGET', '$(shell python -c "import sys,os; print os.path.abspath(sys.argv[1])" $(TARGET))')

Modified: pypy/branch/cpython-extension/pypy/translator/c/src/main.h
==============================================================================
--- pypy/branch/cpython-extension/pypy/translator/c/src/main.h	(original)
+++ pypy/branch/cpython-extension/pypy/translator/c/src/main.h	Wed Apr  7 16:27:49 2010
@@ -15,11 +15,15 @@
 
 #ifndef PYPY_NOT_MAIN_FILE
 
+#ifndef PYPY_MAIN_FUNCTION
+#define PYPY_MAIN_FUNCTION main
+#endif
+
 #ifdef MS_WINDOWS
 #include "src/winstuff.c"
 #endif
 
-int main(int argc, char *argv[])
+int PYPY_MAIN_FUNCTION(int argc, char *argv[])
 {
     char *errmsg;
     int i, exitcode;

Modified: pypy/branch/cpython-extension/pypy/translator/c/test/test_standalone.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/translator/c/test/test_standalone.py	(original)
+++ pypy/branch/cpython-extension/pypy/translator/c/test/test_standalone.py	Wed Apr  7 16:27:49 2010
@@ -16,11 +16,13 @@
 class StandaloneTests(object):
     config = None
 
-    def compile(self, entry_point, debug=True):
+    def compile(self, entry_point, debug=True, shared=False):
         t = TranslationContext(self.config)
         t.buildannotator().build_types(entry_point, [s_list_of_strings])
         t.buildrtyper().specialize()
 
+        t.config.translation.shared = shared
+
         cbuilder = CStandaloneBuilder(t, entry_point, t.config)
         if debug:
             cbuilder.generate_source(defines=cbuilder.DEBUG_DEFINES)
@@ -587,6 +589,17 @@
         # The traceback stops at f() because it's the first function that
         # captures the AssertionError, which makes the program abort.
 
+    def test_shared(self):
+        def f(argv):
+            print len(argv)
+        def entry_point(argv):
+            f(argv)
+            return 0
+        t, cbuilder = self.compile(entry_point, shared=True)
+        assert cbuilder.shared_library_name is not None
+        assert cbuilder.shared_library_name != cbuilder.executable_name
+        out, err = cbuilder.cmdexec("a b")
+        assert out == "3"
 
 class TestMaemo(TestStandalone):
     def setup_class(cls):

Modified: pypy/branch/cpython-extension/pypy/translator/driver.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/translator/driver.py	(original)
+++ pypy/branch/cpython-extension/pypy/translator/driver.py	Wed Apr  7 16:27:49 2010
@@ -516,12 +516,16 @@
             exename = mkexename(self.c_entryp)
             newexename = self.compute_exe_name()
             shutil.copy(str(exename), str(newexename))
+            if self.cbuilder.shared_library_name is not None:
+                soname = self.cbuilder.shared_library_name
+                newsoname = newexename.new(basename=soname.basename)
+                shutil.copy(str(soname), str(newsoname))
             self.c_entryp = newexename
         self.log.info("created: %s" % (self.c_entryp,))
 
     def task_compile_c(self): # xxx messy
         cbuilder = self.cbuilder
-        cbuilder.compile()
+        cbuilder.compile(exe_name=self.compute_exe_name().basename)
 
         if self.standalone:
             self.c_entryp = cbuilder.executable_name



More information about the Pypy-commit mailing list