blob: b584ec598ffa49237d5a26c0a945a0d1c5bd717a [file] [log] [blame]
Guido van Rossumf06ee5f1996-11-27 19:52:01 +00001#! /usr/bin/env python
Guido van Rossumdbaf3321994-10-03 10:25:54 +00002
Guido van Rossum96c4dd91996-08-26 05:14:20 +00003"""Freeze a Python script into a binary.
Guido van Rossumdbaf3321994-10-03 10:25:54 +00004
Guido van Rossum96c4dd91996-08-26 05:14:20 +00005usage: freeze [options...] script.py [module]...
Guido van Rossum00ff4331994-10-03 16:33:08 +00006
Guido van Rossum96c4dd91996-08-26 05:14:20 +00007Options:
Guido van Rossum00ff4331994-10-03 16:33:08 +00008
Guido van Rossum9a6e8551997-08-10 16:47:17 +00009-p prefix: This is the prefix used when you ran ``make install''
Guido van Rossum96c4dd91996-08-26 05:14:20 +000010 in the Python build directory.
Guido van Rossumd8336c21994-10-05 16:13:01 +000011 (If you never ran this, freeze won't work.)
Guido van Rossum96c4dd91996-08-26 05:14:20 +000012 The default is whatever sys.prefix evaluates to.
Guido van Rossum0b4b8a21997-08-10 16:56:48 +000013 It can also be the top directory of the Python source
14 tree; then -P must point to the build tree.
Guido van Rossumd8336c21994-10-05 16:13:01 +000015
Guido van Rossum150316e1995-08-08 14:21:07 +000016-P exec_prefix: Like -p but this is the 'exec_prefix', used to
Guido van Rossum0b4b8a21997-08-10 16:56:48 +000017 install objects etc. The default is whatever sys.exec_prefix
18 evaluates to, or the -p argument if given.
19 If -p points to the Python source tree, -P must point
20 to the build tree, if different.
Guido van Rossum150316e1995-08-08 14:21:07 +000021
Guido van Rossumd8336c21994-10-05 16:13:01 +000022-e extension: A directory containing additional .o files that
23 may be used to resolve modules. This directory
24 should also have a Setup file describing the .o files.
25 More than one -e option may be given.
26
Guido van Rossum96c4dd91996-08-26 05:14:20 +000027-o dir: Directory where the output files are created; default '.'.
28
Guido van Rossum9a6e8551997-08-10 16:47:17 +000029-h: Print this help message.
30
Guido van Rossum58a59481997-08-14 01:45:33 +000031-w: Toggle Windows (NT or 95) behavior.
32 (For debugging only -- on a win32 platform, win32 behaviour
33 is automatic.)
34
35-s subsystem: Specify the subsystem; 'windows' or 'console' (default).
36 (For Windows only.)
37
Guido van Rossum96c4dd91996-08-26 05:14:20 +000038Arguments:
39
Guido van Rossumd4cc04c1996-06-17 17:49:13 +000040script.py: The Python script to be executed by the resulting binary.
Guido van Rossum0b4b8a21997-08-10 16:56:48 +000041 It *must* end with a .py suffix!
Guido van Rossumd8336c21994-10-05 16:13:01 +000042
43module ...: Additional Python modules (referenced by pathname)
44 that will be included in the resulting binary. These
45 may be .py or .pyc files.
Guido van Rossum150316e1995-08-08 14:21:07 +000046
47NOTES:
48
49In order to use freeze successfully, you must have built Python and
Guido van Rossumd4cc04c1996-06-17 17:49:13 +000050installed it ("make install").
Guido van Rossum150316e1995-08-08 14:21:07 +000051
Guido van Rossum96c4dd91996-08-26 05:14:20 +000052The script should not use modules provided only as shared libraries;
53if it does, the resulting binary is not self-contained.
Guido van Rossumd8336c21994-10-05 16:13:01 +000054"""
Guido van Rossum00ff4331994-10-03 16:33:08 +000055
56
Guido van Rossum00ff4331994-10-03 16:33:08 +000057# Import standard modules
58
Guido van Rossumd8336c21994-10-05 16:13:01 +000059import cmp
Guido van Rossumdbaf3321994-10-03 10:25:54 +000060import getopt
Guido van Rossum00ff4331994-10-03 16:33:08 +000061import os
Guido van Rossumdbaf3321994-10-03 10:25:54 +000062import string
Guido van Rossum00ff4331994-10-03 16:33:08 +000063import sys
64import addpack
Guido van Rossumdbaf3321994-10-03 10:25:54 +000065
Guido van Rossumdbaf3321994-10-03 10:25:54 +000066
Guido van Rossum00ff4331994-10-03 16:33:08 +000067# Import the freeze-private modules
68
Guido van Rossumd8336c21994-10-05 16:13:01 +000069import checkextensions
Guido van Rossum00ff4331994-10-03 16:33:08 +000070import findmodules
71import makeconfig
72import makefreeze
73import makemakefile
74import parsesetup
75
Guido van Rossum00ff4331994-10-03 16:33:08 +000076
77# Main program
78
Guido van Rossumdbaf3321994-10-03 10:25:54 +000079def main():
Guido van Rossum0b4b8a21997-08-10 16:56:48 +000080 # overridable context
81 prefix = None # settable with -p option
82 exec_prefix = None # settable with -P option
83 extensions = []
84 path = sys.path
85 odir = ''
Guido van Rossum58a59481997-08-14 01:45:33 +000086 win = sys.platform[:3] == 'win'
Guido van Rossum00ff4331994-10-03 16:33:08 +000087
Guido van Rossum94ce0d11997-12-08 05:01:06 +000088 # modules that are imported by the Python runtime
89 implicits = ["site", "exceptions"]
90
Guido van Rossum0b4b8a21997-08-10 16:56:48 +000091 # output files
92 frozen_c = 'frozen.c'
93 config_c = 'config.c'
94 target = 'a.out' # normally derived from script name
95 makefile = 'Makefile'
Guido van Rossum58a59481997-08-14 01:45:33 +000096 subsystem = 'console'
Guido van Rossum00ff4331994-10-03 16:33:08 +000097
Guido van Rossum0b4b8a21997-08-10 16:56:48 +000098 # parse command line
99 try:
Guido van Rossum58a59481997-08-14 01:45:33 +0000100 opts, args = getopt.getopt(sys.argv[1:], 'he:o:p:P:s:w')
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000101 except getopt.error, msg:
102 usage('getopt error: ' + str(msg))
Guido van Rossum00ff4331994-10-03 16:33:08 +0000103
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000104 # proces option arguments
105 for o, a in opts:
106 if o == '-h':
107 print __doc__
108 return
109 if o == '-e':
110 extensions.append(a)
111 if o == '-o':
112 odir = a
113 if o == '-p':
114 prefix = a
115 if o == '-P':
116 exec_prefix = a
Guido van Rossum58a59481997-08-14 01:45:33 +0000117 if o == '-w':
118 win = not win
119 if o == '-s':
120 if not win:
121 usage("-s subsystem option only on Windows")
122 subsystem = a
Guido van Rossumdbaf3321994-10-03 10:25:54 +0000123
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000124 # default prefix and exec_prefix
125 if not exec_prefix:
126 if prefix:
127 exec_prefix = prefix
128 else:
129 exec_prefix = sys.exec_prefix
130 if not prefix:
131 prefix = sys.prefix
Guido van Rossum9a6e8551997-08-10 16:47:17 +0000132
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000133 # determine whether -p points to the Python source tree
134 ishome = os.path.exists(os.path.join(prefix, 'Include', 'pythonrun.h'))
Guido van Rossumdbaf3321994-10-03 10:25:54 +0000135
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000136 # locations derived from options
137 version = sys.version[:3]
138 if ishome:
139 print "(Using Python source directory)"
140 binlib = exec_prefix
141 incldir = os.path.join(prefix, 'Include')
142 config_c_in = os.path.join(prefix, 'Modules', 'config.c.in')
Guido van Rossum58a59481997-08-14 01:45:33 +0000143 frozenmain_c = os.path.join(prefix, 'Python', 'frozenmain.c')
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000144 makefile_in = os.path.join(exec_prefix, 'Modules', 'Makefile')
145 else:
146 binlib = os.path.join(exec_prefix,
147 'lib', 'python%s' % version, 'config')
148 incldir = os.path.join(prefix, 'include', 'python%s' % version)
149 config_c_in = os.path.join(binlib, 'config.c.in')
150 frozenmain_c = os.path.join(binlib, 'frozenmain.c')
151 makefile_in = os.path.join(binlib, 'Makefile')
152 supp_sources = []
153 defines = []
154 includes = ['-I' + incldir, '-I' + binlib]
Guido van Rossumd8336c21994-10-05 16:13:01 +0000155
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000156 # sanity check of directories and files
157 for dir in [prefix, exec_prefix, binlib, incldir] + extensions:
158 if not os.path.exists(dir):
159 usage('needed directory %s not found' % dir)
160 if not os.path.isdir(dir):
161 usage('%s: not a directory' % dir)
Guido van Rossum58a59481997-08-14 01:45:33 +0000162 if win:
163 files = supp_sources
164 else:
165 files = [config_c_in, makefile_in] + supp_sources
166 for file in supp_sources:
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000167 if not os.path.exists(file):
168 usage('needed file %s not found' % file)
169 if not os.path.isfile(file):
170 usage('%s: not a plain file' % file)
Guido van Rossum58a59481997-08-14 01:45:33 +0000171 if not win:
172 for dir in extensions:
173 setup = os.path.join(dir, 'Setup')
174 if not os.path.exists(setup):
175 usage('needed file %s not found' % setup)
176 if not os.path.isfile(setup):
177 usage('%s: not a plain file' % setup)
Guido van Rossum00ff4331994-10-03 16:33:08 +0000178
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000179 # check that enough arguments are passed
180 if not args:
181 usage('at least one filename argument required')
Guido van Rossumd4cc04c1996-06-17 17:49:13 +0000182
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000183 # check that the script name ends in ".py"
184 if args[0][-3:] != ".py":
185 usage('the script name must have a .py suffix')
Guido van Rossum00ff4331994-10-03 16:33:08 +0000186
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000187 # check that file arguments exist
188 for arg in args:
189 if not os.path.exists(arg):
190 usage('argument %s not found' % arg)
191 if not os.path.isfile(arg):
192 usage('%s: not a plain file' % arg)
Guido van Rossum00ff4331994-10-03 16:33:08 +0000193
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000194 # process non-option arguments
195 scriptfile = args[0]
196 modules = args[1:]
Guido van Rossum00ff4331994-10-03 16:33:08 +0000197
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000198 # derive target name from script name
199 base = os.path.basename(scriptfile)
200 base, ext = os.path.splitext(base)
201 if base:
202 if base != scriptfile:
203 target = base
204 else:
205 target = base + '.bin'
Guido van Rossum00ff4331994-10-03 16:33:08 +0000206
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000207 # handle -o option
208 base_frozen_c = frozen_c
209 base_config_c = config_c
210 base_target = target
211 if odir and not os.path.isdir(odir):
212 try:
213 os.mkdir(odir)
214 print "Created output directory", odir
215 except os.error, msg:
216 usage('%s: mkdir failed (%s)' % (odir, str(msg)))
217 if odir:
218 frozen_c = os.path.join(odir, frozen_c)
219 config_c = os.path.join(odir, config_c)
220 target = os.path.join(odir, target)
221 makefile = os.path.join(odir, makefile)
Guido van Rossum00ff4331994-10-03 16:33:08 +0000222
Guido van Rossum94ce0d11997-12-08 05:01:06 +0000223 for mod in implicits:
224 modules.append(findmodules.findmodule(mod))
225
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000226 # Actual work starts here...
Guido van Rossumd8336c21994-10-05 16:13:01 +0000227
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000228 dict = findmodules.findmodules(scriptfile, modules, path)
229 names = dict.keys()
230 names.sort()
231 print "Modules being frozen:"
232 for name in names:
233 print '\t', name
Guido van Rossumdbaf3321994-10-03 10:25:54 +0000234
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000235 backup = frozen_c + '~'
236 try:
237 os.rename(frozen_c, backup)
238 except os.error:
239 backup = None
240 outfp = open(frozen_c, 'w')
241 try:
242 makefreeze.makefreeze(outfp, dict)
243 finally:
244 outfp.close()
245 if backup:
246 if cmp.cmp(backup, frozen_c):
247 sys.stderr.write('%s not changed, not written\n' %
248 frozen_c)
249 os.rename(backup, frozen_c)
Guido van Rossumdbaf3321994-10-03 10:25:54 +0000250
Guido van Rossum58a59481997-08-14 01:45:33 +0000251 if win:
252 # Taking a shortcut here...
253 import winmakemakefile
254 outfp = open(makefile, 'w')
255 try:
256 winmakemakefile.makemakefile(outfp,
257 locals(),
258 [frozenmain_c, frozen_c],
259 target)
260 finally:
261 outfp.close()
262 return
263
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000264 builtins = []
265 unknown = []
266 mods = dict.keys()
267 mods.sort()
268 for mod in mods:
269 if dict[mod] == '<builtin>':
270 builtins.append(mod)
271 elif dict[mod] == '<unknown>':
272 unknown.append(mod)
Guido van Rossumdbaf3321994-10-03 10:25:54 +0000273
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000274 addfiles = []
275 if unknown:
276 addfiles, addmods = \
277 checkextensions.checkextensions(unknown, extensions)
278 for mod in addmods:
279 unknown.remove(mod)
280 builtins = builtins + addmods
281 if unknown:
282 sys.stderr.write('Warning: unknown modules remain: %s\n' %
283 string.join(unknown))
Guido van Rossumdbaf3321994-10-03 10:25:54 +0000284
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000285 builtins.sort()
286 infp = open(config_c_in)
287 backup = config_c + '~'
288 try:
289 os.rename(config_c, backup)
290 except os.error:
291 backup = None
292 outfp = open(config_c, 'w')
293 try:
294 makeconfig.makeconfig(infp, outfp, builtins)
295 finally:
296 outfp.close()
297 infp.close()
298 if backup:
299 if cmp.cmp(backup, config_c):
300 sys.stderr.write('%s not changed, not written\n' %
301 config_c)
302 os.rename(backup, config_c)
Guido van Rossumdbaf3321994-10-03 10:25:54 +0000303
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000304 cflags = defines + includes + ['$(OPT)']
305 libs = [os.path.join(binlib, 'libpython$(VERSION).a')]
Guido van Rossum00ff4331994-10-03 16:33:08 +0000306
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000307 somevars = {}
Guido van Rossum345df171997-11-22 22:10:01 +0000308 if os.path.exists(makefile_in):
309 makevars = parsesetup.getmakevars(makefile_in)
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000310 for key in makevars.keys():
311 somevars[key] = makevars[key]
Guido van Rossum00ff4331994-10-03 16:33:08 +0000312
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000313 somevars['CFLAGS'] = string.join(cflags) # override
314 files = ['$(OPT)', '$(LDFLAGS)', base_config_c, base_frozen_c] + \
315 supp_sources + addfiles + libs + \
316 ['$(MODLIBS)', '$(LIBS)', '$(SYSLIBS)']
Guido van Rossum00ff4331994-10-03 16:33:08 +0000317
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000318 backup = makefile + '~'
319 try:
320 os.rename(makefile, backup)
321 except os.error:
322 backup = None
323 outfp = open(makefile, 'w')
324 try:
325 makemakefile.makemakefile(outfp, somevars, files, base_target)
326 finally:
327 outfp.close()
328 if backup:
329 if not cmp.cmp(backup, makefile):
330 print 'previous Makefile saved as', backup
331 else:
332 sys.stderr.write('%s not changed, not written\n' %
333 makefile)
334 os.rename(backup, makefile)
335
336 # Done!
337
338 if odir:
339 print 'Now run "make" in', odir,
340 print 'to build the target:', base_target
341 else:
342 print 'Now run "make" to build the target:', base_target
Guido van Rossum00ff4331994-10-03 16:33:08 +0000343
Guido van Rossumd8336c21994-10-05 16:13:01 +0000344
345# Print usage message and exit
346
Guido van Rossum9a6e8551997-08-10 16:47:17 +0000347def usage(msg):
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000348 sys.stdout = sys.stderr
349 print "Error:", msg
350 print "Use ``%s -h'' for help" % sys.argv[0]
351 sys.exit(2)
Guido van Rossumd8336c21994-10-05 16:13:01 +0000352
353
Guido van Rossumdbaf3321994-10-03 10:25:54 +0000354main()
Guido van Rossum0b4b8a21997-08-10 16:56:48 +0000355
356# Local Variables:
357# indent-tabs-mode: nil
358# End: