]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/doxygengen_spec.py
BaseTools: Refactor python except statements
[mirror_edk2.git] / BaseTools / Scripts / PackageDocumentTools / plugins / EdkPlugins / edk2 / model / doxygengen_spec.py
1 ## @file
2 #
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.
5 #
6 # Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
7 #
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
12 #
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.
15
16 import plugins.EdkPlugins.basemodel.doxygen as doxygen
17 import os
18 try:
19 import wx
20 gInGui = True
21 except:
22 gInGui = False
23 import re
24 import plugins.EdkPlugins.edk2.model.inf as inf
25 import plugins.EdkPlugins.edk2.model.dec as dec
26 from plugins.EdkPlugins.basemodel.message import *
27
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'
40 }
41
42 _dec_key_description_mapping_table = {
43 'DEC_SPECIFICATION': 'Version of DEC file specification',
44 'PACKAGE_GUID': 'Package Guid'
45 }
46 class DoxygenAction:
47 """This is base class for all doxygen action.
48 """
49
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
55 """
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.
62 self._log = log
63 self._mode = mode
64 self._verbose = verbose
65 self._doxygenCallback = None
66 self._chmCallback = None
67
68 def Log(self, message, level='info'):
69 if self._log is not None:
70 self._log(message, level)
71
72 def IsVerbose(self):
73 return self._verbose
74
75 def Generate(self):
76 """Generate interface called by outer directly"""
77 self.Log(">>>>>> Start generate doxygen document for %s... Zzz....\n" % self._projname)
78
79 # create doxygen config file at first
80 self._configFile = doxygen.DoxygenConfigFile()
81 self._configFile.SetOutputDir(self._outputPath)
82
83 self._configFile.SetWarningFilePath(os.path.join(self._outputPath, 'warning.txt'))
84 if self._mode.lower() == 'html':
85 self._configFile.SetHtmlMode()
86 else:
87 self._configFile.SetChmMode()
88
89 self.Log(" >>>>>> Initialize doxygen config file...Zzz...\n")
90 self.InitializeConfigFile()
91
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')
96 return False
97 else:
98 self.Log("Success to create doxygen index page file %s \n" % indexPagePath)
99
100 # Add index page doxygen file to file list.
101 self._configFile.AddFile(indexPagePath)
102
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)
107
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):
112 return False
113 else:
114 self.Log("Fail to create doxygen process!", 'error')
115 return False
116
117 return True
118
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.
122 """
123
124 def GenerateIndexPage(self):
125 """Generate doxygen index page. Inherited class should implement it."""
126 return None
127
128 def RegisterCallbackDoxygenProcess(self, callback):
129 self._doxygenCallback = callback
130
131 def RegisterCallbackCHMProcess(self, callback):
132 self._chmCallback = callback
133
134 class PlatformDocumentAction(DoxygenAction):
135 """Generate platform doxygen document, will be implement at future."""
136
137 class PackageDocumentAction(DoxygenAction):
138 """Generate package reference document"""
139
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)
143 self._pObj = pObj
144 self._arch = arch
145 self._tooltag = tooltag
146 self._macros = macros
147 self._onlyIncludeDocument = onlyInclude
148
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')
158 else:
159 self._arch = None
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')
165
166 for macro in self._macros:
167 self._configFile.AddPreDefined(macro)
168
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')
178
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')
185 else:
186 self._tooltag = None
187 self._configFile.AddPreDefined('_MSC_EXTENSIONS')
188 self._configFile.AddPreDefined('__GNUC__')
189 self._configFile.AddPreDefined('__INTEL_COMPILER')
190
191 self._configFile.AddPreDefined('ASM_PFX= ')
192 self._configFile.AddPreDefined('OPTIONAL= ')
193
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())
201
202 defSection = fObj.GetSectionByName('defines')[0]
203 baseSection = doxygen.Section('PackageBasicInformation', 'Package Basic Information')
204 descr = '<TABLE>'
205 for obj in defSection.GetObjects():
206 if obj.GetKey() in _dec_key_description_mapping_table.keys():
207 descr += '<TR>'
208 descr += '<TD><B>%s</B></TD>' % _dec_key_description_mapping_table[obj.GetKey()]
209 descr += '<TD>%s</TD>' % obj.GetValue()
210 descr += '</TR>'
211 descr += '</TABLE><br>'
212 baseSection.AddDescription(descr)
213 pdObj.AddSection(baseSection)
214
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)
220
221 self.AddAllIncludeFiles(self._pObj, self._configFile)
222 pages = self.GenerateIncludesSubPage(self._pObj, self._configFile)
223 if len(pages) != 0:
224 pdObj.AddPages(pages)
225 pages = self.GenerateLibraryClassesSubPage(self._pObj, self._configFile)
226 if len(pages) != 0:
227 pdObj.AddPages(pages)
228 pages = self.GeneratePcdSubPages(self._pObj, self._configFile)
229 if len(pages) != 0:
230 pdObj.AddPages(pages)
231 pages = self.GenerateGuidSubPages(self._pObj, self._configFile)
232 if len(pages) != 0:
233 pdObj.AddPages(pages)
234 pages = self.GeneratePpiSubPages(self._pObj, self._configFile)
235 if len(pages) != 0:
236 pdObj.AddPages(pages)
237 pages = self.GenerateProtocolSubPages(self._pObj, self._configFile)
238 if len(pages) != 0:
239 pdObj.AddPages(pages)
240 if not self._onlyIncludeDocument:
241 pdObj.AddPages(self.GenerateModulePages(self._pObj, self._configFile))
242
243 pdObj.Save()
244 return pdObj.GetFilename()
245
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'))
255
256 rootArray = []
257 pageRoot = doxygen.Page("Public Includes", "%s_public_includes" % pObj.GetName())
258 objs = pObj.GetFileObj().GetSectionObjectsByName('includes')
259 if len(objs) == 0: return []
260
261 for obj in objs:
262 # Add path to include path
263 path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetPath())
264 configFile.AddIncludePath(path)
265
266 # only list common folder's include file
267 if obj.GetArch().lower() != 'common':
268 continue
269
270 bNeedAddIncludePage = False
271 topPage = doxygen.Page(self._ConvertPathToDoxygen(path, pObj), 'public_include_top')
272
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))
280 else:
281 if file.lower() in ['library', 'protocol', 'guid', 'ppi', 'ia32', 'x64', 'ipf', 'ebc', 'arm', 'pi', 'uefi', 'aarch64']:
282 continue
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')
293 if bNeedAddSubPage:
294 bNeedAddIncludePage = True
295 pageRoot.AddPage(subpage)
296 topPage.AddDescription('</ul>\n')
297 if bNeedAddIncludePage:
298 pageRoot.AddPage(topPage)
299
300 if pageRoot.GetSubpageCount() != 0:
301 return [pageRoot]
302 else:
303 return []
304
305 def GenerateLibraryClassesSubPage(self, pObj, configFile):
306 """
307 Generate sub page for library class for package.
308 One DEC file maybe contains many library class sections
309 for different architecture.
310
311 @param fObj DEC file object.
312 """
313 rootArray = []
314 pageRoot = doxygen.Page("Library Class", "%s_libraryclass" % pObj.GetName())
315 objs = pObj.GetFileObj().GetSectionObjectsByName('libraryclass', self._arch)
316 if len(objs) == 0: return []
317
318 if self._arch is not None:
319 for obj in objs:
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)
336 else:
337 archPageDict = {}
338 for obj in objs:
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())
359
360 self.ProcessSourceFileForInclude(fullPath, pObj, configFile)
361 rootArray.append(pageRoot)
362 return rootArray
363
364 def ProcessSourceFileForInclude(self, path, pObj, configFile, infObj=None):
365 """
366 @param path the analysising file full path
367 @param pObj package object
368 @param configFile doxygen config file.
369 """
370
371 if gInGui:
372 wx.Yield()
373 if not os.path.exists(path):
374 ErrorMsg('Source file path %s does not exist!' % path)
375 return
376
377 if configFile.FileExists(path):
378 return
379
380 try:
381 f = open(path, 'r')
382 lines = f.readlines()
383 f.close()
384 except IOError:
385 ErrorMsg('Fail to open file %s' % path)
386 return
387
388 configFile.AddFile(path)
389 return
390 no = 0
391 for no in xrange(len(lines)):
392 if len(lines[no].strip()) == 0:
393 continue
394 if lines[no].strip()[:2] in ['##', '//', '/*', '*/']:
395 continue
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())
399 if not mo:
400 continue
401 mo = re.match(r"^[#\w\s]+[<\"]([\\/\w.]+)[>\"]$", lines[no].strip())
402 filePath = mo.groups()[0]
403
404 if filePath is None or len(filePath) == 0:
405 continue
406
407 # find header file in module's path firstly.
408 fullPath = None
409
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('\\', '/')
413 else:
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):
420 fullPath = incPath
421 break
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()))
426 if not decObj:
427 ErrorMsg ('Fail to create pacakge object for %s' % obj.GetPackageName())
428 continue
429 if not decObj.Parse():
430 ErrorMsg ('Fail to load package object for %s' % obj.GetPackageName())
431 continue
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))
437 break
438 if fullPath is not None:
439 break
440
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')
443 return
444 else:
445 fullPath = fullPath.replace('\\', '/')
446 if self.IsVerbose():
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)
450
451 def AddAllIncludeFiles(self, pObj, configFile):
452 objs = pObj.GetFileObj().GetSectionObjectsByName('includes')
453 for obj in objs:
454 incPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetPath())
455 for root, dirs, files in os.walk(incPath):
456 for dir in dirs:
457 if dir.lower() in _ignore_dir:
458 dirs.remove(dir)
459 for file in files:
460 path = os.path.normpath(os.path.join(root, file))
461 configFile.AddFile(path.replace('/', '\\'))
462
463 def GeneratePcdSubPages(self, pObj, configFile):
464 """
465 Generate sub pages for package's PCD definition.
466 @param pObj package object
467 @param configFile config file object
468 """
469 rootArray = []
470 objs = pObj.GetFileObj().GetSectionObjectsByName('pcd')
471 if len(objs) == 0:
472 return []
473
474 pcdRootPage = doxygen.Page('PCD', 'pcd_root_page')
475 typeRootPageDict = {}
476 typeArchRootPageDict = {}
477 for obj in objs:
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')
487 desc = '<TABLE>'
488 desc += '<TR>'
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>'
494 desc += '</TR>'
495 desc += '<TR>'
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()
501 desc += '</TR>'
502 desc += '</TABLE>'
503 section.AddDescription(desc)
504 pcdPage.AddSection(section)
505 typeRoot.AddPage(pcdPage)
506 else:
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')
517 desc = '<TABLE>'
518 desc += '<TR>'
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>'
524 desc += '</TR>'
525 desc += '<TR>'
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()
531 desc += '</TR>'
532 desc += '</TABLE>'
533 section.AddDescription(desc)
534 pcdPage.AddSection(section)
535 typeArchRoot.AddPage(pcdPage)
536 return [pcdRootPage]
537
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')
545 desc = '<TABLE>'
546 desc += '<TR>'
547 desc += '<TD><CAPTION>GUID\'s Guid Name</CAPTION></TD><TD><CAPTION>GUID\'s Guid</CAPTION></TD>'
548 desc += '</TR>'
549 desc += '<TR>'
550 desc += '<TD>%s</TD>' % obj.GetName()
551 desc += '<TD>%s</TD>' % obj.GetGuid()
552 desc += '</TR>'
553 desc += '</TABLE>'
554 section.AddDescription(desc)
555 guidPage.AddSection(section)
556 refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile)
557 if refFile:
558 relPath = refFile[len(pObj.GetWorkspace()) + 1:]
559 if len(comments) == 0:
560 guidPage.AddDescription(' \\copydoc %s <br>' % relPath)
561
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)
567 return guidPage
568
569 def GenerateGuidSubPages(self, pObj, configFile):
570 """
571 Generate sub pages for package's GUID definition.
572 @param pObj package object
573 @param configFilf doxygen config file object
574 """
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:
579 for obj in objs:
580 pageRoot.AddPage(self._GenerateGuidSubPage(pObj, obj, configFile))
581 else:
582 guidArchRootPageDict = {}
583 for obj in objs:
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))
590 return [pageRoot]
591
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')
598 desc = '<TABLE>'
599 desc += '<TR>'
600 desc += '<TD><CAPTION>PPI\'s Guid Name</CAPTION></TD><TD><CAPTION>PPI\'s Guid</CAPTION></TD>'
601 desc += '</TR>'
602 desc += '<TR>'
603 desc += '<TD>%s</TD>' % obj.GetName()
604 desc += '<TD>%s</TD>' % obj.GetGuid()
605 desc += '</TR>'
606 desc += '</TABLE>'
607 section.AddDescription(desc)
608 guidPage.AddSection(section)
609 refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile)
610 if refFile:
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)
619
620 return guidPage
621
622 def GeneratePpiSubPages(self, pObj, configFile):
623 """
624 Generate sub pages for package's GUID definition.
625 @param pObj package object
626 @param configFilf doxygen config file object
627 """
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:
632 for obj in objs:
633 pageRoot.AddPage(self._GeneratePpiSubPage(pObj, obj, configFile))
634 else:
635 guidArchRootPageDict = {}
636 for obj in objs:
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))
643 return [pageRoot]
644
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')
651 desc = '<TABLE>'
652 desc += '<TR>'
653 desc += '<TD><CAPTION>PROTOCOL\'s Guid Name</CAPTION></TD><TD><CAPTION>PROTOCOL\'s Guid</CAPTION></TD>'
654 desc += '</TR>'
655 desc += '<TR>'
656 desc += '<TD>%s</TD>' % obj.GetName()
657 desc += '<TD>%s</TD>' % obj.GetGuid()
658 desc += '</TR>'
659 desc += '</TABLE>'
660 section.AddDescription(desc)
661 guidPage.AddSection(section)
662
663 refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile)
664 if refFile:
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)
673
674 return guidPage
675
676 def GenerateProtocolSubPages(self, pObj, configFile):
677 """
678 Generate sub pages for package's GUID definition.
679 @param pObj package object
680 @param configFilf doxygen config file object
681 """
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:
686 for obj in objs:
687 pageRoot.AddPage(self._GenerateProtocolSubPage(pObj, obj, configFile))
688 else:
689 guidArchRootPageDict = {}
690 for obj in objs:
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))
697 return [pageRoot]
698
699 def FindHeaderFileForGuid(self, pObj, name, configFile):
700 """
701 For declaration header file for GUID/PPI/Protocol.
702
703 @param pObj package object
704 @param name guid/ppi/protocol's name
705 @param configFile config file object
706
707 @return full path of header file and None if not found.
708 """
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):
713 startPath = incPath
714
715 for root, dirs, files in os.walk(startPath):
716 for dir in dirs:
717 if dir.lower() in _ignore_dir:
718 dirs.remove(dir)
719 for file in files:
720 fPath = os.path.join(root, file)
721 if not IsCHeaderFile(fPath):
722 continue
723 try:
724 f = open(fPath, 'r')
725 lines = f.readlines()
726 f.close()
727 except IOError:
728 self.Log('Fail to open file %s\n' % fPath)
729 continue
730 for line in lines:
731 if line.find(name) != -1 and \
732 line.find('extern') != -1:
733 return fPath.replace('\\', '/')
734 return None
735
736 def GetPackageModuleList(self, pObj):
737 """
738 Get all module's INF path under package's root path
739 @param pObj package object
740 @return arrary of INF full path
741 """
742 mArray = []
743 packPath = pObj.GetFileObj().GetPackageRootPath()
744 if not os.path.exists:
745 return None
746 for root, dirs, files in os.walk(packPath):
747 for dir in dirs:
748 if dir.lower() in _ignore_dir:
749 dirs.remove(dir)
750 for file in files:
751 if CheckPathPostfix(file, 'inf'):
752 fPath = os.path.join(root, file).replace('\\', '/')
753 mArray.append(fPath)
754 return mArray
755
756 def GenerateModulePages(self, pObj, configFile):
757 """
758 Generate sub pages for package's module which is under the package
759 root directory.
760
761 @param pObj package object
762 @param configFilf doxygen config file object
763 """
764 infList = self.GetPackageModuleList(pObj)
765 rootPages = []
766 libObjs = []
767 modObjs = []
768 for infpath in infList:
769 infObj = inf.INFFile(infpath)
770 #infObj = INFFileObject.INFFile (pObj.GetWorkspacePath(),
771 # inf)
772 if not infObj:
773 self.Log('Fail create INF object for %s' % inf)
774 continue
775 if not infObj.Parse():
776 self.Log('Fail to load INF file %s' % inf)
777 continue
778 if infObj.GetProduceLibraryClass() is not None:
779 libObjs.append(infObj)
780 else:
781 modObjs.append(infObj)
782
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))
788
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))
794
795 return rootPages
796
797 def GenerateModulePage(self, pObj, infObj, configFile, isLib):
798 """
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
803
804 @param module doxygen page object
805 """
806 workspace = pObj.GetWorkspace()
807 refDecObjs = []
808 for obj in infObj.GetSectionObjectsByName('packages'):
809 decObj = dec.DECFile(os.path.join(workspace, obj.GetPath()))
810 if not decObj:
811 ErrorMsg ('Fail to create pacakge object for %s' % obj.GetPackageName())
812 continue
813 if not decObj.Parse():
814 ErrorMsg ('Fail to load package object for %s' % obj.GetPackageName())
815 continue
816 refDecObjs.append(decObj)
817
818 modPage = doxygen.Page('%s' % infObj.GetBaseName(),
819 'module_%s' % infObj.GetBaseName())
820 modPage.AddDescription(infObj.GetFileHeader())
821
822 basicInfSection = doxygen.Section('BasicModuleInformation', 'Basic Module Information')
823 desc = "<TABLE>"
824 for obj in infObj.GetSectionObjectsByName('defines'):
825 key = obj.GetKey()
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('|')
830 desc += '<TR>'
831 desc += '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table[key]
832 desc += '<TD>%s</TD>' % clsname
833 desc += '</TR>'
834
835 desc += '<TR>'
836 desc += '<TD><B>Supported Module Types</B></TD>'
837 desc += '<TD>%s</TD>' % types
838 desc += '</TR>'
839 else:
840 desc += '<TR>'
841 desc += '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table[key]
842 if key == 'EFI_SPECIFICATION_VERSION' and value == '0x00020000':
843 value = '2.0'
844 desc += '<TD>%s</TD>' % value
845 desc += '</TR>'
846 desc += '</TABLE>'
847 basicInfSection.AddDescription(desc)
848 modPage.AddSection(basicInfSection)
849
850 # Add protocol section
851 data = []
852 for obj in infObj.GetSectionObjectsByName('pcd', self._arch):
853 data.append(obj.GetPcdName().strip())
854 if len(data) != 0:
855 s = doxygen.Section('Pcds', 'Pcds')
856 desc = "<TABLE>"
857 desc += '<TR><TD><B>PCD Name</B></TD><TD><B>TokenSpace</B></TD><TD><B>Package</B></TD></TR>'
858 for item in data:
859 desc += '<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
864 desc += '</TR>'
865 desc += "</TABLE>"
866 s.AddDescription(desc)
867 modPage.AddSection(s)
868
869 # Add protocol section
870 #sects = infObj.GetSectionByString('protocol')
871 data = []
872 #for sect in sects:
873 for obj in infObj.GetSectionObjectsByName('protocol', self._arch):
874 data.append(obj.GetName().strip())
875 if len(data) != 0:
876 s = doxygen.Section('Protocols', 'Protocols')
877 desc = "<TABLE>"
878 desc += '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
879 for item in data:
880 desc += '<TR>'
881 desc += '<TD>%s</TD>' % item
882 pkgbasename = self.SearchProtocolPackage(item, workspace, refDecObjs)
883 desc += '<TD>%s</TD>' % pkgbasename
884 desc += '</TR>'
885 desc += "</TABLE>"
886 s.AddDescription(desc)
887 modPage.AddSection(s)
888
889 # Add ppi section
890 #sects = infObj.GetSectionByString('ppi')
891 data = []
892 #for sect in sects:
893 for obj in infObj.GetSectionObjectsByName('ppi', self._arch):
894 data.append(obj.GetName().strip())
895 if len(data) != 0:
896 s = doxygen.Section('Ppis', 'Ppis')
897 desc = "<TABLE>"
898 desc += '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
899 for item in data:
900 desc += '<TR>'
901 desc += '<TD>%s</TD>' % item
902 pkgbasename = self.SearchPpiPackage(item, workspace, refDecObjs)
903 desc += '<TD>%s</TD>' % pkgbasename
904 desc += '</TR>'
905 desc += "</TABLE>"
906 s.AddDescription(desc)
907 modPage.AddSection(s)
908
909 # Add guid section
910 #sects = infObj.GetSectionByString('guid')
911 data = []
912 #for sect in sects:
913 for obj in infObj.GetSectionObjectsByName('guid', self._arch):
914 data.append(obj.GetName().strip())
915 if len(data) != 0:
916 s = doxygen.Section('Guids', 'Guids')
917 desc = "<TABLE>"
918 desc += '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
919 for item in data:
920 desc += '<TR>'
921 desc += '<TD>%s</TD>' % item
922 pkgbasename = self.SearchGuidPackage(item, workspace, refDecObjs)
923 desc += '<TD>%s</TD>' % pkgbasename
924 desc += '</TR>'
925 desc += "</TABLE>"
926 s.AddDescription(desc)
927 modPage.AddSection(s)
928
929 section = doxygen.Section('LibraryClasses', 'Library Classes')
930 desc = "<TABLE>"
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>'
932 if isLib:
933 desc += '<TR>'
934 desc += '<TD>%s</TD>' % infObj.GetProduceLibraryClass()
935 desc += '<TD>Produce</TD>'
936 try:
937 pkgname, hPath = self.SearchLibraryClassHeaderFile(infObj.GetProduceLibraryClass(),
938 workspace,
939 refDecObjs)
940 except:
941 self.Log ('fail to get package header file for lib class %s' % infObj.GetProduceLibraryClass())
942 pkgname = 'NULL'
943 hPath = 'NULL'
944 desc += '<TD>%s</TD>' % pkgname
945 if hPath != "NULL":
946 #desc += '<TD>\link %s \endlink</TD>' % hPath
947 desc += '<TD>%s</TD>' % hPath
948 else:
949 desc += '<TD>%s</TD>' % hPath
950 desc += '</TR>'
951 for lcObj in infObj.GetSectionObjectsByName('libraryclasses', self._arch):
952 desc += '<TR>'
953 desc += '<TD>%s</TD>' % lcObj.GetClass()
954 retarr = self.SearchLibraryClassHeaderFile(lcObj.GetClass(),
955 workspace,
956 refDecObjs)
957 if retarr is not None:
958 pkgname, hPath = retarr
959 else:
960 self.Log('Fail find the library class %s definition from module %s dependent package!' % (lcObj.GetClass(), infObj.GetFilename()), 'error')
961 pkgname = 'NULL'
962 hPath = 'NULL'
963 desc += '<TD>Consume</TD>'
964 desc += '<TD>%s</TD>' % pkgname
965 desc += '<TD>%s</TD>' % hPath
966 desc += '</TR>'
967 desc += "</TABLE>"
968 section.AddDescription(desc)
969 modPage.AddSection(section)
970
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)
981 else:
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)
987
988 #sects = infObj.GetSectionByString('depex')
989 data = []
990 #for sect in sects:
991 for obj in infObj.GetSectionObjectsByName('depex'):
992 data.append(str(obj))
993 if len(data) != 0:
994 s = doxygen.Section('DependentSection', 'Module Dependencies')
995 s.AddDescription('<br>'.join(data))
996 modPage.AddSection(s)
997
998 return modPage
999
1000 def TranslateUniFile(self, path):
1001 newpath = path + '.dox'
1002 #import core.textfile as textfile
1003 #file = textfile.TextFile(path)
1004
1005 try:
1006 file = open(path, 'rb')
1007 except (IOError, OSError) as msg:
1008 return None
1009
1010 t = file.read()
1011 file.close()
1012
1013 output = '/** @file \n'
1014 #output = '<html><body>'
1015 arr = t.split('\r\n')
1016 for line in arr:
1017 if line.find('@file') != -1:
1018 continue
1019 if line.find('*/') != -1:
1020 continue
1021 line = line.strip()
1022 if line.strip().startswith('/'):
1023 arr = line.split(' ')
1024 if len(arr) > 1:
1025 line = ' '.join(arr[1:])
1026 else:
1027 continue
1028 output += '%s<br>\n' % line
1029 output += '**/'
1030
1031 if os.path.exists(newpath):
1032 os.remove(newpath)
1033
1034 file = open(newpath, "w")
1035 file.write(output)
1036 file.close()
1037 return newpath
1038
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()
1044 return None
1045
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()
1051 return None
1052
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()
1058 return None
1059
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()
1065 return None
1066
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('\\', '/')
1075
1076 return None
1077
1078 def _ConvertPathToDoxygen(self, path, pObj):
1079 pRootPath = pObj.GetWorkspace()
1080 path = path[len(pRootPath) + 1:]
1081 return path.replace('\\', '/')
1082
1083 def IsCHeaderFile(path):
1084 return CheckPathPostfix(path, 'h')
1085
1086 def CheckPathPostfix(path, str):
1087 index = path.rfind('.')
1088 if index == -1:
1089 return False
1090 if path[index + 1:].lower() == str.lower():
1091 return True
1092 return False