|
1 #!/usr/bin/python |
|
2 # |
|
3 # Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 # All rights reserved. |
|
5 # This component and the accompanying materials are made available |
|
6 # under the terms of "Eclipse Public License v1.0" |
|
7 # which accompanies this distribution, and is available |
|
8 # at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
9 # |
|
10 # Initial Contributors: |
|
11 # Nokia Corporation - initial contribution. |
|
12 # |
|
13 # Contributors: |
|
14 # |
|
15 # Description: |
|
16 # This utility is used to find out the size in disk of files |
|
17 # written to ROM images (or compiled). Script finds out Symbian |
|
18 # build enviornment binary file paths based on iby-file(s) or |
|
19 # mmp-files, and prints out file sizes. |
|
20 # |
|
21 # Run the script with option --help to see the parameters |
|
22 |
|
23 import os.path, fnmatch, re, subprocess, glob |
|
24 from optparse import OptionParser |
|
25 from itertools import chain |
|
26 |
|
27 RE_MMP_TARGET = re.compile(r"\s*TARGET\s+(\S+)", re.IGNORECASE) |
|
28 RE_DEFINE = re.compile(r"^define\s*(\S+)\s+(\S+)\s*$", re.IGNORECASE) |
|
29 RE_IBYTARGET = re.compile(r"^(?:file|data)=(\S+)\s+\S+\s*$", re.IGNORECASE) |
|
30 |
|
31 # Base defines used in IBY files |
|
32 BASE_DEFINES = [("ABI_DIR", r"\epoc32\release\armv5"), |
|
33 ("BUILD_DIR", r"urel"), |
|
34 ("DATAZ_", r"\epoc32\data\z"), |
|
35 ("RESOURCE_FILES_DIR", r"resource"), |
|
36 ("ZRESOURCE", r"DATAZ_\resource"), |
|
37 ("ZSYSTEM", r"DATAZ_\system"), |
|
38 ("ZPRIVATE", r"DATAZ_\private")] |
|
39 |
|
40 def flatten(listOfLists): |
|
41 return list(chain(*listOfLists)) |
|
42 |
|
43 def cppFile(source, cppDefines = None, include = None): |
|
44 ''' Preprocess source with epoc32/include, and return preprocessed lines ''' |
|
45 includePaths = [r"/epoc32/include"] |
|
46 |
|
47 if cppDefines: |
|
48 cppDefines = " ".join(["-D%s" % d for d in cppDefines]) |
|
49 else: |
|
50 cppDefines = "" |
|
51 if include: |
|
52 path, filename = os.path.split(include) |
|
53 includePaths.append(path) |
|
54 |
|
55 include = "-include " + include |
|
56 |
|
57 else: |
|
58 include = "" |
|
59 |
|
60 drive, tail = os.path.splitdrive(source) |
|
61 command = r'cpp %s %s %s "%s"' % (" ".join(["-I %s" % i for i in includePaths]), |
|
62 cppDefines, include, source) |
|
63 process = subprocess.Popen(command, |
|
64 shell = True, |
|
65 cwd = "%s\\" % drive, |
|
66 stdout = subprocess.PIPE) |
|
67 for line in process.stdout.readlines(): |
|
68 yield line |
|
69 |
|
70 def replaceDefines(line, defines): |
|
71 ''' Replace the macro definitions recursively ''' |
|
72 oldLine = None |
|
73 while oldLine != line: |
|
74 oldLine = line |
|
75 for search, replace in defines: |
|
76 line = line.replace(search, replace) |
|
77 return line |
|
78 |
|
79 def parseIby(lines): |
|
80 ''' Parse IBY file lines, using defines ''' |
|
81 defines = BASE_DEFINES[:] |
|
82 for l in lines: |
|
83 defineMatch = RE_DEFINE.match(l) |
|
84 if defineMatch: |
|
85 search, replace = defineMatch.groups() |
|
86 defines.append((search, replace)) |
|
87 else: |
|
88 yield replaceDefines(l, defines) |
|
89 |
|
90 def getIbySources(ibyfile, cppDefines = None, include = None): |
|
91 ''' Get IBY file source files''' |
|
92 drive, tail = os.path.splitdrive(ibyfile) |
|
93 for l in parseIby(cppFile(ibyfile, cppDefines, include)): |
|
94 match = RE_IBYTARGET.match(l) |
|
95 if match: |
|
96 yield drive + match.group(1) |
|
97 |
|
98 def findFiles(root, pattern): |
|
99 ''' Find files recursively ''' |
|
100 for path, dirs, files in os.walk(root): |
|
101 for f in fnmatch.filter(files, pattern): |
|
102 yield os.path.join(path, f) |
|
103 |
|
104 def getMmpTarget(mmpfile): |
|
105 ''' Get the target binary name from mmp-file ''' |
|
106 for l in open(mmpfile, "r").readlines(): |
|
107 match = RE_MMP_TARGET.search(l) |
|
108 if match: |
|
109 return match.group(1) |
|
110 return None |
|
111 |
|
112 def getMmpTargets(mmpRoot): |
|
113 ''' Get the target binary paths of all mmp-files found under root ''' |
|
114 drive, tail = os.path.splitdrive(mmpRoot) |
|
115 |
|
116 totalSize = 0 |
|
117 for mmp in findFiles(mmpRoot, "*.mmp"): |
|
118 target = getMmpTarget(mmp) |
|
119 if not target: |
|
120 continue |
|
121 binPath = drive + "/epoc32/release/armv5/urel/" + target |
|
122 if os.path.exists(binPath): |
|
123 yield binPath |
|
124 |
|
125 def getSizes(binaries): |
|
126 ''' Get the sizes of given files, return list of tuples (size|None, file) ''' |
|
127 for binPath in binaries: |
|
128 if not os.path.exists(binPath): |
|
129 yield None, binPath |
|
130 else: |
|
131 yield os.path.getsize(binPath), binPath |
|
132 |
|
133 def printSizes(sizes): |
|
134 ''' Print file sizes and a total ''' |
|
135 totalSize = 0 |
|
136 for size, binPath in sizes: |
|
137 if size: |
|
138 totalSize = totalSize + size |
|
139 |
|
140 print "%s\t%s" % (size, binPath) |
|
141 |
|
142 print "%d\tTotal" % totalSize |
|
143 |
|
144 def main(): |
|
145 parser = OptionParser() |
|
146 parser.add_option( |
|
147 "--mmproot", dest = "mmproot", |
|
148 help = "root for searching mmp-files (whose target is used for filenames)") |
|
149 parser.add_option( |
|
150 "--ibyfile", dest = "ibyfile", |
|
151 help = "ibyfile(s) which are processed to find out target file paths") |
|
152 parser.add_option( |
|
153 "--sortname", dest = "sortname", action = "store_true", default = False, |
|
154 help = "sort files by name") |
|
155 parser.add_option( |
|
156 "--sortsize", dest = "sortsize", action = "store_true", default = False, |
|
157 help = "sort files by size") |
|
158 parser.add_option( |
|
159 "--cppdefines", dest = "cppdefines", |
|
160 help = "cpp defines for iby, e.g. --cppdefines __JAVA,__JAVA_MIDP20") |
|
161 parser.add_option( |
|
162 "--include", dest = "include", |
|
163 help = "Include file for iby cpp, e.g. --include /epoc32/include/config/ncp52/bldpublic.hrh") |
|
164 (options, args) = parser.parse_args() |
|
165 |
|
166 if options.mmproot: |
|
167 binaries = getMmpTargets(options.mmproot) |
|
168 |
|
169 elif options.ibyfile: |
|
170 cppdefines = options.cppdefines and options.cppdefines.split(",") |
|
171 |
|
172 ibys = glob.glob(options.ibyfile) |
|
173 binaries = flatten([getIbySources(iby, cppdefines, options.include) |
|
174 for iby in ibys]) |
|
175 |
|
176 sizes = getSizes(binaries) |
|
177 |
|
178 if options.sortsize: |
|
179 sizes = sorted(sizes) |
|
180 if options.sortname: |
|
181 sizes = sorted(sizes, cmp=lambda x,y: cmp(x[1], y[1])) |
|
182 |
|
183 printSizes(sizes) |
|
184 |
|
185 if __name__ == "__main__": |
|
186 main() |