Deleting merge zombie.
This commit is contained in:
parent
0d00254cc1
commit
1b776a2745
|
@ -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()
|
Loading…
Reference in New Issue