build/buildutils/armsize.py
changeset 87 1627c337e51e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/build/buildutils/armsize.py	Fri Oct 29 11:49:32 2010 +0300
@@ -0,0 +1,186 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of "Eclipse Public License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description: 
+#  This utility is used to find out the size in disk of files 
+#  written to ROM images (or compiled). Script finds out Symbian 
+#  build enviornment binary file paths based on iby-file(s) or 
+#  mmp-files, and prints out file sizes.
+#
+#  Run the script with option --help to see the parameters
+
+import os.path, fnmatch, re, subprocess, glob
+from optparse import OptionParser
+from itertools import chain
+
+RE_MMP_TARGET = re.compile(r"\s*TARGET\s+(\S+)", re.IGNORECASE)
+RE_DEFINE = re.compile(r"^define\s*(\S+)\s+(\S+)\s*$", re.IGNORECASE)
+RE_IBYTARGET = re.compile(r"^(?:file|data)=(\S+)\s+\S+\s*$", re.IGNORECASE)
+
+# Base defines used in IBY files
+BASE_DEFINES = [("ABI_DIR", r"\epoc32\release\armv5"),
+                ("BUILD_DIR", r"urel"),
+                ("DATAZ_", r"\epoc32\data\z"),
+                ("RESOURCE_FILES_DIR", r"resource"),
+                ("ZRESOURCE", r"DATAZ_\resource"),
+                ("ZSYSTEM", r"DATAZ_\system"),
+                ("ZPRIVATE", r"DATAZ_\private")]
+
+def flatten(listOfLists):
+    return list(chain(*listOfLists))
+
+def cppFile(source, cppDefines = None, include = None):
+    ''' Preprocess source with epoc32/include, and return preprocessed lines '''
+    includePaths = [r"/epoc32/include"]
+
+    if cppDefines:
+        cppDefines = " ".join(["-D%s" % d for d in cppDefines])
+    else:
+        cppDefines = ""
+    if include:
+        path, filename = os.path.split(include)
+        includePaths.append(path)
+
+        include = "-include " + include
+        
+    else:
+        include = ""
+
+    drive, tail = os.path.splitdrive(source)
+    command = r'cpp %s %s %s "%s"' % (" ".join(["-I %s" % i for i in includePaths]),
+                                      cppDefines, include, source)
+    process = subprocess.Popen(command, 
+                               shell = True,
+                               cwd = "%s\\" % drive,
+                               stdout = subprocess.PIPE)
+    for line in process.stdout.readlines():
+        yield line
+
+def replaceDefines(line, defines):
+    ''' Replace the macro definitions recursively '''
+    oldLine = None
+    while oldLine != line:
+        oldLine = line
+        for search, replace in defines:
+            line = line.replace(search, replace)
+    return line
+
+def parseIby(lines):
+    ''' Parse IBY file lines, using defines '''
+    defines = BASE_DEFINES[:]
+    for l in lines:
+        defineMatch = RE_DEFINE.match(l)
+        if defineMatch:
+            search, replace = defineMatch.groups()
+            defines.append((search, replace))
+        else:
+            yield replaceDefines(l, defines)
+            
+def getIbySources(ibyfile, cppDefines = None, include = None):
+    ''' Get IBY file source files'''
+    drive, tail = os.path.splitdrive(ibyfile)
+    for l in parseIby(cppFile(ibyfile, cppDefines, include)):
+        match = RE_IBYTARGET.match(l)
+        if match:
+            yield drive + match.group(1)
+
+def findFiles(root, pattern):
+    ''' Find files recursively '''
+    for path, dirs, files in os.walk(root):
+        for f in fnmatch.filter(files, pattern):
+            yield os.path.join(path, f)
+
+def getMmpTarget(mmpfile):
+    ''' Get the target binary name from mmp-file '''
+    for l in open(mmpfile, "r").readlines():
+        match = RE_MMP_TARGET.search(l)
+        if match:
+            return match.group(1)
+    return None
+
+def getMmpTargets(mmpRoot):
+    ''' Get the target binary paths of all mmp-files found under root '''
+    drive, tail = os.path.splitdrive(mmpRoot)
+
+    totalSize = 0
+    for mmp in findFiles(mmpRoot, "*.mmp"):
+        target = getMmpTarget(mmp)
+        if not target:
+            continue
+        binPath = drive + "/epoc32/release/armv5/urel/" + target
+        if os.path.exists(binPath):
+            yield binPath
+
+def getSizes(binaries):
+    ''' Get the sizes of given files, return list of tuples (size|None, file) '''
+    for binPath in binaries:
+        if not os.path.exists(binPath):
+            yield None, binPath
+        else:
+            yield os.path.getsize(binPath), binPath
+
+def printSizes(sizes):
+    ''' Print file sizes and a total '''
+    totalSize = 0
+    for size, binPath in sizes:
+        if size:
+            totalSize = totalSize + size
+
+        print "%s\t%s" % (size, binPath)
+
+    print "%d\tTotal" % totalSize
+
+def main():
+    parser = OptionParser()
+    parser.add_option(
+        "--mmproot", dest = "mmproot",
+        help = "root for searching mmp-files (whose target is used for filenames)")
+    parser.add_option(
+        "--ibyfile", dest = "ibyfile",
+        help = "ibyfile(s) which are processed to find out target file paths")
+    parser.add_option(
+        "--sortname", dest = "sortname", action = "store_true", default = False,
+        help = "sort files by name")
+    parser.add_option(
+        "--sortsize", dest = "sortsize", action = "store_true", default = False,
+        help = "sort files by size")
+    parser.add_option(
+        "--cppdefines", dest = "cppdefines",
+        help = "cpp defines for iby, e.g. --cppdefines __JAVA,__JAVA_MIDP20")
+    parser.add_option(
+        "--include", dest = "include",
+        help = "Include file for iby cpp, e.g. --include /epoc32/include/config/ncp52/bldpublic.hrh")
+    (options, args) = parser.parse_args()
+
+    if options.mmproot:
+        binaries = getMmpTargets(options.mmproot)
+
+    elif options.ibyfile:
+        cppdefines = options.cppdefines and options.cppdefines.split(",")
+
+        ibys = glob.glob(options.ibyfile)
+        binaries = flatten([getIbySources(iby, cppdefines, options.include) 
+                            for iby in ibys])
+        
+    sizes = getSizes(binaries)
+
+    if options.sortsize:
+        sizes = sorted(sizes)
+    if options.sortname:
+        sizes = sorted(sizes, cmp=lambda x,y: cmp(x[1], y[1]))
+
+    printSizes(sizes)
+
+if __name__ == "__main__":
+    main()