diff options
Diffstat (limited to 'Tools/Python')
-rwxr-xr-x | Tools/Python/Calc-Deps.py | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/Tools/Python/Calc-Deps.py b/Tools/Python/Calc-Deps.py new file mode 100755 index 0000000..a0afa3f --- /dev/null +++ b/Tools/Python/Calc-Deps.py @@ -0,0 +1,201 @@ +#!/usr/bin/env python + +"""Calculate the dependencies a given module has by looking through the source +code to see what guids and functions are referenced to see which Packages and +Library Classes need to be referenced. """ + +import os, sys, re, getopt, string, glob, xml.dom.minidom, pprint +from XmlRoutines import * + +# Map each function name back to the lib class that declares it. +function_table = {} + +# Map each guid name to a package name. +cname_table = {} + +def inWorkspace(rel_path): + """Treat the given path as relative to the workspace.""" + + # Make sure the user has set the workspace variable: + try: + return os.path.join(os.environ["WORKSPACE"], rel_path ) + except: + print "Oops! You must set the WORKSPACE environment variable to run this script." + sys.exit() + +def getIdentifiers(infiles): + + """Build a set of all the identifiers in this file.""" + + # Start with an empty set. + ids = set() + + for infile in infiles: + + # Open the file + f = open(infile) + + # Create some lexical categories that we will use to filter out + strings=re.compile('L?"[^"]*"') + chars=re.compile("'[^']*'") + hex=re.compile("0[Xx][0-9a-fA-F]*") + keywords = re.compile('for|do|while|if|else|break|int|unsigned|switch|volatile|goto|case|char|long|struct|return|extern') + common = re.compile('VOID|UINTN|UINT32|UINT8|UINT64') + + # Compile a Regular expression to grab all the identifers from the input. + identifier = re.compile('[_a-zA-Z][0-9_a-zA-Z]{3,}') + + for line in f.readlines(): + + # Filter some lexical categories out. + # for filter in [strings, chars, hex, keywords, common]: + for filter in [strings, chars, hex]: + line = re.sub(filter, '', line) + + # Add all the identifiers that we found on this line. + ids = ids.union(set(identifier.findall(line))) + + # Close the file + f.close() + + # Return the set of identifiers. + return ids + + +def search_classes(ids): + + """ Search the set of classes for functions.""" + + # Start with an empty set. + classes = set() + + for id in ids: + try: + # If it is not a "hit" in the table add it to the set. + classes.add(function_table[id]) + except: + # If it is not a "hit" in the table, ignore it. + pass + + return classes + +def search_cnames(ids): + + """Search all the Packages to see if this code uses a Guid from one of them. + Return a set of matching packages.""" + + packages = set() + + for id in ids: + try: + # If it is not a "hit" in the table add it to the set. + packages.add(cname_table[id]) + except: + # If it is not a "hit" in the table, ignore it. + pass + + return packages + +def getSpds(): + + """Open the database and get all the spd files out.""" + + # Open the database + database = xml.dom.minidom.parse(inWorkspace("Tools/Conf/FrameworkDatabase.db")) + + # Get a list of all the packages + for filename in XmlList(database, "/FrameworkDatabase/PackageList/Filename"): + spdFile = XmlElementData(filename) + + # Now open the spd file and build the database of guids. + getCNames(inWorkspace(spdFile)) + getLibClasses(inWorkspace(spdFile)) + +def getCNames(spdFile): + + """Extract all the C_Names from an spd file.""" + + # Begin to parse the XML of the .spd + spd = xml.dom.minidom.parse(spdFile) + + # Get the name of the package + packageName = XmlElement(spd, "PackageSurfaceArea/SpdHeader/PackageName") + + # Find the C_Name + for cname in XmlList(spd, "/PackageSurfaceArea/GuidDeclarations/Entry/C_Name") + \ + XmlList(spd, "/PackageSurfaceArea/PcdDeclarations/PcdEntry/C_Name") + \ + XmlList(spd, "/PackageSurfaceArea/PpiDeclarations/Entry/C_Name") + \ + XmlList(spd, "/PackageSurfaceArea/ProtocolDeclarations/Entry/C_Name"): + + # Get the text of the <C_Name> tag. + cname_text = XmlElementData(cname) + + # Map the <C_Name> to the <PackageName>. We will use this to lookup every + # identifier in the Input Code. + cname_table[cname_text] = packageName + + return + +def getLibClasses(spdFile): + + """Extract all the Lib Classes from an spd file.""" + + # Begin to parse the XML of the .spd + spd = xml.dom.minidom.parse(spdFile) + + # Get the guid of the package + packageGuid = XmlElement(spd, "/PackageSurfaceArea/SpdHeader/GuidValue") + + for libClass in XmlList(spd, "/PackageSurfaceArea/LibraryClassDeclarations/LibraryClass"): + className = XmlAttribute(libClass, "Name") + headerfile = XmlElementData(libClass.getElementsByTagName("IncludeHeader")[0]) + + packageRoot=os.path.dirname(spdFile) + + headerfile = os.path.join(packageRoot, headerfile) + + f = open(headerfile) + + # This pattern can pick out function names if the EFI coding + # standard is followed. We could also use dumpbin on library + # instances to get a list of symbols. + functionPattern = re.compile("([_a-zA-Z][_a-zA-Z0-9]*) *\( *"); + + for line in f.readlines(): + m = functionPattern.match(line) + if m: + functionName = m.group(1) + # Map it! + function_table[functionName] = (className, packageGuid) + + f.close() + +def guid(strVal): + """Make a guid number out of a guid hex string.""" + return long(strVal.replace('-',''), 16) + +# This acts like the main() function for the script, unless it is 'import'ed into another +# script. +if __name__ == '__main__': + + # Create a pretty printer for dumping data structures in a readable form. + pp = pprint.PrettyPrinter(indent=2) + + # Process the command line args. + optlist, args = getopt.getopt(sys.argv[1:], 'h', [ 'example-long-arg=', 'testing']) + + """You should pass a file name as a paramter. It should be preprocessed text +of all the .c and .h files in your module, which is cat'ed together into one +large file.""" + + # Scrape out all the things that look like identifiers. + ids = getIdentifiers(args) + + # Read in the spds from the workspace to find the Guids. + getSpds() + + # Debug stuff. + print pp.pprint(function_table) + print pp.pprint(cname_table) + print "Classes = ", pp.pprint(list(search_classes(ids))) + print "C_Names = ", pp.pprint(list(search_cnames(ids))) |