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 # This program and the accompanying materials are licensed and made available
9 # under the terms and conditions of the BSD License which accompanies this
10 # distribution. The full text of the license may be found at
11 # http://opensource.org/licenses/bsd-license.php
13 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 """This file produce action class to generate doxygen document for edk2 codebase.
17 The action classes are shared by GUI and command line tools.
19 from plugins
.EdkPlugins
.basemodel
import doxygen
27 from plugins
.EdkPlugins
.edk2
.model
import inf
28 from plugins
.EdkPlugins
.edk2
.model
import dec
29 from plugins
.EdkPlugins
.basemodel
.message
import *
31 _ignore_dir
= ['.svn', '_svn', 'cvs']
32 _inf_key_description_mapping_table
= {
33 'INF_VERSION':'Version of INF file specification',
34 #'BASE_NAME':'Module Name',
35 'FILE_GUID':'Module Guid',
36 'MODULE_TYPE': 'Module Type',
37 'VERSION_STRING': 'Module Version',
38 'LIBRARY_CLASS': 'Produced Library Class',
39 'EFI_SPECIFICATION_VERSION': 'UEFI Specification Version',
40 'PI_SPECIFICATION_VERSION': 'PI Specification Version',
41 'ENTRY_POINT': 'Module Entry Point Function',
42 'CONSTRUCTOR': 'Library Constructor Function'
45 _dec_key_description_mapping_table
= {
46 'DEC_SPECIFICATION': 'Version of DEC file specification',
47 'PACKAGE_GUID': 'Package Guid'
50 """This is base class for all doxygen action.
53 def __init__(self
, doxPath
, chmPath
, outputPath
, projname
, mode
='html', log
=None, verbose
=False):
54 """Constructor function.
55 @param doxPath the obosolution path of doxygen execute file.
56 @param outputPath the obosolution output path.
57 @param log log function for output message
59 self
._doxPath
= doxPath
60 self
._chmPath
= chmPath
61 self
._outputPath
= outputPath
62 self
._projname
= projname
63 self
._configFile
= None # doxygen config file is used by doxygen exe file
64 self
._indexPageFile
= None # doxygen page file for index page.
67 self
._verbose
= verbose
68 self
._doxygenCallback
= None
69 self
._chmCallback
= None
71 def Log(self
, message
, level
='info'):
72 if self
._log
is not None:
73 self
._log
(message
, level
)
79 """Generate interface called by outer directly"""
80 self
.Log(">>>>>> Start generate doxygen document for %s... Zzz....\n" % self
._projname
)
82 # create doxygen config file at first
83 self
._configFile
= doxygen
.DoxygenConfigFile()
84 self
._configFile
.SetOutputDir(self
._outputPath
)
86 self
._configFile
.SetWarningFilePath(os
.path
.join(self
._outputPath
, 'warning.txt'))
87 if self
._mode
.lower() == 'html':
88 self
._configFile
.SetHtmlMode()
90 self
._configFile
.SetChmMode()
92 self
.Log(" >>>>>> Initialize doxygen config file...Zzz...\n")
93 self
.InitializeConfigFile()
95 self
.Log(" >>>>>> Generate doxygen index page file...Zzz...\n")
96 indexPagePath
= self
.GenerateIndexPage()
97 if indexPagePath
is None:
98 self
.Log("Fail to generate index page!\n", 'error')
101 self
.Log("Success to create doxygen index page file %s \n" % indexPagePath
)
103 # Add index page doxygen file to file list.
104 self
._configFile
.AddFile(indexPagePath
)
106 # save config file to output path
107 configFilePath
= os
.path
.join(self
._outputPath
, self
._projname
+ '.doxygen_config')
108 self
._configFile
.Generate(configFilePath
)
109 self
.Log(" <<<<<< Success Save doxygen config file to %s...\n" % configFilePath
)
111 # launch doxygen tool to generate document
112 if self
._doxygenCallback
is not None:
113 self
.Log(" >>>>>> Start doxygen process...Zzz...\n")
114 if not self
._doxygenCallback
(self
._doxPath
, configFilePath
):
117 self
.Log("Fail to create doxygen process!", 'error')
122 def InitializeConfigFile(self
):
123 """Initialize config setting for doxygen project. It will be invoked after config file
124 object is created. Inherited class should implement it.
127 def GenerateIndexPage(self
):
128 """Generate doxygen index page. Inherited class should implement it."""
131 def RegisterCallbackDoxygenProcess(self
, callback
):
132 self
._doxygenCallback
= callback
134 def RegisterCallbackCHMProcess(self
, callback
):
135 self
._chmCallback
= callback
137 class PlatformDocumentAction(DoxygenAction
):
138 """Generate platform doxygen document, will be implement at future."""
140 class PackageDocumentAction(DoxygenAction
):
141 """Generate package reference document"""
143 def __init__(self
, doxPath
, chmPath
, outputPath
, pObj
, mode
='html', log
=None, arch
=None, tooltag
=None,
144 onlyInclude
=False, verbose
=False):
145 DoxygenAction
.__init
__(self
, doxPath
, chmPath
, outputPath
, pObj
.GetName(), mode
, log
, verbose
)
148 self
._tooltag
= tooltag
149 self
._onlyIncludeDocument
= onlyInclude
151 def InitializeConfigFile(self
):
152 if self
._arch
== 'IA32':
153 self
._configFile
.AddPreDefined('MDE_CPU_IA32')
154 elif self
._arch
== 'X64':
155 self
._configFile
.AddPreDefined('MDE_CPU_X64')
156 elif self
._arch
== 'IPF':
157 self
._configFile
.AddPreDefined('MDE_CPU_IPF')
158 elif self
._arch
== 'EBC':
159 self
._configFile
.AddPreDefined('MDE_CPU_EBC')
162 self
._configFile
.AddPreDefined('MDE_CPU_IA32')
163 self
._configFile
.AddPreDefined('MDE_CPU_X64')
164 self
._configFile
.AddPreDefined('MDE_CPU_IPF')
165 self
._configFile
.AddPreDefined('MDE_CPU_EBC')
166 self
._configFile
.AddPreDefined('MDE_CPU_ARM')
168 namestr
= self
._pObj
.GetName()
169 if self
._arch
is not None:
170 namestr
+= '[%s]' % self
._arch
171 if self
._tooltag
is not None:
172 namestr
+= '[%s]' % self
._tooltag
173 self
._configFile
.SetProjectName(namestr
)
174 self
._configFile
.SetStripPath(self
._pObj
.GetWorkspace())
175 self
._configFile
.SetProjectVersion(self
._pObj
.GetFileObj().GetVersion())
176 self
._configFile
.AddPattern('*.decdoxygen')
178 if self
._tooltag
.lower() == 'msft':
179 self
._configFile
.AddPreDefined('_MSC_EXTENSIONS')
180 elif self
._tooltag
.lower() == 'gnu':
181 self
._configFile
.AddPreDefined('__GNUC__')
182 elif self
._tooltag
.lower() == 'intel':
183 self
._configFile
.AddPreDefined('__INTEL_COMPILER')
186 self
._configFile
.AddPreDefined('_MSC_EXTENSIONS')
187 self
._configFile
.AddPreDefined('__GNUC__')
188 self
._configFile
.AddPreDefined('__INTEL_COMPILER')
190 self
._configFile
.AddPreDefined('ASM_PFX= ')
191 self
._configFile
.AddPreDefined('OPTIONAL= ')
193 def GenerateIndexPage(self
):
194 """Generate doxygen index page. Inherited class should implement it."""
195 fObj
= self
._pObj
.GetFileObj()
196 pdObj
= doxygen
.DoxygenFile('%s Package Document' % self
._pObj
.GetName(),
197 '%s.decdoxygen' % self
._pObj
.GetFilename())
198 self
._configFile
.AddFile(pdObj
.GetFilename())
199 pdObj
.AddDescription(fObj
.GetFileHeader())
201 defSection
= fObj
.GetSectionByName('defines')[0]
202 baseSection
= doxygen
.Section('PackageBasicInformation', 'Package Basic Information')
204 for obj
in defSection
.GetObjects():
205 if obj
.GetKey() in _dec_key_description_mapping_table
.keys():
207 descr
+= '<TD><B>%s</B></TD>' % _dec_key_description_mapping_table
[obj
.GetKey()]
208 descr
+= '<TD>%s</TD>' % obj
.GetValue()
210 descr
+= '</TABLE><br>'
211 baseSection
.AddDescription(descr
)
212 pdObj
.AddSection(baseSection
)
214 knownIssueSection
= doxygen
.Section('Known_Issue_section', 'Known Issue')
215 knownIssueSection
.AddDescription('<ul>')
216 knownIssueSection
.AddDescription('<li> OPTIONAL macro for function parameter can not be dealed with doxygen, so it disapear in this document! </li>')
217 knownIssueSection
.AddDescription('</ul>')
218 pdObj
.AddSection(knownIssueSection
)
220 self
.AddAllIncludeFiles(self
._pObj
, self
._configFile
)
221 pages
= self
.GenerateIncludesSubPage(self
._pObj
, self
._configFile
)
223 pdObj
.AddPages(pages
)
224 pages
= self
.GenerateLibraryClassesSubPage(self
._pObj
, self
._configFile
)
226 pdObj
.AddPages(pages
)
227 pages
= self
.GeneratePcdSubPages(self
._pObj
, self
._configFile
)
229 pdObj
.AddPages(pages
)
230 pages
= self
.GenerateGuidSubPages(self
._pObj
, self
._configFile
)
232 pdObj
.AddPages(pages
)
233 pages
= self
.GeneratePpiSubPages(self
._pObj
, self
._configFile
)
235 pdObj
.AddPages(pages
)
236 pages
= self
.GenerateProtocolSubPages(self
._pObj
, self
._configFile
)
238 pdObj
.AddPages(pages
)
239 if not self
._onlyIncludeDocument
:
240 pdObj
.AddPages(self
.GenerateModulePages(self
._pObj
, self
._configFile
))
243 return pdObj
.GetFilename()
245 def GenerateIncludesSubPage(self
, pObj
, configFile
):
246 # by default add following path as include path to config file
247 pkpath
= pObj
.GetFileObj().GetPackageRootPath()
248 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include'))
249 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include', 'Library'))
250 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include', 'Protocol'))
251 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include', 'Ppi'))
252 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include', 'Guid'))
253 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include', 'IndustryStandard'))
256 pageRoot
= doxygen
.Page("Public Includes", "%s_public_includes" % pObj
.GetName())
257 objs
= pObj
.GetFileObj().GetSectionObjectsByName('includes')
258 if len(objs
) == 0: return []
261 # Add path to include path
262 path
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetPath())
263 configFile
.AddIncludePath(path
)
265 # only list common folder's include file
266 if obj
.GetArch().lower() != 'common':
269 bNeedAddIncludePage
= False
270 topPage
= doxygen
.Page(self
._ConvertPathToDoxygen
(path
, pObj
), 'public_include_top')
272 topPage
.AddDescription('<ul>\n')
273 for file in os
.listdir(path
):
274 if file.lower() in _ignore_dir
: continue
275 fullpath
= os
.path
.join(path
, file)
276 if os
.path
.isfile(fullpath
):
277 self
.ProcessSourceFileForInclude(fullpath
, pObj
, configFile
)
278 topPage
.AddDescription('<li> \link %s\endlink </li>\n' % self
._ConvertPathToDoxygen
(fullpath
, pObj
))
280 if file.lower() in ['library', 'protocol', 'guid', 'ppi', 'ia32', 'x64', 'ipf', 'ebc', 'arm', 'pi', 'uefi', 'aarch64']:
282 bNeedAddSubPage
= False
283 subpage
= doxygen
.Page(self
._ConvertPathToDoxygen
(fullpath
, pObj
), 'public_include_%s' % file)
284 subpage
.AddDescription('<ul>\n')
285 for subfile
in os
.listdir(fullpath
):
286 if subfile
.lower() in _ignore_dir
: continue
287 bNeedAddSubPage
= True
288 subfullpath
= os
.path
.join(fullpath
, subfile
)
289 self
.ProcessSourceFileForInclude(subfullpath
, pObj
, configFile
)
290 subpage
.AddDescription('<li> \link %s \endlink </li>\n' % self
._ConvertPathToDoxygen
(subfullpath
, pObj
))
291 subpage
.AddDescription('</ul>\n')
293 bNeedAddIncludePage
= True
294 pageRoot
.AddPage(subpage
)
295 topPage
.AddDescription('</ul>\n')
296 if bNeedAddIncludePage
:
297 pageRoot
.AddPage(topPage
)
299 if pageRoot
.GetSubpageCount() != 0:
304 def GenerateLibraryClassesSubPage(self
, pObj
, configFile
):
306 Generate sub page for library class for package.
307 One DEC file maybe contains many library class sections
308 for different architecture.
310 @param fObj DEC file object.
313 pageRoot
= doxygen
.Page("Library Class", "%s_libraryclass" % pObj
.GetName())
314 objs
= pObj
.GetFileObj().GetSectionObjectsByName('libraryclass', self
._arch
)
315 if len(objs
) == 0: return []
317 if self
._arch
is not None:
319 classPage
= doxygen
.Page(obj
.GetClassName(),
320 "lc_%s" % obj
.GetClassName())
321 comments
= obj
.GetComment()
322 if len(comments
) != 0:
323 classPage
.AddDescription('<br>\n'.join(comments
) + '<br>\n')
324 pageRoot
.AddPage(classPage
)
325 path
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetHeaderFile())
326 path
= path
[len(pObj
.GetWorkspace()) + 1:]
327 if len(comments
) == 0:
328 classPage
.AddDescription('\copydoc %s<p>' % obj
.GetHeaderFile())
329 section
= doxygen
.Section('ref', 'Refer to Header File')
330 section
.AddDescription('\link %s\n' % obj
.GetHeaderFile())
331 section
.AddDescription(' \endlink<p>\n')
332 classPage
.AddSection(section
)
333 fullPath
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetHeaderFile())
334 self
.ProcessSourceFileForInclude(fullPath
, pObj
, configFile
)
338 if obj
.GetArch() not in archPageDict
.keys():
339 archPageDict
[obj
.GetArch()] = doxygen
.Page(obj
.GetArch(),
340 'lc_%s' % obj
.GetArch())
341 pageRoot
.AddPage(archPageDict
[obj
.GetArch()])
342 subArchRoot
= archPageDict
[obj
.GetArch()]
343 classPage
= doxygen
.Page(obj
.GetClassName(),
344 "lc_%s" % obj
.GetClassName())
345 comments
= obj
.GetComment()
346 if len(comments
) != 0:
347 classPage
.AddDescription('<br>\n'.join(comments
) + '<br>\n')
348 subArchRoot
.AddPage(classPage
)
349 path
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetHeaderFile())
350 path
= path
[len(pObj
.GetWorkspace()) + 1:]
351 if len(comments
) == 0:
352 classPage
.AddDescription('\copydoc %s<p>' % obj
.GetHeaderFile())
353 section
= doxygen
.Section('ref', 'Refer to Header File')
354 section
.AddDescription('\link %s\n' % obj
.GetHeaderFile())
355 section
.AddDescription(' \endlink<p>\n')
356 classPage
.AddSection(section
)
357 fullPath
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetHeaderFile())
359 self
.ProcessSourceFileForInclude(fullPath
, pObj
, configFile
)
360 rootArray
.append(pageRoot
)
363 def ProcessSourceFileForInclude(self
, path
, pObj
, configFile
, infObj
=None):
365 @param path the analysising file full path
366 @param pObj package object
367 @param configFile doxygen config file.
371 if not os
.path
.exists(path
):
372 ErrorMsg('Source file path %s does not exist!' % path
)
375 if configFile
.FileExists(path
):
379 with
open(path
, 'r') as f
:
380 lines
= f
.readlines()
381 except UnicodeDecodeError:
384 ErrorMsg('Fail to open file %s' % path
)
387 configFile
.AddFile(path
)
390 for no
in range(len(lines
)):
391 if len(lines
[no
].strip()) == 0:
393 if lines
[no
].strip()[:2] in ['##', '//', '/*', '*/']:
395 index
= lines
[no
].lower().find('include')
396 #mo = IncludePattern.finditer(lines[no].lower())
397 mo
= re
.match(r
"^#\s*include\s+[<\"]([\\/\w
.]+)[>\"]$
", lines[no].strip().lower())
400 mo = re.match(r"^
[#\w\s]+[<\"]([\\/\w.]+)[>\"]$", lines[no].strip())
401 filePath
= mo
.groups()[0]
403 if filePath
is None or len(filePath
) == 0:
406 # find header file in module's path firstly.
409 if os
.path
.exists(os
.path
.join(os
.path
.dirname(path
), filePath
)):
410 # Find the file in current directory
411 fullPath
= os
.path
.join(os
.path
.dirname(path
), filePath
).replace('\\', '/')
413 # find in depedent package's include path
414 incObjs
= pObj
.GetFileObj().GetSectionObjectsByName('includes')
415 for incObj
in incObjs
:
416 incPath
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), incObj
.GetPath()).strip()
417 incPath
= os
.path
.realpath(os
.path
.join(incPath
, filePath
))
418 if os
.path
.exists(incPath
):
421 if infObj
is not None:
422 pkgInfObjs
= infObj
.GetSectionObjectsByName('packages')
423 for obj
in pkgInfObjs
:
424 decObj
= dec
.DECFile(os
.path
.join(pObj
.GetWorkspace(), obj
.GetPath()))
426 ErrorMsg ('Fail to create pacakge object for %s' % obj
.GetPackageName())
428 if not decObj
.Parse():
429 ErrorMsg ('Fail to load package object for %s' % obj
.GetPackageName())
431 incObjs
= decObj
.GetSectionObjectsByName('includes')
432 for incObj
in incObjs
:
433 incPath
= os
.path
.join(decObj
.GetPackageRootPath(), incObj
.GetPath()).replace('\\', '/')
434 if os
.path
.exists(os
.path
.join(incPath
, filePath
)):
435 fullPath
= os
.path
.join(os
.path
.join(incPath
, filePath
))
437 if fullPath
is not None:
440 if fullPath
is None and self
.IsVerbose():
441 self
.Log('Can not resolve header file %s for file %s in package %s\n' % (filePath
, path
, pObj
.GetFileObj().GetFilename()), 'error')
444 fullPath
= fullPath
.replace('\\', '/')
446 self
.Log('Preprocessing: Add include file %s for file %s\n' % (fullPath
, path
))
447 #LogMsg ('Preprocessing: Add include file %s for file %s' % (fullPath, path))
448 self
.ProcessSourceFileForInclude(fullPath
, pObj
, configFile
, infObj
)
450 def AddAllIncludeFiles(self
, pObj
, configFile
):
451 objs
= pObj
.GetFileObj().GetSectionObjectsByName('includes')
453 incPath
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetPath())
454 for root
, dirs
, files
in os
.walk(incPath
):
456 if dir.lower() in _ignore_dir
:
459 path
= os
.path
.normpath(os
.path
.join(root
, file))
460 configFile
.AddFile(path
.replace('/', '\\'))
462 def GeneratePcdSubPages(self
, pObj
, configFile
):
464 Generate sub pages for package's PCD definition.
465 @param pObj package object
466 @param configFile config file object
469 objs
= pObj
.GetFileObj().GetSectionObjectsByName('pcd')
473 pcdRootPage
= doxygen
.Page('PCD', 'pcd_root_page')
474 typeRootPageDict
= {}
475 typeArchRootPageDict
= {}
477 if obj
.GetPcdType() not in typeRootPageDict
.keys():
478 typeRootPageDict
[obj
.GetPcdType()] = doxygen
.Page(obj
.GetPcdType(), 'pcd_%s_root_page' % obj
.GetPcdType())
479 pcdRootPage
.AddPage(typeRootPageDict
[obj
.GetPcdType()])
480 typeRoot
= typeRootPageDict
[obj
.GetPcdType()]
481 if self
._arch
is not None:
482 pcdPage
= doxygen
.Page('%s' % obj
.GetPcdName(),
483 'pcd_%s_%s_%s' % (obj
.GetPcdType(), obj
.GetArch(), obj
.GetPcdName().split('.')[1]))
484 pcdPage
.AddDescription('<br>\n'.join(obj
.GetComment()) + '<br>\n')
485 section
= doxygen
.Section('PCDinformation', 'PCD Information')
488 desc
+= '<TD><CAPTION>Name</CAPTION></TD>'
489 desc
+= '<TD><CAPTION>Token Space</CAPTION></TD>'
490 desc
+= '<TD><CAPTION>Token number</CAPTION></TD>'
491 desc
+= '<TD><CAPTION>Data Type</CAPTION></TD>'
492 desc
+= '<TD><CAPTION>Default Value</CAPTION></TD>'
495 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdName().split('.')[1]
496 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdName().split('.')[0]
497 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdToken()
498 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdDataType()
499 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdValue()
502 section
.AddDescription(desc
)
503 pcdPage
.AddSection(section
)
504 typeRoot
.AddPage(pcdPage
)
506 keystr
= obj
.GetPcdType() + obj
.GetArch()
507 if keystr
not in typeArchRootPageDict
.keys():
508 typeArchRootPage
= doxygen
.Page(obj
.GetArch(), 'pcd_%s_%s_root_page' % (obj
.GetPcdType(), obj
.GetArch()))
509 typeArchRootPageDict
[keystr
] = typeArchRootPage
510 typeRoot
.AddPage(typeArchRootPage
)
511 typeArchRoot
= typeArchRootPageDict
[keystr
]
512 pcdPage
= doxygen
.Page('%s' % obj
.GetPcdName(),
513 'pcd_%s_%s_%s' % (obj
.GetPcdType(), obj
.GetArch(), obj
.GetPcdName().split('.')[1]))
514 pcdPage
.AddDescription('<br>\n'.join(obj
.GetComment()) + '<br>\n')
515 section
= doxygen
.Section('PCDinformation', 'PCD Information')
518 desc
+= '<TD><CAPTION>Name</CAPTION></TD>'
519 desc
+= '<TD><CAPTION>Token Space</CAPTION></TD>'
520 desc
+= '<TD><CAPTION>Token number</CAPTION></TD>'
521 desc
+= '<TD><CAPTION>Data Type</CAPTION></TD>'
522 desc
+= '<TD><CAPTION>Default Value</CAPTION></TD>'
525 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdName().split('.')[1]
526 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdName().split('.')[0]
527 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdToken()
528 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdDataType()
529 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdValue()
532 section
.AddDescription(desc
)
533 pcdPage
.AddSection(section
)
534 typeArchRoot
.AddPage(pcdPage
)
537 def _GenerateGuidSubPage(self
, pObj
, obj
, configFile
):
538 guidPage
= doxygen
.Page('%s' % obj
.GetName(),
539 'guid_%s_%s' % (obj
.GetArch(), obj
.GetName()))
540 comments
= obj
.GetComment()
541 if len(comments
) != 0:
542 guidPage
.AddDescription('<br>'.join(obj
.GetComment()) + '<br>')
543 section
= doxygen
.Section('BasicGuidInfo', 'GUID Information')
546 desc
+= '<TD><CAPTION>GUID\'s Guid Name</CAPTION></TD><TD><CAPTION>GUID\'s Guid</CAPTION></TD>'
549 desc
+= '<TD>%s</TD>' % obj
.GetName()
550 desc
+= '<TD>%s</TD>' % obj
.GetGuid()
553 section
.AddDescription(desc
)
554 guidPage
.AddSection(section
)
555 refFile
= self
.FindHeaderFileForGuid(pObj
, obj
.GetName(), configFile
)
557 relPath
= refFile
[len(pObj
.GetWorkspace()) + 1:]
558 if len(comments
) == 0:
559 guidPage
.AddDescription(' \\copydoc %s <br>' % relPath
)
561 section
= doxygen
.Section('ref', 'Refer to Header File')
562 section
.AddDescription('\link %s\n' % relPath
)
563 section
.AddDescription('\endlink\n')
564 self
.ProcessSourceFileForInclude(refFile
, pObj
, configFile
)
565 guidPage
.AddSection(section
)
568 def GenerateGuidSubPages(self
, pObj
, configFile
):
570 Generate sub pages for package's GUID definition.
571 @param pObj package object
572 @param configFilf doxygen config file object
574 pageRoot
= doxygen
.Page('GUID', 'guid_root_page')
575 objs
= pObj
.GetFileObj().GetSectionObjectsByName('guids', self
._arch
)
576 if len(objs
) == 0: return []
577 if self
._arch
is not None:
579 pageRoot
.AddPage(self
._GenerateGuidSubPage
(pObj
, obj
, configFile
))
581 guidArchRootPageDict
= {}
583 if obj
.GetArch() not in guidArchRootPageDict
.keys():
584 guidArchRoot
= doxygen
.Page(obj
.GetArch(), 'guid_arch_root_%s' % obj
.GetArch())
585 pageRoot
.AddPage(guidArchRoot
)
586 guidArchRootPageDict
[obj
.GetArch()] = guidArchRoot
587 guidArchRoot
= guidArchRootPageDict
[obj
.GetArch()]
588 guidArchRoot
.AddPage(self
._GenerateGuidSubPage
(pObj
, obj
, configFile
))
591 def _GeneratePpiSubPage(self
, pObj
, obj
, configFile
):
592 guidPage
= doxygen
.Page(obj
.GetName(), 'ppi_page_%s' % obj
.GetName())
593 comments
= obj
.GetComment()
594 if len(comments
) != 0:
595 guidPage
.AddDescription('<br>'.join(obj
.GetComment()) + '<br>')
596 section
= doxygen
.Section('BasicPpiInfo', 'PPI Information')
599 desc
+= '<TD><CAPTION>PPI\'s Guid Name</CAPTION></TD><TD><CAPTION>PPI\'s Guid</CAPTION></TD>'
602 desc
+= '<TD>%s</TD>' % obj
.GetName()
603 desc
+= '<TD>%s</TD>' % obj
.GetGuid()
606 section
.AddDescription(desc
)
607 guidPage
.AddSection(section
)
608 refFile
= self
.FindHeaderFileForGuid(pObj
, obj
.GetName(), configFile
)
610 relPath
= refFile
[len(pObj
.GetWorkspace()) + 1:]
611 if len(comments
) == 0:
612 guidPage
.AddDescription(' \\copydoc %s <br>' % relPath
)
613 section
= doxygen
.Section('ref', 'Refer to Header File')
614 section
.AddDescription('\link %s\n' % relPath
)
615 section
.AddDescription('\endlink\n')
616 self
.ProcessSourceFileForInclude(refFile
, pObj
, configFile
)
617 guidPage
.AddSection(section
)
621 def GeneratePpiSubPages(self
, pObj
, configFile
):
623 Generate sub pages for package's GUID definition.
624 @param pObj package object
625 @param configFilf doxygen config file object
627 pageRoot
= doxygen
.Page('PPI', 'ppi_root_page')
628 objs
= pObj
.GetFileObj().GetSectionObjectsByName('ppis', self
._arch
)
629 if len(objs
) == 0: return []
630 if self
._arch
is not None:
632 pageRoot
.AddPage(self
._GeneratePpiSubPage
(pObj
, obj
, configFile
))
634 guidArchRootPageDict
= {}
636 if obj
.GetArch() not in guidArchRootPageDict
.keys():
637 guidArchRoot
= doxygen
.Page(obj
.GetArch(), 'ppi_arch_root_%s' % obj
.GetArch())
638 pageRoot
.AddPage(guidArchRoot
)
639 guidArchRootPageDict
[obj
.GetArch()] = guidArchRoot
640 guidArchRoot
= guidArchRootPageDict
[obj
.GetArch()]
641 guidArchRoot
.AddPage(self
._GeneratePpiSubPage
(pObj
, obj
, configFile
))
644 def _GenerateProtocolSubPage(self
, pObj
, obj
, configFile
):
645 guidPage
= doxygen
.Page(obj
.GetName(), 'protocol_page_%s' % obj
.GetName())
646 comments
= obj
.GetComment()
647 if len(comments
) != 0:
648 guidPage
.AddDescription('<br>'.join(obj
.GetComment()) + '<br>')
649 section
= doxygen
.Section('BasicProtocolInfo', 'PROTOCOL Information')
652 desc
+= '<TD><CAPTION>PROTOCOL\'s Guid Name</CAPTION></TD><TD><CAPTION>PROTOCOL\'s Guid</CAPTION></TD>'
655 desc
+= '<TD>%s</TD>' % obj
.GetName()
656 desc
+= '<TD>%s</TD>' % obj
.GetGuid()
659 section
.AddDescription(desc
)
660 guidPage
.AddSection(section
)
662 refFile
= self
.FindHeaderFileForGuid(pObj
, obj
.GetName(), configFile
)
664 relPath
= refFile
[len(pObj
.GetWorkspace()) + 1:]
665 if len(comments
) == 0:
666 guidPage
.AddDescription(' \\copydoc %s <br>' % relPath
)
667 section
= doxygen
.Section('ref', 'Refer to Header File')
668 section
.AddDescription('\link %s\n' % relPath
)
669 section
.AddDescription('\endlink\n')
670 self
.ProcessSourceFileForInclude(refFile
, pObj
, configFile
)
671 guidPage
.AddSection(section
)
675 def GenerateProtocolSubPages(self
, pObj
, configFile
):
677 Generate sub pages for package's GUID definition.
678 @param pObj package object
679 @param configFilf doxygen config file object
681 pageRoot
= doxygen
.Page('PROTOCOL', 'protocol_root_page')
682 objs
= pObj
.GetFileObj().GetSectionObjectsByName('protocols', self
._arch
)
683 if len(objs
) == 0: return []
684 if self
._arch
is not None:
686 pageRoot
.AddPage(self
._GenerateProtocolSubPage
(pObj
, obj
, configFile
))
688 guidArchRootPageDict
= {}
690 if obj
.GetArch() not in guidArchRootPageDict
.keys():
691 guidArchRoot
= doxygen
.Page(obj
.GetArch(), 'protocol_arch_root_%s' % obj
.GetArch())
692 pageRoot
.AddPage(guidArchRoot
)
693 guidArchRootPageDict
[obj
.GetArch()] = guidArchRoot
694 guidArchRoot
= guidArchRootPageDict
[obj
.GetArch()]
695 guidArchRoot
.AddPage(self
._GenerateProtocolSubPage
(pObj
, obj
, configFile
))
698 def FindHeaderFileForGuid(self
, pObj
, name
, configFile
):
700 For declaration header file for GUID/PPI/Protocol.
702 @param pObj package object
703 @param name guid/ppi/protocol's name
704 @param configFile config file object
706 @return full path of header file and None if not found.
708 startPath
= pObj
.GetFileObj().GetPackageRootPath()
709 incPath
= os
.path
.join(startPath
, 'Include').replace('\\', '/')
710 # if <PackagePath>/include exist, then search header under it.
711 if os
.path
.exists(incPath
):
714 for root
, dirs
, files
in os
.walk(startPath
):
716 if dir.lower() in _ignore_dir
:
719 fPath
= os
.path
.join(root
, file)
720 if not IsCHeaderFile(fPath
):
724 lines
= f
.readlines()
727 self
.Log('Fail to open file %s\n' % fPath
)
730 if line
.find(name
) != -1 and \
731 line
.find('extern') != -1:
732 return fPath
.replace('\\', '/')
735 def GetPackageModuleList(self
, pObj
):
737 Get all module's INF path under package's root path
738 @param pObj package object
739 @return arrary of INF full path
742 packPath
= pObj
.GetFileObj().GetPackageRootPath()
743 if not os
.path
.exists
:
745 for root
, dirs
, files
in os
.walk(packPath
):
747 if dir.lower() in _ignore_dir
:
750 if CheckPathPostfix(file, 'inf'):
751 fPath
= os
.path
.join(root
, file).replace('\\', '/')
755 def GenerateModulePages(self
, pObj
, configFile
):
757 Generate sub pages for package's module which is under the package
760 @param pObj package object
761 @param configFilf doxygen config file object
763 infList
= self
.GetPackageModuleList(pObj
)
767 for infpath
in infList
:
768 infObj
= inf
.INFFile(infpath
)
769 #infObj = INFFileObject.INFFile (pObj.GetWorkspacePath(),
772 self
.Log('Fail create INF object for %s' % inf
)
774 if not infObj
.Parse():
775 self
.Log('Fail to load INF file %s' % inf
)
777 if infObj
.GetProduceLibraryClass() is not None:
778 libObjs
.append(infObj
)
780 modObjs
.append(infObj
)
782 if len(libObjs
) != 0:
783 libRootPage
= doxygen
.Page('Libraries', 'lib_root_page')
784 rootPages
.append(libRootPage
)
785 for libInf
in libObjs
:
786 libRootPage
.AddPage(self
.GenerateModulePage(pObj
, libInf
, configFile
, True))
788 if len(modObjs
) != 0:
789 modRootPage
= doxygen
.Page('Modules', 'module_root_page')
790 rootPages
.append(modRootPage
)
791 for modInf
in modObjs
:
792 modRootPage
.AddPage(self
.GenerateModulePage(pObj
, modInf
, configFile
, False))
796 def GenerateModulePage(self
, pObj
, infObj
, configFile
, isLib
):
798 Generate page for a module/library.
799 @param infObj INF file object for module/library
800 @param configFile doxygen config file object
801 @param isLib Whether this module is libary
803 @param module doxygen page object
805 workspace
= pObj
.GetWorkspace()
807 for obj
in infObj
.GetSectionObjectsByName('packages'):
808 decObj
= dec
.DECFile(os
.path
.join(workspace
, obj
.GetPath()))
810 ErrorMsg ('Fail to create pacakge object for %s' % obj
.GetPackageName())
812 if not decObj
.Parse():
813 ErrorMsg ('Fail to load package object for %s' % obj
.GetPackageName())
815 refDecObjs
.append(decObj
)
817 modPage
= doxygen
.Page('%s' % infObj
.GetBaseName(),
818 'module_%s' % infObj
.GetBaseName())
819 modPage
.AddDescription(infObj
.GetFileHeader())
821 basicInfSection
= doxygen
.Section('BasicModuleInformation', 'Basic Module Information')
823 for obj
in infObj
.GetSectionObjectsByName('defines'):
825 value
= obj
.GetValue()
826 if key
not in _inf_key_description_mapping_table
.keys(): continue
827 if key
== 'LIBRARY_CLASS' and value
.find('|') != -1:
828 clsname
, types
= value
.split('|')
830 desc
+= '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table
[key
]
831 desc
+= '<TD>%s</TD>' % clsname
835 desc
+= '<TD><B>Supported Module Types</B></TD>'
836 desc
+= '<TD>%s</TD>' % types
840 desc
+= '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table
[key
]
841 if key
== 'EFI_SPECIFICATION_VERSION' and value
== '0x00020000':
843 desc
+= '<TD>%s</TD>' % value
846 basicInfSection
.AddDescription(desc
)
847 modPage
.AddSection(basicInfSection
)
849 # Add protocol section
851 for obj
in infObj
.GetSectionObjectsByName('pcd', self
._arch
):
852 data
.append(obj
.GetPcdName().strip())
854 s
= doxygen
.Section('Pcds', 'Pcds')
856 desc
+= '<TR><TD><B>PCD Name</B></TD><TD><B>TokenSpace</B></TD><TD><B>Package</B></TD></TR>'
859 desc
+= '<TD>%s</TD>' % item
.split('.')[1]
860 desc
+= '<TD>%s</TD>' % item
.split('.')[0]
861 pkgbasename
= self
.SearchPcdPackage(item
, workspace
, refDecObjs
)
862 desc
+= '<TD>%s</TD>' % pkgbasename
865 s
.AddDescription(desc
)
866 modPage
.AddSection(s
)
868 # Add protocol section
869 #sects = infObj.GetSectionByString('protocol')
872 for obj
in infObj
.GetSectionObjectsByName('protocol', self
._arch
):
873 data
.append(obj
.GetName().strip())
875 s
= doxygen
.Section('Protocols', 'Protocols')
877 desc
+= '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
880 desc
+= '<TD>%s</TD>' % item
881 pkgbasename
= self
.SearchProtocolPackage(item
, workspace
, refDecObjs
)
882 desc
+= '<TD>%s</TD>' % pkgbasename
885 s
.AddDescription(desc
)
886 modPage
.AddSection(s
)
889 #sects = infObj.GetSectionByString('ppi')
892 for obj
in infObj
.GetSectionObjectsByName('ppi', self
._arch
):
893 data
.append(obj
.GetName().strip())
895 s
= doxygen
.Section('Ppis', 'Ppis')
897 desc
+= '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
900 desc
+= '<TD>%s</TD>' % item
901 pkgbasename
= self
.SearchPpiPackage(item
, workspace
, refDecObjs
)
902 desc
+= '<TD>%s</TD>' % pkgbasename
905 s
.AddDescription(desc
)
906 modPage
.AddSection(s
)
909 #sects = infObj.GetSectionByString('guid')
912 for obj
in infObj
.GetSectionObjectsByName('guid', self
._arch
):
913 data
.append(obj
.GetName().strip())
915 s
= doxygen
.Section('Guids', 'Guids')
917 desc
+= '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
920 desc
+= '<TD>%s</TD>' % item
921 pkgbasename
= self
.SearchGuidPackage(item
, workspace
, refDecObjs
)
922 desc
+= '<TD>%s</TD>' % pkgbasename
925 s
.AddDescription(desc
)
926 modPage
.AddSection(s
)
928 section
= doxygen
.Section('LibraryClasses', 'Library Classes')
930 desc
+= '<TR><TD><B>Name</B></TD><TD><B>Type</B></TD><TD><B>Package</B></TD><TD><B>Header File</B></TD></TR>'
933 desc
+= '<TD>%s</TD>' % infObj
.GetProduceLibraryClass()
934 desc
+= '<TD>Produce</TD>'
936 pkgname
, hPath
= self
.SearchLibraryClassHeaderFile(infObj
.GetProduceLibraryClass(),
940 self
.Log ('fail to get package header file for lib class %s' % infObj
.GetProduceLibraryClass())
943 desc
+= '<TD>%s</TD>' % pkgname
945 desc
+= '<TD>\link %s \endlink</TD>' % hPath
947 desc
+= '<TD>%s</TD>' % hPath
949 for lcObj
in infObj
.GetSectionObjectsByName('libraryclasses', self
._arch
):
951 desc
+= '<TD>%s</TD>' % lcObj
.GetClass()
952 retarr
= self
.SearchLibraryClassHeaderFile(lcObj
.GetClass(),
955 if retarr
is not None:
956 pkgname
, hPath
= retarr
958 self
.Log('Fail find the library class %s definition from module %s dependent package!' % (lcObj
.GetClass(), infObj
.GetFilename()), 'error')
961 desc
+= '<TD>Consume</TD>'
962 desc
+= '<TD>%s</TD>' % pkgname
963 desc
+= '<TD>\link %s \endlink</TD>' % hPath
966 section
.AddDescription(desc
)
967 modPage
.AddSection(section
)
969 section
= doxygen
.Section('SourceFiles', 'Source Files')
970 section
.AddDescription('<ul>\n')
971 for obj
in infObj
.GetSourceObjects(self
._arch
, self
._tooltag
):
972 sPath
= infObj
.GetModuleRootPath()
973 sPath
= os
.path
.join(sPath
, obj
.GetSourcePath()).replace('\\', '/').strip()
974 if sPath
.lower().endswith('.uni') or sPath
.lower().endswith('.s') or sPath
.lower().endswith('.asm') or sPath
.lower().endswith('.nasm'):
975 newPath
= self
.TranslateUniFile(sPath
)
976 configFile
.AddFile(newPath
)
977 newPath
= newPath
[len(pObj
.GetWorkspace()) + 1:]
978 section
.AddDescription('<li> \link %s \endlink </li>' % newPath
)
980 self
.ProcessSourceFileForInclude(sPath
, pObj
, configFile
, infObj
)
981 sPath
= sPath
[len(pObj
.GetWorkspace()) + 1:]
982 section
.AddDescription('<li>\link %s \endlink </li>' % sPath
)
983 section
.AddDescription('</ul>\n')
984 modPage
.AddSection(section
)
986 #sects = infObj.GetSectionByString('depex')
989 for obj
in infObj
.GetSectionObjectsByName('depex'):
990 data
.append(str(obj
))
992 s
= doxygen
.Section('DependentSection', 'Module Dependencies')
993 s
.AddDescription('<br>'.join(data
))
994 modPage
.AddSection(s
)
998 def TranslateUniFile(self
, path
):
999 newpath
= path
+ '.dox'
1000 #import core.textfile as textfile
1001 #file = textfile.TextFile(path)
1004 file = open(path
, 'r')
1005 except (IOError, OSError) as msg
:
1011 output
= '/** @file \n'
1012 #output = '<html><body>'
1013 arr
= t
.split('\r\n')
1015 if line
.find('@file') != -1:
1017 if line
.find('*/') != -1:
1020 if line
.strip().startswith('/'):
1021 arr
= line
.split(' ')
1023 line
= ' '.join(arr
[1:])
1026 output
+= '%s<br>\n' % line
1029 if os
.path
.exists(newpath
):
1032 file = open(newpath
, "w")
1037 def SearchPcdPackage(self
, pcdname
, workspace
, decObjs
):
1038 for decObj
in decObjs
:
1039 for pcd
in decObj
.GetSectionObjectsByName('pcd'):
1040 if pcdname
== pcd
.GetPcdName():
1041 return decObj
.GetBaseName()
1044 def SearchProtocolPackage(self
, protname
, workspace
, decObjs
):
1045 for decObj
in decObjs
:
1046 for proto
in decObj
.GetSectionObjectsByName('protocol'):
1047 if protname
== proto
.GetName():
1048 return decObj
.GetBaseName()
1051 def SearchPpiPackage(self
, ppiname
, workspace
, decObjs
):
1052 for decObj
in decObjs
:
1053 for ppi
in decObj
.GetSectionObjectsByName('ppi'):
1054 if ppiname
== ppi
.GetName():
1055 return decObj
.GetBaseName()
1058 def SearchGuidPackage(self
, guidname
, workspace
, decObjs
):
1059 for decObj
in decObjs
:
1060 for guid
in decObj
.GetSectionObjectsByName('guid'):
1061 if guidname
== guid
.GetName():
1062 return decObj
.GetBaseName()
1065 def SearchLibraryClassHeaderFile(self
, className
, workspace
, decObjs
):
1066 for decObj
in decObjs
:
1067 for cls
in decObj
.GetSectionObjectsByName('libraryclasses'):
1068 if cls
.GetClassName().strip() == className
:
1069 path
= cls
.GetHeaderFile().strip()
1070 path
= os
.path
.join(decObj
.GetPackageRootPath(), path
)
1071 path
= path
[len(workspace
) + 1:]
1072 return decObj
.GetBaseName(), path
.replace('\\', '/')
1076 def _ConvertPathToDoxygen(self
, path
, pObj
):
1077 pRootPath
= pObj
.GetWorkspace()
1078 path
= path
[len(pRootPath
) + 1:]
1079 return path
.replace('\\', '/')
1081 def IsCHeaderFile(path
):
1082 return CheckPathPostfix(path
, 'h')
1084 def CheckPathPostfix(path
, str):
1085 index
= path
.rfind('.')
1088 if path
[index
+ 1:].lower() == str.lower():