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 import plugins
.EdkPlugins
.basemodel
.doxygen
as doxygen
27 import plugins
.EdkPlugins
.edk2
.model
.inf
as inf
28 import plugins
.EdkPlugins
.edk2
.model
.dec
as 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
):
380 lines
= f
.readlines()
383 ErrorMsg('Fail to open file %s' % path
)
386 configFile
.AddFile(path
)
389 for no
in xrange(len(lines
)):
390 if len(lines
[no
].strip()) == 0:
392 if lines
[no
].strip()[:2] in ['##', '//', '/*', '*/']:
394 index
= lines
[no
].lower().find('include')
395 #mo = IncludePattern.finditer(lines[no].lower())
396 mo
= re
.match(r
"^#\s*include\s+[<\"]([\\/\w
.]+)[>\"]$
", lines[no].strip().lower())
399 mo = re.match(r"^
[#\w\s]+[<\"]([\\/\w.]+)[>\"]$", lines[no].strip())
400 filePath
= mo
.groups()[0]
402 if filePath
is None or len(filePath
) == 0:
405 # find header file in module's path firstly.
408 if os
.path
.exists(os
.path
.join(os
.path
.dirname(path
), filePath
)):
409 # Find the file in current directory
410 fullPath
= os
.path
.join(os
.path
.dirname(path
), filePath
).replace('\\', '/')
412 # find in depedent package's include path
413 incObjs
= pObj
.GetFileObj().GetSectionObjectsByName('includes')
414 for incObj
in incObjs
:
415 incPath
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), incObj
.GetPath()).strip()
416 incPath
= os
.path
.realpath(os
.path
.join(incPath
, filePath
))
417 if os
.path
.exists(incPath
):
420 if infObj
is not None:
421 pkgInfObjs
= infObj
.GetSectionObjectsByName('packages')
422 for obj
in pkgInfObjs
:
423 decObj
= dec
.DECFile(os
.path
.join(pObj
.GetWorkspace(), obj
.GetPath()))
425 ErrorMsg ('Fail to create pacakge object for %s' % obj
.GetPackageName())
427 if not decObj
.Parse():
428 ErrorMsg ('Fail to load package object for %s' % obj
.GetPackageName())
430 incObjs
= decObj
.GetSectionObjectsByName('includes')
431 for incObj
in incObjs
:
432 incPath
= os
.path
.join(decObj
.GetPackageRootPath(), incObj
.GetPath()).replace('\\', '/')
433 if os
.path
.exists(os
.path
.join(incPath
, filePath
)):
434 fullPath
= os
.path
.join(os
.path
.join(incPath
, filePath
))
436 if fullPath
is not None:
439 if fullPath
is None and self
.IsVerbose():
440 self
.Log('Can not resolve header file %s for file %s in package %s\n' % (filePath
, path
, pObj
.GetFileObj().GetFilename()), 'error')
443 fullPath
= fullPath
.replace('\\', '/')
445 self
.Log('Preprocessing: Add include file %s for file %s\n' % (fullPath
, path
))
446 #LogMsg ('Preprocessing: Add include file %s for file %s' % (fullPath, path))
447 self
.ProcessSourceFileForInclude(fullPath
, pObj
, configFile
, infObj
)
449 def AddAllIncludeFiles(self
, pObj
, configFile
):
450 objs
= pObj
.GetFileObj().GetSectionObjectsByName('includes')
452 incPath
= os
.path
.join(pObj
.GetFileObj().GetPackageRootPath(), obj
.GetPath())
453 for root
, dirs
, files
in os
.walk(incPath
):
455 if dir.lower() in _ignore_dir
:
458 path
= os
.path
.normpath(os
.path
.join(root
, file))
459 configFile
.AddFile(path
.replace('/', '\\'))
461 def GeneratePcdSubPages(self
, pObj
, configFile
):
463 Generate sub pages for package's PCD definition.
464 @param pObj package object
465 @param configFile config file object
468 objs
= pObj
.GetFileObj().GetSectionObjectsByName('pcd')
472 pcdRootPage
= doxygen
.Page('PCD', 'pcd_root_page')
473 typeRootPageDict
= {}
474 typeArchRootPageDict
= {}
476 if obj
.GetPcdType() not in typeRootPageDict
.keys():
477 typeRootPageDict
[obj
.GetPcdType()] = doxygen
.Page(obj
.GetPcdType(), 'pcd_%s_root_page' % obj
.GetPcdType())
478 pcdRootPage
.AddPage(typeRootPageDict
[obj
.GetPcdType()])
479 typeRoot
= typeRootPageDict
[obj
.GetPcdType()]
480 if self
._arch
is not None:
481 pcdPage
= doxygen
.Page('%s' % obj
.GetPcdName(),
482 'pcd_%s_%s_%s' % (obj
.GetPcdType(), obj
.GetArch(), obj
.GetPcdName().split('.')[1]))
483 pcdPage
.AddDescription('<br>\n'.join(obj
.GetComment()) + '<br>\n')
484 section
= doxygen
.Section('PCDinformation', 'PCD Information')
487 desc
+= '<TD><CAPTION>Name</CAPTION></TD>'
488 desc
+= '<TD><CAPTION>Token Space</CAPTION></TD>'
489 desc
+= '<TD><CAPTION>Token number</CAPTION></TD>'
490 desc
+= '<TD><CAPTION>Data Type</CAPTION></TD>'
491 desc
+= '<TD><CAPTION>Default Value</CAPTION></TD>'
494 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdName().split('.')[1]
495 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdName().split('.')[0]
496 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdToken()
497 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdDataType()
498 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdValue()
501 section
.AddDescription(desc
)
502 pcdPage
.AddSection(section
)
503 typeRoot
.AddPage(pcdPage
)
505 keystr
= obj
.GetPcdType() + obj
.GetArch()
506 if keystr
not in typeArchRootPageDict
.keys():
507 typeArchRootPage
= doxygen
.Page(obj
.GetArch(), 'pcd_%s_%s_root_page' % (obj
.GetPcdType(), obj
.GetArch()))
508 typeArchRootPageDict
[keystr
] = typeArchRootPage
509 typeRoot
.AddPage(typeArchRootPage
)
510 typeArchRoot
= typeArchRootPageDict
[keystr
]
511 pcdPage
= doxygen
.Page('%s' % obj
.GetPcdName(),
512 'pcd_%s_%s_%s' % (obj
.GetPcdType(), obj
.GetArch(), obj
.GetPcdName().split('.')[1]))
513 pcdPage
.AddDescription('<br>\n'.join(obj
.GetComment()) + '<br>\n')
514 section
= doxygen
.Section('PCDinformation', 'PCD Information')
517 desc
+= '<TD><CAPTION>Name</CAPTION></TD>'
518 desc
+= '<TD><CAPTION>Token Space</CAPTION></TD>'
519 desc
+= '<TD><CAPTION>Token number</CAPTION></TD>'
520 desc
+= '<TD><CAPTION>Data Type</CAPTION></TD>'
521 desc
+= '<TD><CAPTION>Default Value</CAPTION></TD>'
524 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdName().split('.')[1]
525 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdName().split('.')[0]
526 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdToken()
527 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdDataType()
528 desc
+= '<TD><CAPTION>%s</CAPTION></TD>' % obj
.GetPcdValue()
531 section
.AddDescription(desc
)
532 pcdPage
.AddSection(section
)
533 typeArchRoot
.AddPage(pcdPage
)
536 def _GenerateGuidSubPage(self
, pObj
, obj
, configFile
):
537 guidPage
= doxygen
.Page('%s' % obj
.GetName(),
538 'guid_%s_%s' % (obj
.GetArch(), obj
.GetName()))
539 comments
= obj
.GetComment()
540 if len(comments
) != 0:
541 guidPage
.AddDescription('<br>'.join(obj
.GetComment()) + '<br>')
542 section
= doxygen
.Section('BasicGuidInfo', 'GUID Information')
545 desc
+= '<TD><CAPTION>GUID\'s Guid Name</CAPTION></TD><TD><CAPTION>GUID\'s Guid</CAPTION></TD>'
548 desc
+= '<TD>%s</TD>' % obj
.GetName()
549 desc
+= '<TD>%s</TD>' % obj
.GetGuid()
552 section
.AddDescription(desc
)
553 guidPage
.AddSection(section
)
554 refFile
= self
.FindHeaderFileForGuid(pObj
, obj
.GetName(), configFile
)
556 relPath
= refFile
[len(pObj
.GetWorkspace()) + 1:]
557 if len(comments
) == 0:
558 guidPage
.AddDescription(' \\copydoc %s <br>' % relPath
)
560 section
= doxygen
.Section('ref', 'Refer to Header File')
561 section
.AddDescription('\link %s\n' % relPath
)
562 section
.AddDescription('\endlink\n')
563 self
.ProcessSourceFileForInclude(refFile
, pObj
, configFile
)
564 guidPage
.AddSection(section
)
567 def GenerateGuidSubPages(self
, pObj
, configFile
):
569 Generate sub pages for package's GUID definition.
570 @param pObj package object
571 @param configFilf doxygen config file object
573 pageRoot
= doxygen
.Page('GUID', 'guid_root_page')
574 objs
= pObj
.GetFileObj().GetSectionObjectsByName('guids', self
._arch
)
575 if len(objs
) == 0: return []
576 if self
._arch
is not None:
578 pageRoot
.AddPage(self
._GenerateGuidSubPage
(pObj
, obj
, configFile
))
580 guidArchRootPageDict
= {}
582 if obj
.GetArch() not in guidArchRootPageDict
.keys():
583 guidArchRoot
= doxygen
.Page(obj
.GetArch(), 'guid_arch_root_%s' % obj
.GetArch())
584 pageRoot
.AddPage(guidArchRoot
)
585 guidArchRootPageDict
[obj
.GetArch()] = guidArchRoot
586 guidArchRoot
= guidArchRootPageDict
[obj
.GetArch()]
587 guidArchRoot
.AddPage(self
._GenerateGuidSubPage
(pObj
, obj
, configFile
))
590 def _GeneratePpiSubPage(self
, pObj
, obj
, configFile
):
591 guidPage
= doxygen
.Page(obj
.GetName(), 'ppi_page_%s' % obj
.GetName())
592 comments
= obj
.GetComment()
593 if len(comments
) != 0:
594 guidPage
.AddDescription('<br>'.join(obj
.GetComment()) + '<br>')
595 section
= doxygen
.Section('BasicPpiInfo', 'PPI Information')
598 desc
+= '<TD><CAPTION>PPI\'s Guid Name</CAPTION></TD><TD><CAPTION>PPI\'s Guid</CAPTION></TD>'
601 desc
+= '<TD>%s</TD>' % obj
.GetName()
602 desc
+= '<TD>%s</TD>' % obj
.GetGuid()
605 section
.AddDescription(desc
)
606 guidPage
.AddSection(section
)
607 refFile
= self
.FindHeaderFileForGuid(pObj
, obj
.GetName(), configFile
)
609 relPath
= refFile
[len(pObj
.GetWorkspace()) + 1:]
610 if len(comments
) == 0:
611 guidPage
.AddDescription(' \\copydoc %s <br>' % relPath
)
612 section
= doxygen
.Section('ref', 'Refer to Header File')
613 section
.AddDescription('\link %s\n' % relPath
)
614 section
.AddDescription('\endlink\n')
615 self
.ProcessSourceFileForInclude(refFile
, pObj
, configFile
)
616 guidPage
.AddSection(section
)
620 def GeneratePpiSubPages(self
, pObj
, configFile
):
622 Generate sub pages for package's GUID definition.
623 @param pObj package object
624 @param configFilf doxygen config file object
626 pageRoot
= doxygen
.Page('PPI', 'ppi_root_page')
627 objs
= pObj
.GetFileObj().GetSectionObjectsByName('ppis', self
._arch
)
628 if len(objs
) == 0: return []
629 if self
._arch
is not None:
631 pageRoot
.AddPage(self
._GeneratePpiSubPage
(pObj
, obj
, configFile
))
633 guidArchRootPageDict
= {}
635 if obj
.GetArch() not in guidArchRootPageDict
.keys():
636 guidArchRoot
= doxygen
.Page(obj
.GetArch(), 'ppi_arch_root_%s' % obj
.GetArch())
637 pageRoot
.AddPage(guidArchRoot
)
638 guidArchRootPageDict
[obj
.GetArch()] = guidArchRoot
639 guidArchRoot
= guidArchRootPageDict
[obj
.GetArch()]
640 guidArchRoot
.AddPage(self
._GeneratePpiSubPage
(pObj
, obj
, configFile
))
643 def _GenerateProtocolSubPage(self
, pObj
, obj
, configFile
):
644 guidPage
= doxygen
.Page(obj
.GetName(), 'protocol_page_%s' % obj
.GetName())
645 comments
= obj
.GetComment()
646 if len(comments
) != 0:
647 guidPage
.AddDescription('<br>'.join(obj
.GetComment()) + '<br>')
648 section
= doxygen
.Section('BasicProtocolInfo', 'PROTOCOL Information')
651 desc
+= '<TD><CAPTION>PROTOCOL\'s Guid Name</CAPTION></TD><TD><CAPTION>PROTOCOL\'s Guid</CAPTION></TD>'
654 desc
+= '<TD>%s</TD>' % obj
.GetName()
655 desc
+= '<TD>%s</TD>' % obj
.GetGuid()
658 section
.AddDescription(desc
)
659 guidPage
.AddSection(section
)
661 refFile
= self
.FindHeaderFileForGuid(pObj
, obj
.GetName(), configFile
)
663 relPath
= refFile
[len(pObj
.GetWorkspace()) + 1:]
664 if len(comments
) == 0:
665 guidPage
.AddDescription(' \\copydoc %s <br>' % relPath
)
666 section
= doxygen
.Section('ref', 'Refer to Header File')
667 section
.AddDescription('\link %s\n' % relPath
)
668 section
.AddDescription('\endlink\n')
669 self
.ProcessSourceFileForInclude(refFile
, pObj
, configFile
)
670 guidPage
.AddSection(section
)
674 def GenerateProtocolSubPages(self
, pObj
, configFile
):
676 Generate sub pages for package's GUID definition.
677 @param pObj package object
678 @param configFilf doxygen config file object
680 pageRoot
= doxygen
.Page('PROTOCOL', 'protocol_root_page')
681 objs
= pObj
.GetFileObj().GetSectionObjectsByName('protocols', self
._arch
)
682 if len(objs
) == 0: return []
683 if self
._arch
is not None:
685 pageRoot
.AddPage(self
._GenerateProtocolSubPage
(pObj
, obj
, configFile
))
687 guidArchRootPageDict
= {}
689 if obj
.GetArch() not in guidArchRootPageDict
.keys():
690 guidArchRoot
= doxygen
.Page(obj
.GetArch(), 'protocol_arch_root_%s' % obj
.GetArch())
691 pageRoot
.AddPage(guidArchRoot
)
692 guidArchRootPageDict
[obj
.GetArch()] = guidArchRoot
693 guidArchRoot
= guidArchRootPageDict
[obj
.GetArch()]
694 guidArchRoot
.AddPage(self
._GenerateProtocolSubPage
(pObj
, obj
, configFile
))
697 def FindHeaderFileForGuid(self
, pObj
, name
, configFile
):
699 For declaration header file for GUID/PPI/Protocol.
701 @param pObj package object
702 @param name guid/ppi/protocol's name
703 @param configFile config file object
705 @return full path of header file and None if not found.
707 startPath
= pObj
.GetFileObj().GetPackageRootPath()
708 incPath
= os
.path
.join(startPath
, 'Include').replace('\\', '/')
709 # if <PackagePath>/include exist, then search header under it.
710 if os
.path
.exists(incPath
):
713 for root
, dirs
, files
in os
.walk(startPath
):
715 if dir.lower() in _ignore_dir
:
718 fPath
= os
.path
.join(root
, file)
719 if not IsCHeaderFile(fPath
):
723 lines
= f
.readlines()
726 self
.Log('Fail to open file %s\n' % fPath
)
729 if line
.find(name
) != -1 and \
730 line
.find('extern') != -1:
731 return fPath
.replace('\\', '/')
734 def GetPackageModuleList(self
, pObj
):
736 Get all module's INF path under package's root path
737 @param pObj package object
738 @return arrary of INF full path
741 packPath
= pObj
.GetFileObj().GetPackageRootPath()
742 if not os
.path
.exists
:
744 for root
, dirs
, files
in os
.walk(packPath
):
746 if dir.lower() in _ignore_dir
:
749 if CheckPathPostfix(file, 'inf'):
750 fPath
= os
.path
.join(root
, file).replace('\\', '/')
754 def GenerateModulePages(self
, pObj
, configFile
):
756 Generate sub pages for package's module which is under the package
759 @param pObj package object
760 @param configFilf doxygen config file object
762 infList
= self
.GetPackageModuleList(pObj
)
766 for infpath
in infList
:
767 infObj
= inf
.INFFile(infpath
)
768 #infObj = INFFileObject.INFFile (pObj.GetWorkspacePath(),
771 self
.Log('Fail create INF object for %s' % inf
)
773 if not infObj
.Parse():
774 self
.Log('Fail to load INF file %s' % inf
)
776 if infObj
.GetProduceLibraryClass() is not None:
777 libObjs
.append(infObj
)
779 modObjs
.append(infObj
)
781 if len(libObjs
) != 0:
782 libRootPage
= doxygen
.Page('Libraries', 'lib_root_page')
783 rootPages
.append(libRootPage
)
784 for libInf
in libObjs
:
785 libRootPage
.AddPage(self
.GenerateModulePage(pObj
, libInf
, configFile
, True))
787 if len(modObjs
) != 0:
788 modRootPage
= doxygen
.Page('Modules', 'module_root_page')
789 rootPages
.append(modRootPage
)
790 for modInf
in modObjs
:
791 modRootPage
.AddPage(self
.GenerateModulePage(pObj
, modInf
, configFile
, False))
795 def GenerateModulePage(self
, pObj
, infObj
, configFile
, isLib
):
797 Generate page for a module/library.
798 @param infObj INF file object for module/library
799 @param configFile doxygen config file object
800 @param isLib Whether this module is libary
802 @param module doxygen page object
804 workspace
= pObj
.GetWorkspace()
806 for obj
in infObj
.GetSectionObjectsByName('packages'):
807 decObj
= dec
.DECFile(os
.path
.join(workspace
, obj
.GetPath()))
809 ErrorMsg ('Fail to create pacakge object for %s' % obj
.GetPackageName())
811 if not decObj
.Parse():
812 ErrorMsg ('Fail to load package object for %s' % obj
.GetPackageName())
814 refDecObjs
.append(decObj
)
816 modPage
= doxygen
.Page('%s' % infObj
.GetBaseName(),
817 'module_%s' % infObj
.GetBaseName())
818 modPage
.AddDescription(infObj
.GetFileHeader())
820 basicInfSection
= doxygen
.Section('BasicModuleInformation', 'Basic Module Information')
822 for obj
in infObj
.GetSectionObjectsByName('defines'):
824 value
= obj
.GetValue()
825 if key
not in _inf_key_description_mapping_table
.keys(): continue
826 if key
== 'LIBRARY_CLASS' and value
.find('|') != -1:
827 clsname
, types
= value
.split('|')
829 desc
+= '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table
[key
]
830 desc
+= '<TD>%s</TD>' % clsname
834 desc
+= '<TD><B>Supported Module Types</B></TD>'
835 desc
+= '<TD>%s</TD>' % types
839 desc
+= '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table
[key
]
840 if key
== 'EFI_SPECIFICATION_VERSION' and value
== '0x00020000':
842 desc
+= '<TD>%s</TD>' % value
845 basicInfSection
.AddDescription(desc
)
846 modPage
.AddSection(basicInfSection
)
848 # Add protocol section
850 for obj
in infObj
.GetSectionObjectsByName('pcd', self
._arch
):
851 data
.append(obj
.GetPcdName().strip())
853 s
= doxygen
.Section('Pcds', 'Pcds')
855 desc
+= '<TR><TD><B>PCD Name</B></TD><TD><B>TokenSpace</B></TD><TD><B>Package</B></TD></TR>'
858 desc
+= '<TD>%s</TD>' % item
.split('.')[1]
859 desc
+= '<TD>%s</TD>' % item
.split('.')[0]
860 pkgbasename
= self
.SearchPcdPackage(item
, workspace
, refDecObjs
)
861 desc
+= '<TD>%s</TD>' % pkgbasename
864 s
.AddDescription(desc
)
865 modPage
.AddSection(s
)
867 # Add protocol section
868 #sects = infObj.GetSectionByString('protocol')
871 for obj
in infObj
.GetSectionObjectsByName('protocol', self
._arch
):
872 data
.append(obj
.GetName().strip())
874 s
= doxygen
.Section('Protocols', 'Protocols')
876 desc
+= '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
879 desc
+= '<TD>%s</TD>' % item
880 pkgbasename
= self
.SearchProtocolPackage(item
, workspace
, refDecObjs
)
881 desc
+= '<TD>%s</TD>' % pkgbasename
884 s
.AddDescription(desc
)
885 modPage
.AddSection(s
)
888 #sects = infObj.GetSectionByString('ppi')
891 for obj
in infObj
.GetSectionObjectsByName('ppi', self
._arch
):
892 data
.append(obj
.GetName().strip())
894 s
= doxygen
.Section('Ppis', 'Ppis')
896 desc
+= '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
899 desc
+= '<TD>%s</TD>' % item
900 pkgbasename
= self
.SearchPpiPackage(item
, workspace
, refDecObjs
)
901 desc
+= '<TD>%s</TD>' % pkgbasename
904 s
.AddDescription(desc
)
905 modPage
.AddSection(s
)
908 #sects = infObj.GetSectionByString('guid')
911 for obj
in infObj
.GetSectionObjectsByName('guid', self
._arch
):
912 data
.append(obj
.GetName().strip())
914 s
= doxygen
.Section('Guids', 'Guids')
916 desc
+= '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
919 desc
+= '<TD>%s</TD>' % item
920 pkgbasename
= self
.SearchGuidPackage(item
, workspace
, refDecObjs
)
921 desc
+= '<TD>%s</TD>' % pkgbasename
924 s
.AddDescription(desc
)
925 modPage
.AddSection(s
)
927 section
= doxygen
.Section('LibraryClasses', 'Library Classes')
929 desc
+= '<TR><TD><B>Name</B></TD><TD><B>Type</B></TD><TD><B>Package</B></TD><TD><B>Header File</B></TD></TR>'
932 desc
+= '<TD>%s</TD>' % infObj
.GetProduceLibraryClass()
933 desc
+= '<TD>Produce</TD>'
935 pkgname
, hPath
= self
.SearchLibraryClassHeaderFile(infObj
.GetProduceLibraryClass(),
939 self
.Log ('fail to get package header file for lib class %s' % infObj
.GetProduceLibraryClass())
942 desc
+= '<TD>%s</TD>' % pkgname
944 desc
+= '<TD>\link %s \endlink</TD>' % hPath
946 desc
+= '<TD>%s</TD>' % hPath
948 for lcObj
in infObj
.GetSectionObjectsByName('libraryclasses', self
._arch
):
950 desc
+= '<TD>%s</TD>' % lcObj
.GetClass()
951 retarr
= self
.SearchLibraryClassHeaderFile(lcObj
.GetClass(),
954 if retarr
is not None:
955 pkgname
, hPath
= retarr
957 self
.Log('Fail find the library class %s definition from module %s dependent package!' % (lcObj
.GetClass(), infObj
.GetFilename()), 'error')
960 desc
+= '<TD>Consume</TD>'
961 desc
+= '<TD>%s</TD>' % pkgname
962 desc
+= '<TD>\link %s \endlink</TD>' % hPath
965 section
.AddDescription(desc
)
966 modPage
.AddSection(section
)
968 section
= doxygen
.Section('SourceFiles', 'Source Files')
969 section
.AddDescription('<ul>\n')
970 for obj
in infObj
.GetSourceObjects(self
._arch
, self
._tooltag
):
971 sPath
= infObj
.GetModuleRootPath()
972 sPath
= os
.path
.join(sPath
, obj
.GetSourcePath()).replace('\\', '/').strip()
973 if sPath
.lower().endswith('.uni') or sPath
.lower().endswith('.s') or sPath
.lower().endswith('.asm') or sPath
.lower().endswith('.nasm'):
974 newPath
= self
.TranslateUniFile(sPath
)
975 configFile
.AddFile(newPath
)
976 newPath
= newPath
[len(pObj
.GetWorkspace()) + 1:]
977 section
.AddDescription('<li> \link %s \endlink </li>' % newPath
)
979 self
.ProcessSourceFileForInclude(sPath
, pObj
, configFile
, infObj
)
980 sPath
= sPath
[len(pObj
.GetWorkspace()) + 1:]
981 section
.AddDescription('<li>\link %s \endlink </li>' % sPath
)
982 section
.AddDescription('</ul>\n')
983 modPage
.AddSection(section
)
985 #sects = infObj.GetSectionByString('depex')
988 for obj
in infObj
.GetSectionObjectsByName('depex'):
989 data
.append(str(obj
))
991 s
= doxygen
.Section('DependentSection', 'Module Dependencies')
992 s
.AddDescription('<br>'.join(data
))
993 modPage
.AddSection(s
)
997 def TranslateUniFile(self
, path
):
998 newpath
= path
+ '.dox'
999 #import core.textfile as textfile
1000 #file = textfile.TextFile(path)
1003 file = open(path
, 'rb')
1004 except (IOError, OSError), msg
:
1010 output
= '/** @file \n'
1011 #output = '<html><body>'
1012 arr
= t
.split('\r\n')
1014 if line
.find('@file') != -1:
1016 if line
.find('*/') != -1:
1019 if line
.strip().startswith('/'):
1020 arr
= line
.split(' ')
1022 line
= ' '.join(arr
[1:])
1025 output
+= '%s<br>\n' % line
1028 if os
.path
.exists(newpath
):
1031 file = open(newpath
, "w")
1036 def SearchPcdPackage(self
, pcdname
, workspace
, decObjs
):
1037 for decObj
in decObjs
:
1038 for pcd
in decObj
.GetSectionObjectsByName('pcd'):
1039 if pcdname
== pcd
.GetPcdName():
1040 return decObj
.GetBaseName()
1043 def SearchProtocolPackage(self
, protname
, workspace
, decObjs
):
1044 for decObj
in decObjs
:
1045 for proto
in decObj
.GetSectionObjectsByName('protocol'):
1046 if protname
== proto
.GetName():
1047 return decObj
.GetBaseName()
1050 def SearchPpiPackage(self
, ppiname
, workspace
, decObjs
):
1051 for decObj
in decObjs
:
1052 for ppi
in decObj
.GetSectionObjectsByName('ppi'):
1053 if ppiname
== ppi
.GetName():
1054 return decObj
.GetBaseName()
1057 def SearchGuidPackage(self
, guidname
, workspace
, decObjs
):
1058 for decObj
in decObjs
:
1059 for guid
in decObj
.GetSectionObjectsByName('guid'):
1060 if guidname
== guid
.GetName():
1061 return decObj
.GetBaseName()
1064 def SearchLibraryClassHeaderFile(self
, className
, workspace
, decObjs
):
1065 for decObj
in decObjs
:
1066 for cls
in decObj
.GetSectionObjectsByName('libraryclasses'):
1067 if cls
.GetClassName().strip() == className
:
1068 path
= cls
.GetHeaderFile().strip()
1069 path
= os
.path
.join(decObj
.GetPackageRootPath(), path
)
1070 path
= path
[len(workspace
) + 1:]
1071 return decObj
.GetBaseName(), path
.replace('\\', '/')
1075 def _ConvertPathToDoxygen(self
, path
, pObj
):
1076 pRootPath
= pObj
.GetWorkspace()
1077 path
= path
[len(pRootPath
) + 1:]
1078 return path
.replace('\\', '/')
1080 def IsCHeaderFile(path
):
1081 return CheckPathPostfix(path
, 'h')
1083 def CheckPathPostfix(path
, str):
1084 index
= path
.rfind('.')
1087 if path
[index
+ 1:].lower() == str.lower():