## @file # # This file produce action class to generate doxygen document for edk2 codebase. # The action classes are shared by GUI and command line tools. # # Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
# # SPDX-License-Identifier: BSD-2-Clause-Patent from plugins.EdkPlugins.basemodel import doxygen import os try: import wx gInGui = True except: gInGui = False import re from plugins.EdkPlugins.edk2.model import inf from plugins.EdkPlugins.edk2.model import dec from plugins.EdkPlugins.basemodel.message import * _ignore_dir = ['.svn', '_svn', 'cvs'] _inf_key_description_mapping_table = { 'INF_VERSION':'Version of INF file specification', #'BASE_NAME':'Module Name', 'FILE_GUID':'Module Guid', 'MODULE_TYPE': 'Module Type', 'VERSION_STRING': 'Module Version', 'LIBRARY_CLASS': 'Produced Library Class', 'EFI_SPECIFICATION_VERSION': 'UEFI Specification Version', 'PI_SPECIFICATION_VERSION': 'PI Specification Version', 'ENTRY_POINT': 'Module Entry Point Function', 'CONSTRUCTOR': 'Library Constructor Function' } _dec_key_description_mapping_table = { 'DEC_SPECIFICATION': 'Version of DEC file specification', 'PACKAGE_GUID': 'Package Guid' } class DoxygenAction: """This is base class for all doxygen action. """ def __init__(self, doxPath, chmPath, outputPath, projname, mode='html', log=None, verbose=False): """Constructor function. @param doxPath the obosolution path of doxygen execute file. @param outputPath the obosolution output path. @param log log function for output message """ self._doxPath = doxPath self._chmPath = chmPath self._outputPath = outputPath self._projname = projname self._configFile = None # doxygen config file is used by doxygen exe file self._indexPageFile = None # doxygen page file for index page. self._log = log self._mode = mode self._verbose = verbose self._doxygenCallback = None self._chmCallback = None def Log(self, message, level='info'): if self._log is not None: self._log(message, level) def IsVerbose(self): return self._verbose def Generate(self): """Generate interface called by outer directly""" self.Log(">>>>>> Start generate doxygen document for %s... Zzz....\n" % self._projname) # create doxygen config file at first self._configFile = doxygen.DoxygenConfigFile() self._configFile.SetOutputDir(self._outputPath) self._configFile.SetWarningFilePath(os.path.join(self._outputPath, 'warning.txt')) if self._mode.lower() == 'html': self._configFile.SetHtmlMode() else: self._configFile.SetChmMode() self.Log(" >>>>>> Initialize doxygen config file...Zzz...\n") self.InitializeConfigFile() self.Log(" >>>>>> Generate doxygen index page file...Zzz...\n") indexPagePath = self.GenerateIndexPage() if indexPagePath is None: self.Log("Fail to generate index page!\n", 'error') return False else: self.Log("Success to create doxygen index page file %s \n" % indexPagePath) # Add index page doxygen file to file list. self._configFile.AddFile(indexPagePath) # save config file to output path configFilePath = os.path.join(self._outputPath, self._projname + '.doxygen_config') self._configFile.Generate(configFilePath) self.Log(" <<<<<< Success Save doxygen config file to %s...\n" % configFilePath) # launch doxygen tool to generate document if self._doxygenCallback is not None: self.Log(" >>>>>> Start doxygen process...Zzz...\n") if not self._doxygenCallback(self._doxPath, configFilePath): return False else: self.Log("Fail to create doxygen process!", 'error') return False return True def InitializeConfigFile(self): """Initialize config setting for doxygen project. It will be invoked after config file object is created. Inherited class should implement it. """ def GenerateIndexPage(self): """Generate doxygen index page. Inherited class should implement it.""" return None def RegisterCallbackDoxygenProcess(self, callback): self._doxygenCallback = callback def RegisterCallbackCHMProcess(self, callback): self._chmCallback = callback class PlatformDocumentAction(DoxygenAction): """Generate platform doxygen document, will be implement at future.""" class PackageDocumentAction(DoxygenAction): """Generate package reference document""" def __init__(self, doxPath, chmPath, outputPath, pObj, mode='html', log=None, arch=None, tooltag=None, macros=[], onlyInclude=False, verbose=False): DoxygenAction.__init__(self, doxPath, chmPath, outputPath, pObj.GetName(), mode, log, verbose) self._pObj = pObj self._arch = arch self._tooltag = tooltag self._macros = macros self._onlyIncludeDocument = onlyInclude def InitializeConfigFile(self): if self._arch == 'IA32': self._configFile.AddPreDefined('MDE_CPU_IA32') elif self._arch == 'X64': self._configFile.AddPreDefined('MDE_CPU_X64') elif self._arch == 'IPF': self._configFile.AddPreDefined('MDE_CPU_IPF') elif self._arch == 'EBC': self._configFile.AddPreDefined('MDE_CPU_EBC') else: self._arch = None self._configFile.AddPreDefined('MDE_CPU_IA32') self._configFile.AddPreDefined('MDE_CPU_X64') self._configFile.AddPreDefined('MDE_CPU_IPF') self._configFile.AddPreDefined('MDE_CPU_EBC') self._configFile.AddPreDefined('MDE_CPU_ARM') for macro in self._macros: self._configFile.AddPreDefined(macro) namestr = self._pObj.GetName() if self._arch is not None: namestr += '[%s]' % self._arch if self._tooltag is not None: namestr += '[%s]' % self._tooltag self._configFile.SetProjectName(namestr) self._configFile.SetStripPath(self._pObj.GetWorkspace()) self._configFile.SetProjectVersion(self._pObj.GetFileObj().GetVersion()) self._configFile.AddPattern('*.decdoxygen') if self._tooltag.lower() == 'msft': self._configFile.AddPreDefined('_MSC_EXTENSIONS') elif self._tooltag.lower() == 'gnu': self._configFile.AddPreDefined('__GNUC__') elif self._tooltag.lower() == 'intel': self._configFile.AddPreDefined('__INTEL_COMPILER') else: self._tooltag = None self._configFile.AddPreDefined('_MSC_EXTENSIONS') self._configFile.AddPreDefined('__GNUC__') self._configFile.AddPreDefined('__INTEL_COMPILER') self._configFile.AddPreDefined('ASM_PFX= ') self._configFile.AddPreDefined('OPTIONAL= ') def GenerateIndexPage(self): """Generate doxygen index page. Inherited class should implement it.""" fObj = self._pObj.GetFileObj() pdObj = doxygen.DoxygenFile('%s Package Document' % self._pObj.GetName(), '%s.decdoxygen' % self._pObj.GetFilename()) self._configFile.AddFile(pdObj.GetFilename()) pdObj.AddDescription(fObj.GetFileHeader()) defSection = fObj.GetSectionByName('defines')[0] baseSection = doxygen.Section('PackageBasicInformation', 'Package Basic Information') descr = '' for obj in defSection.GetObjects(): if obj.GetKey() in _dec_key_description_mapping_table.keys(): descr += '' descr += '' % _dec_key_description_mapping_table[obj.GetKey()] descr += '' % obj.GetValue() descr += '' descr += '
%s%s

