Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit baf0603

Browse files
committed
New version, with contributions from Sjoerd Mullender and Mark Hammond.
Sjoerd writes: This version of freeze creates one file per Python module, instead of one humongous file for all Python modules. bkfile: new module to used to write files with backups. No new file is produced if the new contents is identical to the old. New option "-x excluded-module" for modulefinder test program. New option "-i filename" for freeze main program to include a list of options in place of the -i option.
1 parent 6c74fea commit baf0603

8 files changed

Lines changed: 189 additions & 89 deletions

File tree

Tools/freeze/README

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,12 @@ such as /usr/joe/python/Tools/freeze/freeze.py).
7777
What do I do next?
7878
------------------
7979

80-
Freeze creates three files: frozen.c, config.c and Makefile. To
81-
produce the frozen version of your program, you can simply type
82-
"make". This should produce a binary file. If the filename argument
83-
to Freeze was "hello.py", the binary will be called "hello".
80+
Freeze creates a number of files: frozen.c, config.c and Makefile,
81+
plus one file for each Python module that gets included named
82+
M_<module>.c. To produce the frozen version of your program, you can
83+
simply type "make". This should produce a binary file. If the
84+
filename argument to Freeze was "hello.py", the binary will be called
85+
"hello".
8486

8587
Note: you can use the -o option to freeze to specify an alternative
8688
directory where these files are created. This makes it easier to

Tools/freeze/bkfile.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
_orig_open = open
2+
3+
class _BkFile:
4+
def __init__(self, file, mode, bufsize):
5+
import os
6+
self.__filename = file
7+
self.__backup = file + '~'
8+
try:
9+
os.unlink(self.__backup)
10+
except os.error:
11+
pass
12+
try:
13+
os.rename(file, self.__backup)
14+
except os.error:
15+
self.__backup = None
16+
self.__file = _orig_open(file, mode, bufsize)
17+
self.closed = self.__file.closed
18+
self.fileno = self.__file.fileno
19+
self.flush = self.__file.flush
20+
self.isatty = self.__file.isatty
21+
self.mode = self.__file.mode
22+
self.name = self.__file.name
23+
self.read = self.__file.read
24+
self.readinto = self.__file.readinto
25+
self.readline = self.__file.readline
26+
self.readlines = self.__file.readlines
27+
self.seek = self.__file.seek
28+
self.softspace = self.__file.softspace
29+
self.tell = self.__file.tell
30+
self.truncate = self.__file.truncate
31+
self.write = self.__file.write
32+
self.writelines = self.__file.writelines
33+
34+
def close(self):
35+
self.__file.close()
36+
if self.__backup is None:
37+
return
38+
import cmp
39+
# don't use cmp.cmp because of NFS bugs :-( and
40+
# anyway, the stat mtime values differ so do_cmp will
41+
# most likely be called anyway
42+
if cmp.do_cmp(self.__backup, self.__filename):
43+
import os
44+
os.unlink(self.__filename)
45+
os.rename(self.__backup, self.__filename)
46+
47+
def open(file, mode = 'r', bufsize = -1):
48+
if 'w' not in mode:
49+
return _orig_open(file, mode, bufsize)
50+
return _BkFile(file, mode, bufsize)

Tools/freeze/checkextensions_win32.py

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@
99
1010
So my basic stragtegy is:
1111
12-
* Have a Windows INI file which "describes" an extension module.
12+
* Have some Windows INI files which "describe" one or more extension modules.
13+
(Freeze comes with a default one for all known modules - but you can specify
14+
your own).
1315
* This description can include:
1416
- The MSVC .dsp file for the extension. The .c source file names
1517
are extraced from there.
16-
- Specific compiler options
18+
- Specific compiler/linker options
1719
- Flag to indicate if Unicode compilation is expected.
1820
1921
At the moment the name and location of this INI file is hardcoded,
@@ -52,31 +54,52 @@ def AddLinkerLib(self, lib):
5254
def GetLinkerLibs(self):
5355
return self.linkerLibs
5456

55-
def checkextensions(unknown, ignored):
57+
def checkextensions(unknown, extra_inis):
5658
# Create a table of frozen extensions
5759

58-
mapFileName = os.path.join( os.path.split(sys.argv[0])[0], "extensions_win32.ini")
60+
defaultMapName = os.path.join( os.path.split(sys.argv[0])[0], "extensions_win32.ini")
61+
if not os.path.isfile(defaultMapName):
62+
sys.stderr.write("WARNING: %s can not be found - standard extensions may not be found" % mapFileName)
63+
else:
64+
# must go on end, so other inis can override.
65+
extra_inis.append(defaultMapName)
66+
5967
ret = []
6068
for mod in unknown:
61-
defn = get_extension_defn( mod, mapFileName )
62-
if defn is not None:
63-
ret.append( defn )
69+
for ini in extra_inis:
70+
# print "Looking for", mod, "in", win32api.GetFullPathName(ini),"...",
71+
defn = get_extension_defn( mod, ini )
72+
if defn is not None:
73+
# print "Yay - found it!"
74+
ret.append( defn )
75+
break
76+
# print "Nope!"
77+
else: # For not broken!
78+
sys.stderr.write("No definition of module %s in any specified map file.\n" % (mod))
79+
6480
return ret
6581

