summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Ward <gward@python.net>2000-09-30 20:37:56 (GMT)
committerGreg Ward <gward@python.net>2000-09-30 20:37:56 (GMT)
commit1297b5ce67642dba35615121825fb1621e28e6b8 (patch)
tree824ce022fc27bdd679732b2bc3dbdbfcafcfc6c4
parent4752769d08c3ef950d31b926751d5e4d1dae294f (diff)
downloadcpython-1297b5ce67642dba35615121825fb1621e28e6b8.zip
cpython-1297b5ce67642dba35615121825fb1621e28e6b8.tar.gz
cpython-1297b5ce67642dba35615121825fb1621e28e6b8.tar.bz2
Added 'byte_compile(): an all-singing, all-dancing wrapper around the
standard 'py_compile.compile()' function. Laundry list of features: - handles standard Distutils 'force', 'verbose', 'dry_run' flags - handles various levels of optimization: can compile directly in this interpreter process, or write a temporary script that is then executed by a new interpreter with the appropriate flags - can rewrite the source filename by stripping an optional prefix and preprending an optional base dir.
-rw-r--r--Lib/distutils/util.py131
1 files changed, 129 insertions, 2 deletions
diff --git a/Lib/distutils/util.py b/Lib/distutils/util.py
index 1a1ec6d..0323484 100644
--- a/Lib/distutils/util.py
+++ b/Lib/distutils/util.py
@@ -8,8 +8,9 @@ one of the other *util.py modules.
__revision__ = "$Id$"
-import sys, os, string, re, shutil
-from distutils.errors import *
+import sys, os, string, re
+from distutils.errors import DistutilsPlatformError
+from distutils.dep_util import newer
from distutils.spawn import spawn
@@ -289,3 +290,129 @@ def strtobool (val):
return 0
else:
raise ValueError, "invalid truth value %s" % `val`
+
+
+def byte_compile (py_files,
+ optimize=0, force=0,
+ prefix=None, base_dir=None,
+ verbose=1, dry_run=0,
+ direct=None):
+ """Byte-compile a collection of Python source files to either
+ .pyc or .pyo files in the same directory. 'optimize' must be
+ one of the following:
+ 0 - don't optimize (generate .pyc)
+ 1 - normal optimization (like "python -O")
+ 2 - extra optimization (like "python -OO")
+ If 'force' is true, all files are recompiled regardless of
+ timestamps.
+
+ The source filename encoded in each bytecode file defaults to the
+ filenames listed in 'py_files'; you can modify these with 'prefix' and
+ 'basedir'. 'prefix' is a string that will be stripped off of each
+ source filename, and 'base_dir' is a directory name that will be
+ prepended (after 'prefix' is stripped). You can supply either or both
+ (or neither) of 'prefix' and 'base_dir', as you wish.
+
+ If 'verbose' is true, prints out a report of each file. If 'dry_run'
+ is true, doesn't actually do anything that would affect the filesystem.
+
+ Byte-compilation is either done directly in this interpreter process
+ with the standard py_compile module, or indirectly by writing a
+ temporary script and executing it. Normally, you should let
+ 'byte_compile()' figure out to use direct compilation or not (see
+ the source for details). The 'direct' flag is used by the script
+ generated in indirect mode; unless you know what you're doing, leave
+ it set to None.
+ """
+
+ # First, if the caller didn't force us into direct or indirect mode,
+ # figure out which mode we should be in. We take a conservative
+ # approach: choose direct mode *only* if the current interpreter is
+ # in debug mode and optimize is 0. If we're not in debug mode (-O
+ # or -OO), we don't know which level of optimization this
+ # interpreter is running with, so we can't do direct
+ # byte-compilation and be certain that it's the right thing. Thus,
+ # always compile indirectly if the current interpreter is in either
+ # optimize mode, or if either optimization level was requested by
+ # the caller.
+ if direct is None:
+ direct = (__debug__ and optimize == 0)
+
+ # "Indirect" byte-compilation: write a temporary script and then
+ # run it with the appropriate flags.
+ if not direct:
+ from tempfile import mktemp
+ script_name = mktemp(".py")
+ if verbose:
+ print "writing byte-compilation script '%s'" % script_name
+ if not dry_run:
+ script = open(script_name, "w")
+
+ script.write("""\
+from distutils.util import byte_compile
+files = [
+""")
+ script.write(string.join(map(repr, py_files), ",\n") + "]\n")
+ script.write("""
+byte_compile(files, optimize=%s, force=%s,
+ prefix=%s, base_dir=%s,
+ verbose=%s, dry_run=0,
+ direct=1)
+""" % (`optimize`, `force`, `prefix`, `base_dir`, `verbose`))
+
+ script.close()
+
+ cmd = [sys.executable, script_name]
+ if optimize == 1:
+ cmd.insert(1, "-O")
+ elif optimize == 2:
+ cmd.insert(1, "-OO")
+ spawn(cmd, verbose=verbose, dry_run=dry_run)
+
+ # "Direct" byte-compilation: use the py_compile module to compile
+ # right here, right now. Note that the script generated in indirect
+ # mode simply calls 'byte_compile()' in direct mode, a weird sort of
+ # cross-process recursion. Hey, it works!
+ else:
+ from py_compile import compile
+
+ for file in py_files:
+ if file[-3:] != ".py":
+ raise ValueError, \
+ "invalid filename: %s doesn't end with '.py'" % `file`
+
+ # Terminology from the py_compile module:
+ # cfile - byte-compiled file
+ # dfile - purported source filename (same as 'file' by default)
+ cfile = file + (__debug__ and "c" or "o")
+ dfile = file
+ if prefix:
+ if file[:len(prefix)] != prefix:
+ raise ValueError, \
+ ("invalid prefix: filename %s doesn't start with %s"
+ % (`file`, `prefix`))
+ dfile = dfile[len(prefix):]
+ if base_dir:
+ dfile = os.path.join(base_dir, dfile)
+
+ cfile_base = os.path.basename(cfile)
+ if direct:
+ if force or newer(file, cfile):
+ if verbose:
+ print "byte-compiling %s to %s" % (file, cfile_base)
+ if not dry_run:
+ compile(file, cfile, dfile)
+ else:
+ if verbose:
+ print "skipping byte-compilation of %s to %s" % \
+ (file, cfile_base)
+
+# byte_compile ()
+
+
+if __name__ == "__main__":
+ import glob
+ f = glob.glob("command/*.py")
+ byte_compile(f, optimize=0, prefix="command/", base_dir="/usr/lib/python")
+ #byte_compile(f, optimize=1)
+ #byte_compile(f, optimize=2)