3 # changes made by strubi@blender.nl
5 """Freeze a Python script into a binary.
7 usage: freeze [options...] script [module]...
10 -p prefix: This is the prefix used when you ran ``make install''
11 in the Python build directory.
12 (If you never ran this, freeze won't work.)
13 The default is whatever sys.prefix evaluates to.
14 It can also be the top directory of the Python source
15 tree; then -P must point to the build tree.
17 -P exec_prefix: Like -p but this is the 'exec_prefix', used to
18 install objects etc. The default is whatever sys.exec_prefix
19 evaluates to, or the -p argument if given.
20 If -p points to the Python source tree, -P must point
21 to the build tree, if different.
23 -e extension: A directory containing additional .o files that
24 may be used to resolve modules. This directory
25 should also have a Setup file describing the .o files.
26 On Windows, the name of a .INI file describing one
27 or more extensions is passed.
28 More than one -e option may be given.
30 -o dir: Directory where the output files are created; default '.'.
32 -m: Additional arguments are module names instead of filenames.
34 -a package=dir: Additional directories to be added to the package's
35 __path__. Used to simulate directories added by the
36 package at runtime (eg, by OpenGL and win32com).
37 More than one -a option may be given for each package.
39 -l file: Pass the file to the linker (windows only)
41 -d: Debugging mode for the module finder.
43 -q: Make the module finder totally quiet.
45 -h: Print this help message.
47 -x module Exclude the specified module.
49 -i filename: Include a file with additional command line options. Used
50 to prevent command lines growing beyond the capabilities of
51 the shell/OS. All arguments specified in filename
52 are read and the -i option replaced with the parsed
53 params (note - quoting args in this file is NOT supported)
55 -s subsystem: Specify the subsystem (For Windows only.);
56 'console' (default), 'windows', 'service' or 'com_dll'
58 -w: Toggle Windows (NT or 95) behavior.
59 (For debugging only -- on a win32 platform, win32 behavior
64 script: The Python script to be executed by the resulting binary.
66 module ...: Additional Python modules (referenced by pathname)
67 that will be included in the resulting binary. These
68 may be .py or .pyc files. If -m is specified, these are
69 module names that are search in the path instead.
73 In order to use freeze successfully, you must have built Python and
74 installed it ("make install").
76 The script should not use modules provided only as shared libraries;
77 if it does, the resulting binary is not self-contained.
81 # Import standard modules
89 # Import the freeze-private modules
91 import checkextensions
103 # overridable context
104 prefix = None # settable with -p option
105 exec_prefix = None # settable with -P option
107 exclude = [] # settable with -x option
108 addn_link = [] # settable with -l, but only honored under Windows.
113 win = sys.platform[:3] == 'win'
115 # default the exclude list for each platform
116 if win: exclude = exclude + [
117 'dos', 'dospath', 'mac', 'macpath', 'macfs', 'MACFS', 'posix', 'os2', 'ce']
119 # modules that are imported by the Python runtime
120 #implicits = ["site", "exceptions"]
121 implicits = ["exceptions"]
124 frozen_c = 'frozen.c'
125 config_c = 'config.c'
126 target = 'a.out' # normally derived from script name
127 makefile = 'Makefile'
128 subsystem = 'console'
130 # parse command line by first replacing any "-i" options with the file contents.
132 while pos < len(sys.argv)-1: # last option can not be "-i", so this ensures "pos+1" is in range!
133 if sys.argv[pos] == '-i':
135 options = string.split(open(sys.argv[pos+1]).read())
137 usage("File name '%s' specified with the -i option can not be read - %s" % (sys.argv[pos+1], why) )
138 # Replace the '-i' and the filename with the read params.
139 sys.argv[pos:pos+2] = options
140 pos = pos + len(options) - 1 # Skip the name and the included args.
143 # Now parse the command line with the extras inserted.
145 opts, args = getopt.getopt(sys.argv[1:], 'a:de:hmo:p:P:I:qs:wx:l:')
146 except getopt.error, msg:
147 usage('getopt error: ' + str(msg))
149 # proces option arguments
158 if o == '-I': # include path
174 usage("-s subsystem option only on Windows")
181 apply(modulefinder.AddPackagePath, tuple(string.split(a,"=", 2)))
183 # default prefix and exec_prefix
188 exec_prefix = sys.exec_prefix
192 # determine whether -p points to the Python source tree
193 ishome = os.path.exists(os.path.join(prefix, 'Python', 'ceval.c'))
195 # locations derived from options
196 version = sys.version[:3]
198 extensions_c = 'frozen_extensions.c'
200 print "(Using Python source directory)"
202 incldir = os.path.join(prefix, 'Include')
203 config_h_dir = exec_prefix
204 config_c_in = os.path.join(prefix, 'Modules', 'config.c.in')
205 frozenmain_c = os.path.join(prefix, 'Python', 'frozenmain.c')
206 makefile_in = os.path.join(exec_prefix, 'Modules', 'Makefile')
208 frozendllmain_c = os.path.join(exec_prefix, 'Pc\\frozen_dllmain.c')
210 binlib = os.path.join(exec_prefix,
211 'lib', 'python%s' % version, 'config')
212 incldir = os.path.join(prefix, 'include', 'python%s' % version)
213 config_h_dir = os.path.join(exec_prefix, 'include',
214 'python%s' % version)
215 config_c_in = os.path.join(binlib, 'config.c.in')
216 frozenmain_c = os.path.join(binlib, 'frozenmain.c')
217 makefile_in = os.path.join(binlib, 'Makefile')
218 frozendllmain_c = os.path.join(binlib, 'frozen_dllmain.c')
221 includes = ['-I' + incldir, '-I' + config_h_dir]
223 # sanity check of directories and files
224 check_dirs = [prefix, exec_prefix, binlib, incldir]
225 if not win: check_dirs = check_dirs + extensions # These are not directories on Windows.
226 for dir in check_dirs:
227 if not os.path.exists(dir):
228 usage('needed directory %s not found' % dir)
229 if not os.path.isdir(dir):
230 usage('%s: not a directory' % dir)
232 files = supp_sources + extensions # extensions are files on Windows.
234 files = [config_c_in, makefile_in] + supp_sources
235 for file in supp_sources:
236 if not os.path.exists(file):
237 usage('needed file %s not found' % file)
238 if not os.path.isfile(file):
239 usage('%s: not a plain file' % file)
241 for dir in extensions:
242 setup = os.path.join(dir, 'Setup')
243 if not os.path.exists(setup):
244 usage('needed file %s not found' % setup)
245 if not os.path.isfile(setup):
246 usage('%s: not a plain file' % setup)
248 # check that enough arguments are passed
250 usage('at least one filename argument required')
252 # check that file arguments exist
256 # if user specified -m on the command line before _any_
257 # file names, then nothing should be checked (as the
258 # very first file should be a module name)
261 if not os.path.exists(arg):
262 usage('argument %s not found' % arg)
263 if not os.path.isfile(arg):
264 usage('%s: not a plain file' % arg)
266 # process non-option arguments
270 # derive target name from script name
271 base = os.path.basename(scriptfile)
272 base, ext = os.path.splitext(base)
274 if base != scriptfile:
277 target = base + '.bin'
280 base_frozen_c = frozen_c
281 base_config_c = config_c
283 if odir and not os.path.isdir(odir):
286 print "Created output directory", odir
287 except os.error, msg:
288 usage('%s: mkdir failed (%s)' % (odir, str(msg)))
291 base = os.path.join(odir, '')
292 frozen_c = os.path.join(odir, frozen_c)
293 config_c = os.path.join(odir, config_c)
294 target = os.path.join(odir, target)
295 makefile = os.path.join(odir, makefile)
296 if win: extensions_c = os.path.join(odir, extensions_c)
298 # Handle special entry point requirements
299 # (on Windows, some frozen programs do not use __main__, but
300 # import the module directly. Eg, DLLs, Services, etc
301 custom_entry_point = None # Currently only used on Windows
302 python_entry_is_main = 1 # Is the entry point called __main__?
303 # handle -s option on Windows
305 import winmakemakefile
307 custom_entry_point, python_entry_is_main = \
308 winmakemakefile.get_custom_entry_point(subsystem)
309 except ValueError, why:
313 # Actual work starts here...
315 # collect all modules of the program
316 dir = os.path.dirname(scriptfile)
318 mf = modulefinder.ModuleFinder(path, debug, exclude)
320 if win and subsystem=='service':
321 # If a Windows service, then add the "built-in" module.
322 mod = mf.add_module("servicemanager")
323 mod.__file__="dummy.pyd" # really built-in to the resulting EXE
325 for mod in implicits:
333 mf.import_hook(mod[:-2], None, ["*"])
339 # Add the main script as either __main__, or the actual module name.
340 if python_entry_is_main:
341 mf.run_script(scriptfile)
343 mf.load_file(scriptfile)
350 # generate output for frozen modules
351 files = makefreeze.makefreeze(base, dict, debug, custom_entry_point, 1)
352 # look for unfrozen modules (builtin and of unknown origin)
358 if dict[mod].__code__:
360 if not dict[mod].__file__:
365 # search for unknown modules in extensions directories (not on Windows)
367 frozen_extensions = [] # Windows list of modules.
368 if unknown or (not win and builtins):
370 addfiles, addmods = \
371 checkextensions.checkextensions(unknown+builtins,
378 # Do the windows thang...
379 import checkextensions_win32
380 # Get a list of CExtension instances, each describing a module
381 # (including its source files)
382 frozen_extensions = checkextensions_win32.checkextensions(
383 unknown, extensions, prefix)
384 for mod in frozen_extensions:
385 unknown.remove(mod.name)
387 # report unknown modules
389 sys.stderr.write('Warning: unknown modules remain: %s\n' %
390 string.join(unknown))
392 # windows gets different treatment
394 # Taking a shortcut here...
395 import winmakemakefile, checkextensions_win32
396 checkextensions_win32.write_extension_table(extensions_c,
398 # Create a module definition for the bootstrap C code.
399 xtras = [frozenmain_c, os.path.basename(frozen_c),
400 frozendllmain_c, os.path.basename(extensions_c)] + files
401 maindefn = checkextensions_win32.CExtension( '__main__', xtras )
402 frozen_extensions.append( maindefn )
403 outfp = open(makefile, 'w')
405 winmakemakefile.makemakefile(outfp,
408 os.path.basename(target))
413 # generate config.c and Makefile
415 infp = open(config_c_in)
416 outfp = bkfile.open(config_c, 'w')
418 makeconfig.makeconfig(infp, outfp, builtins)
423 cflags = defines + includes + ['$(OPT)']
424 libs = [os.path.join(binlib, 'libpython$(VERSION).a')]
427 if os.path.exists(makefile_in):
428 makevars = parsesetup.getmakevars(makefile_in)
429 for key in makevars.keys():
430 somevars[key] = makevars[key]
432 somevars['CFLAGS'] = string.join(cflags) # override
433 files = ['$(OPT)', '$(LDFLAGS)', base_config_c, base_frozen_c] + \
434 files + supp_sources + addfiles + libs + \
435 ['$(MODLIBS)', '$(LIBS)', '$(SYSLIBS)']
437 outfp = bkfile.open(makefile, 'w')
439 makemakefile.makemakefile(outfp, somevars, files, base_target)
446 print 'Now run "make" in', odir,
447 print 'to build the target:', base_target
449 print 'Now run "make" to build the target:', base_target
452 # Print usage message and exit
455 sys.stdout = sys.stderr
457 print "Use ``%s -h'' for help" % sys.argv[0]