6682
def get_extension_defn(moduleName, mapFileName):
6783
if win32api is None: return None
6884
dsp = win32api.GetProfileVal(moduleName, "dsp", "", mapFileName)
6985
if dsp=="":
70-
sys.stderr.write("No definition of module %s in map file '%s'\n" % (moduleName, mapFileName))
7186
return None
7287

7388
# We allow environment variables in the file name
7489
dsp = win32api.ExpandEnvironmentStrings(dsp)
90+
# If the path to the .DSP file is not absolute, assume it is relative
91+
# to the description file.
92+
if not os.path.isabs(dsp):
93+
dsp = os.path.join( os.path.split(mapFileName)[0], dsp)
94+
# Parse it to extract the source files.
7595
sourceFiles = parse_dsp(dsp)
7696
if sourceFiles is None:
7797
return None
7898

7999
module = CExtension(moduleName, sourceFiles)
100+
# Put the path to the DSP into the environment so entries can reference it.
101+
os.environ['dsp_path'] = os.path.split(dsp)[0]
102+
os.environ['ini_path'] = os.path.split(mapFileName)[0]
80103

81104
cl_options = win32api.GetProfileVal(moduleName, "cl", "", mapFileName)
82105
if cl_options:
@@ -90,7 +113,7 @@ def get_extension_defn(moduleName, mapFileName):
90113

91114
libs = string.split(win32api.GetProfileVal(moduleName, "libs", "", mapFileName))
92115
for lib in libs:
93-
module.AddLinkerLib(lib)
116+
module.AddLinkerLib(win32api.ExpandEnvironmentStrings(lib))
94117

95118
for exc in exclude:
96119
if exc in module.sourceFiles:

Tools/freeze/extensions_win32.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,6 @@ Unicode = 1
112112
; Pythonwin
113113
[win32ui]
114114
dsp=%PYTHONEX%\Pythonwin\win32ui.dsp
115-
cl=/I %PYTHONEX%\win32\src
115+
cl=/D _AFXDLL /D FREEZE_WIN32UI /GX /I %PYTHONEX%\win32\src
116116
libs=mfc42.lib
117117

Tools/freeze/freeze.py

Lines changed: 39 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
usage: freeze [options...] script [module]...
66
77
Options:
8-
98
-p prefix: This is the prefix used when you ran ``make install''
109
in the Python build directory.
1110
(If you never ran this, freeze won't work.)
@@ -22,6 +21,8 @@
2221
-e extension: A directory containing additional .o files that
2322
may be used to resolve modules. This directory
2423
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.
2526
More than one -e option may be given.
2627
2728
-o dir: Directory where the output files are created; default '.'.
@@ -41,15 +42,20 @@
4142
4243
-h: Print this help message.
4344
44-
-w: Toggle Windows (NT or 95) behavior.
45-
(For debugging only -- on a win32 platform, win32 behaviour
46-
is automatic.)
47-
4845
-x module Exclude the specified module.
4946
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)
52+
5053
-s subsystem: Specify the subsystem (For Windows only.);
5154
'console' (default), 'windows', 'service' or 'com_dll'
5255
56+
-w: Toggle Windows (NT or 95) behavior.
57+
(For debugging only -- on a win32 platform, win32 behaviour
58+
is automatic.)
5359
5460
Arguments:
5561
@@ -87,6 +93,7 @@
8793
import makefreeze
8894
import makemakefile
8995
import parsesetup
96+
import bkfile
9097

9198

9299
# Main program
@@ -105,8 +112,8 @@ def main():
105112
win = sys.platform[:3] == 'win'
106113

107114
# default the exclude list for each platform
108-
## if win: exclude = exclude + [
109-
## 'dos', 'dospath', 'mac', 'macpath', 'MACFS', 'posix', 'os2']
115+
if win: exclude = exclude + [
116+
'dos', 'dospath', 'mac', 'macpath', 'macfs', 'MACFS', 'posix', 'os2']
110117

111118
# modules that are imported by the Python runtime
112119
implicits = ["site", "exceptions"]
@@ -118,7 +125,20 @@ def main():
118125
makefile = 'Makefile'
119126
subsystem = 'console'
120127

