cx_Freeze / FreezePython.py

import optparse
import os
import shutil
import stat
import sys

import Freezer
import ModuleFinder

USAGE = \
"""
%prog [options] [SCRIPT]

Freeze a Python script and all of its referenced modules to a base
executable which can then be distributed without requiring a Python
installation."""

VERSION = \
"""
%prog 3.0.3
Copyright (c) 2002-2006 Computronix Corporation. All rights reserved."""

# parse the command line
parser = optparse.OptionParser(version = VERSION.strip(),
        usage = USAGE.strip())
parser.add_option("-O",
        action = "store_true",
        dest = "optimized",
        help = "optimize generated bytecode as per PYTHONOPTIMIZE; "
               "use -OO in order to remove doc strings")
parser.add_option("-c", "--compress",
        action = "store_true",
        dest = "compress",
        help = "compress byte code in zip files")
parser.add_option("--base-name", "--base-binary",
        dest = "baseName",
        metavar = "NAME",
        help = "file on which to base the target file; if the name of the "
               "file is not an absolute file name, the subdirectory bases "
               "(rooted in the directory in which the freezer is found) "
               "will be searched for a file matching the name")
parser.add_option("--init-script",
        dest = "initScript",
        metavar = "NAME",
        help = "script which will be executed upon startup; if the name of "
               "the file is not an absolute file name, the subdirectory "
               "initscripts (rooted in the directory in which the freezer is "
               "found) will be searched for a file matching the name")
parser.add_option("--target-dir", "--install-dir",
        dest = "targetDir",
        metavar = "DIR",
        help = "the directory in which to place the target file and "
               "any dependent files")
parser.add_option("--target-name",
        dest = "targetName",
        metavar = "NAME",
        help = "the name of the file to create instead of the base name "
               "of the script and the extension of the base binary")
parser.add_option("--shared-lib-name",
        dest = "sharedLibName",
        metavar = "NAME",
        help = "the name of the shared library (DLL) implementing the Python "
               "runtime which is required for a frozen binary to work")
parser.add_option("--no-copy-deps", "--keep-path",
        dest = "copyDeps",
        default = True,
        action = "store_false",
        help = "do not copy the dependent files (extensions, shared "
               "libraries, etc.) to the target directory; this also modifies "
               "the default init script to ConsoleKeepPath.py and means that "
               "the target executable requires a Python installation to "
               "execute properly")
parser.add_option("--default-path",
        dest = "defaultPath",
        metavar = "DIRS",
        help = "list of paths separated by the standard path separator for "
               "the platform which will be used to initialize sys.path prior "
               "to running the module finder")
parser.add_option("--include-path",
        dest = "includePath",
        metavar = "DIRS",
        help = "list of paths separated by the standard path separator for "
               "the platform which will be used to modify sys.path prior to "
               "running the module finder")
parser.add_option("--replace-paths",
        dest = "replacePaths",
        metavar = "DIRECTIVES",
        help = "replace all the paths in modules found in the given paths "
               "with the given replacement string; multiple values are "
               "separated by the standard path separator and each value is of "
               "the form path=replacement_string; path can be * which means "
               "all paths not already specified")
parser.add_option("--include-modules",
        dest = "includeModules",
        metavar = "NAMES",
        help = "comma separated list of modules to include")
parser.add_option("--exclude-modules",
        dest = "excludeModules",
        metavar = "NAMES",
        help = "comma separated list of modules to exclude")
parser.add_option("--ext-list-file",
        dest = "extListFile",
        metavar = "NAME",
        help = "name of file in which to place the list of dependent files "
               "which were copied into the target directory")
parser.add_option("-z", "--zip-include",
        dest = "zipIncludes",
        action = "append",
        default = [],
        metavar = "SPEC",
        help = "name of file to add to the zip file or a specification of the "
               "form name=arcname which will specify the archive name to use; "
               "multiple --zip-include arguments can be used")
options, args = parser.parse_args()

# perform some massaging of the arguments and options
if len(args) == 1:
    options.script, = args
elif len(args) == 0:
    options.script = None
else:
    parser.error("too many arguments")

if options.script is None and options.includeModules is None \
        and options.copyDeps:
    parser.error("a script or a list of modules must be specified")

if options.targetName is None and options.script is None:
    parser.error("a script or a target name must be specified")

defaultName = "Console"
if not options.copyDeps:
    defaultName = "ConsoleKeepPath"
if sys.platform == "win32":
    defaultName += ".exe"
options.baseName = Freezer.FullFileName("bases", options.baseName, defaultName)

defaultName = "Console.py"
if not options.copyDeps:
    defaultName = "ConsoleKeepPath.py"
options.initScript = Freezer.FullFileName("initscripts", options.initScript,
        defaultName)

if options.targetName is None:
    if options.script is None:
        parser.error("a script or a target name must be specified")
    name, ext = os.path.splitext(os.path.basename(options.script))
    baseName, ext = os.path.splitext(os.path.basename(options.baseName))
    options.targetName = name + ext

if options.targetDir is None:
    options.targetName = os.path.abspath(options.targetName)
    options.targetDir = os.path.dirname(options.targetName)
else:
    options.targetName = os.path.join(options.targetDir, options.targetName)

# determine the list of modules to exclude from the output
excludes = []
if options.excludeModules:
    excludes = options.excludeModules.split(",")

# modify sys.path as needed
if options.defaultPath is not None:
    sys.path = options.defaultPath.split(os.pathsep)
if options.includePath is not None:
    sys.path = options.includePath.split(os.pathsep) + sys.path
if options.script is not None:
    sys.path.insert(0, os.path.dirname(options.script))

# determine path replacements
replacePaths = {}
if options.replacePaths:
    starDirective = None
    for directive in options.replacePaths.split(os.pathsep):
        fromPath, replacement = directive.split("=")
        if fromPath == "*":
            starDirective = replacement
        else:
            replacePaths[fromPath] = replacement
    if starDirective is not None:
        for path in sys.path:
            if not path:
                continue
            path = path + os.sep
            if path and path not in replacePaths:
                replacePaths[path] = starDirective

# locate all of the modules
finder = ModuleFinder.ModuleFinder(excludes, replacePaths)
if options.script is not None:
    finder.run_script(options.script)
if options.includeModules:
    for name in options.includeModules.split(","):
        finder.import_hook(name)
if options.compress:
    finder.import_hook("zlib")
finder.load_file(options.initScript, "cx_Freeze__init__")
if options.copyDeps:
    Freezer.CreateExtensionLoaders(finder)

# report the result of the module location process
finder.report()

# start the freezing process
if not os.path.exists(options.targetDir):
    os.makedirs(options.targetDir)
if os.path.exists(options.targetName):
    os.chmod(options.targetName, 0777)
    os.remove(options.targetName)
shutil.copy(options.baseName, options.targetName)
if not os.access(options.targetName, os.W_OK):
    mode = os.stat(options.targetName).st_mode
    os.chmod(options.targetName, mode | stat.S_IWUSR)
Freezer.Freeze(options.targetName, finder, options.zipIncludes,
        options.compress)
if options.copyDeps:
    sharedLibName = options.sharedLibName or getattr(sys, "dllname", None)
    if sharedLibName is not None:
        finder.AddDependentFile(sharedLibName)
    finder.CopyDependentFiles(options.targetDir, options.extListFile)

print "Frozen binary %s created." % options.targetName
print "Done."
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.