home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C / Applications / Python 1.3 / source code / Tools / freeze / nfreeze.py < prev    next >
Encoding:
Python Source  |  1995-12-17  |  7.7 KB  |  313 lines  |  [TEXT/R*ch]

  1. #! /usr/local/bin/python
  2.  
  3. # "Freeze" a Python script into a binary.
  4. # Usage: see variable usage_msg below (before the imports!)
  5.  
  6. # This version builds the frozen binary in a temporary directory;
  7. # courtesy Jaap Vermeulen.  Use the -l option to get the functionality
  8. # of the standard version.
  9.  
  10. # HINTS:
  11. # - Edit the lines marked XXX below to localize.
  12. # - You must have done "make inclinstall libainstall" in the Python
  13. #   build directory.
  14. # - The script should not use dynamically loaded modules
  15. #   (*.so on most systems).
  16.  
  17.  
  18. # Usage message
  19.  
  20. usage_msg = """
  21. usage: freeze [-p prefix] [-e extension] [-l] ... script [module] ...
  22.  
  23. -p prefix:    This is the prefix used when you ran
  24.               'Make inclinstall libainstall' in the Python build directory.
  25.               (If you never ran this, freeze won't work.)
  26.               The default is /usr/local.
  27.  
  28. -e extension: A directory containing additional .o files that
  29.               may be used to resolve modules.  This directory
  30.               should also have a Setup file describing the .o files.
  31.               More than one -e option may be given.
  32.  
  33. -l:           Local compilation. Instead of using a temporary directory
  34.               that is removed after succesful compilation, the current
  35.               directory is used and temporary files are not removed.
  36.  
  37. script:       The Python script to be executed by the resulting binary.
  38.  
  39. module ...:   Additional Python modules (referenced by pathname)
  40.               that will be included in the resulting binary.  These
  41.               may be .py or .pyc files.
  42. """
  43.  
  44.  
  45. # XXX Change the following line to point to your Tools/freeze directory
  46. PACK = '/ufs/guido/src/python/Tools/freeze'
  47.  
  48. # XXX Change the following line to point to your install prefix
  49. PREFIX = '/usr/local'
  50.  
  51. # XXX Change the following line to point to your favority temporary  directory
  52. TMPDIR = '/usr/tmp'
  53.  
  54.  
  55. # Import standard modules
  56.  
  57. import cmp
  58. import getopt
  59. import os
  60. import string
  61. import sys
  62. import addpack
  63.  
  64.  
  65. # Set the directory to look for the freeze-private modules
  66.  
  67. dir = os.path.dirname(sys.argv[0])
  68. if dir:
  69.     pack = dir
  70. else:
  71.     pack = PACK
  72. addpack.addpack(pack)
  73.  
  74.  
  75. # Establish temporary directory name
  76.  
  77. tmpdir = os.path.join(TMPDIR, 'freeze.' + `os.getpid()`)
  78.  
  79.  
  80. # Import the freeze-private modules
  81.  
  82. import checkextensions
  83. import findmodules
  84. import makeconfig
  85. import makefreeze
  86. import makemakefile
  87. import parsesetup
  88.  
  89.  
  90. # Main program
  91.  
  92. def main():
  93.     # module variable
  94.     global tmpdir
  95.  
  96.     # overridable context
  97.     prefix = PREFIX            # settable with -p option
  98.     extensions = []
  99.     path = sys.path
  100.  
  101.     # output files
  102.     frozen_c = 'frozen.c'
  103.     config_c = 'config.c'
  104.     target = 'a.out'        # normally derived from script name
  105.     makefile = 'Makefile'
  106.  
  107.     # parse command line
  108.     try:
  109.         opts, args = getopt.getopt(sys.argv[1:], 'e:p:l')
  110.     except getopt.error, msg:
  111.         usage('getopt error: ' + str(msg))
  112.  
  113.     # proces option arguments
  114.     for o, a in opts:
  115.         if o == '-e':
  116.             extensions.append(a)
  117.         if o == '-l':
  118.             tmpdir = None
  119.         if o == '-p':
  120.             prefix = a
  121.  
  122.     # locations derived from options
  123.     binlib = os.path.join(prefix, 'lib/python/lib')
  124.     incldir = os.path.join(prefix, 'include/Py')
  125.     config_c_in = os.path.join(binlib, 'config.c.in')
  126.     frozenmain_c = os.path.join(binlib, 'frozenmain.c')
  127.     makefile_in = os.path.join(binlib, 'Makefile')
  128.     defines = ['-DHAVE_CONFIG_H', '-DUSE_FROZEN', '-DNO_MAIN',
  129.            '-DPYTHONPATH=\\"$(PYTHONPATH)\\"']
  130.     includes = ['-I' + incldir, '-I' + binlib]
  131.  
  132.     # sanity check of directories and files
  133.     for dir in [prefix, binlib, incldir] + extensions:
  134.         if not os.path.exists(dir):
  135.             usage('needed directory %s not found' % dir)
  136.         if not os.path.isdir(dir):
  137.             usage('%s: not a directory' % dir)
  138.     for file in config_c_in, makefile_in, frozenmain_c:
  139.         if not os.path.exists(file):
  140.             usage('needed file %s not found' % file)
  141.         if not os.path.isfile(file):
  142.             usage('%s: not a plain file' % file)
  143.     for dir in extensions:
  144.         setup = os.path.join(dir, 'Setup')
  145.         if not os.path.exists(setup):
  146.             usage('needed file %s not found' % setup)
  147.         if not os.path.isfile(setup):
  148.             usage('%s: not a plain file' % setup)
  149.  
  150.     # check that enough arguments are passed
  151.     if not args:
  152.         usage('at least one filename argument required')
  153.  
  154.     # check that file arguments exist
  155.     for arg in args:
  156.         if not os.path.exists(arg):
  157.             usage('argument %s not found' % arg)
  158.         if not os.path.isfile(arg):
  159.             usage('%s: not a plain file' % arg)
  160.  
  161.     # process non-option arguments
  162.     scriptfile = args[0]
  163.     modules = args[1:]
  164.  
  165.     # derive target name from script name
  166.     base = os.path.basename(scriptfile)
  167.     base, ext = os.path.splitext(base)
  168.     if base:
  169.         if base != scriptfile:
  170.             target = base
  171.         else:
  172.             target = base + '.bin'
  173.  
  174.     # use temporary directory
  175.     if tmpdir:
  176.         try: os.mkdir(tmpdir, 0700)
  177.         except os.error, errmsg:
  178.             sys.stderr.write('mkdir: (%s) %s\n' % errmsg)
  179.             sys.stderr.write('Error: cannot create temporary directory: %s\n' % (tmpdir,))
  180.             sys.exit(2)
  181.         frozen_c = os.path.join(tmpdir, frozen_c)
  182.         config_c = os.path.join(tmpdir, config_c)
  183.         makefile = os.path.join(tmpdir, makefile)
  184.  
  185.     dict = findmodules.findmodules(scriptfile, modules, path)
  186.  
  187.     # Actual work starts here...
  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)', config_c, frozen_c, frozenmain_c] + \
  259.         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, target)
  270.     finally:
  271.         outfp.close()
  272.     if backup:
  273.         if not cmp.cmp(backup, makefile):
  274.             print 'previous Makefile saved as', backup
  275.  
  276.     # Done!
  277.  
  278.     if tmpdir:
  279.         # Run make
  280.         curdir = os.getcwd()
  281.         os.chdir(tmpdir)
  282.         status = os.system('make > /dev/null')
  283.         os.chdir(curdir)
  284.  
  285.         if status:
  286.             sys.stderr.write('Compilation failed. Files left in %s\n' % 
  287.      (tmpdir,))
  288.         else:
  289.             tmptarget = os.path.join(tmpdir, target)
  290.             try: os.rename(tmptarget, target)
  291.             except os.error:
  292.                 os.system('cp %s %s' % (tmptarget, target))
  293.             os.system('rm -rf %s' % (tmpdir,))
  294.             print 'Frozen target:', target
  295.         tmpdir = None
  296.     else:
  297.         print 'Now run make to build the target:', target
  298.  
  299.  
  300. # Print usage message and exit
  301.  
  302. def usage(msg = None):
  303.     if msg:
  304.         sys.stderr.write(str(msg) + '\n')
  305.     sys.stderr.write(usage_msg)
  306.     sys.exit(2)
  307.  
  308.  
  309. try: main()
  310. finally:
  311.     if tmpdir:
  312.         os.system('rm -rf %s' % (tmpdir,))
  313.