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 += '%s | ' % _dec_key_description_mapping_table[obj.GetKey()]
+ descr += '%s | ' % obj.GetValue()
+ descr += '
'
+ descr += '
'
+ baseSection.AddDescription(descr)
+ pdObj.AddSection(baseSection)
+
+ knownIssueSection = doxygen.Section('Known_Issue_section', 'Known Issue')
+ knownIssueSection.AddDescription('')
+ knownIssueSection.AddDescription('- OPTIONAL macro for function parameter can not be dealed with doxygen, so it disapear in this document!
')
+ 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')
+ for file in os.listdir(path):
+ if file.lower() in _ignore_dir: continue
+ fullpath = os.path.join(path, file)
+ if os.path.isfile(fullpath):
+ self.ProcessSourceFileForInclude(fullpath, pObj, configFile)
+ topPage.AddDescription('- \link %s\endlink
\n' % self._ConvertPathToDoxygen(fullpath, pObj))
+ else:
+ if file.lower() in ['library', 'protocol', 'guid', 'ppi', 'ia32', 'x64', 'ipf', 'ebc', 'arm', 'pi', 'uefi', 'aarch64']:
+ continue
+ bNeedAddSubPage = False
+ subpage = doxygen.Page(self._ConvertPathToDoxygen(fullpath, pObj), 'public_include_%s' % file)
+ subpage.AddDescription('\n')
+ for subfile in os.listdir(fullpath):
+ if subfile.lower() in _ignore_dir: continue
+ bNeedAddSubPage = True
+ subfullpath = os.path.join(fullpath, subfile)
+ self.ProcessSourceFileForInclude(subfullpath, pObj, configFile)
+ subpage.AddDescription('- \link %s \endlink
\n' % self._ConvertPathToDoxygen(subfullpath, pObj))
+ subpage.AddDescription('
\n')
+ if bNeedAddSubPage:
+ bNeedAddIncludePage = True
+ pageRoot.AddPage(subpage)
+ 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 += 'Name | '
+ desc += 'Token Space | '
+ desc += 'Token number | '
+ desc += 'Data Type | '
+ desc += 'Default Value | '
+ desc += '
'
+ desc += ''
+ desc += '%s | ' % obj.GetPcdName().split('.')[1]
+ desc += '%s | ' % obj.GetPcdName().split('.')[0]
+ desc += '%s | ' % obj.GetPcdToken()
+ desc += '%s | ' % obj.GetPcdDataType()
+ desc += '%s | ' % obj.GetPcdValue()
+ desc += '
'
+ desc += '
'
+ 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 += 'Name | '
+ desc += 'Token Space | '
+ desc += 'Token number | '
+ desc += 'Data Type | '
+ desc += 'Default Value | '
+ desc += '
'
+ desc += ''
+ desc += '%s | ' % obj.GetPcdName().split('.')[1]
+ desc += '%s | ' % obj.GetPcdName().split('.')[0]
+ desc += '%s | ' % obj.GetPcdToken()
+ desc += '%s | ' % obj.GetPcdDataType()
+ desc += '%s | ' % obj.GetPcdValue()
+ desc += '
'
+ desc += '
'
+ 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 += 'GUID\'s Guid Name | GUID\'s Guid | '
+ desc += '
'
+ desc += ''
+ desc += '%s | ' % obj.GetName()
+ desc += '%s | ' % obj.GetGuid()
+ desc += '
'
+ desc += '
'
+ 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 += 'PPI\'s Guid Name | PPI\'s Guid | '
+ desc += '
'
+ desc += ''
+ desc += '%s | ' % obj.GetName()
+ desc += '%s | ' % obj.GetGuid()
+ desc += '
'
+ desc += '
'
+ 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 += 'PROTOCOL\'s Guid Name | PROTOCOL\'s Guid | '
+ desc += '
'
+ desc += ''
+ desc += '%s | ' % obj.GetName()
+ desc += '%s | ' % obj.GetGuid()
+ desc += '
'
+ desc += '
'
+ 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 += '%s | ' % _inf_key_description_mapping_table[key]
+ desc += '%s | ' % clsname
+ desc += '
'
+
+ desc += ''
+ desc += 'Supported Module Types | '
+ desc += '%s | ' % types
+ desc += '
'
+ else:
+ desc += ''
+ desc += '%s | ' % _inf_key_description_mapping_table[key]
+ if key == 'EFI_SPECIFICATION_VERSION' and value == '0x00020000':
+ value = '2.0'
+ desc += '%s | ' % value
+ desc += '
'
+ desc += '
'
+ 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 += 'PCD Name | TokenSpace | Package |
'
+ for item in data:
+ desc += ''
+ desc += '%s | ' % item.split('.')[1]
+ desc += '%s | ' % item.split('.')[0]
+ pkgbasename = self.SearchPcdPackage(item, workspace, refDecObjs)
+ desc += '%s | ' % pkgbasename
+ desc += '
'
+ desc += "
"
+ 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 += 'Name | Package |
'
+ for item in data:
+ desc += ''
+ desc += '%s | ' % item
+ pkgbasename = self.SearchProtocolPackage(item, workspace, refDecObjs)
+ desc += '%s | ' % pkgbasename
+ desc += '
'
+ desc += "
"
+ 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 += 'Name | Package |
'
+ for item in data:
+ desc += ''
+ desc += '%s | ' % item
+ pkgbasename = self.SearchPpiPackage(item, workspace, refDecObjs)
+ desc += '%s | ' % pkgbasename
+ desc += '
'
+ desc += "
"
+ 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 += 'Name | Package |
'
+ for item in data:
+ desc += ''
+ desc += '%s | ' % item
+ pkgbasename = self.SearchGuidPackage(item, workspace, refDecObjs)
+ desc += '%s | ' % pkgbasename
+ desc += '
'
+ desc += "
"
+ s.AddDescription(desc)
+ modPage.AddSection(s)
+
+ section = doxygen.Section('LibraryClasses', 'Library Classes')
+ desc = ""
+ desc += 'Name | Type | Package | Header File |
'
+ if isLib:
+ desc += ''
+ desc += '%s | ' % infObj.GetProduceLibraryClass()
+ desc += 'Produce | '
+ 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 += '%s | ' % pkgname
+ if hPath != "NULL":
+ desc += '\link %s \endlink | ' % hPath
+ else:
+ desc += '%s | ' % hPath
+ desc += '
'
+ for lcObj in infObj.GetSectionObjectsByName('libraryclasses', self._arch):
+ desc += ''
+ desc += '%s | ' % 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 += 'Consume | '
+ desc += '%s | ' % pkgname
+ desc += '\link %s \endlink | ' % hPath
+ desc += '
'
+ desc += "
"
+ section.AddDescription(desc)
+ modPage.AddSection(section)
+
+ section = doxygen.Section('SourceFiles', 'Source Files')
+ section.AddDescription('\n')
+ for obj in infObj.GetSourceObjects(self._arch, self._tooltag):
+ sPath = infObj.GetModuleRootPath()
+ sPath = os.path.join(sPath, obj.GetSourcePath()).replace('\\', '/').strip()
+ if sPath.lower().endswith('.uni') or sPath.lower().endswith('.s') or sPath.lower().endswith('.asm') or sPath.lower().endswith('.nasm'):
+ newPath = self.TranslateUniFile(sPath)
+ configFile.AddFile(newPath)
+ newPath = newPath[len(pObj.GetWorkspace()) + 1:]
+ section.AddDescription('- \link %s \endlink
' % newPath)
+ else:
+ self.ProcessSourceFileForInclude(sPath, pObj, configFile, infObj)
+ sPath = sPath[len(pObj.GetWorkspace()) + 1:]
+ section.AddDescription('- \link %s \endlink
' % sPath)
+ 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