' baseSection.AddDescription(descr) pdObj.AddSection(baseSection) knownIssueSection = doxygen.Section('Known_Issue_section', 'Known Issue') knownIssueSection.AddDescription('') pdObj.AddSection(knownIssueSection) self.AddAllIncludeFiles(self._pObj, self._configFile) pages = self.GenerateIncludesSubPage(self._pObj, self._configFile) if len(pages) != 0: pdObj.AddPages(pages) pages = self.GenerateLibraryClassesSubPage(self._pObj, self._configFile) if len(pages) != 0: pdObj.AddPages(pages) pages = self.GeneratePcdSubPages(self._pObj, self._configFile) if len(pages) != 0: pdObj.AddPages(pages) pages = self.GenerateGuidSubPages(self._pObj, self._configFile) if len(pages) != 0: pdObj.AddPages(pages) pages = self.GeneratePpiSubPages(self._pObj, self._configFile) if len(pages) != 0: pdObj.AddPages(pages) pages = self.GenerateProtocolSubPages(self._pObj, self._configFile) if len(pages) != 0: pdObj.AddPages(pages) if not self._onlyIncludeDocument: pdObj.AddPages(self.GenerateModulePages(self._pObj, self._configFile)) pdObj.Save() return pdObj.GetFilename() def GenerateIncludesSubPage(self, pObj, configFile): # by default add following path as include path to config file pkpath = pObj.GetFileObj().GetPackageRootPath() configFile.AddIncludePath(os.path.join(pkpath, 'Include')) configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Library')) configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Protocol')) configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Ppi')) configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Guid')) configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'IndustryStandard')) rootArray = [] pageRoot = doxygen.Page("Public Includes", "%s_public_includes" % pObj.GetName()) objs = pObj.GetFileObj().GetSectionObjectsByName('includes') if len(objs) == 0: return [] for obj in objs: # Add path to include path path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetPath()) configFile.AddIncludePath(path) # only list common folder's include file if obj.GetArch().lower() != 'common': continue bNeedAddIncludePage = False topPage = doxygen.Page(self._ConvertPathToDoxygen(path, pObj), 'public_include_top') topPage.AddDescription('\n') if bNeedAddIncludePage: pageRoot.AddPage(topPage) if pageRoot.GetSubpageCount() != 0: return [pageRoot] else: return [] def GenerateLibraryClassesSubPage(self, pObj, configFile): """ Generate sub page for library class for package. One DEC file maybe contains many library class sections for different architecture. @param fObj DEC file object. """ rootArray = [] pageRoot = doxygen.Page("Library Class", "%s_libraryclass" % pObj.GetName()) objs = pObj.GetFileObj().GetSectionObjectsByName('libraryclass', self._arch) if len(objs) == 0: return [] if self._arch is not None: for obj in objs: classPage = doxygen.Page(obj.GetClassName(), "lc_%s" % obj.GetClassName()) comments = obj.GetComment() if len(comments) != 0: classPage.AddDescription('
\n'.join(comments) + '
\n') pageRoot.AddPage(classPage) path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile()) path = path[len(pObj.GetWorkspace()) + 1:] if len(comments) == 0: classPage.AddDescription('\copydoc %s

' % obj.GetHeaderFile()) section = doxygen.Section('ref', 'Refer to Header File') section.AddDescription('\link %s\n' % obj.GetHeaderFile()) section.AddDescription(' \endlink

\n') classPage.AddSection(section) fullPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile()) self.ProcessSourceFileForInclude(fullPath, pObj, configFile) else: archPageDict = {} for obj in objs: if obj.GetArch() not in archPageDict.keys(): archPageDict[obj.GetArch()] = doxygen.Page(obj.GetArch(), 'lc_%s' % obj.GetArch()) pageRoot.AddPage(archPageDict[obj.GetArch()]) subArchRoot = archPageDict[obj.GetArch()] classPage = doxygen.Page(obj.GetClassName(), "lc_%s" % obj.GetClassName()) comments = obj.GetComment() if len(comments) != 0: classPage.AddDescription('
\n'.join(comments) + '
\n') subArchRoot.AddPage(classPage) path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile()) path = path[len(pObj.GetWorkspace()) + 1:] if len(comments) == 0: classPage.AddDescription('\copydoc %s

' % obj.GetHeaderFile()) section = doxygen.Section('ref', 'Refer to Header File') section.AddDescription('\link %s\n' % obj.GetHeaderFile()) section.AddDescription(' \endlink

\n') classPage.AddSection(section) fullPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile()) self.ProcessSourceFileForInclude(fullPath, pObj, configFile) rootArray.append(pageRoot) return rootArray def ProcessSourceFileForInclude(self, path, pObj, configFile, infObj=None): """ @param path the analysising file full path @param pObj package object @param configFile doxygen config file. """ if gInGui: wx.Yield() if not os.path.exists(path): ErrorMsg('Source file path %s does not exist!' % path) return if configFile.FileExists(path): return try: f = open(path, 'r') lines = f.readlines() f.close() except IOError: ErrorMsg('Fail to open file %s' % path) return configFile.AddFile(path) return no = 0 for no in range(len(lines)): if len(lines[no].strip()) == 0: continue if lines[no].strip()[:2] in ['##', '//', '/*', '*/']: continue index = lines[no].lower().find('include') #mo = IncludePattern.finditer(lines[no].lower()) mo = re.match(r"^#\s*include\s+[<\"]([\\/\w.]+)[>\"]$", lines[no].strip().lower()) if not mo: continue mo = re.match(r"^[#\w\s]+[<\"]([\\/\w.]+)[>\"]$", lines[no].strip()) filePath = mo.groups()[0] if filePath is None or len(filePath) == 0: continue # find header file in module's path firstly. fullPath = None if os.path.exists(os.path.join(os.path.dirname(path), filePath)): # Find the file in current directory fullPath = os.path.join(os.path.dirname(path), filePath).replace('\\', '/') else: # find in depedent package's include path incObjs = pObj.GetFileObj().GetSectionObjectsByName('includes') for incObj in incObjs: incPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), incObj.GetPath()).strip() incPath = os.path.realpath(os.path.join(incPath, filePath)) if os.path.exists(incPath): fullPath = incPath break if infObj is not None: pkgInfObjs = infObj.GetSectionObjectsByName('packages') for obj in pkgInfObjs: decObj = dec.DECFile(os.path.join(pObj.GetWorkspace(), obj.GetPath())) if not decObj: ErrorMsg ('Fail to create pacakge object for %s' % obj.GetPackageName()) continue if not decObj.Parse(): ErrorMsg ('Fail to load package object for %s' % obj.GetPackageName()) continue incObjs = decObj.GetSectionObjectsByName('includes') for incObj in incObjs: incPath = os.path.join(decObj.GetPackageRootPath(), incObj.GetPath()).replace('\\', '/') if os.path.exists(os.path.join(incPath, filePath)): fullPath = os.path.join(os.path.join(incPath, filePath)) break if fullPath is not None: break if fullPath is None and self.IsVerbose(): self.Log('Can not resolve header file %s for file %s in package %s\n' % (filePath, path, pObj.GetFileObj().GetFilename()), 'error') return else: fullPath = fullPath.replace('\\', '/') if self.IsVerbose(): self.Log('Preprocessing: Add include file %s for file %s\n' % (fullPath, path)) #LogMsg ('Preprocessing: Add include file %s for file %s' % (fullPath, path)) self.ProcessSourceFileForInclude(fullPath, pObj, configFile, infObj) def AddAllIncludeFiles(self, pObj, configFile): objs = pObj.GetFileObj().GetSectionObjectsByName('includes') for obj in objs: incPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetPath()) for root, dirs, files in os.walk(incPath): for dir in dirs: if dir.lower() in _ignore_dir: dirs.remove(dir) for file in files: path = os.path.normpath(os.path.join(root, file)) configFile.AddFile(path.replace('/', '\\')) def GeneratePcdSubPages(self, pObj, configFile): """ Generate sub pages for package's PCD definition. @param pObj package object @param configFile config file object """ rootArray = [] objs = pObj.GetFileObj().GetSectionObjectsByName('pcd') if len(objs) == 0: return [] pcdRootPage = doxygen.Page('PCD', 'pcd_root_page') typeRootPageDict = {} typeArchRootPageDict = {} for obj in objs: if obj.GetPcdType() not in typeRootPageDict.keys(): typeRootPageDict[obj.GetPcdType()] = doxygen.Page(obj.GetPcdType(), 'pcd_%s_root_page' % obj.GetPcdType()) pcdRootPage.AddPage(typeRootPageDict[obj.GetPcdType()]) typeRoot = typeRootPageDict[obj.GetPcdType()] if self._arch is not None: pcdPage = doxygen.Page('%s' % obj.GetPcdName(), 'pcd_%s_%s_%s' % (obj.GetPcdType(), obj.GetArch(), obj.GetPcdName().split('.')[1])) pcdPage.AddDescription('
\n'.join(obj.GetComment()) + '
\n') section = doxygen.Section('PCDinformation', 'PCD Information') desc = '' desc += '' desc += '' desc += '' desc += '' desc += '' desc += '' desc += '' desc += '' desc += '' % obj.GetPcdName().split('.')[1] desc += '' % obj.GetPcdName().split('.')[0] desc += '' % obj.GetPcdToken() desc += '' % obj.GetPcdDataType() desc += '' % obj.GetPcdValue() desc += '' desc += '
Name
Token Space
Token number
Data Type
Default Value
%s
%s
%s
%s
%s
' section.AddDescription(desc) pcdPage.AddSection(section) typeRoot.AddPage(pcdPage) else: keystr = obj.GetPcdType() + obj.GetArch() if keystr not in typeArchRootPageDict.keys(): typeArchRootPage = doxygen.Page(obj.GetArch(), 'pcd_%s_%s_root_page' % (obj.GetPcdType(), obj.GetArch())) typeArchRootPageDict[keystr] = typeArchRootPage typeRoot.AddPage(typeArchRootPage) typeArchRoot = typeArchRootPageDict[keystr] pcdPage = doxygen.Page('%s' % obj.GetPcdName(), 'pcd_%s_%s_%s' % (obj.GetPcdType(), obj.GetArch(), obj.GetPcdName().split('.')[1])) pcdPage.AddDescription('
\n'.join(obj.GetComment()) + '
\n') section = doxygen.Section('PCDinformation', 'PCD Information') desc = '' desc += '' desc += '' desc += '' desc += '' desc += '' desc += '' desc += '' desc += '' desc += '' % obj.GetPcdName().split('.')[1] desc += '' % obj.GetPcdName().split('.')[0] desc += '' % obj.GetPcdToken() desc += '' % obj.GetPcdDataType() desc += '' % obj.GetPcdValue() desc += '' desc += '
Name
Token Space
Token number
Data Type
Default Value
%s
%s
%s
%s
%s
' section.AddDescription(desc) pcdPage.AddSection(section) typeArchRoot.AddPage(pcdPage) return [pcdRootPage] def _GenerateGuidSubPage(self, pObj, obj, configFile): guidPage = doxygen.Page('%s' % obj.GetName(), 'guid_%s_%s' % (obj.GetArch(), obj.GetName())) comments = obj.GetComment() if len(comments) != 0: guidPage.AddDescription('
'.join(obj.GetComment()) + '
') section = doxygen.Section('BasicGuidInfo', 'GUID Information') desc = '' desc += '' desc += '' desc += '' desc += '' desc += '' % obj.GetName() desc += '' % obj.GetGuid() desc += '' desc += '
GUID\'s Guid Name
GUID\'s Guid
%s%s
' section.AddDescription(desc) guidPage.AddSection(section) refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile) if refFile: relPath = refFile[len(pObj.GetWorkspace()) + 1:] if len(comments) == 0: guidPage.AddDescription(' \\copydoc %s
' % relPath) section = doxygen.Section('ref', 'Refer to Header File') section.AddDescription('\link %s\n' % relPath) section.AddDescription('\endlink\n') self.ProcessSourceFileForInclude(refFile, pObj, configFile) guidPage.AddSection(section) return guidPage def GenerateGuidSubPages(self, pObj, configFile): """ Generate sub pages for package's GUID definition. @param pObj package object @param configFilf doxygen config file object """ pageRoot = doxygen.Page('GUID', 'guid_root_page') objs = pObj.GetFileObj().GetSectionObjectsByName('guids', self._arch) if len(objs) == 0: return [] if self._arch is not None: for obj in objs: pageRoot.AddPage(self._GenerateGuidSubPage(pObj, obj, configFile)) else: guidArchRootPageDict = {} for obj in objs: if obj.GetArch() not in guidArchRootPageDict.keys(): guidArchRoot = doxygen.Page(obj.GetArch(), 'guid_arch_root_%s' % obj.GetArch()) pageRoot.AddPage(guidArchRoot) guidArchRootPageDict[obj.GetArch()] = guidArchRoot guidArchRoot = guidArchRootPageDict[obj.GetArch()] guidArchRoot.AddPage(self._GenerateGuidSubPage(pObj, obj, configFile)) return [pageRoot] def _GeneratePpiSubPage(self, pObj, obj, configFile): guidPage = doxygen.Page(obj.GetName(), 'ppi_page_%s' % obj.GetName()) comments = obj.GetComment() if len(comments) != 0: guidPage.AddDescription('
'.join(obj.GetComment()) + '
') section = doxygen.Section('BasicPpiInfo', 'PPI Information') desc = '' desc += '' desc += '' desc += '' desc += '' desc += '' % obj.GetName() desc += '' % obj.GetGuid() desc += '' desc += '
PPI\'s Guid Name
PPI\'s Guid
%s%s
' section.AddDescription(desc) guidPage.AddSection(section) refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile) if refFile: relPath = refFile[len(pObj.GetWorkspace()) + 1:] if len(comments) == 0: guidPage.AddDescription(' \\copydoc %s
' % relPath) section = doxygen.Section('ref', 'Refer to Header File') section.AddDescription('\link %s\n' % relPath) section.AddDescription('\endlink\n') self.ProcessSourceFileForInclude(refFile, pObj, configFile) guidPage.AddSection(section) return guidPage def GeneratePpiSubPages(self, pObj, configFile): """ Generate sub pages for package's GUID definition. @param pObj package object @param configFilf doxygen config file object """ pageRoot = doxygen.Page('PPI', 'ppi_root_page') objs = pObj.GetFileObj().GetSectionObjectsByName('ppis', self._arch) if len(objs) == 0: return [] if self._arch is not None: for obj in objs: pageRoot.AddPage(self._GeneratePpiSubPage(pObj, obj, configFile)) else: guidArchRootPageDict = {} for obj in objs: if obj.GetArch() not in guidArchRootPageDict.keys(): guidArchRoot = doxygen.Page(obj.GetArch(), 'ppi_arch_root_%s' % obj.GetArch()) pageRoot.AddPage(guidArchRoot) guidArchRootPageDict[obj.GetArch()] = guidArchRoot guidArchRoot = guidArchRootPageDict[obj.GetArch()] guidArchRoot.AddPage(self._GeneratePpiSubPage(pObj, obj, configFile)) return [pageRoot] def _GenerateProtocolSubPage(self, pObj, obj, configFile): guidPage = doxygen.Page(obj.GetName(), 'protocol_page_%s' % obj.GetName()) comments = obj.GetComment() if len(comments) != 0: guidPage.AddDescription('
'.join(obj.GetComment()) + '
') section = doxygen.Section('BasicProtocolInfo', 'PROTOCOL Information') desc = '' desc += '' desc += '' desc += '' desc += '' desc += '' % obj.GetName() desc += '' % obj.GetGuid() desc += '' desc += '
PROTOCOL\'s Guid Name
PROTOCOL\'s Guid
%s%s
' section.AddDescription(desc) guidPage.AddSection(section) refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile) if refFile: relPath = refFile[len(pObj.GetWorkspace()) + 1:] if len(comments) == 0: guidPage.AddDescription(' \\copydoc %s
' % relPath) section = doxygen.Section('ref', 'Refer to Header File') section.AddDescription('\link %s\n' % relPath) section.AddDescription('\endlink\n') self.ProcessSourceFileForInclude(refFile, pObj, configFile) guidPage.AddSection(section) return guidPage def GenerateProtocolSubPages(self, pObj, configFile): """ Generate sub pages for package's GUID definition. @param pObj package object @param configFilf doxygen config file object """ pageRoot = doxygen.Page('PROTOCOL', 'protocol_root_page') objs = pObj.GetFileObj().GetSectionObjectsByName('protocols', self._arch) if len(objs) == 0: return [] if self._arch is not None: for obj in objs: pageRoot.AddPage(self._GenerateProtocolSubPage(pObj, obj, configFile)) else: guidArchRootPageDict = {} for obj in objs: if obj.GetArch() not in guidArchRootPageDict.keys(): guidArchRoot = doxygen.Page(obj.GetArch(), 'protocol_arch_root_%s' % obj.GetArch()) pageRoot.AddPage(guidArchRoot) guidArchRootPageDict[obj.GetArch()] = guidArchRoot guidArchRoot = guidArchRootPageDict[obj.GetArch()] guidArchRoot.AddPage(self._GenerateProtocolSubPage(pObj, obj, configFile)) return [pageRoot] def FindHeaderFileForGuid(self, pObj, name, configFile): """ For declaration header file for GUID/PPI/Protocol. @param pObj package object @param name guid/ppi/protocol's name @param configFile config file object @return full path of header file and None if not found. """ startPath = pObj.GetFileObj().GetPackageRootPath() incPath = os.path.join(startPath, 'Include').replace('\\', '/') # if /include exist, then search header under it. if os.path.exists(incPath): startPath = incPath for root, dirs, files in os.walk(startPath): for dir in dirs: if dir.lower() in _ignore_dir: dirs.remove(dir) for file in files: fPath = os.path.join(root, file) if not IsCHeaderFile(fPath): continue try: f = open(fPath, 'r') lines = f.readlines() f.close() except IOError: self.Log('Fail to open file %s\n' % fPath) continue for line in lines: if line.find(name) != -1 and \ line.find('extern') != -1: return fPath.replace('\\', '/') return None def GetPackageModuleList(self, pObj): """ Get all module's INF path under package's root path @param pObj package object @return arrary of INF full path """ mArray = [] packPath = pObj.GetFileObj().GetPackageRootPath() if not os.path.exists: return None for root, dirs, files in os.walk(packPath): for dir in dirs: if dir.lower() in _ignore_dir: dirs.remove(dir) for file in files: if CheckPathPostfix(file, 'inf'): fPath = os.path.join(root, file).replace('\\', '/') mArray.append(fPath) return mArray def GenerateModulePages(self, pObj, configFile): """ Generate sub pages for package's module which is under the package root directory. @param pObj package object @param configFilf doxygen config file object """ infList = self.GetPackageModuleList(pObj) rootPages = [] libObjs = [] modObjs = [] for infpath in infList: infObj = inf.INFFile(infpath) #infObj = INFFileObject.INFFile (pObj.GetWorkspacePath(), # inf) if not infObj: self.Log('Fail create INF object for %s' % inf) continue if not infObj.Parse(): self.Log('Fail to load INF file %s' % inf) continue if infObj.GetProduceLibraryClass() is not None: libObjs.append(infObj) else: modObjs.append(infObj) if len(libObjs) != 0: libRootPage = doxygen.Page('Libraries', 'lib_root_page') rootPages.append(libRootPage) for libInf in libObjs: libRootPage.AddPage(self.GenerateModulePage(pObj, libInf, configFile, True)) if len(modObjs) != 0: modRootPage = doxygen.Page('Modules', 'module_root_page') rootPages.append(modRootPage) for modInf in modObjs: modRootPage.AddPage(self.GenerateModulePage(pObj, modInf, configFile, False)) return rootPages def GenerateModulePage(self, pObj, infObj, configFile, isLib): """ Generate page for a module/library. @param infObj INF file object for module/library @param configFile doxygen config file object @param isLib Whether this module is library @param module doxygen page object """ workspace = pObj.GetWorkspace() refDecObjs = [] for obj in infObj.GetSectionObjectsByName('packages'): decObj = dec.DECFile(os.path.join(workspace, obj.GetPath())) if not decObj: ErrorMsg ('Fail to create pacakge object for %s' % obj.GetPackageName()) continue if not decObj.Parse(): ErrorMsg ('Fail to load package object for %s' % obj.GetPackageName()) continue refDecObjs.append(decObj) modPage = doxygen.Page('%s' % infObj.GetBaseName(), 'module_%s' % infObj.GetBaseName()) modPage.AddDescription(infObj.GetFileHeader()) basicInfSection = doxygen.Section('BasicModuleInformation', 'Basic Module Information') desc = "" for obj in infObj.GetSectionObjectsByName('defines'): key = obj.GetKey() value = obj.GetValue() if key not in _inf_key_description_mapping_table.keys(): continue if key == 'LIBRARY_CLASS' and value.find('|') != -1: clsname, types = value.split('|') desc += '' desc += '' % _inf_key_description_mapping_table[key] desc += '' % clsname desc += '' desc += '' desc += '' desc += '' % types desc += '' else: desc += '' desc += '' % _inf_key_description_mapping_table[key] if key == 'EFI_SPECIFICATION_VERSION' and value == '0x00020000': value = '2.0' desc += '' % value desc += '' desc += '
%s%s
Supported Module Types%s
%s%s
' basicInfSection.AddDescription(desc) modPage.AddSection(basicInfSection) # Add protocol section data = [] for obj in infObj.GetSectionObjectsByName('pcd', self._arch): data.append(obj.GetPcdName().strip()) if len(data) != 0: s = doxygen.Section('Pcds', 'Pcds') desc = "" desc += '' for item in data: desc += '' desc += '' % item.split('.')[1] desc += '' % item.split('.')[0] pkgbasename = self.SearchPcdPackage(item, workspace, refDecObjs) desc += '' % pkgbasename desc += '' desc += "
PCD NameTokenSpacePackage
%s%s%s
" s.AddDescription(desc) modPage.AddSection(s) # Add protocol section #sects = infObj.GetSectionByString('protocol') data = [] #for sect in sects: for obj in infObj.GetSectionObjectsByName('protocol', self._arch): data.append(obj.GetName().strip()) if len(data) != 0: s = doxygen.Section('Protocols', 'Protocols') desc = "" desc += '' for item in data: desc += '' desc += '' % item pkgbasename = self.SearchProtocolPackage(item, workspace, refDecObjs) desc += '' % pkgbasename desc += '' desc += "
NamePackage
%s%s
" s.AddDescription(desc) modPage.AddSection(s) # Add ppi section #sects = infObj.GetSectionByString('ppi') data = [] #for sect in sects: for obj in infObj.GetSectionObjectsByName('ppi', self._arch): data.append(obj.GetName().strip()) if len(data) != 0: s = doxygen.Section('Ppis', 'Ppis') desc = "" desc += '' for item in data: desc += '' desc += '' % item pkgbasename = self.SearchPpiPackage(item, workspace, refDecObjs) desc += '' % pkgbasename desc += '' desc += "
NamePackage
%s%s
" s.AddDescription(desc) modPage.AddSection(s) # Add guid section #sects = infObj.GetSectionByString('guid') data = [] #for sect in sects: for obj in infObj.GetSectionObjectsByName('guid', self._arch): data.append(obj.GetName().strip()) if len(data) != 0: s = doxygen.Section('Guids', 'Guids') desc = "" desc += '' for item in data: desc += '' desc += '' % item pkgbasename = self.SearchGuidPackage(item, workspace, refDecObjs) desc += '' % pkgbasename desc += '' desc += "
NamePackage
%s%s
" s.AddDescription(desc) modPage.AddSection(s) section = doxygen.Section('LibraryClasses', 'Library Classes') desc = "" desc += '' if isLib: desc += '' desc += '' % infObj.GetProduceLibraryClass() desc += '' try: pkgname, hPath = self.SearchLibraryClassHeaderFile(infObj.GetProduceLibraryClass(), workspace, refDecObjs) except: self.Log ('fail to get package header file for lib class %s' % infObj.GetProduceLibraryClass()) pkgname = 'NULL' hPath = 'NULL' desc += '' % pkgname if hPath != "NULL": #desc += '' % hPath desc += '' % hPath else: desc += '' % hPath desc += '' for lcObj in infObj.GetSectionObjectsByName('libraryclasses', self._arch): desc += '' desc += '' % lcObj.GetClass() retarr = self.SearchLibraryClassHeaderFile(lcObj.GetClass(), workspace, refDecObjs) if retarr is not None: pkgname, hPath = retarr else: self.Log('Fail find the library class %s definition from module %s dependent package!' % (lcObj.GetClass(), infObj.GetFilename()), 'error') pkgname = 'NULL' hPath = 'NULL' desc += '' desc += '' % pkgname desc += '' % hPath desc += '' desc += "
NameTypePackageHeader File
%sProduce%s\link %s \endlink%s%s
%sConsume%s%s
" section.AddDescription(desc) modPage.AddSection(section) section = doxygen.Section('SourceFiles', 'Source Files') section.AddDescription('

\n') modPage.AddSection(section) #sects = infObj.GetSectionByString('depex') data = [] #for sect in sects: for obj in infObj.GetSectionObjectsByName('depex'): data.append(str(obj)) if len(data) != 0: s = doxygen.Section('DependentSection', 'Module Dependencies') s.AddDescription('
'.join(data)) modPage.AddSection(s) return modPage def TranslateUniFile(self, path): newpath = path + '.dox' #import core.textfile as textfile #file = textfile.TextFile(path) try: file = open(path, 'r') except (IOError, OSError) as msg: return None t = file.read() file.close() output = '/** @file \n' #output = '' arr = t.split('\r\n') for line in arr: if line.find('@file') != -1: continue if line.find('*/') != -1: continue line = line.strip() if line.strip().startswith('/'): arr = line.split(' ') if len(arr) > 1: line = ' '.join(arr[1:]) else: continue output += '%s
\n' % line output += '**/' if os.path.exists(newpath): os.remove(newpath) file = open(newpath, "w") file.write(output) file.close() return newpath def SearchPcdPackage(self, pcdname, workspace, decObjs): for decObj in decObjs: for pcd in decObj.GetSectionObjectsByName('pcd'): if pcdname == pcd.GetPcdName(): return decObj.GetBaseName() return None def SearchProtocolPackage(self, protname, workspace, decObjs): for decObj in decObjs: for proto in decObj.GetSectionObjectsByName('protocol'): if protname == proto.GetName(): return decObj.GetBaseName() return None def SearchPpiPackage(self, ppiname, workspace, decObjs): for decObj in decObjs: for ppi in decObj.GetSectionObjectsByName('ppi'): if ppiname == ppi.GetName(): return decObj.GetBaseName() return None def SearchGuidPackage(self, guidname, workspace, decObjs): for decObj in decObjs: for guid in decObj.GetSectionObjectsByName('guid'): if guidname == guid.GetName(): return decObj.GetBaseName() return None def SearchLibraryClassHeaderFile(self, className, workspace, decObjs): for decObj in decObjs: for cls in decObj.GetSectionObjectsByName('libraryclasses'): if cls.GetClassName().strip() == className: path = cls.GetHeaderFile().strip() path = os.path.join(decObj.GetPackageRootPath(), path) path = path[len(workspace) + 1:] return decObj.GetBaseName(), path.replace('\\', '/') return None def _ConvertPathToDoxygen(self, path, pObj): pRootPath = pObj.GetWorkspace() path = path[len(pRootPath) + 1:] return path.replace('\\', '/') def IsCHeaderFile(path): return CheckPathPostfix(path, 'h') def CheckPathPostfix(path, str): index = path.rfind('.') if index == -1: return False if path[index + 1:].lower() == str.lower(): return True return False