3 """Freeze a Python script into a binary.
5 usage: freeze [options...] script [module]...
8 -p prefix: This is the prefix used when you ran ``make install''
9 in the Python build directory.
10 (If you never ran this, freeze won't work.)
11 The default is whatever sys.prefix evaluates to.
12 It can also be the top directory of the Python source
13 tree; then -P must point to the build tree.
15 -P exec_prefix: Like -p but this is the 'exec_prefix', used to
16 install objects etc. The default is whatever sys.exec_prefix
17 evaluates to, or the -p argument if given.
18 If -p points to the Python source tree, -P must point
19 to the build tree, if different.
21 -e extension: A directory containing additional .o files that
22 may be used to resolve modules. This directory
23 should also have a Setup file describing the .o files.
24 On Windows, the name of a .INI file describing one
25 or more extensions is passed.
26 More than one -e option may be given.
28 -o dir: Directory where the output files are created; default '.'.
30 -m: Additional arguments are module names instead of filenames.
32 -a package=dir: Additional directories to be added to the package's
33 __path__. Used to simulate directories added by the
34 package at runtime (eg, by OpenGL and win32com).
35 More than one -a option may be given for each package.
37 -l file: Pass the file to the linker (windows only)
39 -d: Debugging mode for the module finder.
41 -q: Make the module finder totally quiet.
43 -h: Print this help message.
45 -x module Exclude the specified module.
47 -i filename: Include a file with additional command line options. Used
48 to prevent command lines growing beyond the capabilities of
49 the shell/OS. All arguments specified in filename
50 are read and the -i option replaced with the parsed
51 params (note - quoting args in this file is NOT supported)
53 -s subsystem: Specify the subsystem (For Windows only.);
54 'console' (default), 'windows', 'service' or 'com_dll'
56 -w: Toggle Windows (NT or 95) behavior.
57 (For debugging only -- on a win32 platform, win32 behaviour
62 script: The Python script to be executed by the resulting binary.
64 module ...: Additional Python modules (referenced by pathname)
65 that will be included in the resulting binary. These
66 may be .py or .pyc files. If -m is specified, these are
67 module names that are search in the path instead.
71 In order to use freeze successfully, you must have built Python and
72 installed it ("make install").
74 The script should not use modules provided only as shared libraries;
75 if it does, the resulting binary is not self-contained.
79 # Import standard modules
88 # Import the freeze-private modules
90 import checkextensions
102 # overridable context
103 prefix
= None # settable with -p option
104 exec_prefix
= None # settable with -P option
106 exclude
= [] # settable with -x option
107 addn_link
= [] # settable with -l, but only honored under Windows.
112 win
= sys
.platform
[:3] == 'win'
114 # default the exclude list for each platform
115 if win
: exclude
= exclude
+ [
116 'dos', 'dospath', 'mac', 'macpath', 'macfs', 'MACFS', 'posix', 'os2']
118 # modules that are imported by the Python runtime
119 implicits
= ["site", "exceptions"]
122 frozen_c
= 'frozen.c'
123 config_c
= 'config.c'
124 target
= 'a.out' # normally derived from script name
125 makefile
= 'Makefile'
126 subsystem
= 'console'
128 # parse command line by first replacing any "-i" options with the file contents.
130 while pos
< len(sys
.argv
)-1: # last option can not be "-i", so this ensures "pos+1" is in range!
131 if sys
.argv
[pos
] == '-i':
133 options
= string
.split(open(sys
.argv
[pos
+1]).read())
135 usage("File name '%s' specified with the -i option can not be read - %s" % (sys
.argv
[pos
+1], why
) )
136 # Replace the '-i' and the filename with the read params.
137 sys
.argv
[pos
:pos
+2] = options
138 pos
= pos
+ len(options
) - 1 # Skip the name and the included args.
141 # Now parse the command line with the extras inserted.
143 opts
, args
= getopt
.getopt(sys
.argv
[1:], 'a:de:hmo:p:P:qs:wx:l:')
144 except getopt
.error
, msg
:
145 usage('getopt error: ' + str(msg
))
147 # proces option arguments
170 usage("-s subsystem option only on Windows")
177 apply(modulefinder
.AddPackagePath
, tuple(string
.split(a
,"=", 2)))
179 # default prefix and exec_prefix
184 exec_prefix
= sys
.exec_prefix
188 # determine whether -p points to the Python source tree
189 ishome
= os
.path
.exists(os
.path
.join(prefix
, 'Python', 'ceval.c'))
191 # locations derived from options
192 version
= sys
.version
[:3]
194 extensions_c
= 'frozen_extensions.c'
196 print "(Using Python source directory)"
198 incldir
= os
.path
.join(prefix
, 'Include')
199 config_h_dir
= exec_prefix
200 config_c_in
= os
.path
.join(prefix
, 'Modules', 'config.c.in')
201 frozenmain_c
= os
.path
.join(prefix
, 'Python', 'frozenmain.c')
202 makefile_in
= os
.path
.join(exec_prefix
, 'Modules', 'Makefile')
204 frozendllmain_c
= os
.path
.join(exec_prefix
, 'Pc\\frozen_dllmain.c')
206 binlib
= os
.path
.join(exec_prefix
,
207 'lib', 'python%s' % version
, 'config')
208 incldir
= os
.path
.join(prefix
, 'include', 'python%s' % version
)
209 config_h_dir
= os
.path
.join(exec_prefix
, 'include',
210 'python%s' % version
)
211 config_c_in
= os
.path
.join(binlib
, 'config.c.in')
212 frozenmain_c
= os
.path
.join(binlib
, 'frozenmain.c')
213 makefile_in
= os
.path
.join(binlib
, 'Makefile')
214 frozendllmain_c
= os
.path
.join(binlib
, 'frozen_dllmain.c')
217 includes
= ['-I' + incldir
, '-I' + config_h_dir
]
219 # sanity check of directories and files
220 check_dirs
= [prefix
, exec_prefix
, binlib
, incldir
]
221 if not win
: check_dirs
= check_dirs
+ extensions
# These are not directories on Windows.
222 for dir in check_dirs
:
223 if not os
.path
.exists(dir):
224 usage('needed directory %s not found' % dir)
225 if not os
.path
.isdir(dir):
226 usage('%s: not a directory' % dir)
228 files
= supp_sources
+ extensions
# extensions are files on Windows.
230 files
= [config_c_in
, makefile_in
] + supp_sources
231 for file in supp_sources
:
232 if not os
.path
.exists(file):
233 usage('needed file %s not found' % file)
234 if not os
.path
.isfile(file):
235 usage('%s: not a plain file' % file)
237 for dir in extensions
:
238 setup
= os
.path
.join(dir, 'Setup')
239 if not os
.path
.exists(setup
):
240 usage('needed file %s not found' % setup
)
241 if not os
.path
.isfile(setup
):
242 usage('%s: not a plain file' % setup
)
244 # check that enough arguments are passed
246 usage('at least one filename argument required')
248 # check that file arguments exist
252 # if user specified -m on the command line before _any_
253 # file names, then nothing should be checked (as the
254 # very first file should be a module name)
257 if not os
.path
.exists(arg
):
258 usage('argument %s not found' % arg
)
259 if not os
.path
.isfile(arg
):
260 usage('%s: not a plain file' % arg
)
262 # process non-option arguments
266 # derive target name from script name
267 base
= os
.path
.basename(scriptfile
)
268 base
, ext
= os
.path
.splitext(base
)
270 if base
!= scriptfile
:
273 target
= base
+ '.bin'
276 base_frozen_c
= frozen_c
277 base_config_c
= config_c
279 if odir
and not os
.path
.isdir(odir
):
282 print "Created output directory", odir
283 except os
.error
, msg
:
284 usage('%s: mkdir failed (%s)' % (odir
, str(msg
)))
287 base
= os
.path
.join(odir
, '')
288 frozen_c
= os
.path
.join(odir
, frozen_c
)
289 config_c
= os
.path
.join(odir
, config_c
)
290 target
= os
.path
.join(odir
, target
)
291 makefile
= os
.path
.join(odir
, makefile
)
292 if win
: extensions_c
= os
.path
.join(odir
, extensions_c
)
294 # Handle special entry point requirements
295 # (on Windows, some frozen programs do not use __main__, but
296 # import the module directly. Eg, DLLs, Services, etc
297 custom_entry_point
= None # Currently only used on Windows
298 python_entry_is_main
= 1 # Is the entry point called __main__?
299 # handle -s option on Windows
301 import winmakemakefile
303 custom_entry_point
, python_entry_is_main
= \
304 winmakemakefile
.get_custom_entry_point(subsystem
)
305 except ValueError, why
:
309 # Actual work starts here...
311 # collect all modules of the program
312 dir = os
.path
.dirname(scriptfile
)
314 mf
= modulefinder
.ModuleFinder(path
, debug
, exclude
)
316 if win
and subsystem
=='service':
317 # If a Windows service, then add the "built-in" module.
318 mod
= mf
.add_module("servicemanager")
319 mod
.__file
__="dummy.pyd" # really built-in to the resulting EXE
321 for mod
in implicits
:
329 mf
.import_hook(mod
[:-2], None, ["*"])
335 # Add the main script as either __main__, or the actual module name.
336 if python_entry_is_main
:
337 mf
.run_script(scriptfile
)
340 mf
.import_hook(scriptfile
)
342 mf
.load_file(scriptfile
)
349 # generate output for frozen modules
350 files
= makefreeze
.makefreeze(base
, dict, debug
, custom_entry_point
)
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(
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]