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 from ...basemodel
import doxygen
24 from ...edk2
.model
import inf
25 from ...edk2
.model
import dec
26 from ...basemodel
.message
import *
28 _ignore_dir
= ['.svn', '_svn', 'cvs']
29 _inf_key_description_mapping_table
= {
30 'INF_VERSION':'Version of INF file specification',
31 #'BASE_NAME':'Module Name',
32 'FILE_GUID':'Module Guid',
33 'MODULE_TYPE': 'Module Type',
34 'VERSION_STRING': 'Module Version',
35 'LIBRARY_CLASS': 'Produced Library Class',
36 'EFI_SPECIFICATION_VERSION': 'UEFI Specification Version',
37 'PI_SPECIFICATION_VERSION': 'PI Specification Version',
38 'ENTRY_POINT': 'Module Entry Point Function',
39 'CONSTRUCTOR': 'Library Constructor Function'
42 _dec_key_description_mapping_table
= {
43 'DEC_SPECIFICATION': 'Version of DEC file specification',
44 'PACKAGE_GUID': 'Package Guid'
47 """This is base class for all doxygen action.
50 def __init__(self
, doxPath
, chmPath
, outputPath
, projname
, mode
='html', log
=None, verbose
=False):
51 """Constructor function.
52 @param doxPath the obosolution path of doxygen execute file.
53 @param outputPath the obosolution output path.
54 @param log log function for output message
56 self
._doxPath
= doxPath
57 self
._chmPath
= chmPath
58 self
._outputPath
= outputPath
59 self
._projname
= projname
60 self
._configFile
= None # doxygen config file is used by doxygen exe file
61 self
._indexPageFile
= None # doxygen page file for index page.
64 self
._verbose
= verbose
65 self
._doxygenCallback
= None
66 self
._chmCallback
= None
68 def Log(self
, message
, level
='info'):
69 if self
._log
is not None:
70 self
._log
(message
, level
)
76 """Generate interface called by outer directly"""
77 self
.Log(">>>>>> Start generate doxygen document for %s... Zzz....\n" % self
._projname
)
79 # create doxygen config file at first
80 self
._configFile
= doxygen
.DoxygenConfigFile()
81 self
._configFile
.SetOutputDir(self
._outputPath
)
83 self
._configFile
.SetWarningFilePath(os
.path
.join(self
._outputPath
, 'warning.txt'))
84 if self
._mode
.lower() == 'html':
85 self
._configFile
.SetHtmlMode()
87 self
._configFile
.SetChmMode()
89 self
.Log(" >>>>>> Initialize doxygen config file...Zzz...\n")
90 self
.InitializeConfigFile()
92 self
.Log(" >>>>>> Generate doxygen index page file...Zzz...\n")
93 indexPagePath
= self
.GenerateIndexPage()
94 if indexPagePath
is None:
95 self
.Log("Fail to generate index page!\n", 'error')
98 self
.Log("Success to create doxygen index page file %s \n" % indexPagePath
)
100 # Add index page doxygen file to file list.
101 self
._configFile
.AddFile(indexPagePath
)
103 # save config file to output path
104 configFilePath
= os
.path
.join(self
._outputPath
, self
._projname
+ '.doxygen_config')
105 self
._configFile
.Generate(configFilePath
)
106 self
.Log(" <<<<<< Success Save doxygen config file to %s...\n" % configFilePath
)
108 # launch doxygen tool to generate document
109 if self
._doxygenCallback
is not None:
110 self
.Log(" >>>>>> Start doxygen process...Zzz...\n")
111 if not self
._doxygenCallback
(self
._doxPath
, configFilePath
):
114 self
.Log("Fail to create doxygen process!", 'error')
119 def InitializeConfigFile(self
):
120 """Initialize config setting for doxygen project. It will be invoked after config file
121 object is created. Inherited class should implement it.
124 def GenerateIndexPage(self
):
125 """Generate doxygen index page. Inherited class should implement it."""
128 def RegisterCallbackDoxygenProcess(self
, callback
):
129 self
._doxygenCallback
= callback
131 def RegisterCallbackCHMProcess(self
, callback
):
132 self
._chmCallback
= callback
134 class PlatformDocumentAction(DoxygenAction
):
135 """Generate platform doxygen document, will be implement at future."""
137 class PackageDocumentAction(DoxygenAction
):
138 """Generate package reference document"""
140 def __init__(self
, doxPath
, chmPath
, outputPath
, pObj
, mode
='html', log
=None, arch
=None, tooltag
=None,
141 macros
=[], onlyInclude
=False, verbose
=False):
142 DoxygenAction
.__init
__(self
, doxPath
, chmPath
, outputPath
, pObj
.GetName(), mode
, log
, verbose
)
145 self
._tooltag
= tooltag
146 self
._macros
= macros
147 self
._onlyIncludeDocument
= onlyInclude
149 def InitializeConfigFile(self
):
150 if self
._arch
== 'IA32':
151 self
._configFile
.AddPreDefined('MDE_CPU_IA32')
152 elif self
._arch
== 'X64':
153 self
._configFile
.AddPreDefined('MDE_CPU_X64')
154 elif self
._arch
== 'IPF':
155 self
._configFile
.AddPreDefined('MDE_CPU_IPF')
156 elif self
._arch
== 'EBC':
157 self
._configFile
.AddPreDefined('MDE_CPU_EBC')
160 self
._configFile
.AddPreDefined('MDE_CPU_IA32')
161 self
._configFile
.AddPreDefined('MDE_CPU_X64')
162 self
._configFile
.AddPreDefined('MDE_CPU_IPF')
163 self
._configFile
.AddPreDefined('MDE_CPU_EBC')
164 self
._configFile
.AddPreDefined('MDE_CPU_ARM')
166 for macro
in self
._macros
:
167 self
._configFile
.AddPreDefined(macro
)
169 namestr
= self
._pObj
.GetName()
170 if self
._arch
is not None:
171 namestr
+= '[%s]' % self
._arch
172 if self
._tooltag
is not None:
173 namestr
+= '[%s]' % self
._tooltag
174 self
._configFile
.SetProjectName(namestr
)
175 self
._configFile
.SetStripPath(self
._pObj
.GetWorkspace())
176 self
._configFile
.SetProjectVersion(self
._pObj
.GetFileObj().GetVersion())
177 self
._configFile
.AddPattern('*.decdoxygen')
179 if self
._tooltag
.lower() == 'msft':
180 self
._configFile
.AddPreDefined('_MSC_EXTENSIONS')
181 elif self
._tooltag
.lower() == 'gnu':
182 self
._configFile
.AddPreDefined('__GNUC__')
183 elif self
._tooltag
.lower() == 'intel':
184 self
._configFile
.AddPreDefined('__INTEL_COMPILER')
187 self
._configFile
.AddPreDefined('_MSC_EXTENSIONS')
188 self
._configFile
.AddPreDefined('__GNUC__')
189 self
._configFile
.AddPreDefined('__INTEL_COMPILER')
191 self
._configFile
.AddPreDefined('ASM_PFX= ')
192 self
._configFile
.AddPreDefined('OPTIONAL= ')
194 def GenerateIndexPage(self
):
195 """Generate doxygen index page. Inherited class should implement it."""
196 fObj
= self
._pObj
.GetFileObj()
197 pdObj
= doxygen
.DoxygenFile('%s Package Document' % self
._pObj
.GetName(),
198 '%s.decdoxygen' % self
._pObj
.GetFilename())
199 self
._configFile
.AddFile(pdObj
.GetFilename())
200 pdObj
.AddDescription(fObj
.GetFileHeader())
202 defSection
= fObj
.GetSectionByName('defines')[0]
203 baseSection
= doxygen
.Section('PackageBasicInformation', 'Package Basic Information')
205 for obj
in defSection
.GetObjects():
206 if obj
.GetKey() in _dec_key_description_mapping_table
.keys():
208 descr
+= '<TD><B>%s</B></TD>' % _dec_key_description_mapping_table
[obj
.GetKey()]
209 descr
+= '<TD>%s</TD>' % obj
.GetValue()
211 descr
+= '</TABLE><br>'
212 baseSection
.AddDescription(descr
)
213 pdObj
.AddSection(baseSection
)
215 knownIssueSection
= doxygen
.Section('Known_Issue_section', 'Known Issue')
216 knownIssueSection
.AddDescription('<ul>')
217 knownIssueSection
.AddDescription('<li> OPTIONAL macro for function parameter can not be dealed with doxygen, so it disapear in this document! </li>')
218 knownIssueSection
.AddDescription('</ul>')
219 pdObj
.AddSection(knownIssueSection
)
221 self
.AddAllIncludeFiles(self
._pObj
, self
._configFile
)
222 pages
= self
.GenerateIncludesSubPage(self
._pObj
, self
._configFile
)
224 pdObj
.AddPages(pages
)
225 pages
= self
.GenerateLibraryClassesSubPage(self
._pObj
, self
._configFile
)
227 pdObj
.AddPages(pages
)
228 pages
= self
.GeneratePcdSubPages(self
._pObj
, self
._configFile
)
230 pdObj
.AddPages(pages
)
231 pages
= self
.GenerateGuidSubPages(self
._pObj
, self
._configFile
)
233 pdObj
.AddPages(pages
)
234 pages
= self
.GeneratePpiSubPages(self
._pObj
, self
._configFile
)
236 pdObj
.AddPages(pages
)
237 pages
= self
.GenerateProtocolSubPages(self
._pObj
, self
._configFile
)
239 pdObj
.AddPages(pages
)
240 if not self
._onlyIncludeDocument
:
241 pdObj
.AddPages(self
.GenerateModulePages(self
._pObj
, self
._configFile
))
244 return pdObj
.GetFilename()
246 def GenerateIncludesSubPage(self
, pObj
, configFile
):
247 # by default add following path as include path to config file
248 pkpath
= pObj
.GetFileObj().GetPackageRootPath()
249 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include'))
250 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include', 'Library'))
251 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include', 'Protocol'))
252 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include', 'Ppi'))
253 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include', 'Guid'))
254 configFile
.AddIncludePath(os
.path
.join(pkpath
, 'Include', 'IndustryStandard'))
257 pageRoot
= doxygen
.Page("Public Includes", "%s_public_includes" % pObj
.GetName())
258 objs
= pObj
.GetFileObj().GetSectionObjectsByName('includes')
259 if len(objs
) == 0: return []
262 # Add path to include path
263 path
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetPath())
264 configFile
.AddIncludePath(path
)
266 # only list common folder's include file
267 if obj
.GetArch().lower() != 'common':
270 bNeedAddIncludePage
= False
271 topPage
= doxygen
.Page(self
._ConvertPathToDoxygen
(path
, pObj
), 'public_include_top')
273 topPage
.AddDescription('<ul>\n')
274 for file in os
.listdir(path
):
275 if file.lower() in _ignore_dir
: continue
276 fullpath
= os
.path
.join(path
, file)
277 if os
.path
.isfile(fullpath
):
278 self
.ProcessSourceFileForInclude(fullpath
, pObj
, configFile
)
279 topPage
.AddDescription('<li> \link %s\endlink </li>\n' % self
._ConvertPathToDoxygen
(fullpath
, pObj
))
281 if file.lower() in ['library', 'protocol', 'guid', 'ppi', 'ia32', 'x64', 'ipf', 'ebc', 'arm', 'pi', 'uefi', 'aarch64']:
283 bNeedAddSubPage
= False
284 subpage
= doxygen
.Page(self
._ConvertPathToDoxygen
(fullpath
, pObj
), 'public_include_%s' % file)
285 subpage
.AddDescription('<ul>\n')
286 for subfile
in os
.listdir(fullpath
):
287 if subfile
.lower() in _ignore_dir
: continue
288 bNeedAddSubPage
= True
289 subfullpath
= os
.path
.join(fullpath
, subfile
)
290 self
.ProcessSourceFileForInclude(subfullpath
, pObj
, configFile
)
291 subpage
.AddDescription('<li> \link %s \endlink </li>\n' % self
._ConvertPathToDoxygen
(subfullpath
, pObj
))
292 subpage
.AddDescription('</ul>\n')
294 bNeedAddIncludePage
= True
295 pageRoot
.AddPage(subpage
)
296 topPage
.AddDescription('</ul>\n')
297 if bNeedAddIncludePage
:
298 pageRoot
.AddPage(topPage
)
300 if pageRoot
.GetSubpageCount() != 0:
305 def GenerateLibraryClassesSubPage(self
, pObj
, configFile
):
307 Generate sub page for library class for package.
308 One DEC file maybe contains many library class sections
309 for different architecture.
311 @param fObj DEC file object.
314 pageRoot
= doxygen
.Page("Library Class", "%s_libraryclass" % pObj
.GetName())
315 objs
= pObj
.GetFileObj().GetSectionObjectsByName('libraryclass', self
._arch
)
316 if len(objs
) == 0: return []
318 if self
._arch
is not None:
320 classPage
= doxygen
.Page(obj
.GetClassName(),
321 "lc_%s" % obj
.GetClassName())
322 comments
= obj
.GetComment()
323 if len(comments
) != 0:
324 classPage
.AddDescription('<br>\n'.join(comments
) + '<br>\n')
325 pageRoot
.AddPage(classPage
)
326 path
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetHeaderFile())
327 path
= path
[len(pObj
.GetWorkspace()) + 1:]
328 if len(comments
) == 0:
329 classPage
.AddDescription('\copydoc %s<p>' % obj
.GetHeaderFile())
330 section
= doxygen
.Section('ref', 'Refer to Header File')
331 section
.AddDescription('\link %s\n' % obj
.GetHeaderFile())
332 section
.AddDescription(' \endlink<p>\n')
333 classPage
.AddSection(section
)
334 fullPath
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetHeaderFile())
335 self
.ProcessSourceFileForInclude(fullPath
, pObj
, configFile
)
339 if obj
.GetArch() not in archPageDict
.keys():
340 archPageDict
[obj
.GetArch()] = doxygen
.Page(obj
.GetArch(),
341 'lc_%s' % obj
.GetArch())
342 pageRoot
.AddPage(archPageDict
[obj
.GetArch()])
343 subArchRoot
= archPageDict
[obj
.GetArch()]
344 classPage
= doxygen
.Page(obj
.GetClassName(),
345 "lc_%s" % obj
.GetClassName())
346 comments
= obj
.GetComment()
347 if len(comments
) != 0:
348 classPage
.AddDescription('<br>\n'.join(comments
) + '<br>\n')
349 subArchRoot
.AddPage(classPage
)
350 path
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetHeaderFile())
351 path
= path
[len(pObj
.GetWorkspace()) + 1:]
352 if len(comments
) == 0:
353 classPage
.AddDescription('\copydoc %s<p>' % obj
.GetHeaderFile())
354 section
= doxygen
.Section('ref', 'Refer to Header File')
355 section
.AddDescription('\link %s\n' % obj
.GetHeaderFile())
356 section
.AddDescription(' \endlink<p>\n')
357 classPage
.AddSection(section
)
358 fullPath
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetHeaderFile())
360 self
.ProcessSourceFileForInclude(fullPath
, pObj
, configFile
)
361 rootArray
.append(pageRoot
)
364 def ProcessSourceFileForInclude(self
, path
, pObj
, configFile
, infObj
=None):
366 @param path the analysising file full path
367 @param pObj package object
368 @param configFile doxygen config file.
373 if not os
.path
.exists(path
):
374 ErrorMsg('Source file path %s does not exist!' % path
)
377 if configFile
.FileExists(path
):
382 lines
= f
.readlines()
385 ErrorMsg('Fail to open file %s' % path
)
388 configFile
.AddFile(path
)
391 for no
in range(len(lines
)):
392 if len(lines
[no
].strip()) == 0:
394 if lines
[no
].strip()[:2] in ['##', '//', '/*', '*/']:
396 index
= lines
[no
].lower().find('include')
397 #mo = IncludePattern.finditer(lines[no].lower())
398 mo
= re
.match(r
"^#\s*include\s+[<\"]([\\/\w
.]+)[>\"]$
", lines[no].strip().lower())
401 mo = re.match(r"^
[#\w\s]+[<\"]([\\/\w.]+)[>\"]$", lines[no].strip())
402 filePath
= mo
.groups()[0]
404 if filePath
is None or len(filePath
) == 0:
407 # find header file in module's path firstly.
410 if os
.path
.exists(os
.path
.join(os
.path
.dirname(path
), filePath
)):
411 # Find the file in current directory
412 fullPath
= os
.path
.join(os
.path
.dirname(path
), filePath
).replace('\\', '/')
414 # find in depedent package's include path
415 incObjs
= pObj
.GetFileObj().GetSectionObjectsByName('includes')
416 for incObj
in incObjs
:
417 incPath
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), incObj
.GetPath()).strip()
418 incPath
= os
.path
.realpath(os
.path
.join(incPath
, filePath
))
419 if os
.path
.exists(incPath
):
422 if infObj
is not None:
423 pkgInfObjs
= infObj
.GetSectionObjectsByName('packages')
424 for obj
in pkgInfObjs
:
425 decObj
= dec
.DECFile(os
.path
.join(pObj
.GetWorkspace(), obj
.GetPath()))
427 ErrorMsg ('Fail to create pacakge object for %s' % obj
.GetPackageName())
429 if not decObj
.Parse():
430 ErrorMsg ('Fail to load package object for %s' % obj
.GetPackageName())
432 incObjs
= decObj
.GetSectionObjectsByName('includes')
433 for incObj
in incObjs
:
434 incPath
= os
.path
.join(decObj
.GetPackageRootPath(), incObj
.GetPath()).replace('\\', '/')
435 if os
.path
.exists(os
.path
.join(incPath
, filePath
)):
436 fullPath
= os
.path
.join(os
.path
.join(incPath
, filePath
))
438 if fullPath
is not None:
441 if fullPath
is None and self
.IsVerbose():
442 self
.Log('Can not resolve header file %s for file %s in package %s\n' % (filePath
, path
, pObj
.GetFileObj().GetFilename()), 'error')
445 fullPath
= fullPath
.replace('\\', '/')
447 self
.Log('Preprocessing: Add include file %s for file %s\n' % (fullPath
, path
))
448 #LogMsg ('Preprocessing: Add include file %s for file %s' % (fullPath, path))
449 self
.ProcessSourceFileForInclude(fullPath
, pObj
, configFile
, infObj
)
451 def AddAllIncludeFiles(self
, pObj
, configFile
):
452 objs
= pObj
.GetFileObj().GetSectionObjectsByName('includes')
454 incPath
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetPath())
455 for root
, dirs
, files
in os
.walk(incPath
):
457 if dir.lower() in _ignore_dir
:
460 path
= os
.path
.normpath(os
.path
.join(root
, file))
461 configFile
.AddFile(path
.replace('/', '\\'))
463 def GeneratePcdSubPages(self
, pObj
, configFile
):
465 Generate sub pages for package's PCD definition.
466 @param pObj package object
467 @param configFile config file object
470 objs
= pObj
.GetFileObj().GetSectionObjectsByName('pcd')
474 pcdRootPage
= doxygen
.Page('PCD', 'pcd_root_page')
475 typeRootPageDict
= {}
476 typeArchRootPageDict
= {}
478 if obj
.GetPcdType() not in typeRootPageDict
.keys():
479 typeRootPageDict
[obj
.GetPcdType()] = doxygen
.Page(obj
.GetPcdType(), 'pcd_%s_root_page' % obj
.GetPcdType())
480 pcdRootPage
.AddPage(typeRootPageDict
[obj
.GetPcdType()])
481 typeRoot
= typeRootPageDict
[obj
.GetPcdType()]
482 if self
._arch
is not None:
483 pcdPage
= doxygen
.Page('%s' % obj
.GetPcdName(),
484 'pcd_%s_%s_%s' % (obj
.GetPcdType(), obj
.GetArch(), obj
.GetPcdName().split('.')[1]))
485 pcdPage
.AddDescription('<br>\n'.join(obj
.GetComment()) + '<br>\n')
486 section
= doxygen
.Section('PCDinformation', 'PCD Information')
489 desc
+= '<TD><CAPTION>Name</CAPTION></TD>'
490 desc
+= '<TD><CAPTION>Token Space</CAPTION></TD>'
491 desc
+= '<TD><CAPTION>Token number</CAPTION></TD>'
492 desc
+= '<TD><CAPTION>Data Type</CAPTION></TD>'
493 desc
+= '<TD><CAPTION>Default Value</CAPTION></TD>'
496 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdName().split('.')[1]
497 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdName().split('.')[0]
498 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdToken()
499 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdDataType()
500 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdValue()
503 section
.AddDescription(desc
)
504 pcdPage
.AddSection(section
)
505 typeRoot
.AddPage(pcdPage
)
507 keystr
= obj
.GetPcdType() + obj
.GetArch()
508 if keystr
not in typeArchRootPageDict
.keys():
509 typeArchRootPage
= doxygen
.Page(obj
.GetArch(), 'pcd_%s_%s_root_page' % (obj
.GetPcdType(), obj
.GetArch()))
510 typeArchRootPageDict
[keystr
] = typeArchRootPage
511 typeRoot
.AddPage(typeArchRootPage
)
512 typeArchRoot
= typeArchRootPageDict
[keystr
]
513 pcdPage
= doxygen
.Page('%s' % obj
.GetPcdName(),
514 'pcd_%s_%s_%s' % (obj
.GetPcdType(), obj
.GetArch(), obj
.GetPcdName().split('.')[1]))
515 pcdPage
.AddDescription('<br>\n'.join(obj
.GetComment()) + '<br>\n')
516 section
= doxygen
.Section('PCDinformation', 'PCD Information')
519 desc
+= '<TD><CAPTION>Name</CAPTION></TD>'
520 desc
+= '<TD><CAPTION>Token Space</CAPTION></TD>'
521 desc
+= '<TD><CAPTION>Token number</CAPTION></TD>'
522 desc
+= '<TD><CAPTION>Data Type</CAPTION></TD>'
523 desc
+= '<TD><CAPTION>Default Value</CAPTION></TD>'
526 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdName().split('.')[1]
527 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdName().split('.')[0]
528 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdToken()
529 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdDataType()
530 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdValue()
533 section
.AddDescription(desc
)
534 pcdPage
.AddSection(section
)
535 typeArchRoot
.AddPage(pcdPage
)
538 def _GenerateGuidSubPage(self
, pObj
, obj
, configFile
):
539 guidPage
= doxygen
.Page('%s' % obj
.GetName(),
540 'guid_%s_%s' % (obj
.GetArch(), obj
.GetName()))
541 comments
= obj
.GetComment()
542 if len(comments
) != 0:
543 guidPage
.AddDescription('<br>'.join(obj
.GetComment()) + '<br>')
544 section
= doxygen
.Section('BasicGuidInfo', 'GUID Information')
547 desc
+= '<TD><CAPTION>GUID\'s Guid Name</CAPTION></TD><TD><CAPTION>GUID\'s Guid</CAPTION></TD>'
550 desc
+= '<TD>%s</TD>' % obj
.GetName()
551 desc
+= '<TD>%s</TD>' % obj
.GetGuid()
554 section
.AddDescription(desc
)
555 guidPage
.AddSection(section
)
556 refFile
= self
.FindHeaderFileForGuid(pObj
, obj
.GetName(), configFile
)
558 relPath
= refFile
[len(pObj
.GetWorkspace()) + 1:]
559 if len(comments
) == 0:
560 guidPage
.AddDescription(' \\copydoc %s <br>' % relPath
)
562 section
= doxygen
.Section('ref', 'Refer to Header File')
563 section
.AddDescription('\link %s\n' % relPath
)
564 section
.AddDescription('\endlink\n')
565 self
.ProcessSourceFileForInclude(refFile
, pObj
, configFile
)
566 guidPage
.AddSection(section
)
569 def GenerateGuidSubPages(self
, pObj
, configFile
):
571 Generate sub pages for package's GUID definition.
572 @param pObj package object
573 @param configFilf doxygen config file object
575 pageRoot
= doxygen
.Page('GUID', 'guid_root_page')
576 objs
= pObj
.GetFileObj().GetSectionObjectsByName('guids', self
._arch
)
577 if len(objs
) == 0: return []
578 if self
._arch
is not None:
580 pageRoot
.AddPage(self
._GenerateGuidSubPage
(pObj
, obj
, configFile
))
582 guidArchRootPageDict
= {}
584 if obj
.GetArch() not in guidArchRootPageDict
.keys():
585 guidArchRoot
= doxygen
.Page(obj
.GetArch(), 'guid_arch_root_%s' % obj
.GetArch())
586 pageRoot
.AddPage(guidArchRoot
)
587 guidArchRootPageDict
[obj
.GetArch()] = guidArchRoot
588 guidArchRoot
= guidArchRootPageDict
[obj
.GetArch()]
589 guidArchRoot
.AddPage(self
._GenerateGuidSubPage
(pObj
, obj
, configFile
))
592 def _GeneratePpiSubPage(self
, pObj
, obj
, configFile
):
593 guidPage
= doxygen
.Page(obj
.GetName(), 'ppi_page_%s' % obj
.GetName())
594 comments
= obj
.GetComment()
595 if len(comments
) != 0:
596 guidPage
.AddDescription('<br>'.join(obj
.GetComment()) + '<br>')
597 section
= doxygen
.Section('BasicPpiInfo', 'PPI Information')
600 desc
+= '<TD><CAPTION>PPI\'s Guid Name</CAPTION></TD><TD><CAPTION>PPI\'s Guid</CAPTION></TD>'
603 desc
+= '<TD>%s</TD>' % obj
.GetName()
604 desc
+= '<TD>%s</TD>' % obj
.GetGuid()
607 section
.AddDescription(desc
)
608 guidPage
.AddSection(section
)
609 refFile
= self
.FindHeaderFileForGuid(pObj
, obj
.GetName(), configFile
)
611 relPath
= refFile
[len(pObj
.GetWorkspace()) + 1:]
612 if len(comments
) == 0:
613 guidPage
.AddDescription(' \\copydoc %s <br>' % relPath
)
614 section
= doxygen
.Section('ref', 'Refer to Header File')
615 section
.AddDescription('\link %s\n' % relPath
)
616 section
.AddDescription('\endlink\n')
617 self
.ProcessSourceFileForInclude(refFile
, pObj
, configFile
)
618 guidPage
.AddSection(section
)
622 def GeneratePpiSubPages(self
, pObj
, configFile
):
624 Generate sub pages for package's GUID definition.
625 @param pObj package object
626 @param configFilf doxygen config file object
628 pageRoot
= doxygen
.Page('PPI', 'ppi_root_page')
629 objs
= pObj
.GetFileObj().GetSectionObjectsByName('ppis', self
._arch
)
630 if len(objs
) == 0: return []
631 if self
._arch
is not None:
633 pageRoot
.AddPage(self
._GeneratePpiSubPage
(pObj
, obj
, configFile
))
635 guidArchRootPageDict
= {}
637 if obj
.GetArch() not in guidArchRootPageDict
.keys():
638 guidArchRoot
= doxygen
.Page(obj
.GetArch(), 'ppi_arch_root_%s' % obj
.GetArch())
639 pageRoot
.AddPage(guidArchRoot
)
640 guidArchRootPageDict
[obj
.GetArch()] = guidArchRoot
641 guidArchRoot
= guidArchRootPageDict
[obj
.GetArch()]
642 guidArchRoot
.AddPage(self
._GeneratePpiSubPage
(pObj
, obj
, configFile
))
645 def _GenerateProtocolSubPage(self
, pObj
, obj
, configFile
):
646 guidPage
= doxygen
.Page(obj
.GetName(), 'protocol_page_%s' % obj
.GetName())
647 comments
= obj
.GetComment()
648 if len(comments
) != 0:
649 guidPage
.AddDescription('<br>'.join(obj
.GetComment()) + '<br>')
650 section
= doxygen
.Section('BasicProtocolInfo', 'PROTOCOL Information')
653 desc
+= '<TD><CAPTION>PROTOCOL\'s Guid Name</CAPTION></TD><TD><CAPTION>PROTOCOL\'s Guid</CAPTION></TD>'
656 desc
+= '<TD>%s</TD>' % obj
.GetName()
657 desc
+= '<TD>%s</TD>' % obj
.GetGuid()
660 section
.AddDescription(desc
)
661 guidPage
.AddSection(section
)
663 refFile
= self
.FindHeaderFileForGuid(pObj
, obj
.GetName(), configFile
)
665 relPath
= refFile
[len(pObj
.GetWorkspace()) + 1:]
666 if len(comments
) == 0:
667 guidPage
.AddDescription(' \\copydoc %s <br>' % relPath
)
668 section
= doxygen
.Section('ref', 'Refer to Header File')
669 section
.AddDescription('\link %s\n' % relPath
)
670 section
.AddDescription('\endlink\n')
671 self
.ProcessSourceFileForInclude(refFile
, pObj
, configFile
)
672 guidPage
.AddSection(section
)
676 def GenerateProtocolSubPages(self
, pObj
, configFile
):
678 Generate sub pages for package's GUID definition.
679 @param pObj package object
680 @param configFilf doxygen config file object
682 pageRoot
= doxygen
.Page('PROTOCOL', 'protocol_root_page')
683 objs
= pObj
.GetFileObj().GetSectionObjectsByName('protocols', self
._arch
)
684 if len(objs
) == 0: return []
685 if self
._arch
is not None:
687 pageRoot
.AddPage(self
._GenerateProtocolSubPage
(pObj
, obj
, configFile
))
689 guidArchRootPageDict
= {}
691 if obj
.GetArch() not in guidArchRootPageDict
.keys():
692 guidArchRoot
= doxygen
.Page(obj
.GetArch(), 'protocol_arch_root_%s' % obj
.GetArch())
693 pageRoot
.AddPage(guidArchRoot
)
694 guidArchRootPageDict
[obj
.GetArch()] = guidArchRoot
695 guidArchRoot
= guidArchRootPageDict
[obj
.GetArch()]
696 guidArchRoot
.AddPage(self
._GenerateProtocolSubPage
(pObj
, obj
, configFile
))
699 def FindHeaderFileForGuid(self
, pObj
, name
, configFile
):
701 For declaration header file for GUID/PPI/Protocol.
703 @param pObj package object
704 @param name guid/ppi/protocol's name
705 @param configFile config file object
707 @return full path of header file and None if not found.
709 startPath
= pObj
.GetFileObj().GetPackageRootPath()
710 incPath
= os
.path
.join(startPath
, 'Include').replace('\\', '/')
711 # if <PackagePath>/include exist, then search header under it.
712 if os
.path
.exists(incPath
):
715 for root
, dirs
, files
in os
.walk(startPath
):
717 if dir.lower() in _ignore_dir
:
720 fPath
= os
.path
.join(root
, file)
721 if not IsCHeaderFile(fPath
):
725 lines
= f
.readlines()
728 self
.Log('Fail to open file %s\n' % fPath
)
731 if line
.find(name
) != -1 and \
732 line
.find('extern') != -1:
733 return fPath
.replace('\\', '/')
736 def GetPackageModuleList(self
, pObj
):
738 Get all module's INF path under package's root path
739 @param pObj package object
740 @return arrary of INF full path
743 packPath
= pObj
.GetFileObj().GetPackageRootPath()
744 if not os
.path
.exists
:
746 for root
, dirs
, files
in os
.walk(packPath
):
748 if dir.lower() in _ignore_dir
:
751 if CheckPathPostfix(file, 'inf'):
752 fPath
= os
.path
.join(root
, file).replace('\\', '/')
756 def GenerateModulePages(self
, pObj
, configFile
):
758 Generate sub pages for package's module which is under the package
761 @param pObj package object
762 @param configFilf doxygen config file object
764 infList
= self
.GetPackageModuleList(pObj
)
768 for infpath
in infList
:
769 infObj
= inf
.INFFile(infpath
)
770 #infObj = INFFileObject.INFFile (pObj.GetWorkspacePath(),
773 self
.Log('Fail create INF object for %s' % inf
)
775 if not infObj
.Parse():
776 self
.Log('Fail to load INF file %s' % inf
)
778 if infObj
.GetProduceLibraryClass() is not None:
779 libObjs
.append(infObj
)
781 modObjs
.append(infObj
)
783 if len(libObjs
) != 0:
784 libRootPage
= doxygen
.Page('Libraries', 'lib_root_page')
785 rootPages
.append(libRootPage
)
786 for libInf
in libObjs
:
787 libRootPage
.AddPage(self
.GenerateModulePage(pObj
, libInf
, configFile
, True))
789 if len(modObjs
) != 0:
790 modRootPage
= doxygen
.Page('Modules', 'module_root_page')
791 rootPages
.append(modRootPage
)
792 for modInf
in modObjs
:
793 modRootPage
.AddPage(self
.GenerateModulePage(pObj
, modInf
, configFile
, False))
797 def GenerateModulePage(self
, pObj
, infObj
, configFile
, isLib
):
799 Generate page for a module/library.
800 @param infObj INF file object for module/library
801 @param configFile doxygen config file object
802 @param isLib Whether this module is libary
804 @param module doxygen page object
806 workspace
= pObj
.GetWorkspace()
808 for obj
in infObj
.GetSectionObjectsByName('packages'):
809 decObj
= dec
.DECFile(os
.path
.join(workspace
, obj
.GetPath()))
811 ErrorMsg ('Fail to create pacakge object for %s' % obj
.GetPackageName())
813 if not decObj
.Parse():
814 ErrorMsg ('Fail to load package object for %s' % obj
.GetPackageName())
816 refDecObjs
.append(decObj
)
818 modPage
= doxygen
.Page('%s' % infObj
.GetBaseName(),
819 'module_%s' % infObj
.GetBaseName())
820 modPage
.AddDescription(infObj
.GetFileHeader())
822 basicInfSection
= doxygen
.Section('BasicModuleInformation', 'Basic Module Information')
824 for obj
in infObj
.GetSectionObjectsByName('defines'):
826 value
= obj
.GetValue()
827 if key
not in _inf_key_description_mapping_table
.keys(): continue
828 if key
== 'LIBRARY_CLASS' and value
.find('|') != -1:
829 clsname
, types
= value
.split('|')
831 desc
+= '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table
[key
]
832 desc
+= '<TD>%s</TD>' % clsname
836 desc
+= '<TD><B>Supported Module Types</B></TD>'
837 desc
+= '<TD>%s</TD>' % types
841 desc
+= '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table
[key
]
842 if key
== 'EFI_SPECIFICATION_VERSION' and value
== '0x00020000':
844 desc
+= '<TD>%s</TD>' % value
847 basicInfSection
.AddDescription(desc
)
848 modPage
.AddSection(basicInfSection
)
850 # Add protocol section
852 for obj
in infObj
.GetSectionObjectsByName('pcd', self
._arch
):
853 data
.append(obj
.GetPcdName().strip())
855 s
= doxygen
.Section('Pcds', 'Pcds')
857 desc
+= '<TR><TD><B>PCD Name</B></TD><TD><B>TokenSpace</B></TD><TD><B>Package</B></TD></TR>'
860 desc
+= '<TD>%s</TD>' % item
.split('.')[1]
861 desc
+= '<TD>%s</TD>' % item
.split('.')[0]
862 pkgbasename
= self
.SearchPcdPackage(item
, workspace
, refDecObjs
)
863 desc
+= '<TD>%s</TD>' % pkgbasename
866 s
.AddDescription(desc
)
867 modPage
.AddSection(s
)
869 # Add protocol section
870 #sects = infObj.GetSectionByString('protocol')
873 for obj
in infObj
.GetSectionObjectsByName('protocol', self
._arch
):
874 data
.append(obj
.GetName().strip())
876 s
= doxygen
.Section('Protocols', 'Protocols')
878 desc
+= '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
881 desc
+= '<TD>%s</TD>' % item
882 pkgbasename
= self
.SearchProtocolPackage(item
, workspace
, refDecObjs
)
883 desc
+= '<TD>%s</TD>' % pkgbasename
886 s
.AddDescription(desc
)
887 modPage
.AddSection(s
)
890 #sects = infObj.GetSectionByString('ppi')
893 for obj
in infObj
.GetSectionObjectsByName('ppi', self
._arch
):
894 data
.append(obj
.GetName().strip())
896 s
= doxygen
.Section('Ppis', 'Ppis')
898 desc
+= '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
901 desc
+= '<TD>%s</TD>' % item
902 pkgbasename
= self
.SearchPpiPackage(item
, workspace
, refDecObjs
)
903 desc
+= '<TD>%s</TD>' % pkgbasename
906 s
.AddDescription(desc
)
907 modPage
.AddSection(s
)
910 #sects = infObj.GetSectionByString('guid')
913 for obj
in infObj
.GetSectionObjectsByName('guid', self
._arch
):
914 data
.append(obj
.GetName().strip())
916 s
= doxygen
.Section('Guids', 'Guids')
918 desc
+= '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
921 desc
+= '<TD>%s</TD>' % item
922 pkgbasename
= self
.SearchGuidPackage(item
, workspace
, refDecObjs
)
923 desc
+= '<TD>%s</TD>' % pkgbasename
926 s
.AddDescription(desc
)
927 modPage
.AddSection(s
)
929 section
= doxygen
.Section('LibraryClasses', 'Library Classes')
931 desc
+= '<TR><TD><B>Name</B></TD><TD><B>Type</B></TD><TD><B>Package</B></TD><TD><B>Header File</B></TD></TR>'
934 desc
+= '<TD>%s</TD>' % infObj
.GetProduceLibraryClass()
935 desc
+= '<TD>Produce</TD>'
937 pkgname
, hPath
= self
.SearchLibraryClassHeaderFile(infObj
.GetProduceLibraryClass(),
941 self
.Log ('fail to get package header file for lib class %s' % infObj
.GetProduceLibraryClass())
944 desc
+= '<TD>%s</TD>' % pkgname
946 #desc += '<TD>\link %s \endlink</TD>' % hPath
947 desc
+= '<TD>%s</TD>' % hPath
949 desc
+= '<TD>%s</TD>' % hPath
951 for lcObj
in infObj
.GetSectionObjectsByName('libraryclasses', self
._arch
):
953 desc
+= '<TD>%s</TD>' % lcObj
.GetClass()
954 retarr
= self
.SearchLibraryClassHeaderFile(lcObj
.GetClass(),
957 if retarr
is not None:
958 pkgname
, hPath
= retarr
960 self
.Log('Fail find the library class %s definition from module %s dependent package!' % (lcObj
.GetClass(), infObj
.GetFilename()), 'error')
963 desc
+= '<TD>Consume</TD>'
964 desc
+= '<TD>%s</TD>' % pkgname
965 desc
+= '<TD>%s</TD>' % hPath
968 section
.AddDescription(desc
)
969 modPage
.AddSection(section
)
971 section
= doxygen
.Section('SourceFiles', 'Source Files')
972 section
.AddDescription('<ul>\n')
973 for obj
in infObj
.GetSourceObjects(self
._arch
, self
._tooltag
):
974 sPath
= infObj
.GetModuleRootPath()
975 sPath
= os
.path
.join(sPath
, obj
.GetSourcePath()).replace('\\', '/').strip()
976 if sPath
.lower().endswith('.uni') or sPath
.lower().endswith('.s') or sPath
.lower().endswith('.asm') or sPath
.lower().endswith('.nasm'):
977 newPath
= self
.TranslateUniFile(sPath
)
978 configFile
.AddFile(newPath
)
979 newPath
= newPath
[len(pObj
.GetWorkspace()) + 1:]
980 section
.AddDescription('<li> \link %s \endlink </li>' % newPath
)
982 self
.ProcessSourceFileForInclude(sPath
, pObj
, configFile
, infObj
)
983 sPath
= sPath
[len(pObj
.GetWorkspace()) + 1:]
984 section
.AddDescription('<li>\link %s \endlink </li>' % sPath
)
985 section
.AddDescription('</ul>\n')
986 modPage
.AddSection(section
)
988 #sects = infObj.GetSectionByString('depex')
991 for obj
in infObj
.GetSectionObjectsByName('depex'):
992 data
.append(str(obj
))
994 s
= doxygen
.Section('DependentSection', 'Module Dependencies')
995 s
.AddDescription('<br>'.join(data
))
996 modPage
.AddSection(s
)
1000 def TranslateUniFile(self
, path
):
1001 newpath
= path
+ '.dox'
1002 #import core.textfile as textfile
1003 #file = textfile.TextFile(path)
1006 file = open(path
, 'r')
1007 except (IOError, OSError) as msg
:
1013 output
= '/** @file \n'
1014 #output = '<html><body>'
1015 arr
= t
.split('\r\n')
1017 if line
.find('@file') != -1:
1019 if line
.find('*/') != -1:
1022 if line
.strip().startswith('/'):
1023 arr
= line
.split(' ')
1025 line
= ' '.join(arr
[1:])
1028 output
+= '%s<br>\n' % line
1031 if os
.path
.exists(newpath
):
1034 file = open(newpath
, "w")
1039 def SearchPcdPackage(self
, pcdname
, workspace
, decObjs
):
1040 for decObj
in decObjs
:
1041 for pcd
in decObj
.GetSectionObjectsByName('pcd'):
1042 if pcdname
== pcd
.GetPcdName():
1043 return decObj
.GetBaseName()
1046 def SearchProtocolPackage(self
, protname
, workspace
, decObjs
):
1047 for decObj
in decObjs
:
1048 for proto
in decObj
.GetSectionObjectsByName('protocol'):
1049 if protname
== proto
.GetName():
1050 return decObj
.GetBaseName()
1053 def SearchPpiPackage(self
, ppiname
, workspace
, decObjs
):
1054 for decObj
in decObjs
:
1055 for ppi
in decObj
.GetSectionObjectsByName('ppi'):
1056 if ppiname
== ppi
.GetName():
1057 return decObj
.GetBaseName()
1060 def SearchGuidPackage(self
, guidname
, workspace
, decObjs
):
1061 for decObj
in decObjs
:
1062 for guid
in decObj
.GetSectionObjectsByName('guid'):
1063 if guidname
== guid
.GetName():
1064 return decObj
.GetBaseName()
1067 def SearchLibraryClassHeaderFile(self
, className
, workspace
, decObjs
):
1068 for decObj
in decObjs
:
1069 for cls
in decObj
.GetSectionObjectsByName('libraryclasses'):
1070 if cls
.GetClassName().strip() == className
:
1071 path
= cls
.GetHeaderFile().strip()
1072 path
= os
.path
.join(decObj
.GetPackageRootPath(), path
)
1073 path
= path
[len(workspace
) + 1:]
1074 return decObj
.GetBaseName(), path
.replace('\\', '/')
1078 def _ConvertPathToDoxygen(self
, path
, pObj
):
1079 pRootPath
= pObj
.GetWorkspace()
1080 path
= path
[len(pRootPath
) + 1:]
1081 return path
.replace('\\', '/')
1083 def IsCHeaderFile(path
):
1084 return CheckPathPostfix(path
, 'h')
1086 def CheckPathPostfix(path
, str):
1087 index
= path
.rfind('.')
1090 if path
[index
+ 1:].lower() == str.lower():