[Distutils] Patch to have distutils generate PYC *and* PYO files

M.-A. Lemburg mal@lemburg.com
Wed Sep 20 07:26:01 2000


This is a multi-part message in MIME format.
--------------BFA08A6E6BF635BA05A3FB1C
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Attached you find a patch against the current CVS tree which allows
distutils to include PYC as well as PYO files.

I haven't dug deep into the option system yet, but it would be
nice if there also were an option which lets the packager
set the optimization level she want to use for the PYO files.

Currently level 1 is used. Level 2 would also eliminate doc-strings
which can sometimes be useful to reduce package size or to hide
interface information.

-- 
Marc-Andre Lemburg
______________________________________________________________________
Business:                                      http://www.lemburg.com/
Python Pages:                           http://www.lemburg.com/python/
--------------BFA08A6E6BF635BA05A3FB1C
Content-Type: text/plain; charset=us-ascii;
 name="distutils-pyo.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="distutils-pyo.patch"

--- CVS-Python/Lib/distutils/util.py	Mon Sep 18 10:31:17 2000
+++ Python+Unicode/Lib/distutils/util.py	Wed Sep 20 13:14:27 2000
@@ -5,11 +5,11 @@ one of the other *util.py modules."""
 
 # created 1999/03/08, Greg Ward
 
 __revision__ = "$Id: util.py,v 1.44 2000/09/15 01:16:14 gward Exp $"
 
-import sys, os, string, re, shutil
+import sys, os, string, re, shutil, py_compile
 from distutils.errors import *
 from distutils.spawn import spawn
 
 
 def get_platform ():
@@ -265,5 +265,39 @@ def execute (func, args, msg=None, verbo
     # And do it, as long as we're not in dry-run mode
     if not dry_run:
         apply(func, args)
 
 # execute()
+
+
+def compile(filename, optimize=None):
+
+    """ Compile the Python script filename.
+
+        If optimize is not given, the current optimization setting is
+        used. Otherwise, optimize must be an integer stating the value
+        of the optimization level to use:
+
+        0 - no optimization (generates .pyc file)
+        1 - normal optimization (generates .pyo file, same as -O)
+        2 - optimize + remove doc-strings (generates .pyo file, -OO)
+
+    """
+    if (optimize is None) or \
+       (not optimize and __debug__) or \
+       (optimize and not __debug__):
+        return py_compile.compile(filename)
+
+    # Otherwise will have to run a system command
+    python = sys.executable
+    filename = os.path.abspath(filename)
+    if optimize:
+        options = '-' + 'O' * optimize
+    else:
+        options = ''
+    command = "import py_compile; py_compile.compile('%s')" % filename
+    rc = os.system('%s %s -c "%s"' % (python, options, command))
+    if rc != 0:
+        # py_compile currently does not pass back errors, so this
+        # is not really executed...
+        raise SyntaxError,'could not compile "%s"' % filename
+
--- CVS-Python/Lib/distutils/command/install_lib.py	Mon Sep 18 10:31:17 2000
+++ Python+Unicode/Lib/distutils/command/install_lib.py	Wed Sep 20 13:19:11 2000
@@ -61,27 +61,24 @@ class install_lib (Command):
         else:
             self.warn("'%s' does not exist -- no Python modules to install" %
                       self.build_dir)
             return
 
-        # (Optionally) compile .py to .pyc
-        # XXX hey! we can't control whether we optimize or not; that's up
-        # to the invocation of the current Python interpreter (at least
-        # according to the py_compile docs).  That sucks.
-
+        # (Optionally) compile .py to .pyc and .pyo
         if self.compile:
-            from py_compile import compile
+            from distutils.util import compile
 
             for f in outfiles:
                 # only compile the file if it is actually a .py file
                 if f[-3:] == '.py':
-                    out_fn = f + (__debug__ and "c" or "o")
-                    compile_msg = "byte-compiling %s to %s" % \
-                                  (f, os.path.basename (out_fn))
-                    skip_msg = "skipping byte-compilation of %s" % f
-                    self.make_file (f, out_fn, compile, (f,),
-                                    compile_msg, skip_msg)
+                    for optimize in (0, 1):
+                        out_fn = f + (optimize and "o" or "c")
+                        compile_msg = "byte-compiling %s to %s" % \
+                                      (f, os.path.basename (out_fn))
+                        skip_msg = "skipping byte-compilation of %s" % f
+                        self.make_file (f, out_fn, compile, (f, optimize),
+                                        compile_msg, skip_msg)
     # run ()
 
 
     def _mutate_outputs (self, has_any, build_cmd, cmd_option, output_dir):
 
@@ -102,12 +99,12 @@ class install_lib (Command):
     # _mutate_outputs ()
 
     def _bytecode_filenames (self, py_filenames):
         bytecode_files = []
         for py_file in py_filenames:
-            bytecode = py_file + (__debug__ and "c" or "o")
-            bytecode_files.append(bytecode)
+            bytecode_files.append(py_file + "c")
+            bytecode_files.append(py_file + "o")
 
         return bytecode_files
         
     def get_outputs (self):
         """Return the list of files that would be installed if this command

--------------BFA08A6E6BF635BA05A3FB1C--