Skip to content

Commit 1b83347

Browse files
committed
enhance build.py to create a python27.zip, and put all the pyo files in it + reference it in the sys.path
with that way, decompress assets the first run are better and each startup time / import are faster. still need to found a way to do the same for site-packages.
1 parent a2d6223 commit 1b83347

File tree

2 files changed

+87
-29
lines changed

2 files changed

+87
-29
lines changed

src/build.py

Lines changed: 86 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/usr/bin/python
22

3-
from os.path import dirname, join
3+
from os.path import dirname, join, isfile, realpath, relpath, split
4+
from zipfile import ZipFile
45
import sys
56
sys.path.insert(0, 'buildlib/jinja2.egg')
67
sys.path.insert(0, 'buildlib')
@@ -39,6 +40,9 @@
3940
'.swp',
4041
]
4142

43+
python_files = []
44+
45+
4246
# Used by render.
4347
environment = jinja2.Environment(loader=jinja2.FileSystemLoader(
4448
join(curdir, 'templates')))
@@ -73,47 +77,97 @@ def is_blacklist(name):
7377
if fnmatch(name, pattern):
7478
return True
7579

80+
def listfiles(d):
81+
basedir = d
82+
subdirlist = []
83+
for item in os.listdir(d):
84+
fn = join(d, item)
85+
if isfile(fn):
86+
yield fn
87+
else:
88+
subdirlist.append(os.path.join(basedir, item))
89+
for subdir in subdirlist:
90+
for fn in listfiles(subdir):
91+
yield fn
92+
93+
def make_pythonzip():
94+
'''
95+
Search for all the python related files, and construct the pythonXX.zip
96+
According to
97+
# http://randomsplat.com/id5-cross-compiling-python-for-embedded-linux.html
98+
site-packages, config and lib-dynload will be not included.
99+
'''
100+
global python_files
101+
d = realpath(join('private', 'lib', 'python2.7'))
102+
103+
# selector function
104+
def select(fn):
105+
if is_blacklist(fn):
106+
return False
107+
fn = realpath(fn)
108+
assert(fn.startswith(d))
109+
fn = fn[len(d):]
110+
if fn.startswith('/site-packages/') or \
111+
fn.startswith('/config/') or \
112+
fn.startswith('/lib-dynload/'):
113+
return False
114+
return fn
115+
116+
# get a list of all python file
117+
python_files = [x for x in listfiles(d) if select(x)]
118+
119+
# create the final zipfile
120+
zfn = join('private', 'lib', 'python27.zip')
121+
zf = ZipFile(zfn, 'w')
122+
123+
# put all the python files in it
124+
for fn in python_files:
125+
afn = fn[len(d):]
126+
zf.write(fn, afn)
127+
zf.close()
128+
129+
76130
def make_tar(fn, source_dirs, ignore_path=[]):
77131
'''
78132
Make a zip file `fn` from the contents of source_dis.
79133
'''
80134

81-
tf = tarfile.open(fn, 'w:gz')
135+
# selector function
136+
def select(fn):
137+
rfn = realpath(fn)
138+
if rfn in python_files:
139+
return False
140+
return not is_blacklist(fn)
82141

142+
# get the files and relpath file of all the directory we asked for
143+
files = []
83144
for sd in source_dirs:
84145
compile_dir(sd)
146+
files += [(x, relpath(realpath(x), sd)) for x in listfiles(sd) if select(x)]
85147

86-
sd = os.path.abspath(sd)
87-
88-
for dir, dirs, files in os.walk(sd):
89-
dirs = [d for d in dirs if not is_blacklist(d)]
90-
91-
ignore = False
92-
for ip in ignore_path:
93-
if dir.startswith(ip):
94-
ignore = True
95-
if ignore:
96-
print 'ignored', fn
97-
continue
98-
99-
for fn in dirs:
100-
fn = os.path.join(dir, fn)
101-
relfn = os.path.relpath(fn, sd)
102-
tf.add(fn, relfn, recursive=False)
103-
104-
for fn in files:
105-
fn = os.path.join(dir, fn)
106-
relfn = os.path.relpath(fn, sd)
107-
if is_blacklist(relfn):
148+
# create tar.gz of thoses files
149+
tf = tarfile.open(fn, 'w:gz')
150+
dirs = []
151+
for fn, afn in files:
152+
dn = dirname(afn)
153+
if dn not in dirs:
154+
# create every dirs first if not exist yet
155+
d = ''
156+
for component in split(dn):
157+
d = join(d, component)
158+
if d.startswith('/'):
159+
d = d[1:]
160+
if d == '' or d in dirs:
108161
continue
109-
tf.add(fn, relfn)
110-
print 'add', fn
162+
dirs.append(d)
163+
tinfo = tarfile.TarInfo(d)
164+
tinfo.type = tarfile.DIRTYPE
165+
tf.addfile(tinfo)
111166

112-
# TODO: Fix me.
113-
# tf.writestr('.nomedia', '')
167+
# put the file
168+
tf.add(fn, afn)
114169
tf.close()
115170

116-
117171
def make_package(args):
118172
version_code = 0
119173
manifest_extra = '<uses-feature android:glEsVersion="0x00020000" />'
@@ -181,6 +235,9 @@ def make_package(args):
181235
if os.path.exists('assets/private.mp3'):
182236
os.unlink('assets/private.mp3')
183237

238+
# In order to speedup import and initial depack,
239+
# construct a python27.zip
240+
make_pythonzip()
184241

185242
# Package up the private and public data.
186243
if args.private:

src/jni/application/python/start.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ int main(int argc, char **argv) {
6161
"private = posix.environ['ANDROID_PRIVATE']\n" \
6262
"argument = posix.environ['ANDROID_ARGUMENT']\n" \
6363
"sys.path[:] = [ \n" \
64+
" private + '/lib/python27.zip', \n" \
6465
" private + '/lib/python2.7/', \n" \
6566
" private + '/lib/python2.7/lib-dynload/', \n" \
6667
" private + '/lib/python2.7/site-packages/', \n" \

0 commit comments

Comments
 (0)