X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=BaseTools%2FScripts%2FPackageDocumentTools%2Fplugins%2FEdkPlugins%2Fedk2%2Fmodel%2Fdoxygengen.py;fp=BaseTools%2FScripts%2FPackageDocumentTools%2Fplugins%2FEdkPlugins%2Fedk2%2Fmodel%2Fdoxygengen.py;h=268ba5c3bdd05ff54fd9cb6e761e9d60007a1619;hb=7ccc9c954c5c8a5b92199e68227384da0b5e4e7d;hp=0000000000000000000000000000000000000000;hpb=316b43dee56837ed7d382e8de4a78d6bb9d14eb7;p=mirror_edk2.git diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/doxygengen.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/doxygengen.py new file mode 100644 index 0000000000..268ba5c3bd --- /dev/null +++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/doxygengen.py @@ -0,0 +1,1089 @@ +## @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.
+# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License which accompanies this +# distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +"""This file produce action class to generate doxygen document for edk2 codebase. + The action classes are shared by GUI and command line tools. +""" +import plugins.EdkPlugins.basemodel.doxygen as doxygen +import os +try: + import wx + gInGui = True +except: + gInGui = False +import re +import plugins.EdkPlugins.edk2.model.inf as inf +import plugins.EdkPlugins.edk2.model.dec as 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 != 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 == 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 != 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, + 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._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') + + namestr = self._pObj.GetName() + if self._arch != None: + namestr += '[%s]' % self._arch + if self._tooltag != 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 != 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) + + no = 0 + for no in xrange(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 == 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 != 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 != None: + break + + if fullPath == 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 != 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 != 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 != 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 != 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() != 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 libary + + @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 + 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 != 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
%sConsume%s\link %s \endlink
" + 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, 'rb') + except (IOError, OSError), 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