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 from plugins
.EdkPlugins
.basemodel
import doxygen
18 from plugins
.EdkPlugins
.edk2
.model
import inf
19 from plugins
.EdkPlugins
.edk2
.model
import dec
20 from plugins
.EdkPlugins
.basemodel
.message
import *
22 _ignore_dir
= ['.svn', '_svn', 'cvs']
23 _inf_key_description_mapping_table
= {
24 'INF_VERSION':'Version of INF file specification',
25 #'BASE_NAME':'Module Name',
26 'FILE_GUID':'Module Guid',
27 'MODULE_TYPE': 'Module Type',
28 'VERSION_STRING': 'Module Version',
29 'LIBRARY_CLASS': 'Produced Library Class',
30 'EFI_SPECIFICATION_VERSION': 'UEFI Specification Version',
31 'PI_SPECIFICATION_VERSION': 'PI Specification Version',
32 'ENTRY_POINT': 'Module Entry Point Function',
33 'CONSTRUCTOR': 'Library Constructor Function'
36 _dec_key_description_mapping_table
= {
37 'DEC_SPECIFICATION': 'Version of DEC file specification',
38 'PACKAGE_GUID': 'Package Guid'
41 """This is base class for all doxygen action.
44 def __init__(self
, doxPath
, chmPath
, outputPath
, projname
, mode
='html', log
=None, verbose
=False):
45 """Constructor function.
46 @param doxPath the obosolution path of doxygen execute file.
47 @param outputPath the obosolution output path.
48 @param log log function for output message
50 self
._doxPath
= doxPath
51 self
._chmPath
= chmPath
52 self
._outputPath
= outputPath
53 self
._projname
= projname
54 self
._configFile
= None # doxygen config file is used by doxygen exe file
55 self
._indexPageFile
= None # doxygen page file for index page.
58 self
._verbose
= verbose
59 self
._doxygenCallback
= None
60 self
._chmCallback
= None
62 def Log(self
, message
, level
='info'):
63 if self
._log
is not None:
64 self
._log
(message
, level
)
70 """Generate interface called by outer directly"""
71 self
.Log(">>>>>> Start generate doxygen document for %s... Zzz....\n" % self
._projname
)
73 # create doxygen config file at first
74 self
._configFile
= doxygen
.DoxygenConfigFile()
75 self
._configFile
.SetOutputDir(self
._outputPath
)
77 self
._configFile
.SetWarningFilePath(os
.path
.join(self
._outputPath
, 'warning.txt'))
78 if self
._mode
.lower() == 'html':
79 self
._configFile
.SetHtmlMode()
81 self
._configFile
.SetChmMode()
83 self
.Log(" >>>>>> Initialize doxygen config file...Zzz...\n")
84 self
.InitializeConfigFile()
86 self
.Log(" >>>>>> Generate doxygen index page file...Zzz...\n")
87 indexPagePath
= self
.GenerateIndexPage()
88 if indexPagePath
is None:
89 self
.Log("Fail to generate index page!\n", 'error')
92 self
.Log("Success to create doxygen index page file %s \n" % indexPagePath
)
94 # Add index page doxygen file to file list.
95 self
._configFile
.AddFile(indexPagePath
)
97 # save config file to output path
98 configFilePath
= os
.path
.join(self
._outputPath
, self
._projname
+ '.doxygen_config')
99 self
._configFile
.Generate(configFilePath
)
100 self
.Log(" <<<<<< Success Save doxygen config file to %s...\n" % configFilePath
)
102 # launch doxygen tool to generate document
103 if self
._doxygenCallback
is not None:
104 self
.Log(" >>>>>> Start doxygen process...Zzz...\n")
105 if not self
._doxygenCallback
(self
._doxPath
, configFilePath
):
108 self
.Log("Fail to create doxygen process!", 'error')
113 def InitializeConfigFile(self
):
114 """Initialize config setting for doxygen project. It will be invoked after config file
115 object is created. Inherited class should implement it.
118 def GenerateIndexPage(self
):
119 """Generate doxygen index page. Inherited class should implement it."""
122 def RegisterCallbackDoxygenProcess(self
, callback
):
123 self
._doxygenCallback
= callback
125 def RegisterCallbackCHMProcess(self
, callback
):
126 self
._chmCallback
= callback
128 class PlatformDocumentAction(DoxygenAction
):
129 """Generate platform doxygen document, will be implement at future."""
131 class PackageDocumentAction(DoxygenAction
):
132 """Generate package reference document"""
134 def __init__(self
, doxPath
, chmPath
, outputPath
, pObj
, mode
='html', log
=None, arch
=None, tooltag
=None,
135 macros
=[], onlyInclude
=False, verbose
=False):
136 DoxygenAction
.__init
__(self
, doxPath
, chmPath
, outputPath
, pObj
.GetName(), mode
, log
, verbose
)
139 self
._tooltag
= tooltag
140 self
._macros
= macros
141 self
._onlyIncludeDocument
= onlyInclude
143 def InitializeConfigFile(self
):
144 if self
._arch
== 'IA32':
145 self
._configFile
.AddPreDefined('MDE_CPU_IA32')
146 elif self
._arch
== 'X64':
147 self
._configFile
.AddPreDefined('MDE_CPU_X64')
148 elif self
._arch
== 'IPF':
149 self
._configFile
.AddPreDefined('MDE_CPU_IPF')
150 elif self
._arch
== 'EBC':
151 self
._configFile
.AddPreDefined('MDE_CPU_EBC')
154 self
._configFile
.AddPreDefined('MDE_CPU_IA32')
155 self
._configFile
.AddPreDefined('MDE_CPU_X64')
156 self
._configFile
.AddPreDefined('MDE_CPU_IPF')
157 self
._configFile
.AddPreDefined('MDE_CPU_EBC')
158 self
._configFile
.AddPreDefined('MDE_CPU_ARM')
160 for macro
in self
._macros
:
161 self
._configFile
.AddPreDefined(macro
)
163 namestr
= self
._pObj
.GetName()
164 if self
._arch
is not None:
165 namestr
+= '[%s]' % self
._arch
166 if self
._tooltag
is not None:
167 namestr
+= '[%s]' % self
._tooltag
168 self
._configFile
.SetProjectName(namestr
)
169 self
._configFile
.SetStripPath(self
._pObj
.GetWorkspace())
170 self
._configFile
.SetProjectVersion(self
._pObj
.GetFileObj().GetVersion())
171 self
._configFile
.AddPattern('*.decdoxygen')
173 if self
._tooltag
.lower() == 'msft':
174 self
._configFile
.AddPreDefined('_MSC_EXTENSIONS')
175 elif self
._tooltag
.lower() == 'gnu':
176 self
._configFile
.AddPreDefined('__GNUC__')
177 elif self
._tooltag
.lower() == 'intel':
178 self
._configFile
.AddPreDefined('__INTEL_COMPILER')
181 self
._configFile
.AddPreDefined('_MSC_EXTENSIONS')
182 self
._configFile
.AddPreDefined('__GNUC__')
183 self
._configFile
.AddPreDefined('__INTEL_COMPILER')
185 self
._configFile
.AddPreDefined('ASM_PFX= ')
186 self
._configFile
.AddPreDefined('OPTIONAL= ')
188 def GenerateIndexPage(self
):
189 """Generate doxygen index page. Inherited class should implement it."""
190 fObj
= self
._pObj
.GetFileObj()
191 pdObj
= doxygen
.DoxygenFile('%s Package Document' % self
._pObj
.GetName(),
192 '%s.decdoxygen' % self
._pObj
.GetFilename())
193 self
._configFile
.AddFile(pdObj
.GetFilename())
194 pdObj
.AddDescription(fObj
.GetFileHeader())
196 defSection
= fObj
.GetSectionByName('defines')[0]
197 baseSection
= doxygen
.Section('PackageBasicInformation', 'Package Basic Information')
199 for obj
in defSection
.GetObjects():
200 if obj
.GetKey() in _dec_key_description_mapping_table
.keys():
202 descr
+= '<TD><B>%s</B></TD>' % _dec_key_description_mapping_table
[obj
.GetKey()]
203 descr
+= '<TD>%s</TD>' % obj
.GetValue()
205 descr
+= '</TABLE><br>'
206 baseSection
.AddDescription(descr
)
207 pdObj
.AddSection(baseSection
)
209 knownIssueSection
= doxygen
.Section('Known_Issue_section', 'Known Issue')
210 knownIssueSection
.AddDescription('<ul>')
211 knownIssueSection
.AddDescription('<li> OPTIONAL macro for function parameter can not be dealed with doxygen, so it disapear in this document! </li>')
212 knownIssueSection
.AddDescription('</ul>')
213 pdObj
.AddSection(knownIssueSection
)
215 self
.AddAllIncludeFiles(self
._pObj
, self
._configFile
)
216 pages
= self
.GenerateIncludesSubPage(self
._pObj
, self
._configFile
)
218 pdObj
.AddPages(pages
)
219 pages
= self
.GenerateLibraryClassesSubPage(self
._pObj
, self
._configFile
)
221 pdObj
.AddPages(pages
)
222 pages
= self
.GeneratePcdSubPages(self
._pObj
, self
._configFile
)
224 pdObj
.AddPages(pages
)
225 pages
= self
.GenerateGuidSubPages(self
._pObj
, self
._configFile
)
227 pdObj
.AddPages(pages
)
228 pages
= self
.GeneratePpiSubPages(self
._pObj
, self
._configFile
)
230 pdObj
.AddPages(pages
)
231 pages
= self
.GenerateProtocolSubPages(self
._pObj
, self
._configFile
)
233 pdObj
.AddPages(pages
)
234 if not self
._onlyIncludeDocument
:
235 pdObj
.AddPages(self
.GenerateModulePages(self
._pObj
, self
._configFile
))
238 return pdObj
.GetFilename()
240 def GenerateIncludesSubPage(self
, pObj
, configFile
):
241 # by default add following path as include path to config file
242 pkpath
= pObj
.GetFileObj().GetPackageRootPath()
243 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include'))
244 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include', 'Library'))
245 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include', 'Protocol'))
246 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include', 'Ppi'))
247 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include', 'Guid'))
248 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include', 'IndustryStandard'))
251 pageRoot
= doxygen
.Page("Public Includes", "%s_public_includes" % pObj
.GetName())
252 objs
= pObj
.GetFileObj().GetSectionObjectsByName('includes')
253 if len(objs
) == 0: return []
256 # Add path to include path
257 path
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetPath())
258 configFile
.AddIncludePath(path
)
260 # only list common folder's include file
261 if obj
.GetArch().lower() != 'common':
264 bNeedAddIncludePage
= False
265 topPage
= doxygen
.Page(self
._ConvertPathToDoxygen
(path
, pObj
), 'public_include_top')
267 topPage
.AddDescription('<ul>\n')
268 for file in os
.listdir(path
):
269 if file.lower() in _ignore_dir
: continue
270 fullpath
= os
.path
.join(path
, file)
271 if os
.path
.isfile(fullpath
):
272 self
.ProcessSourceFileForInclude(fullpath
, pObj
, configFile
)
273 topPage
.AddDescription('<li> \link %s\endlink </li>\n' % self
._ConvertPathToDoxygen
(fullpath
, pObj
))
275 if file.lower() in ['library', 'protocol', 'guid', 'ppi', 'ia32', 'x64', 'ipf', 'ebc', 'arm', 'pi', 'uefi', 'aarch64']:
277 bNeedAddSubPage
= False
278 subpage
= doxygen
.Page(self
._ConvertPathToDoxygen
(fullpath
, pObj
), 'public_include_%s' % file)
279 subpage
.AddDescription('<ul>\n')
280 for subfile
in os
.listdir(fullpath
):
281 if subfile
.lower() in _ignore_dir
: continue
282 bNeedAddSubPage
= True
283 subfullpath
= os
.path
.join(fullpath
, subfile
)
284 self
.ProcessSourceFileForInclude(subfullpath
, pObj
, configFile
)
285 subpage
.AddDescription('<li> \link %s \endlink </li>\n' % self
._ConvertPathToDoxygen
(subfullpath
, pObj
))
286 subpage
.AddDescription('</ul>\n')
288 bNeedAddIncludePage
= True
289 pageRoot
.AddPage(subpage
)
290 topPage
.AddDescription('</ul>\n')
291 if bNeedAddIncludePage
:
292 pageRoot
.AddPage(topPage
)
294 if pageRoot
.GetSubpageCount() != 0:
299 def GenerateLibraryClassesSubPage(self
, pObj
, configFile
):
301 Generate sub page for library class for package.
302 One DEC file maybe contains many library class sections
303 for different architecture.
305 @param fObj DEC file object.
308 pageRoot
= doxygen
.Page("Library Class", "%s_libraryclass" % pObj
.GetName())
309 objs
= pObj
.GetFileObj().GetSectionObjectsByName('libraryclass', self
._arch
)
310 if len(objs
) == 0: return []
312 if self
._arch
is not None:
314 classPage
= doxygen
.Page(obj
.GetClassName(),
315 "lc_%s" % obj
.GetClassName())
316 comments
= obj
.GetComment()
317 if len(comments
) != 0:
318 classPage
.AddDescription('<br>\n'.join(comments
) + '<br>\n')
319 pageRoot
.AddPage(classPage
)
320 path
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetHeaderFile())
321 path
= path
[len(pObj
.GetWorkspace()) + 1:]
322 if len(comments
) == 0:
323 classPage
.AddDescription('\copydoc %s<p>' % obj
.GetHeaderFile())
324 section
= doxygen
.Section('ref', 'Refer to Header File')
325 section
.AddDescription('\link %s\n' % obj
.GetHeaderFile())
326 section
.AddDescription(' \endlink<p>\n')
327 classPage
.AddSection(section
)
328 fullPath
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetHeaderFile())
329 self
.ProcessSourceFileForInclude(fullPath
, pObj
, configFile
)
333 if obj
.GetArch() not in archPageDict
.keys():
334 archPageDict
[obj
.GetArch()] = doxygen
.Page(obj
.GetArch(),
335 'lc_%s' % obj
.GetArch())
336 pageRoot
.AddPage(archPageDict
[obj
.GetArch()])
337 subArchRoot
= archPageDict
[obj
.GetArch()]
338 classPage
= doxygen
.Page(obj
.GetClassName(),
339 "lc_%s" % obj
.GetClassName())
340 comments
= obj
.GetComment()
341 if len(comments
) != 0:
342 classPage
.AddDescription('<br>\n'.join(comments
) + '<br>\n')
343 subArchRoot
.AddPage(classPage
)
344 path
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetHeaderFile())
345 path
= path
[len(pObj
.GetWorkspace()) + 1:]
346 if len(comments
) == 0:
347 classPage
.AddDescription('\copydoc %s<p>' % obj
.GetHeaderFile())
348 section
= doxygen
.Section('ref', 'Refer to Header File')
349 section
.AddDescription('\link %s\n' % obj
.GetHeaderFile())
350 section
.AddDescription(' \endlink<p>\n')
351 classPage
.AddSection(section
)
352 fullPath
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetHeaderFile())
354 self
.ProcessSourceFileForInclude(fullPath
, pObj
, configFile
)
355 rootArray
.append(pageRoot
)
358 def ProcessSourceFileForInclude(self
, path
, pObj
, configFile
, infObj
=None):
360 @param path the analysising file full path
361 @param pObj package object
362 @param configFile doxygen config file.
367 if not os
.path
.exists(path
):
368 ErrorMsg('Source file path %s does not exist!' % path
)
371 if configFile
.FileExists(path
):
376 lines
= f
.readlines()
379 ErrorMsg('Fail to open file %s' % path
)
382 configFile
.AddFile(path
)
385 for no
in range(len(lines
)):
386 if len(lines
[no
].strip()) == 0:
388 if lines
[no
].strip()[:2] in ['##', '//', '/*', '*/']:
390 index
= lines
[no
].lower().find('include')
391 #mo = IncludePattern.finditer(lines[no].lower())
392 mo
= re
.match(r
"^#\s*include\s+[<\"]([\\/\w
.]+)[>\"]$
", lines[no].strip().lower())
395 mo = re.match(r"^
[#\w\s]+[<\"]([\\/\w.]+)[>\"]$", lines[no].strip())
396 filePath
= mo
.groups()[0]
398 if filePath
is None or len(filePath
) == 0:
401 # find header file in module's path firstly.
404 if os
.path
.exists(os
.path
.join(os
.path
.dirname(path
), filePath
)):
405 # Find the file in current directory
406 fullPath
= os
.path
.join(os
.path
.dirname(path
), filePath
).replace('\\', '/')
408 # find in depedent package's include path
409 incObjs
= pObj
.GetFileObj().GetSectionObjectsByName('includes')
410 for incObj
in incObjs
:
411 incPath
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), incObj
.GetPath()).strip()
412 incPath
= os
.path
.realpath(os
.path
.join(incPath
, filePath
))
413 if os
.path
.exists(incPath
):
416 if infObj
is not None:
417 pkgInfObjs
= infObj
.GetSectionObjectsByName('packages')
418 for obj
in pkgInfObjs
:
419 decObj
= dec
.DECFile(os
.path
.join(pObj
.GetWorkspace(), obj
.GetPath()))
421 ErrorMsg ('Fail to create pacakge object for %s' % obj
.GetPackageName())
423 if not decObj
.Parse():
424 ErrorMsg ('Fail to load package object for %s' % obj
.GetPackageName())
426 incObjs
= decObj
.GetSectionObjectsByName('includes')
427 for incObj
in incObjs
:
428 incPath
= os
.path
.join(decObj
.GetPackageRootPath(), incObj
.GetPath()).replace('\\', '/')
429 if os
.path
.exists(os
.path
.join(incPath
, filePath
)):
430 fullPath
= os
.path
.join(os
.path
.join(incPath
, filePath
))
432 if fullPath
is not None:
435 if fullPath
is None and self
.IsVerbose():
436 self
.Log('Can not resolve header file %s for file %s in package %s\n' % (filePath
, path
, pObj
.GetFileObj().GetFilename()), 'error')
439 fullPath
= fullPath
.replace('\\', '/')
441 self
.Log('Preprocessing: Add include file %s for file %s\n' % (fullPath
, path
))
442 #LogMsg ('Preprocessing: Add include file %s for file %s' % (fullPath, path))
443 self
.ProcessSourceFileForInclude(fullPath
, pObj
, configFile
, infObj
)
445 def AddAllIncludeFiles(self
, pObj
, configFile
):
446 objs
= pObj
.GetFileObj().GetSectionObjectsByName('includes')
448 incPath
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetPath())
449 for root
, dirs
, files
in os
.walk(incPath
):
451 if dir.lower() in _ignore_dir
:
454 path
= os
.path
.normpath(os
.path
.join(root
, file))
455 configFile
.AddFile(path
.replace('/', '\\'))
457 def GeneratePcdSubPages(self
, pObj
, configFile
):
459 Generate sub pages for package's PCD definition.
460 @param pObj package object
461 @param configFile config file object
464 objs
= pObj
.GetFileObj().GetSectionObjectsByName('pcd')
468 pcdRootPage
= doxygen
.Page('PCD', 'pcd_root_page')
469 typeRootPageDict
= {}
470 typeArchRootPageDict
= {}
472 if obj
.GetPcdType() not in typeRootPageDict
.keys():
473 typeRootPageDict
[obj
.GetPcdType()] = doxygen
.Page(obj
.GetPcdType(), 'pcd_%s_root_page' % obj
.GetPcdType())
474 pcdRootPage
.AddPage(typeRootPageDict
[obj
.GetPcdType()])
475 typeRoot
= typeRootPageDict
[obj
.GetPcdType()]
476 if self
._arch
is not None:
477 pcdPage
= doxygen
.Page('%s' % obj
.GetPcdName(),
478 'pcd_%s_%s_%s' % (obj
.GetPcdType(), obj
.GetArch(), obj
.GetPcdName().split('.')[1]))
479 pcdPage
.AddDescription('<br>\n'.join(obj
.GetComment()) + '<br>\n')
480 section
= doxygen
.Section('PCDinformation', 'PCD Information')
483 desc
+= '<TD><CAPTION>Name</CAPTION></TD>'
484 desc
+= '<TD><CAPTION>Token Space</CAPTION></TD>'
485 desc
+= '<TD><CAPTION>Token number</CAPTION></TD>'
486 desc
+= '<TD><CAPTION>Data Type</CAPTION></TD>'
487 desc
+= '<TD><CAPTION>Default Value</CAPTION></TD>'
490 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdName().split('.')[1]
491 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdName().split('.')[0]
492 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdToken()
493 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdDataType()
494 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdValue()
497 section
.AddDescription(desc
)
498 pcdPage
.AddSection(section
)
499 typeRoot
.AddPage(pcdPage
)
501 keystr
= obj
.GetPcdType() + obj
.GetArch()
502 if keystr
not in typeArchRootPageDict
.keys():
503 typeArchRootPage
= doxygen
.Page(obj
.GetArch(), 'pcd_%s_%s_root_page' % (obj
.GetPcdType(), obj
.GetArch()))
504 typeArchRootPageDict
[keystr
] = typeArchRootPage
505 typeRoot
.AddPage(typeArchRootPage
)
506 typeArchRoot
= typeArchRootPageDict
[keystr
]
507 pcdPage
= doxygen
.Page('%s' % obj
.GetPcdName(),
508 'pcd_%s_%s_%s' % (obj
.GetPcdType(), obj
.GetArch(), obj
.GetPcdName().split('.')[1]))
509 pcdPage
.AddDescription('<br>\n'.join(obj
.GetComment()) + '<br>\n')
510 section
= doxygen
.Section('PCDinformation', 'PCD Information')
513 desc
+= '<TD><CAPTION>Name</CAPTION></TD>'
514 desc
+= '<TD><CAPTION>Token Space</CAPTION></TD>'
515 desc
+= '<TD><CAPTION>Token number</CAPTION></TD>'
516 desc
+= '<TD><CAPTION>Data Type</CAPTION></TD>'
517 desc
+= '<TD><CAPTION>Default Value</CAPTION></TD>'
520 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdName().split('.')[1]
521 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdName().split('.')[0]
522 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdToken()
523 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdDataType()
524 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdValue()
527 section
.AddDescription(desc
)
528 pcdPage
.AddSection(section
)
529 typeArchRoot
.AddPage(pcdPage
)
532 def _GenerateGuidSubPage(self
, pObj
, obj
, configFile
):
533 guidPage
= doxygen
.Page('%s' % obj
.GetName(),
534 'guid_%s_%s' % (obj
.GetArch(), obj
.GetName()))
535 comments
= obj
.GetComment()
536 if len(comments
) != 0:
537 guidPage
.AddDescription('<br>'.join(obj
.GetComment()) + '<br>')
538 section
= doxygen
.Section('BasicGuidInfo', 'GUID Information')
541 desc
+= '<TD><CAPTION>GUID\'s Guid Name</CAPTION></TD><TD><CAPTION>GUID\'s Guid</CAPTION></TD>'
544 desc
+= '<TD>%s</TD>' % obj
.GetName()
545 desc
+= '<TD>%s</TD>' % obj
.GetGuid()
548 section
.AddDescription(desc
)
549 guidPage
.AddSection(section
)
550 refFile
= self
.FindHeaderFileForGuid(pObj
, obj
.GetName(), configFile
)
552 relPath
= refFile
[len(pObj
.GetWorkspace()) + 1:]
553 if len(comments
) == 0:
554 guidPage
.AddDescription(' \\copydoc %s <br>' % relPath
)
556 section
= doxygen
.Section('ref', 'Refer to Header File')
557 section
.AddDescription('\link %s\n' % relPath
)
558 section
.AddDescription('\endlink\n')
559 self
.ProcessSourceFileForInclude(refFile
, pObj
, configFile
)
560 guidPage
.AddSection(section
)
563 def GenerateGuidSubPages(self
, pObj
, configFile
):
565 Generate sub pages for package's GUID definition.
566 @param pObj package object
567 @param configFilf doxygen config file object
569 pageRoot
= doxygen
.Page('GUID', 'guid_root_page')
570 objs
= pObj
.GetFileObj().GetSectionObjectsByName('guids', self
._arch
)
571 if len(objs
) == 0: return []
572 if self
._arch
is not None:
574 pageRoot
.AddPage(self
._GenerateGuidSubPage
(pObj
, obj
, configFile
))
576 guidArchRootPageDict
= {}
578 if obj
.GetArch() not in guidArchRootPageDict
.keys():
579 guidArchRoot
= doxygen
.Page(obj
.GetArch(), 'guid_arch_root_%s' % obj
.GetArch())
580 pageRoot
.AddPage(guidArchRoot
)
581 guidArchRootPageDict
[obj
.GetArch()] = guidArchRoot
582 guidArchRoot
= guidArchRootPageDict
[obj
.GetArch()]
583 guidArchRoot
.AddPage(self
._GenerateGuidSubPage
(pObj
, obj
, configFile
))
586 def _GeneratePpiSubPage(self
, pObj
, obj
, configFile
):
587 guidPage
= doxygen
.Page(obj
.GetName(), 'ppi_page_%s' % obj
.GetName())
588 comments
= obj
.GetComment()
589 if len(comments
) != 0:
590 guidPage
.AddDescription('<br>'.join(obj
.GetComment()) + '<br>')
591 section
= doxygen
.Section('BasicPpiInfo', 'PPI Information')
594 desc
+= '<TD><CAPTION>PPI\'s Guid Name</CAPTION></TD><TD><CAPTION>PPI\'s Guid</CAPTION></TD>'
597 desc
+= '<TD>%s</TD>' % obj
.GetName()
598 desc
+= '<TD>%s</TD>' % obj
.GetGuid()
601 section
.AddDescription(desc
)
602 guidPage
.AddSection(section
)
603 refFile
= self
.FindHeaderFileForGuid(pObj
, obj
.GetName(), configFile
)
605 relPath
= refFile
[len(pObj
.GetWorkspace()) + 1:]
606 if len(comments
) == 0:
607 guidPage
.AddDescription(' \\copydoc %s <br>' % relPath
)
608 section
= doxygen
.Section('ref', 'Refer to Header File')
609 section
.AddDescription('\link %s\n' % relPath
)
610 section
.AddDescription('\endlink\n')
611 self
.ProcessSourceFileForInclude(refFile
, pObj
, configFile
)
612 guidPage
.AddSection(section
)
616 def GeneratePpiSubPages(self
, pObj
, configFile
):
618 Generate sub pages for package's GUID definition.
619 @param pObj package object
620 @param configFilf doxygen config file object
622 pageRoot
= doxygen
.Page('PPI', 'ppi_root_page')
623 objs
= pObj
.GetFileObj().GetSectionObjectsByName('ppis', self
._arch
)
624 if len(objs
) == 0: return []
625 if self
._arch
is not None:
627 pageRoot
.AddPage(self
._GeneratePpiSubPage
(pObj
, obj
, configFile
))
629 guidArchRootPageDict
= {}
631 if obj
.GetArch() not in guidArchRootPageDict
.keys():
632 guidArchRoot
= doxygen
.Page(obj
.GetArch(), 'ppi_arch_root_%s' % obj
.GetArch())
633 pageRoot
.AddPage(guidArchRoot
)
634 guidArchRootPageDict
[obj
.GetArch()] = guidArchRoot
635 guidArchRoot
= guidArchRootPageDict
[obj
.GetArch()]
636 guidArchRoot
.AddPage(self
._GeneratePpiSubPage
(pObj
, obj
, configFile
))
639 def _GenerateProtocolSubPage(self
, pObj
, obj
, configFile
):
640 guidPage
= doxygen
.Page(obj
.GetName(), 'protocol_page_%s' % obj
.GetName())
641 comments
= obj
.GetComment()
642 if len(comments
) != 0:
643 guidPage
.AddDescription('<br>'.join(obj
.GetComment()) + '<br>')
644 section
= doxygen
.Section('BasicProtocolInfo', 'PROTOCOL Information')
647 desc
+= '<TD><CAPTION>PROTOCOL\'s Guid Name</CAPTION></TD><TD><CAPTION>PROTOCOL\'s Guid</CAPTION></TD>'
650 desc
+= '<TD>%s</TD>' % obj
.GetName()
651 desc
+= '<TD>%s</TD>' % obj
.GetGuid()
654 section
.AddDescription(desc
)
655 guidPage
.AddSection(section
)
657 refFile
= self
.FindHeaderFileForGuid(pObj
, obj
.GetName(), configFile
)
659 relPath
= refFile
[len(pObj
.GetWorkspace()) + 1:]
660 if len(comments
) == 0:
661 guidPage
.AddDescription(' \\copydoc %s <br>' % relPath
)
662 section
= doxygen
.Section('ref', 'Refer to Header File')
663 section
.AddDescription('\link %s\n' % relPath
)
664 section
.AddDescription('\endlink\n')
665 self
.ProcessSourceFileForInclude(refFile
, pObj
, configFile
)
666 guidPage
.AddSection(section
)
670 def GenerateProtocolSubPages(self
, pObj
, configFile
):
672 Generate sub pages for package's GUID definition.
673 @param pObj package object
674 @param configFilf doxygen config file object
676 pageRoot
= doxygen
.Page('PROTOCOL', 'protocol_root_page')
677 objs
= pObj
.GetFileObj().GetSectionObjectsByName('protocols', self
._arch
)
678 if len(objs
) == 0: return []
679 if self
._arch
is not None:
681 pageRoot
.AddPage(self
._GenerateProtocolSubPage
(pObj
, obj
, configFile
))
683 guidArchRootPageDict
= {}
685 if obj
.GetArch() not in guidArchRootPageDict
.keys():
686 guidArchRoot
= doxygen
.Page(obj
.GetArch(), 'protocol_arch_root_%s' % obj
.GetArch())
687 pageRoot
.AddPage(guidArchRoot
)
688 guidArchRootPageDict
[obj
.GetArch()] = guidArchRoot
689 guidArchRoot
= guidArchRootPageDict
[obj
.GetArch()]
690 guidArchRoot
.AddPage(self
._GenerateProtocolSubPage
(pObj
, obj
, configFile
))
693 def FindHeaderFileForGuid(self
, pObj
, name
, configFile
):
695 For declaration header file for GUID/PPI/Protocol.
697 @param pObj package object
698 @param name guid/ppi/protocol's name
699 @param configFile config file object
701 @return full path of header file and None if not found.
703 startPath
= pObj
.GetFileObj().GetPackageRootPath()
704 incPath
= os
.path
.join(startPath
, 'Include').replace('\\', '/')
705 # if <PackagePath>/include exist, then search header under it.
706 if os
.path
.exists(incPath
):
709 for root
, dirs
, files
in os
.walk(startPath
):
711 if dir.lower() in _ignore_dir
:
714 fPath
= os
.path
.join(root
, file)
715 if not IsCHeaderFile(fPath
):
719 lines
= f
.readlines()
722 self
.Log('Fail to open file %s\n' % fPath
)
725 if line
.find(name
) != -1 and \
726 line
.find('extern') != -1:
727 return fPath
.replace('\\', '/')
730 def GetPackageModuleList(self
, pObj
):
732 Get all module's INF path under package's root path
733 @param pObj package object
734 @return arrary of INF full path
737 packPath
= pObj
.GetFileObj().GetPackageRootPath()
738 if not os
.path
.exists
:
740 for root
, dirs
, files
in os
.walk(packPath
):
742 if dir.lower() in _ignore_dir
:
745 if CheckPathPostfix(file, 'inf'):
746 fPath
= os
.path
.join(root
, file).replace('\\', '/')
750 def GenerateModulePages(self
, pObj
, configFile
):
752 Generate sub pages for package's module which is under the package
755 @param pObj package object
756 @param configFilf doxygen config file object
758 infList
= self
.GetPackageModuleList(pObj
)
762 for infpath
in infList
:
763 infObj
= inf
.INFFile(infpath
)
764 #infObj = INFFileObject.INFFile (pObj.GetWorkspacePath(),
767 self
.Log('Fail create INF object for %s' % inf
)
769 if not infObj
.Parse():
770 self
.Log('Fail to load INF file %s' % inf
)
772 if infObj
.GetProduceLibraryClass() is not None:
773 libObjs
.append(infObj
)
775 modObjs
.append(infObj
)
777 if len(libObjs
) != 0:
778 libRootPage
= doxygen
.Page('Libraries', 'lib_root_page')
779 rootPages
.append(libRootPage
)
780 for libInf
in libObjs
:
781 libRootPage
.AddPage(self
.GenerateModulePage(pObj
, libInf
, configFile
, True))
783 if len(modObjs
) != 0:
784 modRootPage
= doxygen
.Page('Modules', 'module_root_page')
785 rootPages
.append(modRootPage
)
786 for modInf
in modObjs
:
787 modRootPage
.AddPage(self
.GenerateModulePage(pObj
, modInf
, configFile
, False))
791 def GenerateModulePage(self
, pObj
, infObj
, configFile
, isLib
):
793 Generate page for a module/library.
794 @param infObj INF file object for module/library
795 @param configFile doxygen config file object
796 @param isLib Whether this module is library
798 @param module doxygen page object
800 workspace
= pObj
.GetWorkspace()
802 for obj
in infObj
.GetSectionObjectsByName('packages'):
803 decObj
= dec
.DECFile(os
.path
.join(workspace
, obj
.GetPath()))
805 ErrorMsg ('Fail to create pacakge object for %s' % obj
.GetPackageName())
807 if not decObj
.Parse():
808 ErrorMsg ('Fail to load package object for %s' % obj
.GetPackageName())
810 refDecObjs
.append(decObj
)
812 modPage
= doxygen
.Page('%s' % infObj
.GetBaseName(),
813 'module_%s' % infObj
.GetBaseName())
814 modPage
.AddDescription(infObj
.GetFileHeader())
816 basicInfSection
= doxygen
.Section('BasicModuleInformation', 'Basic Module Information')
818 for obj
in infObj
.GetSectionObjectsByName('defines'):
820 value
= obj
.GetValue()
821 if key
not in _inf_key_description_mapping_table
.keys(): continue
822 if key
== 'LIBRARY_CLASS' and value
.find('|') != -1:
823 clsname
, types
= value
.split('|')
825 desc
+= '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table
[key
]
826 desc
+= '<TD>%s</TD>' % clsname
830 desc
+= '<TD><B>Supported Module Types</B></TD>'
831 desc
+= '<TD>%s</TD>' % types
835 desc
+= '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table
[key
]
836 if key
== 'EFI_SPECIFICATION_VERSION' and value
== '0x00020000':
838 desc
+= '<TD>%s</TD>' % value
841 basicInfSection
.AddDescription(desc
)
842 modPage
.AddSection(basicInfSection
)
844 # Add protocol section
846 for obj
in infObj
.GetSectionObjectsByName('pcd', self
._arch
):
847 data
.append(obj
.GetPcdName().strip())
849 s
= doxygen
.Section('Pcds', 'Pcds')
851 desc
+= '<TR><TD><B>PCD Name</B></TD><TD><B>TokenSpace</B></TD><TD><B>Package</B></TD></TR>'
854 desc
+= '<TD>%s</TD>' % item
.split('.')[1]
855 desc
+= '<TD>%s</TD>' % item
.split('.')[0]
856 pkgbasename
= self
.SearchPcdPackage(item
, workspace
, refDecObjs
)
857 desc
+= '<TD>%s</TD>' % pkgbasename
860 s
.AddDescription(desc
)
861 modPage
.AddSection(s
)
863 # Add protocol section
864 #sects = infObj.GetSectionByString('protocol')
867 for obj
in infObj
.GetSectionObjectsByName('protocol', self
._arch
):
868 data
.append(obj
.GetName().strip())
870 s
= doxygen
.Section('Protocols', 'Protocols')
872 desc
+= '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
875 desc
+= '<TD>%s</TD>' % item
876 pkgbasename
= self
.SearchProtocolPackage(item
, workspace
, refDecObjs
)
877 desc
+= '<TD>%s</TD>' % pkgbasename
880 s
.AddDescription(desc
)
881 modPage
.AddSection(s
)
884 #sects = infObj.GetSectionByString('ppi')
887 for obj
in infObj
.GetSectionObjectsByName('ppi', self
._arch
):
888 data
.append(obj
.GetName().strip())
890 s
= doxygen
.Section('Ppis', 'Ppis')
892 desc
+= '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
895 desc
+= '<TD>%s</TD>' % item
896 pkgbasename
= self
.SearchPpiPackage(item
, workspace
, refDecObjs
)
897 desc
+= '<TD>%s</TD>' % pkgbasename
900 s
.AddDescription(desc
)
901 modPage
.AddSection(s
)
904 #sects = infObj.GetSectionByString('guid')
907 for obj
in infObj
.GetSectionObjectsByName('guid', self
._arch
):
908 data
.append(obj
.GetName().strip())
910 s
= doxygen
.Section('Guids', 'Guids')
912 desc
+= '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
915 desc
+= '<TD>%s</TD>' % item
916 pkgbasename
= self
.SearchGuidPackage(item
, workspace
, refDecObjs
)
917 desc
+= '<TD>%s</TD>' % pkgbasename
920 s
.AddDescription(desc
)
921 modPage
.AddSection(s
)
923 section
= doxygen
.Section('LibraryClasses', 'Library Classes')
925 desc
+= '<TR><TD><B>Name</B></TD><TD><B>Type</B></TD><TD><B>Package</B></TD><TD><B>Header File</B></TD></TR>'
928 desc
+= '<TD>%s</TD>' % infObj
.GetProduceLibraryClass()
929 desc
+= '<TD>Produce</TD>'
931 pkgname
, hPath
= self
.SearchLibraryClassHeaderFile(infObj
.GetProduceLibraryClass(),
935 self
.Log ('fail to get package header file for lib class %s' % infObj
.GetProduceLibraryClass())
938 desc
+= '<TD>%s</TD>' % pkgname
940 #desc += '<TD>\link %s \endlink</TD>' % hPath
941 desc
+= '<TD>%s</TD>' % hPath
943 desc
+= '<TD>%s</TD>' % hPath
945 for lcObj
in infObj
.GetSectionObjectsByName('libraryclasses', self
._arch
):
947 desc
+= '<TD>%s</TD>' % lcObj
.GetClass()
948 retarr
= self
.SearchLibraryClassHeaderFile(lcObj
.GetClass(),
951 if retarr
is not None:
952 pkgname
, hPath
= retarr
954 self
.Log('Fail find the library class %s definition from module %s dependent package!' % (lcObj
.GetClass(), infObj
.GetFilename()), 'error')
957 desc
+= '<TD>Consume</TD>'
958 desc
+= '<TD>%s</TD>' % pkgname
959 desc
+= '<TD>%s</TD>' % hPath
962 section
.AddDescription(desc
)
963 modPage
.AddSection(section
)
965 section
= doxygen
.Section('SourceFiles', 'Source Files')
966 section
.AddDescription('<ul>\n')
967 for obj
in infObj
.GetSourceObjects(self
._arch
, self
._tooltag
):
968 sPath
= infObj
.GetModuleRootPath()
969 sPath
= os
.path
.join(sPath
, obj
.GetSourcePath()).replace('\\', '/').strip()
970 if sPath
.lower().endswith('.uni') or sPath
.lower().endswith('.s') or sPath
.lower().endswith('.asm') or sPath
.lower().endswith('.nasm'):
971 newPath
= self
.TranslateUniFile(sPath
)
972 configFile
.AddFile(newPath
)
973 newPath
= newPath
[len(pObj
.GetWorkspace()) + 1:]
974 section
.AddDescription('<li> \link %s \endlink </li>' % newPath
)
976 self
.ProcessSourceFileForInclude(sPath
, pObj
, configFile
, infObj
)
977 sPath
= sPath
[len(pObj
.GetWorkspace()) + 1:]
978 section
.AddDescription('<li>\link %s \endlink </li>' % sPath
)
979 section
.AddDescription('</ul>\n')
980 modPage
.AddSection(section
)
982 #sects = infObj.GetSectionByString('depex')
985 for obj
in infObj
.GetSectionObjectsByName('depex'):
986 data
.append(str(obj
))
988 s
= doxygen
.Section('DependentSection', 'Module Dependencies')
989 s
.AddDescription('<br>'.join(data
))
990 modPage
.AddSection(s
)
994 def TranslateUniFile(self
, path
):
995 newpath
= path
+ '.dox'
996 #import core.textfile as textfile
997 #file = textfile.TextFile(path)
1000 file = open(path
, 'r')
1001 except (IOError, OSError) as msg
:
1007 output
= '/** @file \n'
1008 #output = '<html><body>'
1009 arr
= t
.split('\r\n')
1011 if line
.find('@file') != -1:
1013 if line
.find('*/') != -1:
1016 if line
.strip().startswith('/'):
1017 arr
= line
.split(' ')
1019 line
= ' '.join(arr
[1:])
1022 output
+= '%s<br>\n' % line
1025 if os
.path
.exists(newpath
):
1028 file = open(newpath
, "w")
1033 def SearchPcdPackage(self
, pcdname
, workspace
, decObjs
):
1034 for decObj
in decObjs
:
1035 for pcd
in decObj
.GetSectionObjectsByName('pcd'):
1036 if pcdname
== pcd
.GetPcdName():
1037 return decObj
.GetBaseName()
1040 def SearchProtocolPackage(self
, protname
, workspace
, decObjs
):
1041 for decObj
in decObjs
:
1042 for proto
in decObj
.GetSectionObjectsByName('protocol'):
1043 if protname
== proto
.GetName():
1044 return decObj
.GetBaseName()
1047 def SearchPpiPackage(self
, ppiname
, workspace
, decObjs
):
1048 for decObj
in decObjs
:
1049 for ppi
in decObj
.GetSectionObjectsByName('ppi'):
1050 if ppiname
== ppi
.GetName():
1051 return decObj
.GetBaseName()
1054 def SearchGuidPackage(self
, guidname
, workspace
, decObjs
):
1055 for decObj
in decObjs
:
1056 for guid
in decObj
.GetSectionObjectsByName('guid'):
1057 if guidname
== guid
.GetName():
1058 return decObj
.GetBaseName()
1061 def SearchLibraryClassHeaderFile(self
, className
, workspace
, decObjs
):
1062 for decObj
in decObjs
:
1063 for cls
in decObj
.GetSectionObjectsByName('libraryclasses'):
1064 if cls
.GetClassName().strip() == className
:
1065 path
= cls
.GetHeaderFile().strip()
1066 path
= os
.path
.join(decObj
.GetPackageRootPath(), path
)
1067 path
= path
[len(workspace
) + 1:]
1068 return decObj
.GetBaseName(), path
.replace('\\', '/')
1072 def _ConvertPathToDoxygen(self
, path
, pObj
):
1073 pRootPath
= pObj
.GetWorkspace()
1074 path
= path
[len(pRootPath
) + 1:]
1075 return path
.replace('\\', '/')
1077 def IsCHeaderFile(path
):
1078 return CheckPathPostfix(path
, 'h')
1080 def CheckPathPostfix(path
, str):
1081 index
= path
.rfind('.')
1084 if path
[index
+ 1:].lower() == str.lower():