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

Skip to content

Commit d8336c2

Browse files
committed
Lots of things added. README written (mostly).
1 parent ca9321e commit d8336c2

4 files changed

Lines changed: 352 additions & 36 deletions

File tree

Tools/freeze/README

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
THE FREEZE SCRIPT
2+
=================
3+
4+
5+
What is Freeze?
6+
---------------
7+
8+
Freeze make it possible to ship arbitrary Python programs to people
9+
who don't have Python. The shipped file (called a "frozen" version of
10+
your Python program) is an executable, so this only works if your
11+
platform is compatible with that on the receiving end (this is usually
12+
a matter of having the same major operating system revision and CPU
13+
type).
14+
15+
The shipped file contains a Python interpreter and large portions of
16+
the Python run-time. Some measures have been taken to avoid linking
17+
unneeded modules, but the resulting binary is usually not small.
18+
19+
The Python source code of your program (and of the library modules
20+
written in Python that it uses) is not included in the binary --
21+
instead, the compiled byte-code (the instruction stream used
22+
internally by the interpreter) is incorporated. This gives some
23+
protection of your Python source code, though not much -- a
24+
disassembler for Python byte-code is available in the standard Python
25+
library. At least someone running "strings" on your binary won't see
26+
the source.
27+
28+
29+
How does Freeze know which modules to include?
30+
----------------------------------------------
31+
32+
Freeze uses a pretty simple-minded algorithm to find the modules that
33+
your program uses: given a file containing Python source code, it
34+
scans for lines beginning with the word "import" or "from" (possibly
35+
preceded by whitespace) and then it knows where to find the module
36+
name(s) in those lines. It then recursively scans the source for
37+
those modules (if found, and not already processed) in the same way.
38+
39+
Freeze will not see import statements hidden behind another statement,
40+
like this:
41+
42+
if some_test: import M # M not seen
43+
44+
or like this:
45+
46+
import A; import B; import C # B and C not seen
47+
48+
nor will it see import statements constructed using string
49+
operations and passed to 'exec', like this:
50+
51+
exec "import %s" % "M" # M not seen
52+
53+
On the other hand, Freeze will think you are importing a module even
54+
if the import statement it sees will never be executed, like this:
55+
56+
if 0:
57+
import M # M is seen
58+
59+
One tricky issue: Freeze assumes that the Python interpreter and
60+
environment you're using to run Freeze is the same one that would be
61+
used to run your program, which should also be the same whose sources
62+
and installed files you will learn about in the next section. In
63+
particular, your PYTHONPATH setting should be the same as for running
64+
your program locally. (Tip: if the program doesn't run when you type
65+
"python hello.py" there's little chance of getting the frozen version
66+
to run.)
67+
68+
69+
How do I use Freeze?
70+
--------------------
71+
72+
Ideally, you should be able to use it as follows:
73+
74+
python freeze.py hello.py
75+
76+
where hello.py is your program and freeze.py is the main file of
77+
Freeze (in actuality, you'll probably specify an absolute pathname
78+
such as /ufs/guido/src/python/Demo/freeze/freeze.py).
79+
80+
Unfortunately, this doesn't work. Well, it might, but somehow it's
81+
extremely unlikely that it'll work on the first try. (If it does,
82+
skip to the next section.) Most likely you'll get this error message:
83+
84+
needed directory /usr/local/lib/python/lib not found
85+
86+
The reason is that Freeze require that some files that are normally
87+
kept inside the Python build tree are installed, and it searches for
88+
it in the default install location. (The default install prefix is
89+
/usr/local; these particular files are installed at lib/python/lib
90+
under the install prefix.)
91+
92+
The particular set of files needed is installed only if you run "make
93+
libainstall" (note: "liba", not "lib") in the Python build tree (which
94+
is the tree where you build Python -- often, but not necessarily, this
95+
is also the Python source tree). If you have in fact done a "make
96+
libainstall" but used a different prefix, all you need to do is pass
97+
that same prefix to Freeze with the -p option:
98+
99+
python freeze.py -p your-prefix hello.py
100+
101+
(If you haven't run "make libainstall" yet, go and do it now and don't
102+
come back until you've done it.)
103+
104+
105+
How do I configure Freeze?
106+
--------------------------
107+
108+
It's a good idea to change the line marked with XXX in freeze.py (an
109+
assignment to variable PACK) to point to the absolute pathname of the
110+
directory where Freeze lives (Demo/freeze in the Python source tree.)
111+
This makes it possible to call Freeze from other directories.
112+
113+
You can also edit the assignment to variable PREFIX -- this saves a
114+
lot of -p options.
115+
116+
117+
How do I use Freeze with extensions modules?
118+
--------------------------------------------
119+
120+
XXX to be written. (In short: pass -e extensionbuilddir.)
121+
122+
123+
How do I use Freeze with dynamically loaded extension modules?
124+
--------------------------------------------------------------
125+
126+
XXX to be written. (In short: pass -e modulebuilddir -- this even
127+
works if you built the modules in Python's own Modules directory.)
128+
129+
130+
131+
What do I do next?
132+
------------------
133+
134+
Freeze creates three files: frozen.c, config.c and Makefile. To
135+
produce the frozen version of your program, you can simply type
136+
"make". This should produce a binary file. If the filename argument
137+
to Freeze was "hello.py", the binary will be called "hello". On the
138+
other hand, if the argument was "hello", the binary will be called
139+
"hello.bin". If you passed any other filename, all bets are off. :-)
140+
In any case, the name of the file will be printed as the last message
141+
from Freeze.
142+
143+
144+
Help! I've tried everything but it doesn't work!
145+
-------------------------------------------------
146+
147+
Freeze is currently beta software. You could email me a bug report.
148+
Please give as much context as possible -- "Freeze doesn't work" is
149+
not going to get much sympathy. You could fix the bug and send me a
150+
patch. You could learn Tcl.
151+
152+
If you are thinking about debugging Freeze, start playing with a
153+
really simple program first (like "print 'hello world'"). If you
154+
can't get that to work there's something fundamentally wrong with your
155+
environment (or with your understanding of it). Gradually build it up
156+
to use more modules and extensions until you find where it stops
157+
working. After that, you're on your own -- happy hacking!
158+
159+
160+
--Guido van Rossum, CWI, Amsterdam <mailto:[email protected]>
161+
<http://www.cwi.nl/cwi/people/Guido.van.Rossum.html>

