home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / OPENSTEP / Languages / Python / python-14-src / Tools / freeze / freeze.py < prev    next >
Encoding:
Python Source  |  1997-01-17  |  7.4 KB  |  300 lines

  1. #! /usr/local/bin/python
  2.  
  3. """Freeze a Python script into a binary.
  4.  
  5. usage: freeze [options...] script.py [module]...
  6.  
  7. Options:
  8.  
  9. -p prefix:    This is the prefix used when you ran ``name install''
  10.               in the Python build directory.
  11.               (If you never ran this, freeze won't work.)
  12.               The default is whatever sys.prefix evaluates to.
  13.  
  14. -P exec_prefix: Like -p but this is the 'exec_prefix', used to
  15.         install objects etc.  The default is whatever sys.exec_prefix
  16.         evaluates to, or the -p argument if given.
  17.  
  18. -e extension: A directory containing additional .o files that
  19.               may be used to resolve modules.  This directory
  20.               should also have a Setup file describing the .o files.
  21.               More than one -e option may be given.
  22.  
  23. -o dir:       Directory where the output files are created; default '.'.
  24.  
  25. Arguments:
  26.  
  27. script.py:    The Python script to be executed by the resulting binary.
  28.           It *must* end with a .py suffix!
  29.  
  30. module ...:   Additional Python modules (referenced by pathname)
  31.               that will be included in the resulting binary.  These
  32.               may be .py or .pyc files.
  33.  
  34. NOTES:
  35.  
  36. In order to use freeze successfully, you must have built Python and
  37. installed it ("make install").
  38.  
  39. The script should not use modules provided only as shared libraries;
  40. if it does, the resulting binary is not self-contained.
  41. """
  42.  
  43.  
  44. # Import standard modules
  45.  
  46. import cmp
  47. import getopt
  48. import os
  49. import string
  50. import sys
  51. import addpack
  52.  
  53.  
  54. # Import the freeze-private modules
  55.  
  56. import checkextensions
  57. import findmodules
  58. import makeconfig
  59. import makefreeze
  60. import makemakefile
  61. import parsesetup
  62.  
  63.  
  64. # Main program
  65.  
  66. def main():
  67.     # overridable context
  68.     prefix = None            # settable with -p option
  69.     exec_prefix = None        # settable with -P option
  70.     extensions = []
  71.     path = sys.path
  72.     odir = ''
  73.  
  74.     # output files
  75.     frozen_c = 'frozen.c'
  76.     config_c = 'config.c'
  77.     target = 'a.out'        # normally derived from script name
  78.     makefile = 'Makefile'
  79.  
  80.     # parse command line
  81.     try:
  82.         opts, args = getopt.getopt(sys.argv[1:], 'e:o:p:P:')
  83.     except getopt.error, msg:
  84.         usage('getopt error: ' + str(msg))
  85.  
  86.     # proces option arguments
  87.     for o, a in opts:
  88.         if o == '-e':
  89.             extensions.append(a)
  90.         if o == '-o':
  91.             odir = a
  92.         if o == '-p':
  93.             prefix = a
  94.         if o == '-P':
  95.             exec_prefix = a
  96.     
  97.     # default prefix and exec_prefix
  98.     if not exec_prefix:
  99.         if prefix:
  100.             exec_prefix = prefix
  101.         else:
  102.             exec_prefix = sys.exec_prefix
  103.     if not prefix:
  104.         prefix = sys.prefix
  105.  
  106.     # locations derived from options
  107.     version = sys.version[:3]
  108.     binlib = os.path.join(exec_prefix, 'lib/python%s/config' % version)
  109.     incldir = os.path.join(prefix, 'include/python%s' % version)
  110.     config_c_in = os.path.join(binlib, 'config.c.in')
  111.     frozenmain_c = os.path.join(binlib, 'frozenmain.c')
  112.     getpath_c = os.path.join(binlib, 'getpath.c')
  113.     supp_sources = [frozenmain_c, getpath_c]
  114.     makefile_in = os.path.join(binlib, 'Makefile')
  115.     defines = ['-DPYTHONPATH=\\"$(PYTHONPATH)\\"']
  116.     includes = ['-I' + incldir, '-I' + binlib]
  117.  
  118.     # sanity check of directories and files
  119.     for dir in [prefix, exec_prefix, binlib, incldir] + extensions:
  120.         if not os.path.exists(dir):
  121.             usage('needed directory %s not found' % dir)
  122.         if not os.path.isdir(dir):
  123.             usage('%s: not a directory' % dir)
  124.     for file in [config_c_in, makefile_in] + supp_sources:
  125.         if not os.path.exists(file):
  126.             usage('needed file %s not found' % file)
  127.         if not os.path.isfile(file):
  128.             usage('%s: not a plain file' % file)
  129.     for dir in extensions:
  130.         setup = os.path.join(dir, 'Setup')
  131.         if not os.path.exists(setup):
  132.             usage('needed file %s not found' % setup)
  133.         if not os.path.isfile(setup):
  134.             usage('%s: not a plain file' % setup)
  135.  
  136.     # check that enough arguments are passed
  137.     if not args:
  138.         usage('at least one filename argument required')
  139.  
  140.     # check that the script name ends in ".py"
  141.     if args[0][-3:] != ".py":
  142.         usage('the script name must have a .py suffix')
  143.  
  144.     # check that file arguments exist
  145.     for arg in args:
  146.         if not os.path.exists(arg):
  147.             usage('argument %s not found' % arg)
  148.         if not os.path.isfile(arg):
  149.             usage('%s: not a plain file' % arg)
  150.  
  151.     # process non-option arguments
  152.     scriptfile = args[0]
  153.     modules = args[1:]
  154.  
  155.     # derive target name from script name
  156.     base = os.path.basename(scriptfile)
  157.     base, ext = os.path.splitext(base)
  158.     if base:
  159.         if base != scriptfile:
  160.             target = base
  161.         else:
  162.             target = base + '.bin'
  163.     
  164.     # handle -o option
  165.     base_frozen_c = frozen_c
  166.     base_config_c = config_c
  167.     base_target = target
  168.     if odir and not os.path.isdir(odir):
  169.         try:
  170.             os.mkdir(odir)
  171.             print "Created output directory", odir
  172.         except os.error, msg:
  173.             usage('%s: mkdir failed (%s)' % (odir, str(msg)))
  174.     if odir:
  175.         frozen_c = os.path.join(odir, frozen_c)
  176.         config_c = os.path.join(odir, config_c)
  177.         target = os.path.join(odir, target)
  178.         makefile = os.path.join(odir,makefile)
  179.  
  180.     # Actual work starts here...
  181.  
  182.     dict = findmodules.findmodules(scriptfile, modules, path)
  183.     names = dict.keys()
  184.     names.sort()
  185.     print "Modules being frozen:"
  186.     for name in names:
  187.         print '\t', name
  188.  
  189.     backup = frozen_c + '~'
  190.     try:
  191.         os.rename(frozen_c, backup)
  192.     except os.error:
  193.         backup = None
  194.     outfp = open(frozen_c, 'w')
  195.     try:
  196.         makefreeze.makefreeze(outfp, dict)
  197.     finally:
  198.         outfp.close()
  199.     if backup:
  200.         if cmp.cmp(backup, frozen_c):
  201.             sys.stderr.write('%s not changed, not written\n' %
  202.                      frozen_c)
  203.             os.rename(backup, frozen_c)
  204.  
  205.     builtins = []
  206.     unknown = []
  207.     mods = dict.keys()
  208.     mods.sort()
  209.     for mod in mods:
  210.         if dict[mod] == '<builtin>':
  211.             builtins.append(mod)
  212.         elif dict[mod] == '<unknown>':
  213.             unknown.append(mod)
  214.  
  215.     addfiles = []
  216.     if unknown:
  217.         addfiles, addmods = \
  218.               checkextensions.checkextensions(unknown, extensions)
  219.         for mod in addmods:
  220.             unknown.remove(mod)
  221.         builtins = builtins + addmods
  222.     if unknown:
  223.         sys.stderr.write('Warning: unknown modules remain: %s\n' %
  224.                  string.join(unknown))
  225.  
  226.     builtins.sort()
  227.     infp = open(config_c_in)
  228.     backup = config_c + '~'
  229.     try:
  230.         os.rename(config_c, backup)
  231.     except os.error:
  232.         backup = None
  233.     outfp = open(config_c, 'w')
  234.     try:
  235.         makeconfig.makeconfig(infp, outfp, builtins)
  236.     finally:
  237.         outfp.close()
  238.     infp.close()
  239.     if backup:
  240.         if cmp.cmp(backup, config_c):
  241.             sys.stderr.write('%s not changed, not written\n' %
  242.                      config_c)
  243.             os.rename(backup, config_c)
  244.  
  245.     cflags = defines + includes + ['$(OPT)']
  246.     libs = []
  247.     for n in 'Modules', 'Python', 'Objects', 'Parser':
  248.         n = 'lib%s.a' % n
  249.         n = os.path.join(binlib, n)
  250.         libs.append(n)
  251.  
  252.     makevars = parsesetup.getmakevars(makefile_in)
  253.     somevars = {}
  254.     for key in makevars.keys():
  255.         somevars[key] = makevars[key]
  256.  
  257.     somevars['CFLAGS'] = string.join(cflags) # override
  258.     files = ['$(OPT)', '$(LDFLAGS)', base_config_c, base_frozen_c] + \
  259.         supp_sources +  addfiles + libs + \
  260.         ['$(MODLIBS)', '$(LIBS)', '$(SYSLIBS)']
  261.  
  262.     backup = makefile + '~'
  263.     try:
  264.         os.rename(makefile, backup)
  265.     except os.error:
  266.         backup = None
  267.     outfp = open(makefile, 'w')
  268.     try:
  269.         makemakefile.makemakefile(outfp, somevars, files, base_target)
  270.     finally:
  271.         outfp.close()
  272.     if backup:
  273.         if not cmp.cmp(backup, makefile):
  274.             print 'previous Makefile saved as', backup
  275.         else:
  276.             sys.stderr.write('%s not changed, not written\n' %
  277.                      makefile)
  278.             os.rename(backup, makefile)
  279.  
  280.     # Done!
  281.  
  282.     if odir:
  283.         print 'Now run make in', odir,
  284.         print 'to build the target:', base_target
  285.     else:
  286.         print 'Now run make to build the target:', base_target
  287.  
  288.  
  289. # Print usage message and exit
  290.  
  291. def usage(msg = None):
  292.     sys.stderr.write(__doc__)
  293.     # Put the error last since the usage message scrolls off the screen
  294.     if msg:
  295.         sys.stderr.write('\nError: ' + str(msg) + '\n')
  296.     sys.exit(2)
  297.  
  298.  
  299. main()
  300.