mirror of https://github.com/python/cpython.git
Lawrence Hudson, SF #401702: Modify co_filename in frozen programs
This patch was developed primarily to reduce the size of the frozen binary. It is particularly useful when freezing for 'small' platforms, such as Palm OS, where you really want to save that last miserable byte. A limitation of this patch is that it does not provide any feedback about the replacements being made. As the path matching is case-sensitive this may lead to unexpected behaviour for DOS and Windows people, eg > freeze.py -r C:\Python\Lib\=py\ goats.py should probably be: > freeze.py -r c:\python\lib\=py\ goats.py
This commit is contained in:
parent
b845cb0946
commit
6b767ac81a
|
@ -57,6 +57,10 @@
|
|||
(For debugging only -- on a win32 platform, win32 behavior
|
||||
is automatic.)
|
||||
|
||||
-r prefix=f: Replace path prefix.
|
||||
Replace prefix with f in the source path references
|
||||
contained in the resulting binary.
|
||||
|
||||
Arguments:
|
||||
|
||||
script: The Python script to be executed by the resulting binary.
|
||||
|
@ -109,6 +113,7 @@ def main():
|
|||
debug = 1
|
||||
odir = ''
|
||||
win = sys.platform[:3] == 'win'
|
||||
replace_paths = [] # settable with -r option
|
||||
|
||||
# default the exclude list for each platform
|
||||
if win: exclude = exclude + [
|
||||
|
@ -139,7 +144,7 @@ def main():
|
|||
|
||||
# Now parse the command line with the extras inserted.
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], 'a:de:hmo:p:P:qs:wx:l:')
|
||||
opts, args = getopt.getopt(sys.argv[1:], 'r:a:de:hmo:p:P:qs:wx:l:')
|
||||
except getopt.error, msg:
|
||||
usage('getopt error: ' + str(msg))
|
||||
|
||||
|
@ -174,6 +179,9 @@ def main():
|
|||
addn_link.append(a)
|
||||
if o == '-a':
|
||||
apply(modulefinder.AddPackagePath, tuple(string.split(a,"=", 2)))
|
||||
if o == '-r':
|
||||
f,r = string.split(a,"=", 2)
|
||||
replace_paths.append( (f,r) )
|
||||
|
||||
# default prefix and exec_prefix
|
||||
if not exec_prefix:
|
||||
|
@ -310,7 +318,7 @@ def main():
|
|||
# collect all modules of the program
|
||||
dir = os.path.dirname(scriptfile)
|
||||
path[0] = dir
|
||||
mf = modulefinder.ModuleFinder(path, debug, exclude)
|
||||
mf = modulefinder.ModuleFinder(path, debug, exclude, replace_paths)
|
||||
|
||||
if win and subsystem=='service':
|
||||
# If a Windows service, then add the "built-in" module.
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import re
|
||||
import string
|
||||
import sys
|
||||
import new
|
||||
|
||||
IMPORT_NAME = dis.opname.index('IMPORT_NAME')
|
||||
IMPORT_FROM = dis.opname.index('IMPORT_FROM')
|
||||
|
@ -49,7 +50,7 @@ def __repr__(self):
|
|||
|
||||
class ModuleFinder:
|
||||
|
||||
def __init__(self, path=None, debug=0, excludes = []):
|
||||
def __init__(self, path=None, debug=0, excludes = [], replace_paths = []):
|
||||
if path is None:
|
||||
path = sys.path
|
||||
self.path = path
|
||||
|
@ -58,6 +59,8 @@ def __init__(self, path=None, debug=0, excludes = []):
|
|||
self.debug = debug
|
||||
self.indent = 0
|
||||
self.excludes = excludes
|
||||
self.replace_paths = replace_paths
|
||||
self.processed_paths = [] # Used in debugging only
|
||||
|
||||
def msg(self, level, str, *args):
|
||||
if level <= self.debug:
|
||||
|
@ -250,6 +253,8 @@ def load_module(self, fqname, fp, pathname, (suffix, mode, type)):
|
|||
m = self.add_module(fqname)
|
||||
m.__file__ = pathname
|
||||
if co:
|
||||
if self.replace_paths:
|
||||
co = self.replace_paths_in_code(co)
|
||||
m.__code__ = co
|
||||
self.scan_code(co, m)
|
||||
self.msgout(2, "load_module ->", m)
|
||||
|
@ -369,6 +374,32 @@ def report(self):
|
|||
mods.sort()
|
||||
print "?", key, "from", string.join(mods, ', ')
|
||||
|
||||
def replace_paths_in_code(self, co):
|
||||
new_filename = original_filename = os.path.normpath(co.co_filename)
|
||||
for f,r in self.replace_paths:
|
||||
if original_filename.startswith(f):
|
||||
new_filename = r+original_filename[len(f):]
|
||||
break
|
||||
|
||||
if self.debug and original_filename not in self.processed_paths:
|
||||
if new_filename!=original_filename:
|
||||
self.msgout(2, "co_filename %r changed to %r" \
|
||||
% (original_filename,new_filename,))
|
||||
else:
|
||||
self.msgout(2, "co_filename %r remains unchanged" \
|
||||
% (original_filename,))
|
||||
self.processed_paths.append(original_filename)
|
||||
|
||||
consts = list(co.co_consts)
|
||||
for i in range(len(consts)):
|
||||
if isinstance(consts[i], type(co)):
|
||||
consts[i] = self.replace_paths_in_code(consts[i])
|
||||
|
||||
return new.code(co.co_argcount, co.co_nlocals, co.co_stacksize,
|
||||
co.co_flags, co.co_code, tuple(consts), co.co_names,
|
||||
co.co_varnames, new_filename, co.co_name,
|
||||
co.co_firstlineno, co.co_lnotab)
|
||||
|
||||
|
||||
def test():
|
||||
# Parse command line
|
||||
|
|
Loading…
Reference in New Issue