前面提到过在编写UEFI 程序的时候不可避免的需要引用PROTOCOL 等等的 GUID。最近在网上看到了一个Python 编写的工具,作者是Xiang Lian【参考1】,可以将项目中定义的 GUID都提取到一个文件中个,这样便于查找和使用。我实验了一下,挺好用的推荐给大家。
#!/c:\python27\python.exe # # Filename: guidxref.py # Written: Xiang Lian # # # This python script scans through UDK2010 build tree and saves all GUID definitions into # an output file. Refer list TargetFileTypes for currently suported source file types. # #------------------------------------------------------------------------------------------------- # # Rev history: rev 1.0 10/07/2012 # - Guid_In_h had missed some lower-cased GUIDs; # # rev 1.1 10/07/2012 # - Added captured groups in Guid_In_h, refer RegFormatOutput; # # rev 1.2 10/08/2012 # - Swapped content in output line so that GUID strings always come first # # rev 1.5 10/08/2012 # - Simplified os.walk logic to significantly reduce the redundant scans # - Added summary to report total number of files scanned by type # # rev 1.6 10/08/2012 # - Added logging module, to turn on logging output: # . Uncomment the logging.basicConfig line # . Choose level in basicConfig # - Always save result into a newly create output file # # rev 2.0 10/09/2012 # - Created function NormalizeGuidString to replace the buggy RegFormatOutput pattern. # Now all output GUIDs have a fixed length and are made uppercase # # rev 2.2 10/11/2012 # - Added list ExcludedDirs which folders will not be scanned # - Added lambda function toU to conver registry format GUIDs to uppercase # - Output filenames are now including timestamp strings # - Logging filenames are always saved into a newly created file (suffixed with seq#) # # rev 3.0 10/11/2012 # - Added filter to remove some invalid lines in the output # - Output lines are sorted and all duplicates removed # # rev 3.1 10/19/2012 # - Collected all user customizable values/configs into class UserConfig # - Minor adjustment on summary output # # rev 3.2 10/25/2012 # - Modified Guid_In_h pattern to match wider range of GUID formats (in EDK) # # rev 3.3 10/30/2012 # - Defined VimScriptMode switch to output result in vim script format # # rev 3.4 10/31/2012 # - Added .c into the scan file list (TargetFileTypes) # - Added (?i) in Guid_In_h: This makes the entire pattern case in-sensitive # - Resolved lines like: EFI_GUID PciIoProtocolInstallEventGuid = {...}; # - Resolved lines containing tabs # - No more year info in result file name # # rev 3.5 10/31/2012 # - Added NormalizedGuidLine for final validity check # # # # # # # Cases currently cannot be handled: # # EFI_GUID gEfiUsbKeyboardDriverGuid = { # 0xa05f5f78, 0xfb3, 0x4d10, 0x90, 0x90, 0xac, 0x4, 0x6e, 0xeb, 0x7c, 0x3c # }; # #---------------------------------------------------------------------------------------------------- # import os, re, string, sys import logging import datetime # # Global variables # class UserConfig: """ This class defines a set of constants and configurations which can be customized by the script user. """ ScriptRev = " Ver 3.5" # To generate logging output, change this to 1 LoggingEnable = 0 # Set this to 1 to generate the result file in vim script format VimScriptMode = 0 # The maximum character width of the console output line MAXLINEWIDTH = 110 # This list provides all the file types to be scanned TargetFileTypes = {'.h' : 0, '.dec' : 0, '.inf' : 0, '.dsc' : 0, '.c' : 0} # Directories to be excluded from the scan ExcludedDirs = ('.svn', 'Build', 'uefi64native') # Base file name for result file BaseOutputName = "guidxref_" # Base file name for logging output BaseLogName = ".\debug" # This defines the continuation character at end of line ContinuingEol = "\\\n" # Define directive in GUID definition (usually in .h and .c files) DefineDirective = "#define" # Header part of the GUID definition line (usually in INF or DSC files) RegGuidDef = "^.*\=\s*" #note: "^\(.*\)\=\s*" doesn't work! # GUID Definitive format - Below pattern matches lines like: # { 0xbf9d5465, 0x4fc3, 0x4021, {0x92, 0x5, 0xfa, 0x5d, 0x3f, 0xe2, 0xa5, 0x95}} Guid_In_h = "(?i)\{\s*\ 0x([0-9a-f]+),\s*\ 0x([0-9a-f]+),\s*\ 0x([0-9a-f]+),\s*{?\s*\ 0x([0-9a-f]+),\s*\ 0x([0-9a-f]+),\s*\ 0x([0-9a-f]+),\s*\ 0x([0-9a-f]+),\s*\ 0x([0-9a-f]+),\s*\ 0x([0-9a-f]+),\s*\ 0x([0-9a-f]+),\s*\ 0x([0-9a-f]+)\s*}?\s*\}.*" #This is buggy, has already been replaced by NormalizeGuidString2 RegFormatOutput = r"\1-\2-\3-\4\5-\6\7\8\9\10\11" # Note: have to add prefix 'r' to make it raw here # GUID Registry format - Below pattern matches lines like: FILE_GUID = A5102DBA-C528-47bd-A992-A2906ED0D22B Guid_In_Inf = "[0-9a-fA-F]+-[0-9a-fA-F]+-[0-9a-fA-F]+-[0-9a-fA-F]+-[0-9a-fA-F]+" # Normalized GUID lines like: A5102DBA-C528-47bd-A992-A2906ED0D22B xxxx NormalizedGuidLine = r"[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12} [^#]+" #################################### Functions Definition ################################################# def NormalizeGuidString (matchobj): """ Definitive format GUID string normalization - Prefixing with 0s for every captured group Parameter matchobj is a MatchObject instance which contains one or more subgroups of the pattern match done by the re.sub() method. It's same as the return object of re.search(). """ hex = [""] for i in range (1, 12): hex.append(matchobj.group(i)) hex[1] = format (int(hex[1], 16), '08x').upper() hex[2] = format (int(hex[2], 16), '04x').upper() hex[3] = format (int(hex[3], 16), '04x').upper() hex[4] = format (int(hex[4], 16), '02x').upper() hex[5] = format (int(hex[5], 16), '02x').upper() hex[6] = format (int(hex[6], 16), '02x').upper() hex[7] = format (int(hex[7], 16), '02x').upper() hex[8] = format (int(hex[8], 16), '02x').upper() hex[9] = format (int(hex[9], 16), '02x').upper() hex[10] = format (int(hex[10], 16), '02x').upper() hex[11] = format (int(hex[11], 16), '02x').upper() return hex[1]+'-'+hex[2]+'-'+hex[3]+'-'+hex[4]+hex[5]+'-'+hex[6]+hex[7]+hex[8]+hex[9]+hex[10]+hex[11] def SearchGuidsFromList (SrcList, filename): """ This function searchs for GUID definitions from a given string list. """ GuidLines = [] for n,line in enumerate(SrcList): while line.endswith(ContinuingEol): line = line.rstrip(ContinuingEol) #this doesnt work?? line = re.sub("\\\n", "", line) MergeLine = [line, SrcList[n+1]] line = "".join(MergeLine) # This converts a list to a string del SrcList[n+1] #logging.debug (" Merged line #%d, %s", n, line) # Now start searching for GUID pattern # Process .inf and .dsc files match = re.search(Guid_In_Inf, line, re.IGNORECASE | re.MULTILINE) if match: logging.debug ("Found a registry format GUID") line = re.sub(RegGuidDef, filename + " ", line) # Trim out useless part line = re.sub(Guid_In_Inf, lambda toU: toU.group().upper(), line) # Convert GUID to uppercase #str = raw_input ("................................................. Press ENTER key to continue:") line = line.lstrip() line = re.sub("\A(.*?)\s+(.*)", r"\2 \1", line) # Swap it. lx-'\A' and '?' are both important GuidLines.append(line) # Process .h and .dec files match = re.search(Guid_In_h, line, re.IGNORECASE | re.MULTILINE) if match: logging.debug ("Found a definitive GUID") line = re.sub(DefineDirective, "", line) # Trim out useless part line = re.sub(Guid_In_h, NormalizeGuidString, line) # Convert to registry format #str = raw_input ("................................................. Press ENTER key to continue:") line = re.sub(r"\A(.*?)EFI_GUID\s+", "", line) # Trim EFI_GUID line = line.lstrip() line = re.sub("\A(.*?)[ =\t]+(.*)", r"\2 \1", line) # Swap it. lx-'\A' and '?' are both important GuidLines.append(line) return GuidLines def main(): # Configure the logging module to send debug messages to file # # Refer: # logging.debug (msg, *args) # logging.info (msg, *args) # logging.warning (msg, *args) # logging.error (msg, *args) # logging.critical (msg, *args) # logging.setLevel (level) # logging.disable (level) # # Valid values to set for level (by severity) in basicConfig are: NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL # #full format: logging.basicConfig(level=logging.DEBUG, filename='debug.log', format='%(asctime)s %(levelname)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S') if UserConfig.LoggingEnable: for seq in range (0, 99): LogFileName = UserConfig.BaseLogName + format (seq, '02d') + ".log" if not os.path.exists(LogFileName): break seq += 1 logging.basicConfig(level=logging.DEBUG, filename=LogFileName, format='%(levelname)s: %(message)s') # Ensure input parameter is valid if len(sys.argv) < 2: print "Usage - ", sys.argv[0], " <Directory>\n" exit(0) RootDir = sys.argv[1] if (os.path.exists(RootDir) == False): print "Invalid directory name, please try again!" exit(1) # Determine output file now = datetime.datetime.now() ##suffix = now.strftime ("%Y_%m_%d_%H_%M_%S") suffix = now.strftime ("%m_%d_%H_%M_%S") if UserConfig.VimScriptMode == 0: ofile = open(UserConfig.BaseOutputName + suffix + ".txt", "w") # Print header message ofile.write("Generated by " + sys.argv[0] + UserConfig.ScriptRev + "\n") ofile.write("=" * 40 + "\n\n") else: ofile = open(UserConfig.BaseOutputName + suffix + ".vim", "w") # Print header option settings ofile.write(":set mm=2000000\n") ofile.write(":set undolevels=-1\n") # Traverse the root directory path for required source files TotalGuids = 0 TempBuffer = [] for root, dirs, files in os.walk(RootDir): # Check directories to be excluded from the scan for folder in UserConfig.ExcludedDirs: if folder in dirs: dirs.remove(folder) logging.debug (' root = %s', root) #logging.debug (' dirs = %s', dirs) #for file in files: #logging.debug (' file = %s', file) for file in files: for type in UserConfig.TargetFileTypes.keys(): if file.endswith(type): logging.info ("Found needed files = %s\\%s", root, file) UserConfig.TargetFileTypes[type] += 1 # Scan the file for GUID strings try: fullpath = os.path.join(root, "".join(file)) ifile = open(fullpath, "r") except: print folder, "\\", file, " could not be opened, abort!" sys.exit(2) logging.debug ('Opening source file ........%s', fullpath) AllLines = ifile.readlines() GuidList = SearchGuidsFromList (AllLines, "".join(file)) if (len(GuidList) > 0): OutputLineWidth = UserConfig.MAXLINEWIDTH - len(fullpath) print fullpath, "." * OutputLineWidth, len(GuidList) for line in GuidList: # Remove some invalid lines if not re.search (r"\/\/$", line, re.MULTILINE): #lx: "\Z" and "\z" don't work. ?? TempBuffer.append(line) ifile.close() # Remove duplicates from the list # # [Python.docs] A set object is an **unordered** collection of distinct hashable objects. Common uses # include membership testing, removing duplicates from a sequence, and computing mathematical operations # such as intersection, union, difference, and symmetric difference. # TempBuffer = list(set(TempBuffer)) # Now sort the list # # [Python.docs] sorted (iterable [, key][, reverse]) # # key - specifies a function of one argument that is used to extract a comparison key from # each list element: key=str.lower. The default value is None (compare the elements directly) # reverse - a boolean value. If set to True, the list elements are sorted as if each comparison # were reversed. # TempBuffer = sorted(TempBuffer) for line in TempBuffer: if re.match(NormalizedGuidLine, line): # # Ideally we don't need to add this extra validity check on each processed line. However there # are always some corner cases or various special cases which cannot be well handled by current # code logic. These filtered lines here can later be investigated when I have spare time. # TotalGuids += 1 if UserConfig.VimScriptMode: line = re.sub(r"\A([^ ]*) (.*)$", r":%s/\1/\2/e", line) ofile.write(line) else: #lx-Adding following lines will unexpectedly remove the next line as well, why? #TempBuffer.remove(line) print "Invalid line: ", line ofile.close() # Print summary print "\n", "-" * 50, "Summary", "-" * 55 for type in UserConfig.TargetFileTypes.keys(): print "Scanned ", format (UserConfig.TargetFileTypes[type], '04d'), format (type, "4s"), " files" print "\nTotal number of GUIDs found: ", TotalGuids # # Why do we need this? # A .py file can be interpreted by Python as either standalone program to execute directly, # or a module to be imported into other .py files. # 1) Standalone program - __name__ equals to "__main__"; # 2) imported as a module - __name__ equals to something else, therefore contents behind # the if statement won't get executed. # if __name__ == "__main__": main()
下载:
参考:
1. https://github.com/simonlian/guidref/blob/master/guidxref.py