Tools/freeze/checkextensions.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Check for a module in a set of extension directories.
2+
# An extension directory should contain a Setup file
3+
# and one or more .o files or a lib.a file.
4+
5+
import os
6+
import string
7+
import parsesetup
8+
9+
def checkextensions(unknown, extensions):
10+
files = []
11+
modules = []
12+
edict = {}
13+
for e in extensions:
14+
setup = os.path.join(e, 'Setup')
15+
liba = os.path.join(e, 'lib.a')
16+
if not os.path.isfile(liba):
17+
liba = None
18+
edict[e] = parsesetup.getsetupinfo(setup), liba
19+
for mod in unknown:
20+
for e in extensions:
21+
(mods, vars), liba = edict[e]
22+
if not mods.has_key(mod):
23+
continue
24+
modules.append(mod)
25+
if liba:
26+
# If we find a lib.a, use it, ignore the
27+
# .o files, and use *all* libraries for
28+
# *all* modules in the Setup file
29+
if liba in files:
30+
break
31+
files.append(liba)
32+
for m in mods.keys():
33+
files = files + select(e, mods, vars,
34+
m, 1)
35+
break
36+
files = files + select(e, mods, vars, mod, 0)
37+
break
38+
return files, modules
39+
40+
def select(e, mods, vars, mod, skipofiles):
41+
files = []
42+
for w in mods[mod]:
43+
w = treatword(w)
44+
if not w:
45+
continue
46+
w = expandvars(w, vars)
47+
if skipofiles and w[-2:] == '.o':
48+
continue
49+
if w[0] != '-' and w[-2:] in ('.o', '.a'):
50+
w = os.path.join(e, w)
51+
files.append(w)
52+
return files
53+
54+
cc_flags = ['-I', '-D', '-U']
55+
cc_exts = ['.c', '.C', '.cc', '.c++']
56+
57+
def treatword(w):
58+
if w[:2] in cc_flags:
59+
return None
60+
if w[:1] == '-':
61+
return w # Assume loader flag
62+
head, tail = os.path.split(w)
63+
base, ext = os.path.splitext(tail)
64+
if ext in cc_exts:
65+
tail = base + '.o'
66+
w = os.path.join(head, tail)
67+
return w
68+
69+
def expandvars(str, vars):
70+
i = 0
71+
while i < len(str):
72+
i = k = string.find(str, '$', i)
73+
if i < 0:
74+
break
75+
i = i+1
76+
var = str[i:i+1]
77+
i = i+1
78+
if var == '(':
79+
j = string.find(str, ')', i)
80+
if j < 0:
81+
break
82+
var = str[i:j]
83+
i = j+1
84+
if vars.has_key(var):
85+
str = str[:k] + vars[var] + str[i:]
86+
i = k
87+
return str

Tools/freeze/findmodules.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ def findmodules(scriptfile, modules = [], path = sys.path):
2121
for name in modules:
2222
mod = os.path.basename(name)
2323
if mod[-3:] == '.py': mod = mod[:-3]
24+
elif mod[-4:] == '.pyc': mod = mod[:-4]
2425
todo[mod] = name
2526
done = closure(todo)
2627
return done
@@ -94,7 +95,6 @@ def scanfile(filename):
9495
# Return filename, or '<builtin>', or '<unknown>'.
9596

9697
builtins = sys.builtin_module_names
97-
if 'sys' not in builtins: builtins.append('sys')
9898
tails = ['.py', '.pyc']
9999

100100
def findmodule(modname, path = sys.path):

0 commit comments

Comments
 (0)