3 # This file produce action class to generate doxygen document for edk2 codebase.
4 # The action classes are shared by GUI and command line tools.
6 # Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
8 # SPDX-License-Identifier: BSD-2-Clause-Patent
10 """This file produce action class to generate doxygen document for edk2 codebase.
11 The action classes are shared by GUI and command line tools.
13 from plugins
.EdkPlugins
.basemodel
import doxygen
21 from plugins
.EdkPlugins
.edk2
.model
import inf
22 from plugins
.EdkPlugins
.edk2
.model
import dec
23 from plugins
.EdkPlugins
.basemodel
.message
import *
25 _ignore_dir
= ['.svn', '_svn', 'cvs']
26 _inf_key_description_mapping_table
= {
27 'INF_VERSION':'Version of INF file specification',
28 #'BASE_NAME':'Module Name',
29 'FILE_GUID':'Module Guid',
30 'MODULE_TYPE': 'Module Type',
31 'VERSION_STRING': 'Module Version',
32 'LIBRARY_CLASS': 'Produced Library Class',
33 'EFI_SPECIFICATION_VERSION': 'UEFI Specification Version',
34 'PI_SPECIFICATION_VERSION': 'PI Specification Version',
35 'ENTRY_POINT': 'Module Entry Point Function',
36 'CONSTRUCTOR': 'Library Constructor Function'
39 _dec_key_description_mapping_table
= {
40 'DEC_SPECIFICATION': 'Version of DEC file specification',
41 'PACKAGE_GUID': 'Package Guid'
44 """This is base class for all doxygen action.
47 def __init__(self
, doxPath
, chmPath
, outputPath
, projname
, mode
='html', log
=None, verbose
=False):
48 """Constructor function.
49 @param doxPath the obosolution path of doxygen execute file.
50 @param outputPath the obosolution output path.
51 @param log log function for output message
53 self
._doxPath
= doxPath
54 self
._chmPath
= chmPath
55 self
._outputPath
= outputPath
56 self
._projname
= projname
57 self
._configFile
= None # doxygen config file is used by doxygen exe file
58 self
._indexPageFile
= None # doxygen page file for index page.
61 self
._verbose
= verbose
62 self
._doxygenCallback
= None
63 self
._chmCallback
= None
65 def Log(self
, message
, level
='info'):
66 if self
._log
is not None:
67 self
._log
(message
, level
)
73 """Generate interface called by outer directly"""
74 self
.Log(">>>>>> Start generate doxygen document for %s... Zzz....\n" % self
._projname
)
76 # create doxygen config file at first
77 self
._configFile
= doxygen
.DoxygenConfigFile()
78 self
._configFile
.SetOutputDir(self
._outputPath
)
80 self
._configFile
.SetWarningFilePath(os
.path
.join(self
._outputPath
, 'warning.txt'))
81 if self
._mode
.lower() == 'html':
82 self
._configFile
.SetHtmlMode()
84 self
._configFile
.SetChmMode()
86 self
.Log(" >>>>>> Initialize doxygen config file...Zzz...\n")
87 self
.InitializeConfigFile()
89 self
.Log(" >>>>>> Generate doxygen index page file...Zzz...\n")
90 indexPagePath
= self
.GenerateIndexPage()
91 if indexPagePath
is None:
92 self
.Log("Fail to generate index page!\n", 'error')
95 self
.Log("Success to create doxygen index page file %s \n" % indexPagePath
)
97 # Add index page doxygen file to file list.
98 self
._configFile
.AddFile(indexPagePath
)
100 # save config file to output path
101 configFilePath
= os
.path
.join(self
._outputPath
, self
._projname
+ '.doxygen_config')
102 self
._configFile
.Generate(configFilePath
)
103 self
.Log(" <<<<<< Success Save doxygen config file to %s...\n" % configFilePath
)
105 # launch doxygen tool to generate document
106 if self
._doxygenCallback
is not None:
107 self
.Log(" >>>>>> Start doxygen process...Zzz...\n")
108 if not self
._doxygenCallback
(self
._doxPath
, configFilePath
):
111 self
.Log("Fail to create doxygen process!", 'error')
116 def InitializeConfigFile(self
):
117 """Initialize config setting for doxygen project. It will be invoked after config file
118 object is created. Inherited class should implement it.
121 def GenerateIndexPage(self
):
122 """Generate doxygen index page. Inherited class should implement it."""
125 def RegisterCallbackDoxygenProcess(self
, callback
):
126 self
._doxygenCallback
= callback
128 def RegisterCallbackCHMProcess(self
, callback
):
129 self
._chmCallback
= callback
131 class PlatformDocumentAction(DoxygenAction
):
132 """Generate platform doxygen document, will be implement at future."""
134 class PackageDocumentAction(DoxygenAction
):
135 """Generate package reference document"""
137 def __init__(self
, doxPath
, chmPath
, outputPath
, pObj
, mode
='html', log
=None, arch
=None, tooltag
=None,
138 onlyInclude
=False, verbose
=False):
139 DoxygenAction
.__init
__(self
, doxPath
, chmPath
, outputPath
, pObj
.GetName(), mode
, log
, verbose
)
142 self
._tooltag
= tooltag
143 self
._onlyIncludeDocument
= onlyInclude
145 def InitializeConfigFile(self
):
146 if self
._arch
== 'IA32':
147 self
._configFile
.AddPreDefined('MDE_CPU_IA32')
148 elif self
._arch
== 'X64':
149 self
._configFile
.AddPreDefined('MDE_CPU_X64')
150 elif self
._arch
== 'IPF':
151 self
._configFile
.AddPreDefined('MDE_CPU_IPF')
152 elif self
._arch
== 'EBC':
153 self
._configFile
.AddPreDefined('MDE_CPU_EBC')
156 self
._configFile
.AddPreDefined('MDE_CPU_IA32')
157 self
._configFile
.AddPreDefined('MDE_CPU_X64')
158 self
._configFile
.AddPreDefined('MDE_CPU_IPF')
159 self
._configFile
.AddPreDefined('MDE_CPU_EBC')
160 self
._configFile
.AddPreDefined('MDE_CPU_ARM')
162 namestr
= self
._pObj
.GetName()
163 if self
._arch
is not None:
164 namestr
+= '[%s]' % self
._arch
165 if self
._tooltag
is not None:
166 namestr
+= '[%s]' % self
._tooltag
167 self
._configFile
.SetProjectName(namestr
)
168 self
._configFile
.SetStripPath(self
._pObj
.GetWorkspace())
169 self
._configFile
.SetProjectVersion(self
._pObj
.GetFileObj().GetVersion())
170 self
._configFile
.AddPattern('*.decdoxygen')
172 if self
._tooltag
.lower() == 'msft':
173 self
._configFile
.AddPreDefined('_MSC_EXTENSIONS')
174 elif self
._tooltag
.lower() == 'gnu':
175 self
._configFile
.AddPreDefined('__GNUC__')
176 elif self
._tooltag
.lower() == 'intel':
177 self
._configFile
.AddPreDefined('__INTEL_COMPILER')
180 self
._configFile
.AddPreDefined('_MSC_EXTENSIONS')
181 self
._configFile
.AddPreDefined('__GNUC__')
182 self
._configFile
.AddPreDefined('__INTEL_COMPILER')
184 self
._configFile
.AddPreDefined('ASM_PFX= ')
185 self
._configFile
.AddPreDefined('OPTIONAL= ')
187 def GenerateIndexPage(self
):
188 """Generate doxygen index page. Inherited class should implement it."""
189 fObj
= self
._pObj
.GetFileObj()
190 pdObj
= doxygen
.DoxygenFile('%s Package Document' % self
._pObj
.GetName(),
191 '%s.decdoxygen' % self
._pObj
.GetFilename())
192 self
._configFile
.AddFile(pdObj
.GetFilename())
193 pdObj
.AddDescription(fObj
.GetFileHeader())
195 defSection
= fObj
.GetSectionByName('defines')[0]
196 baseSection
= doxygen
.Section('PackageBasicInformation', 'Package Basic Information')
198 for obj
in defSection
.GetObjects():
199 if obj
.GetKey() in _dec_key_description_mapping_table
.keys():
201 descr
+= '<TD><B>%s</B></TD>' % _dec_key_description_mapping_table
[obj
.GetKey()]
202 descr
+= '<TD>%s</TD>' % obj
.GetValue()
204 descr
+= '</TABLE><br>'
205 baseSection
.AddDescription(descr
)
206 pdObj
.AddSection(baseSection
)
208 knownIssueSection
= doxygen
.Section('Known_Issue_section', 'Known Issue')
209 knownIssueSection
.AddDescription('<ul>')
210 knownIssueSection
.AddDescription('<li> OPTIONAL macro for function parameter can not be dealed with doxygen, so it disapear in this document! </li>')
211 knownIssueSection
.AddDescription('</ul>')
212 pdObj
.AddSection(knownIssueSection
)
214 self
.AddAllIncludeFiles(self
._pObj
, self
._configFile
)
215 pages
= self
.GenerateIncludesSubPage(self
._pObj
, self
._configFile
)
217 pdObj
.AddPages(pages
)
218 pages
= self
.GenerateLibraryClassesSubPage(self
._pObj
, self
._configFile
)
220 pdObj
.AddPages(pages
)
221 pages
= self
.GeneratePcdSubPages(self
._pObj
, self
._configFile
)
223 pdObj
.AddPages(pages
)
224 pages
= self
.GenerateGuidSubPages(self
._pObj
, self
._configFile
)
226 pdObj
.AddPages(pages
)
227 pages
= self
.GeneratePpiSubPages(self
._pObj
, self
._configFile
)
229 pdObj
.AddPages(pages
)
230 pages
= self
.GenerateProtocolSubPages(self
._pObj
, self
._configFile
)
232 pdObj
.AddPages(pages
)
233 if not self
._onlyIncludeDocument
:
234 pdObj
.AddPages(self
.GenerateModulePages(self
._pObj
, self
._configFile
))
237 return pdObj
.GetFilename()
239 def GenerateIncludesSubPage(self
, pObj
, configFile
):
240 # by default add following path as include path to config file
241 pkpath
= pObj
.GetFileObj().GetPackageRootPath()
242 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include'))
243 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include', 'Library'))
244 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include', 'Protocol'))
245 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include', 'Ppi'))
246 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include', 'Guid'))
247 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include', 'IndustryStandard'))
250 pageRoot
= doxygen
.Page("Public Includes", "%s_public_includes" % pObj
.GetName())
251 objs
= pObj
.GetFileObj().GetSectionObjectsByName('includes')
252 if len(objs
) == 0: return []
255 # Add path to include path
256 path
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetPath())
257 configFile
.AddIncludePath(path
)
259 # only list common folder's include file
260 if obj
.GetArch().lower() != 'common':
263 bNeedAddIncludePage
= False
264 topPage
= doxygen
.Page(self
._ConvertPathToDoxygen
(path
, pObj
), 'public_include_top')
266 topPage
.AddDescription('<ul>\n')
267 for file in os
.listdir(path
):
268 if file.lower() in _ignore_dir
: continue
269 fullpath
= os
.path
.join(path
, file)
270 if os
.path
.isfile(fullpath
):
271 self
.ProcessSourceFileForInclude(fullpath
, pObj
, configFile
)
272 topPage
.AddDescription('<li> \link %s\endlink </li>\n' % self
._ConvertPathToDoxygen
(fullpath
, pObj
))
274 if file.lower() in ['library', 'protocol', 'guid', 'ppi', 'ia32', 'x64', 'ipf', 'ebc', 'arm', 'pi', 'uefi', 'aarch64']:
276 bNeedAddSubPage
= False
277 subpage
= doxygen
.Page(self
._ConvertPathToDoxygen
(fullpath
, pObj
), 'public_include_%s' % file)
278 subpage
.AddDescription('<ul>\n')
279 for subfile
in os
.listdir(fullpath
):
280 if subfile
.lower() in _ignore_dir
: continue
281 bNeedAddSubPage
= True
282 subfullpath
= os
.path
.join(fullpath
, subfile
)
283 self
.ProcessSourceFileForInclude(subfullpath
, pObj
, configFile
)
284 subpage
.AddDescription('<li> \link %s \endlink </li>\n' % self
._ConvertPathToDoxygen
(subfullpath
, pObj
))
285 subpage
.AddDescription('</ul>\n')
287 bNeedAddIncludePage
= True
288 pageRoot
.AddPage(subpage
)
289 topPage
.AddDescription('</ul>\n')
290 if bNeedAddIncludePage
:
291 pageRoot
.AddPage(topPage
)
293 if pageRoot
.GetSubpageCount() != 0:
298 def GenerateLibraryClassesSubPage(self
, pObj
, configFile
):
300 Generate sub page for library class for package.
301 One DEC file maybe contains many library class sections
302 for different architecture.
304 @param fObj DEC file object.
307 pageRoot
= doxygen
.Page("Library Class", "%s_libraryclass" % pObj
.GetName())
308 objs
= pObj
.GetFileObj().GetSectionObjectsByName('libraryclass', self
._arch
)
309 if len(objs
) == 0: return []
311 if self
._arch
is not None:
313 classPage
= doxygen
.Page(obj
.GetClassName(),
314 "lc_%s" % obj
.GetClassName())
315 comments
= obj
.GetComment()
316 if len(comments
) != 0:
317 classPage
.AddDescription('<br>\n'.join(comments
) + '<br>\n')
318 pageRoot
.AddPage(classPage
)
319 path
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetHeaderFile())
320 path
= path
[len(pObj
.GetWorkspace()) + 1:]
321 if len(comments
) == 0:
322 classPage
.AddDescription('\copydoc %s<p>' % obj
.GetHeaderFile())
323 section
= doxygen
.Section('ref', 'Refer to Header File')
324 section
.AddDescription('\link %s\n' % obj
.GetHeaderFile())
325 section
.AddDescription(' \endlink<p>\n')
326 classPage
.AddSection(section
)
327 fullPath
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetHeaderFile())
328 self
.ProcessSourceFileForInclude(fullPath
, pObj
, configFile
)
332 if obj
.GetArch() not in archPageDict
.keys():
333 archPageDict
[obj
.GetArch()] = doxygen
.Page(obj
.GetArch(),
334 'lc_%s' % obj
.GetArch())
335 pageRoot
.AddPage(archPageDict
[obj
.GetArch()])
336 subArchRoot
= archPageDict
[obj
.GetArch()]
337 classPage
= doxygen
.Page(obj
.GetClassName(),
338 "lc_%s" % obj
.GetClassName())
339 comments
= obj
.GetComment()
340 if len(comments
) != 0:
341 classPage
.AddDescription('<br>\n'.join(comments
) + '<br>\n')
342 subArchRoot
.AddPage(classPage
)
343 path
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetHeaderFile())
344 path
= path
[len(pObj
.GetWorkspace()) + 1:]
345 if len(comments
) == 0:
346 classPage
.AddDescription('\copydoc %s<p>' % obj
.GetHeaderFile())
347 section
= doxygen
.Section('ref', 'Refer to Header File')
348 section
.AddDescription('\link %s\n' % obj
.GetHeaderFile())
349 section
.AddDescription(' \endlink<p>\n')
350 classPage
.AddSection(section
)
351 fullPath
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetHeaderFile())
353 self
.ProcessSourceFileForInclude(fullPath
, pObj
, configFile
)
354 rootArray
.append(pageRoot
)
357 def ProcessSourceFileForInclude(self
, path
, pObj
, configFile
, infObj
=None):
359 @param path the analysising file full path
360 @param pObj package object
361 @param configFile doxygen config file.
365 if not os
.path
.exists(path
):
366 ErrorMsg('Source file path %s does not exist!' % path
)
369 if configFile
.FileExists(path
):
373 with
open(path
, 'r') as f
:
374 lines
= f
.readlines()
375 except UnicodeDecodeError:
378 ErrorMsg('Fail to open file %s' % path
)
381 configFile
.AddFile(path
)
384 for no
in range(len(lines
)):
385 if len(lines
[no
].strip()) == 0:
387 if lines
[no
].strip()[:2] in ['##', '//', '/*', '*/']:
389 index
= lines
[no
].lower().find('include')
390 #mo = IncludePattern.finditer(lines[no].lower())
391 mo
= re
.match(r
"^#\s*include\s+[<\"]([\\/\w
.]+)[>\"]$
", lines[no].strip().lower())
394 mo = re.match(r"^
[#\w\s]+[<\"]([\\/\w.]+)[>\"]$", lines[no].strip())
395 filePath
= mo
.groups()[0]
397 if filePath
is None or len(filePath
) == 0:
400 # find header file in module's path firstly.
403 if os
.path
.exists(os
.path
.join(os
.path
.dirname(path
), filePath
)):
404 # Find the file in current directory
405 fullPath
= os
.path
.join(os
.path
.dirname(path
), filePath
).replace('\\', '/')
407 # find in depedent package's include path
408 incObjs
= pObj
.GetFileObj().GetSectionObjectsByName('includes')
409 for incObj
in incObjs
:
410 incPath
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), incObj
.GetPath()).strip()
411 incPath
= os
.path
.realpath(os
.path
.join(incPath
, filePath
))
412 if os
.path
.exists(incPath
):
415 if infObj
is not None:
416 pkgInfObjs
= infObj
.GetSectionObjectsByName('packages')
417 for obj
in pkgInfObjs
:
418 decObj
= dec
.DECFile(os
.path
.join(pObj
.GetWorkspace(), obj
.GetPath()))
420 ErrorMsg ('Fail to create pacakge object for %s' % obj
.GetPackageName())
422 if not decObj
.Parse():
423 ErrorMsg ('Fail to load package object for %s' % obj
.GetPackageName())
425 incObjs
= decObj
.GetSectionObjectsByName('includes')
426 for incObj
in incObjs
:
427 incPath
= os
.path
.join(decObj
.GetPackageRootPath(), incObj
.GetPath()).replace('\\', '/')
428 if os
.path
.exists(os
.path
.join(incPath
, filePath
)):
429 fullPath
= os
.path
.join(os
.path
.join(incPath
, filePath
))
431 if fullPath
is not None:
434 if fullPath
is None and self
.IsVerbose():
435 self
.Log('Can not resolve header file %s for file %s in package %s\n' % (filePath
, path
, pObj
.GetFileObj().GetFilename()), 'error')
438 fullPath
= fullPath
.replace('\\', '/')
440 self
.Log('Preprocessing: Add include file %s for file %s\n' % (fullPath
, path
))
441 #LogMsg ('Preprocessing: Add include file %s for file %s' % (fullPath, path))
442 self
.ProcessSourceFileForInclude(fullPath
, pObj
, configFile
, infObj
)
444 def AddAllIncludeFiles(self
, pObj
, configFile
):
445 objs
= pObj
.GetFileObj().GetSectionObjectsByName('includes')
447 incPath
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetPath())
448 for root
, dirs
, files
in os
.walk(incPath
):
450 if dir.lower() in _ignore_dir
:
453 path
= os
.path
.normpath(os
.path
.join(root
, file))
454 configFile
.AddFile(path
.replace('/', '\\'))
456 def GeneratePcdSubPages(self
, pObj
, configFile
):
458 Generate sub pages for package's PCD definition.
459 @param pObj package object
460 @param configFile config file object
463 objs
= pObj
.GetFileObj().GetSectionObjectsByName('pcd')
467 pcdRootPage
= doxygen
.Page('PCD', 'pcd_root_page')
468 typeRootPageDict
= {}
469 typeArchRootPageDict
= {}
471 if obj
.GetPcdType() not in typeRootPageDict
.keys():
472 typeRootPageDict
[obj
.GetPcdType()] = doxygen
.Page(obj
.GetPcdType(), 'pcd_%s_root_page' % obj
.GetPcdType())
473 pcdRootPage
.AddPage(typeRootPageDict
[obj
.GetPcdType()])
474 typeRoot
= typeRootPageDict
[obj
.GetPcdType()]
475 if self
._arch
is not None:
476 pcdPage
= doxygen
.Page('%s' % obj
.GetPcdName(),
477 'pcd_%s_%s_%s' % (obj
.GetPcdType(), obj
.GetArch(), obj
.GetPcdName().split('.')[1]))
478 pcdPage
.AddDescription('<br>\n'.join(obj
.GetComment()) + '<br>\n')
479 section
= doxygen
.Section('PCDinformation', 'PCD Information')
482 desc
+= '<TD><CAPTION>Name</CAPTION></TD>'
483 desc
+= '<TD><CAPTION>Token Space</CAPTION></TD>'
484 desc
+= '<TD><CAPTION>Token number</CAPTION></TD>'
485 desc
+= '<TD><CAPTION>Data Type</CAPTION></TD>'
486 desc
+= '<TD><CAPTION>Default Value</CAPTION></TD>'
489 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdName().split('.')[1]
490 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdName().split('.')[0]
491 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdToken()
492 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdDataType()
493 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdValue()
496 section
.AddDescription(desc
)
497 pcdPage
.AddSection(section
)
498 typeRoot
.AddPage(pcdPage
)
500 keystr
= obj
.GetPcdType() + obj
.GetArch()
501 if keystr
not in typeArchRootPageDict
.keys():
502 typeArchRootPage
= doxygen
.Page(obj
.GetArch(), 'pcd_%s_%s_root_page' % (obj
.GetPcdType(), obj
.GetArch()))
503 typeArchRootPageDict
[keystr
] = typeArchRootPage
504 typeRoot
.AddPage(typeArchRootPage
)
505 typeArchRoot
= typeArchRootPageDict
[keystr
]
506 pcdPage
= doxygen
.Page('%s' % obj
.GetPcdName(),
507 'pcd_%s_%s_%s' % (obj
.GetPcdType(), obj
.GetArch(), obj
.GetPcdName().split('.')[1]))
508 pcdPage
.AddDescription('<br>\n'.join(obj
.GetComment()) + '<br>\n')
509 section
= doxygen
.Section('PCDinformation', 'PCD Information')
512 desc
+= '<TD><CAPTION>Name</CAPTION></TD>'
513 desc
+= '<TD><CAPTION>Token Space</CAPTION></TD>'
514 desc
+= '<TD><CAPTION>Token number</CAPTION></TD>'
515 desc
+= '<TD><CAPTION>Data Type</CAPTION></TD>'
516 desc
+= '<TD><CAPTION>Default Value</CAPTION></TD>'
519 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdName().split('.')[1]
520 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdName().split('.')[0]
521 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdToken()
522 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdDataType()
523 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdValue()
526 section
.AddDescription(desc
)
527 pcdPage
.AddSection(section
)
528 typeArchRoot
.AddPage(pcdPage
)
531 def _GenerateGuidSubPage(self
, pObj
, obj
, configFile
):
532 guidPage
= doxygen
.Page('%s' % obj
.GetName(),
533 'guid_%s_%s' % (obj
.GetArch(), obj
.GetName()))
534 comments
= obj
.GetComment()
535 if len(comments
) != 0:
536 guidPage
.AddDescription('<br>'.join(obj
.GetComment()) + '<br>')
537 section
= doxygen
.Section('BasicGuidInfo', 'GUID Information')
540 desc
+= '<TD><CAPTION>GUID\'s Guid Name</CAPTION></TD><TD><CAPTION>GUID\'s Guid</CAPTION></TD>'
543 desc
+= '<TD>%s</TD>' % obj
.GetName()
544 desc
+= '<TD>%s</TD>' % obj
.GetGuid()
547 section
.AddDescription(desc
)
548 guidPage
.AddSection(section
)
549 refFile
= self
.FindHeaderFileForGuid(pObj
, obj
.GetName(), configFile
)
551 relPath
= refFile
[len(pObj
.GetWorkspace()) + 1:]
552 if len(comments
) == 0:
553 guidPage
.AddDescription(' \\copydoc %s <br>' % relPath
)
555 section
= doxygen
.Section('ref', 'Refer to Header File')
556 section
.AddDescription('\link %s\n' % relPath
)
557 section
.AddDescription('\endlink\n')
558 self
.ProcessSourceFileForInclude(refFile
, pObj
, configFile
)
559 guidPage
.AddSection(section
)
562 def GenerateGuidSubPages(self
, pObj
, configFile
):
564 Generate sub pages for package's GUID definition.
565 @param pObj package object
566 @param configFilf doxygen config file object
568 pageRoot
= doxygen
.Page('GUID', 'guid_root_page')
569 objs
= pObj
.GetFileObj().GetSectionObjectsByName('guids', self
._arch
)
570 if len(objs
) == 0: return []
571 if self
._arch
is not None:
573 pageRoot
.AddPage(self
._GenerateGuidSubPage
(pObj
, obj
, configFile
))
575 guidArchRootPageDict
= {}
577 if obj
.GetArch() not in guidArchRootPageDict
.keys():
578 guidArchRoot
= doxygen
.Page(obj
.GetArch(), 'guid_arch_root_%s' % obj
.GetArch())
579 pageRoot
.AddPage(guidArchRoot
)
580 guidArchRootPageDict
[obj
.GetArch()] = guidArchRoot
581 guidArchRoot
= guidArchRootPageDict
[obj
.GetArch()]
582 guidArchRoot
.AddPage(self
._GenerateGuidSubPage
(pObj
, obj
, configFile
))
585 def _GeneratePpiSubPage(self
, pObj
, obj
, configFile
):
586 guidPage
= doxygen
.Page(obj
.GetName(), 'ppi_page_%s' % obj
.GetName())
587 comments
= obj
.GetComment()
588 if len(comments
) != 0:
589 guidPage
.AddDescription('<br>'.join(obj
.GetComment()) + '<br>')
590 section
= doxygen
.Section('BasicPpiInfo', 'PPI Information')
593 desc
+= '<TD><CAPTION>PPI\'s Guid Name</CAPTION></TD><TD><CAPTION>PPI\'s Guid</CAPTION></TD>'
596 desc
+= '<TD>%s</TD>' % obj
.GetName()
597 desc
+= '<TD>%s</TD>' % obj
.GetGuid()
600 section
.AddDescription(desc
)
601 guidPage
.AddSection(section
)
602 refFile
= self
.FindHeaderFileForGuid(pObj
, obj
.GetName(), configFile
)
604 relPath
= refFile
[len(pObj
.GetWorkspace()) + 1:]
605 if len(comments
) == 0:
606 guidPage
.AddDescription(' \\copydoc %s <br>' % relPath
)
607 section
= doxygen
.Section('ref', 'Refer to Header File')
608 section
.AddDescription('\link %s\n' % relPath
)
609 section
.AddDescription('\endlink\n')
610 self
.ProcessSourceFileForInclude(refFile
, pObj
, configFile
)
611 guidPage
.AddSection(section
)
615 def GeneratePpiSubPages(self
, pObj
, configFile
):
617 Generate sub pages for package's GUID definition.
618 @param pObj package object
619 @param configFilf doxygen config file object
621 pageRoot
= doxygen
.Page('PPI', 'ppi_root_page')
622 objs
= pObj
.GetFileObj().GetSectionObjectsByName('ppis', self
._arch
)
623 if len(objs
) == 0: return []
624 if self
._arch
is not None:
626 pageRoot
.AddPage(self
._GeneratePpiSubPage
(pObj
, obj
, configFile
))
628 guidArchRootPageDict
= {}
630 if obj
.GetArch() not in guidArchRootPageDict
.keys():
631 guidArchRoot
= doxygen
.Page(obj
.GetArch(), 'ppi_arch_root_%s' % obj
.GetArch())
632 pageRoot
.AddPage(guidArchRoot
)
633 guidArchRootPageDict
[obj
.GetArch()] = guidArchRoot
634 guidArchRoot
= guidArchRootPageDict
[obj
.GetArch()]
635 guidArchRoot
.AddPage(self
._GeneratePpiSubPage
(pObj
, obj
, configFile
))
638 def _GenerateProtocolSubPage(self
, pObj
, obj
, configFile
):
639 guidPage
= doxygen
.Page(obj
.GetName(), 'protocol_page_%s' % obj
.GetName())
640 comments
= obj
.GetComment()
641 if len(comments
) != 0:
642 guidPage
.AddDescription('<br>'.join(obj
.GetComment()) + '<br>')
643 section
= doxygen
.Section('BasicProtocolInfo', 'PROTOCOL Information')
646 desc
+= '<TD><CAPTION>PROTOCOL\'s Guid Name</CAPTION></TD><TD><CAPTION>PROTOCOL\'s Guid</CAPTION></TD>'
649 desc
+= '<TD>%s</TD>' % obj
.GetName()
650 desc
+= '<TD>%s</TD>' % obj
.GetGuid()
653 section
.AddDescription(desc
)
654 guidPage
.AddSection(section
)
656 refFile
= self
.FindHeaderFileForGuid(pObj
, obj
.GetName(), configFile
)
658 relPath
= refFile
[len(pObj
.GetWorkspace()) + 1:]
659 if len(comments
) == 0:
660 guidPage
.AddDescription(' \\copydoc %s <br>' % relPath
)
661 section
= doxygen
.Section('ref', 'Refer to Header File')
662 section
.AddDescription('\link %s\n' % relPath
)
663 section
.AddDescription('\endlink\n')
664 self
.ProcessSourceFileForInclude(refFile
, pObj
, configFile
)
665 guidPage
.AddSection(section
)
669 def GenerateProtocolSubPages(self
, pObj
, configFile
):
671 Generate sub pages for package's GUID definition.
672 @param pObj package object
673 @param configFilf doxygen config file object
675 pageRoot
= doxygen
.Page('PROTOCOL', 'protocol_root_page')
676 objs
= pObj
.GetFileObj().GetSectionObjectsByName('protocols', self
._arch
)
677 if len(objs
) == 0: return []
678 if self
._arch
is not None:
680 pageRoot
.AddPage(self
._GenerateProtocolSubPage
(pObj
, obj
, configFile
))
682 guidArchRootPageDict
= {}
684 if obj
.GetArch() not in guidArchRootPageDict
.keys():
685 guidArchRoot
= doxygen
.Page(obj
.GetArch(), 'protocol_arch_root_%s' % obj
.GetArch())
686 pageRoot
.AddPage(guidArchRoot
)
687 guidArchRootPageDict
[obj
.GetArch()] = guidArchRoot
688 guidArchRoot
= guidArchRootPageDict
[obj
.GetArch()]
689 guidArchRoot
.AddPage(self
._GenerateProtocolSubPage
(pObj
, obj
, configFile
))
692 def FindHeaderFileForGuid(self
, pObj
, name
, configFile
):
694 For declaration header file for GUID/PPI/Protocol.
696 @param pObj package object
697 @param name guid/ppi/protocol's name
698 @param configFile config file object
700 @return full path of header file and None if not found.
702 startPath
= pObj
.GetFileObj().GetPackageRootPath()
703 incPath
= os
.path
.join(startPath
, 'Include').replace('\\', '/')
704 # if <PackagePath>/include exist, then search header under it.
705 if os
.path
.exists(incPath
):
708 for root
, dirs
, files
in os
.walk(startPath
):
710 if dir.lower() in _ignore_dir
:
713 fPath
= os
.path
.join(root
, file)
714 if not IsCHeaderFile(fPath
):
718 lines
= f
.readlines()
721 self
.Log('Fail to open file %s\n' % fPath
)
724 if line
.find(name
) != -1 and \
725 line
.find('extern') != -1:
726 return fPath
.replace('\\', '/')
729 def GetPackageModuleList(self
, pObj
):
731 Get all module's INF path under package's root path
732 @param pObj package object
733 @return arrary of INF full path
736 packPath
= pObj
.GetFileObj().GetPackageRootPath()
737 if not os
.path
.exists
:
739 for root
, dirs
, files
in os
.walk(packPath
):
741 if dir.lower() in _ignore_dir
:
744 if CheckPathPostfix(file, 'inf'):
745 fPath
= os
.path
.join(root
, file).replace('\\', '/')
749 def GenerateModulePages(self
, pObj
, configFile
):
751 Generate sub pages for package's module which is under the package
754 @param pObj package object
755 @param configFilf doxygen config file object
757 infList
= self
.GetPackageModuleList(pObj
)
761 for infpath
in infList
:
762 infObj
= inf
.INFFile(infpath
)
763 #infObj = INFFileObject.INFFile (pObj.GetWorkspacePath(),
766 self
.Log('Fail create INF object for %s' % inf
)
768 if not infObj
.Parse():
769 self
.Log('Fail to load INF file %s' % inf
)
771 if infObj
.GetProduceLibraryClass() is not None:
772 libObjs
.append(infObj
)
774 modObjs
.append(infObj
)
776 if len(libObjs
) != 0:
777 libRootPage
= doxygen
.Page('Libraries', 'lib_root_page')
778 rootPages
.append(libRootPage
)
779 for libInf
in libObjs
:
780 libRootPage
.AddPage(self
.GenerateModulePage(pObj
, libInf
, configFile
, True))
782 if len(modObjs
) != 0:
783 modRootPage
= doxygen
.Page('Modules', 'module_root_page')
784 rootPages
.append(modRootPage
)
785 for modInf
in modObjs
:
786 modRootPage
.AddPage(self
.GenerateModulePage(pObj
, modInf
, configFile
, False))
790 def GenerateModulePage(self
, pObj
, infObj
, configFile
, isLib
):
792 Generate page for a module/library.
793 @param infObj INF file object for module/library
794 @param configFile doxygen config file object
795 @param isLib Whether this module is libary
797 @param module doxygen page object
799 workspace
= pObj
.GetWorkspace()
801 for obj
in infObj
.GetSectionObjectsByName('packages'):
802 decObj
= dec
.DECFile(os
.path
.join(workspace
, obj
.GetPath()))
804 ErrorMsg ('Fail to create pacakge object for %s' % obj
.GetPackageName())
806 if not decObj
.Parse():
807 ErrorMsg ('Fail to load package object for %s' % obj
.GetPackageName())
809 refDecObjs
.append(decObj
)
811 modPage
= doxygen
.Page('%s' % infObj
.GetBaseName(),
812 'module_%s' % infObj
.GetBaseName())
813 modPage
.AddDescription(infObj
.GetFileHeader())
815 basicInfSection
= doxygen
.Section('BasicModuleInformation', 'Basic Module Information')
817 for obj
in infObj
.GetSectionObjectsByName('defines'):
819 value
= obj
.GetValue()
820 if key
not in _inf_key_description_mapping_table
.keys(): continue
821 if key
== 'LIBRARY_CLASS' and value
.find('|') != -1:
822 clsname
, types
= value
.split('|')
824 desc
+= '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table
[key
]
825 desc
+= '<TD>%s</TD>' % clsname
829 desc
+= '<TD><B>Supported Module Types</B></TD>'
830 desc
+= '<TD>%s</TD>' % types
834 desc
+= '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table
[key
]
835 if key
== 'EFI_SPECIFICATION_VERSION' and value
== '0x00020000':
837 desc
+= '<TD>%s</TD>' % value
840 basicInfSection
.AddDescription(desc
)
841 modPage
.AddSection(basicInfSection
)
843 # Add protocol section
845 for obj
in infObj
.GetSectionObjectsByName('pcd', self
._arch
):
846 data
.append(obj
.GetPcdName().strip())
848 s
= doxygen
.Section('Pcds', 'Pcds')
850 desc
+= '<TR><TD><B>PCD Name</B></TD><TD><B>TokenSpace</B></TD><TD><B>Package</B></TD></TR>'
853 desc
+= '<TD>%s</TD>' % item
.split('.')[1]
854 desc
+= '<TD>%s</TD>' % item
.split('.')[0]
855 pkgbasename
= self
.SearchPcdPackage(item
, workspace
, refDecObjs
)
856 desc
+= '<TD>%s</TD>' % pkgbasename
859 s
.AddDescription(desc
)
860 modPage
.AddSection(s
)
862 # Add protocol section
863 #sects = infObj.GetSectionByString('protocol')
866 for obj
in infObj
.GetSectionObjectsByName('protocol', self
._arch
):
867 data
.append(obj
.GetName().strip())
869 s
= doxygen
.Section('Protocols', 'Protocols')
871 desc
+= '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
874 desc
+= '<TD>%s</TD>' % item
875 pkgbasename
= self
.SearchProtocolPackage(item
, workspace
, refDecObjs
)
876 desc
+= '<TD>%s</TD>' % pkgbasename
879 s
.AddDescription(desc
)
880 modPage
.AddSection(s
)
883 #sects = infObj.GetSectionByString('ppi')
886 for obj
in infObj
.GetSectionObjectsByName('ppi', self
._arch
):
887 data
.append(obj
.GetName().strip())
889 s
= doxygen
.Section('Ppis', 'Ppis')
891 desc
+= '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
894 desc
+= '<TD>%s</TD>' % item
895 pkgbasename
= self
.SearchPpiPackage(item
, workspace
, refDecObjs
)
896 desc
+= '<TD>%s</TD>' % pkgbasename
899 s
.AddDescription(desc
)
900 modPage
.AddSection(s
)
903 #sects = infObj.GetSectionByString('guid')
906 for obj
in infObj
.GetSectionObjectsByName('guid', self
._arch
):
907 data
.append(obj
.GetName().strip())
909 s
= doxygen
.Section('Guids', 'Guids')
911 desc
+= '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
914 desc
+= '<TD>%s</TD>' % item
915 pkgbasename
= self
.SearchGuidPackage(item
, workspace
, refDecObjs
)
916 desc
+= '<TD>%s</TD>' % pkgbasename
919 s
.AddDescription(desc
)
920 modPage
.AddSection(s
)
922 section
= doxygen
.Section('LibraryClasses', 'Library Classes')
924 desc
+= '<TR><TD><B>Name</B></TD><TD><B>Type</B></TD><TD><B>Package</B></TD><TD><B>Header File</B></TD></TR>'
927 desc
+= '<TD>%s</TD>' % infObj
.GetProduceLibraryClass()
928 desc
+= '<TD>Produce</TD>'
930 pkgname
, hPath
= self
.SearchLibraryClassHeaderFile(infObj
.GetProduceLibraryClass(),
934 self
.Log ('fail to get package header file for lib class %s' % infObj
.GetProduceLibraryClass())
937 desc
+= '<TD>%s</TD>' % pkgname
939 desc
+= '<TD>\link %s \endlink</TD>' % hPath
941 desc
+= '<TD>%s</TD>' % hPath
943 for lcObj
in infObj
.GetSectionObjectsByName('libraryclasses', self
._arch
):
945 desc
+= '<TD>%s</TD>' % lcObj
.GetClass()
946 retarr
= self
.SearchLibraryClassHeaderFile(lcObj
.GetClass(),
949 if retarr
is not None:
950 pkgname
, hPath
= retarr
952 self
.Log('Fail find the library class %s definition from module %s dependent package!' % (lcObj
.GetClass(), infObj
.GetFilename()), 'error')
955 desc
+= '<TD>Consume</TD>'
956 desc
+= '<TD>%s</TD>' % pkgname
957 desc
+= '<TD>\link %s \endlink</TD>' % hPath
960 section
.AddDescription(desc
)
961 modPage
.AddSection(section
)
963 section
= doxygen
.Section('SourceFiles', 'Source Files')
964 section
.AddDescription('<ul>\n')
965 for obj
in infObj
.GetSourceObjects(self
._arch
, self
._tooltag
):
966 sPath
= infObj
.GetModuleRootPath()
967 sPath
= os
.path
.join(sPath
, obj
.GetSourcePath()).replace('\\', '/').strip()
968 if sPath
.lower().endswith('.uni') or sPath
.lower().endswith('.s') or sPath
.lower().endswith('.asm') or sPath
.lower().endswith('.nasm'):
969 newPath
= self
.TranslateUniFile(sPath
)
970 configFile
.AddFile(newPath
)
971 newPath
= newPath
[len(pObj
.GetWorkspace()) + 1:]
972 section
.AddDescription('<li> \link %s \endlink </li>' % newPath
)
974 self
.ProcessSourceFileForInclude(sPath
, pObj
, configFile
, infObj
)
975 sPath
= sPath
[len(pObj
.GetWorkspace()) + 1:]
976 section
.AddDescription('<li>\link %s \endlink </li>' % sPath
)
977 section
.AddDescription('</ul>\n')
978 modPage
.AddSection(section
)
980 #sects = infObj.GetSectionByString('depex')
983 for obj
in infObj
.GetSectionObjectsByName('depex'):
984 data
.append(str(obj
))
986 s
= doxygen
.Section('DependentSection', 'Module Dependencies')
987 s
.AddDescription('<br>'.join(data
))
988 modPage
.AddSection(s
)
992 def TranslateUniFile(self
, path
):
993 newpath
= path
+ '.dox'
994 #import core.textfile as textfile
995 #file = textfile.TextFile(path)
998 file = open(path
, 'r')
999 except (IOError, OSError) as msg
:
1005 output
= '/** @file \n'
1006 #output = '<html><body>'
1007 arr
= t
.split('\r\n')
1009 if line
.find('@file') != -1:
1011 if line
.find('*/') != -1:
1014 if line
.strip().startswith('/'):
1015 arr
= line
.split(' ')
1017 line
= ' '.join(arr
[1:])
1020 output
+= '%s<br>\n' % line
1023 if os
.path
.exists(newpath
):
1026 file = open(newpath
, "w")
1031 def SearchPcdPackage(self
, pcdname
, workspace
, decObjs
):
1032 for decObj
in decObjs
:
1033 for pcd
in decObj
.GetSectionObjectsByName('pcd'):
1034 if pcdname
== pcd
.GetPcdName():
1035 return decObj
.GetBaseName()
1038 def SearchProtocolPackage(self
, protname
, workspace
, decObjs
):
1039 for decObj
in decObjs
:
1040 for proto
in decObj
.GetSectionObjectsByName('protocol'):
1041 if protname
== proto
.GetName():
1042 return decObj
.GetBaseName()
1045 def SearchPpiPackage(self
, ppiname
, workspace
, decObjs
):
1046 for decObj
in decObjs
:
1047 for ppi
in decObj
.GetSectionObjectsByName('ppi'):
1048 if ppiname
== ppi
.GetName():
1049 return decObj
.GetBaseName()
1052 def SearchGuidPackage(self
, guidname
, workspace
, decObjs
):
1053 for decObj
in decObjs
:
1054 for guid
in decObj
.GetSectionObjectsByName('guid'):
1055 if guidname
== guid
.GetName():
1056 return decObj
.GetBaseName()
1059 def SearchLibraryClassHeaderFile(self
, className
, workspace
, decObjs
):
1060 for decObj
in decObjs
:
1061 for cls
in decObj
.GetSectionObjectsByName('libraryclasses'):
1062 if cls
.GetClassName().strip() == className
:
1063 path
= cls
.GetHeaderFile().strip()
1064 path
= os
.path
.join(decObj
.GetPackageRootPath(), path
)
1065 path
= path
[len(workspace
) + 1:]
1066 return decObj
.GetBaseName(), path
.replace('\\', '/')
1070 def _ConvertPathToDoxygen(self
, path
, pObj
):
1071 pRootPath
= pObj
.GetWorkspace()
1072 path
= path
[len(pRootPath
) + 1:]
1073 return path
.replace('\\', '/')
1075 def IsCHeaderFile(path
):
1076 return CheckPathPostfix(path
, 'h')
1078 def CheckPathPostfix(path
, str):
1079 index
= path
.rfind('.')
1082 if path
[index
+ 1:].lower() == str.lower():