121-
# parse command line
128+
# parse command line by first replacing any "-i" options with the file contents.
129+
pos = 1
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':
132+
try:
133+
options = string.split(open(sys.argv[pos+1]).read())
134+
except IOError, why:
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.
139+
pos = pos + 1
140+
141+
# Now parse the command line with the extras inserted.
122142
try:
123143
opts, args = getopt.getopt(sys.argv[1:], 'a:de:hmo:p:P:qs:wx:l:')
124144
except getopt.error, msg:
@@ -197,13 +217,15 @@ def main():
197217
includes = ['-I' + incldir, '-I' + config_h_dir]
198218

199219
# sanity check of directories and files
200-
for dir in [prefix, exec_prefix, binlib, incldir] + extensions:
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:
201223
if not os.path.exists(dir):
202224
usage('needed directory %s not found' % dir)
203225
if not os.path.isdir(dir):
204226
usage('%s: not a directory' % dir)
205227
if win:
206-
files = supp_sources
228+
files = supp_sources + extensions # extensions are files on Windows.
207229
else:
208230
files = [config_c_in, makefile_in] + supp_sources
209231
for file in supp_sources:
@@ -260,7 +282,9 @@ def main():
260282
print "Created output directory", odir
261283
except os.error, msg:
262284
usage('%s: mkdir failed (%s)' % (odir, str(msg)))
285+
base = ''
263286
if odir:
287+
base = os.path.join(odir, '')
264288
frozen_c = os.path.join(odir, frozen_c)
265289
config_c = os.path.join(odir, config_c)
266290
target = os.path.join(odir, target)
@@ -323,21 +347,7 @@ def main():
323347
dict = mf.modules
324348

325349
# generate output for frozen modules
326-
backup = frozen_c + '~'
327-
try:
328-
os.rename(frozen_c, backup)
329-
except os.error:
330-
backup = None
331-
outfp = open(frozen_c, 'w')
332-
try:
333-
makefreeze.makefreeze(outfp, dict, debug, custom_entry_point)
334-
finally:
335-
outfp.close()
336-
if backup:
337-
if cmp.cmp(backup, frozen_c):
338-
sys.stderr.write('%s not changed, not written\n' % frozen_c)
339-
os.unlink(frozen_c)
340-
os.rename(backup, frozen_c)
350+
files = makefreeze.makefreeze(base, dict, debug, custom_entry_point)
341351

342352
# look for unfrozen modules (builtin and of unknown origin)
343353
builtins = []
@@ -387,7 +397,7 @@ def main():
387397
frozen_extensions)
388398
# Create a module definition for the bootstrap C code.
389399
xtras = [frozenmain_c, os.path.basename(frozen_c),
390-
frozendllmain_c, extensions_c]
400+
frozendllmain_c, extensions_c] + files
391401
maindefn = checkextensions_win32.CExtension( '__main__', xtras )
392402
frozen_extensions.append( maindefn )
393403
outfp = open(makefile, 'w')
@@ -403,22 +413,12 @@ def main():
403413
# generate config.c and Makefile
404414
builtins.sort()
405415
infp = open(config_c_in)
406-
backup = config_c + '~'
407-
try:
408-
os.rename(config_c, backup)
409-
except os.error:
410-
backup = None
411-
outfp = open(config_c, 'w')
416+
outfp = bkfile.open(config_c, 'w')
412417
try:
413418
makeconfig.makeconfig(infp, outfp, builtins)
414419
finally:
415420
outfp.close()
416421
infp.close()
417-
if backup:
418-
if cmp.cmp(backup, config_c):
419-
sys.stderr.write('%s not changed, not written\n' % config_c)
420-
os.unlink(config_c)
421-
os.rename(backup, config_c)
422422

423423
cflags = defines + includes + ['$(OPT)']
424424
libs = [os.path.join(binlib, 'libpython$(VERSION).a')]
@@ -431,31 +431,14 @@ def main():
431431

432432
somevars['CFLAGS'] = string.join(cflags) # override
433433
files = ['$(OPT)', '$(LDFLAGS)', base_config_c, base_frozen_c] + \
434-
supp_sources + addfiles + libs + \
434+
files + supp_sources + addfiles + libs + \
435435
['$(MODLIBS)', '$(LIBS)', '$(SYSLIBS)']
436436

437-
backup = makefile + '~'
438-
if os.path.exists(makefile):
439-
try:
440-
os.unlink(backup)
441-
except os.error:
442-
pass
443-
try:
444-
os.rename(makefile, backup)
445-
except os.error:
446-
backup = None
447-
outfp = open(makefile, 'w')
437+
outfp = bkfile.open(makefile, 'w')
448438
try:
449439
makemakefile.makemakefile(outfp, somevars, files, base_target)
450440
finally:
451441
outfp.close()
452-
if backup:
453-
if not cmp.cmp(backup, makefile):
454-
print 'previous Makefile saved as', backup
455-
else:
456-
sys.stderr.write('%s not changed, not written\n' % makefile)
457-
os.unlink(makefile)
458-
os.rename(backup, makefile)
459442

460443
# Done!
461444

0 commit comments

Comments
 (0)