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