| #! /usr/local/bin/python |
| |
| # "Freeze" a Python script into a binary. |
| # Usage: see variable usage_msg below (before the imports!) |
| |
| # HINTS: |
| # - Edit the lines marked XXX below to localize. |
| # - You must have done "make inclinstall libainstall" in the Python |
| # build directory. |
| # - The script should not use dynamically loaded modules |
| # (*.so on most systems). |
| |
| |
| # Usage message |
| |
| usage_msg = """ |
| usage: freeze [-p prefix] [-e extension] ... script [module] ... |
| |
| -p prefix: This is the prefix used when you ran |
| 'Make inclinstall libainstall' in the Python build directory. |
| (If you never ran this, freeze won't work.) |
| The default is /usr/local. |
| |
| -e extension: A directory containing additional .o files that |
| may be used to resolve modules. This directory |
| should also have a Setup file describing the .o files. |
| More than one -e option may be given. |
| |
| script: The Python script to be executed by the resulting binary. |
| |
| module ...: Additional Python modules (referenced by pathname) |
| that will be included in the resulting binary. These |
| may be .py or .pyc files. |
| """ |
| |
| |
| # XXX Change the following line to point to your Tools/freeze directory |
| PACK = '/ufs/guido/src/python/Tools/freeze' |
| |
| # XXX Change the following line to point to your install prefix |
| PREFIX = '/usr/local' |
| |
| |
| # Import standard modules |
| |
| import cmp |
| import getopt |
| import os |
| import string |
| import sys |
| import addpack |
| |
| |
| # Set the directory to look for the freeze-private modules |
| |
| dir = os.path.dirname(sys.argv[0]) |
| if dir: |
| pack = dir |
| else: |
| pack = PACK |
| addpack.addpack(pack) |
| |
| |
| # Import the freeze-private modules |
| |
| import checkextensions |
| import findmodules |
| import makeconfig |
| import makefreeze |
| import makemakefile |
| import parsesetup |
| |
| |
| # Main program |
| |
| def main(): |
| # overridable context |
| prefix = PREFIX # settable with -p option |
| extensions = [] |
| path = sys.path |
| |
| # output files |
| frozen_c = 'frozen.c' |
| config_c = 'config.c' |
| target = 'a.out' # normally derived from script name |
| makefile = 'Makefile' |
| |
| # parse command line |
| try: |
| opts, args = getopt.getopt(sys.argv[1:], 'e:p:') |
| except getopt.error, msg: |
| usage('getopt error: ' + str(msg)) |
| |
| # proces option arguments |
| for o, a in opts: |
| if o == '-e': |
| extensions.append(a) |
| if o == '-p': |
| prefix = a |
| |
| # locations derived from options |
| binlib = os.path.join(prefix, 'lib/python/lib') |
| incldir = os.path.join(prefix, 'include/Py') |
| config_c_in = os.path.join(binlib, 'config.c.in') |
| frozenmain_c = os.path.join(binlib, 'frozenmain.c') |
| makefile_in = os.path.join(binlib, 'Makefile') |
| defines = ['-DHAVE_CONFIG_H', '-DUSE_FROZEN', '-DNO_MAIN', |
| '-DPYTHONPATH=\\"$(PYTHONPATH)\\"'] |
| includes = ['-I' + incldir, '-I' + binlib] |
| |
| # sanity check of directories and files |
| for dir in [prefix, binlib, incldir] + extensions: |
| if not os.path.exists(dir): |
| usage('needed directory %s not found' % dir) |
| if not os.path.isdir(dir): |
| usage('%s: not a directory' % dir) |
| for file in config_c_in, makefile_in, frozenmain_c: |
| if not os.path.exists(file): |
| usage('needed file %s not found' % file) |
| if not os.path.isfile(file): |
| usage('%s: not a plain file' % file) |
| for dir in extensions: |
| setup = os.path.join(dir, 'Setup') |
| if not os.path.exists(setup): |
| usage('needed file %s not found' % setup) |
| if not os.path.isfile(setup): |
| usage('%s: not a plain file' % setup) |
| |
| # check that enough arguments are passed |
| if not args: |
| usage('at least one filename argument required') |
| |
| # check that file arguments exist |
| for arg in args: |
| if not os.path.exists(arg): |
| usage('argument %s not found' % arg) |
| if not os.path.isfile(arg): |
| usage('%s: not a plain file' % arg) |
| |
| # process non-option arguments |
| scriptfile = args[0] |
| modules = args[1:] |
| |
| # derive target name from script name |
| base = os.path.basename(scriptfile) |
| base, ext = os.path.splitext(base) |
| if base: |
| if base != scriptfile: |
| target = base |
| else: |
| target = base + '.bin' |
| |
| # Actual work starts here... |
| |
| dict = findmodules.findmodules(scriptfile, modules, path) |
| |
| backup = frozen_c + '~' |
| try: |
| os.rename(frozen_c, backup) |
| except os.error: |
| backup = None |
| outfp = open(frozen_c, 'w') |
| try: |
| makefreeze.makefreeze(outfp, dict) |
| finally: |
| outfp.close() |
| if backup: |
| if cmp.cmp(backup, frozen_c): |
| sys.stderr.write('%s not changed, not written\n' % |
| frozen_c) |
| os.rename(backup, frozen_c) |
| |
| builtins = [] |
| unknown = [] |
| mods = dict.keys() |
| mods.sort() |
| for mod in mods: |
| if dict[mod] == '<builtin>': |
| builtins.append(mod) |
| elif dict[mod] == '<unknown>': |
| unknown.append(mod) |
| |
| addfiles = [] |
| if unknown: |
| addfiles, addmods = \ |
| checkextensions.checkextensions(unknown, extensions) |
| for mod in addmods: |
| unknown.remove(mod) |
| builtins = builtins + addmods |
| if unknown: |
| sys.stderr.write('Warning: unknown modules remain: %s\n' % |
| string.join(unknown)) |
| |
| builtins.sort() |
| infp = open(config_c_in) |
| backup = config_c + '~' |
| try: |
| os.rename(config_c, backup) |
| except os.error: |
| backup = None |
| outfp = open(config_c, 'w') |
| try: |
| makeconfig.makeconfig(infp, outfp, builtins) |
| finally: |
| outfp.close() |
| infp.close() |
| if backup: |
| if cmp.cmp(backup, config_c): |
| sys.stderr.write('%s not changed, not written\n' % |
| config_c) |
| os.rename(backup, config_c) |
| |
| cflags = defines + includes + ['$(OPT)'] |
| libs = [] |
| for n in 'Modules', 'Python', 'Objects', 'Parser': |
| n = 'lib%s.a' % n |
| n = os.path.join(binlib, n) |
| libs.append(n) |
| |
| makevars = parsesetup.getmakevars(makefile_in) |
| somevars = {} |
| for key in makevars.keys(): |
| somevars[key] = makevars[key] |
| |
| somevars['CFLAGS'] = string.join(cflags) # override |
| files = ['$(OPT)', config_c, frozen_c, frozenmain_c] + \ |
| addfiles + libs + \ |
| ['$(MODLIBS)', '$(LIBS)', '$(SYSLIBS)'] |
| |
| outfp = open(makefile, 'w') |
| try: |
| makemakefile.makemakefile(outfp, somevars, files, target) |
| finally: |
| outfp.close() |
| |
| # Done! |
| |
| print 'Now run make to build the target:', target |
| |
| |
| # Print usage message and exit |
| |
| def usage(msg = None): |
| if msg: |
| sys.stderr.write(str(msg) + '\n') |
| sys.stderr.write(usage_msg) |
| sys.exit(2) |
| |
| |
| main() |