diff options
Diffstat (limited to 'Demo/scripts/freeze.py')
-rwxr-xr-x | Demo/scripts/freeze.py | 480 |
1 files changed, 0 insertions, 480 deletions
diff --git a/Demo/scripts/freeze.py b/Demo/scripts/freeze.py deleted file mode 100755 index be6d263..0000000 --- a/Demo/scripts/freeze.py +++ /dev/null @@ -1,480 +0,0 @@ -#! /usr/local/bin/python - -# Given a Python script, create a binary that runs the script. -# The binary is 100% independent of Python libraries and binaries. -# It will not contain any Python source code -- only "compiled" Python -# (as initialized static variables containing marshalled code objects). -# It even does the right thing for dynamically loaded modules! -# The module search path of the binary is set to the current directory. -# -# Some problems remain: -# - It's highly non-portable, since it knows about paths and libraries -# (there's a customization section though, and it knows how to -# distinguish an SGI from a Sun SPARC system -- adding knowledge -# about more systems is left as an exercise for the reader). -# - You need to have the Python source tree lying around as well as -# the "libpython.a" used to generate the Python binary. -# - For scripts that use many modules it generates absurdly large -# files (frozen.c and config.o as well as the final binary), -# and is consequently rather slow. -# -# Caveats: -# - The search for modules sometimes finds modules that are never -# actually imported since the code importing them is never executed. -# - If an imported module isn't found, you get a warning but the -# process of freezing continues. The binary will fail if it -# actually tries to import one of these modules. -# - This often happens with the module 'mac', which module 'os' tries -# to import (to determine whether it is running on a Macintosh). -# You can ignore the warning about this. -# - If the program dynamically reads or generates Python code and -# executes it, this code may reference built-in or library modules -# that aren't present in the frozen binary, and this will fail. -# - Your program may be using external data files, e.g. compiled -# forms definitions (*.fd). These aren't incorporated. Since -# sys.path in the resulting binary only contains '.', if your -# program searches its data files along sys.path (as the 'flp' -# modules does to find its forms definitions), you may need to -# change the program to extend the search path or instruct its users -# to set the environment variable PYTHONPATH to point to your data -# files. -# -# Usage hints: -# - If you have a bunch of scripts that you want to freeze, instead -# of freezing each of them separately, you might consider writing -# a tiny main script that looks at sys.argv[0] and then imports -# the corresponding module. You can then make links to the -# frozen binary named after the various scripts you support. -# Pass the additional scripts as arguments after the main script. -# A minimal script to do this is the following. -# import sys, posixpath -# exec('import ' + posixpath.basename(sys.argv[0]) + '\n') - - -import os -import sys -import regex -import getopt -import regsub -import string -import marshal - -# Function to join two pathnames with a slash in between -j = os.path.join - -################################## -# START OF CONFIGURATION SECTION # -################################## - -# Attempt to guess machine architecture -if os.path.exists('/usr/lib/libgl_s'): ARCH = 'sgi' -elif os.path.exists('/etc/issue'): ARCH = 'sequent' -else: ARCH = 'sun4' - -# Site parametrizations (change to match your site) -CC = 'cc' # C compiler -TOP = '/ufs/guido/src' # Parent of all source trees -PYTHON = j(TOP, 'python') # Top of the Python source tree -SRC = j(PYTHON, 'src') # Python source directory -BLD = j(PYTHON, 'build.' + ARCH) # Python build directory -#BLD = SRC # Use this if you build in SRC - -LIBINST = '/ufs/guido/src/python/irix4/tmp/lib/python/lib' # installed libraries -INCLINST = '/ufs/guido/src/python/irix4/tmp/include/Py' # installed include files - -# Other packages (change to match your site) -DL = j(TOP, 'dl') # Top of the dl source tree -DL_DLD = j(TOP, 'dl-dld') # The dl-dld source directory -DLD = j(TOP, 'dld-3.2.3') # The dld source directory -FORMS = j(TOP, 'forms') # Top of the FORMS source tree -STDWIN = j(TOP, 'stdwin') # Top of the STDWIN source tree -READLINE = j(TOP, 'readline.' + ARCH) # Top of the GNU Readline source tree -SUN_X11 = '/usr/local/X11R5/lib/libX11.a' - -# File names (usually no need to change) -LIBP = [ # Main Python libraries - j(LIBINST, 'libPython.a'), - j(LIBINST, 'libParser.a'), - j(LIBINST, 'libObjects.a'), - j(LIBINST, 'libModules.a') - ] -CONFIG_IN = j(LIBINST, 'config.c.in') # Configuration source file -FMAIN = j(LIBINST, 'frozenmain.c') # Special main source file - -# Libraries needed when linking. First tuple item is built-in module -# for which it is needed (or '*' for always), rest are ld arguments. -# There is a separate list per architecture. -libdeps_sgi = [ \ - ('stdwin', j(STDWIN, 'Build/' + ARCH + '/x11/lib/lib.a')), \ - ('fl', j(FORMS, 'FORMS/libforms.a'), '-lfm_s'), \ - ('*', j(READLINE, 'libreadline.a'), '-ltermcap'), \ - ('al', '-laudio'), \ - ('sv', '-lsvideo', '-lXext'), \ - ('cd', '-lcdaudio', '-lds'), \ - ('cl', '-lcl'), \ - ('imgfile', '-limage', '-lgutil', '-lm'), \ - ('mpz', '/ufs/guido/src/gmp/libgmp.a'), \ - ('*', '-lsun'), \ - ('*', j(DL, 'libdl.a'), '-lmld'), \ - ('*', '-lmpc'), \ - ('fm', '-lfm_s'), \ - ('gl', '-lgl_s', '-lX11_s'), \ - ('stdwin', '-lX11_s'), \ - ('*', '-lm'), \ - ('*', '-lc_s'), \ - ] -libdeps_sun4 = [ \ - ('*', '-Bstatic'), \ - ('stdwin', j(STDWIN, 'Build/' + ARCH + '/x11/lib/lib.a')), \ - ('*', j(READLINE, 'libreadline.a')), \ - ('*', '-lm'), \ - ('*', j(DL_DLD,'libdl.a'), j(DLD,'libdld.a')), \ - ('*', SUN_X11), \ - ('*', '-ltermcap'), \ - ('*', '-lc'), \ - ] -libdeps_sequent = [ \ - ('*', j(LIBINST, 'libreadline.a'), '-ltermcap'), \ - ('*', '-lsocket'), \ - ('*', '-linet'), \ - ('*', '-lnsl'), \ - ('*', '-lm'), \ - ('*', '-lc'), \ - ] -libdeps = eval('libdeps_' + ARCH) - -################################ -# END OF CONFIGURATION SECTION # -################################ - -# Exception used when scanfile fails -NoSuchFile = 'NoSuchFile' - -# Global options -quiet = 0 # -q -verbose = 0 # -v -noexec = 0 # -n -nowrite = 0 # -N -ofile = 'a.out' # -o file - -# Main program -- argument parsing etc. -def main(): - global quiet, verbose, noexec, nowrite, ofile - try: - opts, args = getopt.getopt(sys.argv[1:], 'nNo:qv') - except getopt.error, msg: - usage(str(msg)) - sys.exit(2) - for o, a in opts: - if o == '-n': noexec = 1 - if o == '-N': nowrite = 1 - if o == '-o': ofile = a - if o == '-q': verbose = 0; quiet = 1 - if o == '-v': verbose = verbose + 1; quiet = 0 - if len(args) < 1: - usage('please pass at least one file argument') - sys.exit(2) - process(args[0], args[1:]) - -# Print usage message to stderr -def usage(*msgs): - sys.stdout = sys.stderr - for msg in msgs: print msg - print 'Usage: freeze [options] scriptfile [modulefile ...]' - print '-n : generate the files but don\'t compile and link' - print '-N : don\'t write frozen.c (do compile unless -n given)' - print '-o file : binary output file (default a.out)' - print '-q : quiet (no messages at all except errors)' - print '-v : verbose (lots of extra messages)' - -# Process the script file -def process(filename, addmodules): - global noexec - # - if not quiet: print 'Computing needed modules ...' - todo = {} - todo['__main__'] = filename - for name in addmodules: - mod = os.path.basename(name) - if mod[-3:] == '.py': mod = mod[:-3] - todo[mod] = name - try: - dict = closure(todo) - except NoSuchFile, filename: - sys.stderr.write('Can\'t open file %s\n' % filename) - sys.exit(1) - # - mods = dict.keys() - mods.sort() - # - if verbose: - print '%-15s %s' % ('Module', 'Filename') - for mod in mods: - print '%-15s %s' % (`mod`, dict[mod]) - # - if not quiet: print 'Looking for dynamically linked modules ...' - dlmodules = [] - objs = [] - libs = [] - for mod in mods: - if dict[mod][-2:] == '.o': - if verbose: print 'Found', mod, dict[mod] - dlmodules.append(mod) - objs.append(dict[mod]) - libsname = dict[mod][:-2] + '.libs' - try: - f = open(libsname, 'r') - except IOError: - f = None - if f: - libtext = f.read() - f.close() - for lib in string.split(libtext): - if lib in libs: libs.remove(lib) - libs.append(lib) - # - if not nowrite: - if not quiet: print 'Writing frozen.c ...' - writefrozen('frozen.c', dict) - else: - if not quiet: print 'NOT writing frozen.c ...' - # -## if not dlmodules: - if 0: - config = CONFIG - if not quiet: print 'Using existing', config, '...' - else: - config = 'tmpconfig.c' - if nowrite: - if not quiet: print 'NOT writing config.c ...' - else: - if not quiet: - print 'Writing config.c with dl modules ...' - f = open(CONFIG_IN, 'r') - g = open(config, 'w') - m1 = regex.compile('-- ADDMODULE MARKER 1 --') - m2 = regex.compile('-- ADDMODULE MARKER 2 --') - builtinmodules = [] - stdmodules = ('sys', '__main__', '__builtin__', - 'marshal') - todomodules = builtinmodules + dlmodules - for mod in dict.keys(): - if dict[mod] == '<builtin>' and \ - mod not in stdmodules: - builtinmodules.append(mod) - while 1: - line = f.readline() - if not line: break - g.write(line) - if m1.search(line) >= 0: - if verbose: print 'Marker 1 ...' - for mod in todomodules: - g.write('extern void init' + \ - mod + '();\n') - if m2.search(line) >= 0: - if verbose: print 'Marker 2 ...' - for mod in todomodules: - g.write('{"' + mod + \ - '", init' + mod + '},\n') - g.close() - # - if not quiet: - if noexec: print 'Generating compilation commands ...' - else: print 'Starting compilation ...' - defs = ['-DNO_MAIN', '-DUSE_FROZEN', '-DPYTHONPATH=\'"."\''] - # - incs = ['-I.', '-I' + INCLINST] - if dict.has_key('stdwin'): - incs.append('-I' + j(STDWIN, 'H')) - # - srcs = [config, FMAIN] - # - if type(LIBP) == type(''): - libs.append(LIBP) - else: - for lib in LIBP: - libs.append(lib) - for item in libdeps: - m = item[0] - if m == '*' or dict.has_key(m): - for l in item[1:]: - if l in libs: libs.remove(l) - libs.append(l) - # - sts = 0 - # - cmd = CC + ' -c' - cmd = cmd + ' ' + string.join(defs) - cmd = cmd + ' ' + string.join(incs) - cmd = cmd + ' ' + string.join(srcs) - print cmd - # - if not noexec: - sts = os.system(cmd) - if sts: - print 'Exit status', sts, '-- turning on -n' - noexec = 1 - # - for s in srcs: - s = os.path.basename(s) - if s[-2:] == '.c': s = s[:-2] - o = s + '.o' - objs.insert(0, o) - # - cmd = CC - cmd = cmd + ' ' + string.join(objs) - cmd = cmd + ' ' + string.join(libs) - cmd = cmd + ' -o ' + ofile - print cmd - # - if not noexec: - sts = os.system(cmd) - if sts: - print 'Exit status', sts - else: - print 'Done.' - # - if not quiet and not noexec and sts == 0: - print 'Note: consider this:'; print '\tstrip', ofile - # - sys.exit(sts) - - -# Generate code for a given module -def makecode(filename): - if filename[-2:] == '.o': - return None - try: - f = open(filename, 'r') - except IOError: - return None - if verbose: print 'Making code from', filename, '...' - text = f.read() - code = compile(text, filename, 'exec') - f.close() - return marshal.dumps(code) - - -# Write the C source file containing the frozen Python code -def writefrozen(filename, dict): - f = open(filename, 'w') - codelist = [] - for mod in dict.keys(): - codestring = makecode(dict[mod]) - if codestring is not None: - codelist.append((mod, codestring)) - write = sys.stdout.write - save_stdout = sys.stdout - try: - sys.stdout = f - for mod, codestring in codelist: - if verbose: - write('Writing initializer for %s\n'%mod) - print 'static unsigned char M_' + mod + '[' + \ - str(len(codestring)) + '+1] = {' - for i in range(0, len(codestring), 16): - for c in codestring[i:i+16]: - print str(ord(c)) + ',', - print - print '};' - print 'struct frozen {' - print ' char *name;' - print ' unsigned char *code;' - print ' int size;' - print '} frozen_modules[] = {' - for mod, codestring in codelist: - print ' {"' + mod + '",', - print 'M_' + mod + ',', - print str(len(codestring)) + '},' - print ' {0, 0, 0} /* sentinel */' - print '};' - finally: - sys.stdout = save_stdout - f.close() - - -# Determine the names and filenames of the modules imported by the -# script, recursively. This is done by scanning for lines containing -# import statements. (The scanning has only superficial knowledge of -# Python syntax and no knowledge of semantics, so in theory the result -# may be incorrect -- however this is quite unlikely if you don't -# intentionally obscure your Python code.) - -# Compute the closure of scanfile() -- special first file because of script -def closure(todo): - done = {} - while todo: - newtodo = {} - for modname in todo.keys(): - if not done.has_key(modname): - filename = todo[modname] - if filename is None: - filename = findmodule(modname) - done[modname] = filename - if filename in ('<builtin>', '<unknown>'): - continue - modules = scanfile(filename) - for m in modules: - if not done.has_key(m): - newtodo[m] = None - todo = newtodo - return done - -# Scan a file looking for import statements -importstr = '\(^\|:\)[ \t]*import[ \t]+\([a-zA-Z0-9_, \t]+\)' -fromstr = '\(^\|:\)[ \t]*from[ \t]+\([a-zA-Z0-9_]+\)[ \t]+import[ \t]+' -isimport = regex.compile(importstr) -isfrom = regex.compile(fromstr) -def scanfile(filename): - allmodules = {} - try: - f = open(filename, 'r') - except IOError, msg: - raise NoSuchFile, filename - while 1: - line = f.readline() - if not line: break # EOF - while line[-2:] == '\\\n': # Continuation line - line = line[:-2] + ' ' - line = line + f.readline() - if isimport.search(line) >= 0: - rawmodules = isimport.group(2) - modules = string.splitfields(rawmodules, ',') - for i in range(len(modules)): - modules[i] = string.strip(modules[i]) - elif isfrom.search(line) >= 0: - modules = [isfrom.group(2)] - else: - continue - for mod in modules: - allmodules[mod] = None - f.close() - return allmodules.keys() - -# Find the file containing a module, given its name; None if not found -builtins = sys.builtin_module_names + ['sys'] -def findmodule(modname): - if modname in builtins: return '<builtin>' - for dirname in sys.path: - dlfullname = os.path.join(dirname, modname + 'module.o') - try: - f = open(dlfullname, 'r') - except IOError: - f = None - if f: - f.close() - return dlfullname - fullname = os.path.join(dirname, modname + '.py') - try: - f = open(fullname, 'r') - except IOError: - continue - f.close() - return fullname - if not quiet: - sys.stderr.write('Warning: module %s not found\n' % modname) - return '<unknown>' - - -# Call the main program -main() |