diff options
Diffstat (limited to 'BaseTools/Scripts/PackageDocumentTools')
20 files changed, 7069 insertions, 7069 deletions
diff --git a/BaseTools/Scripts/PackageDocumentTools/Readme.md b/BaseTools/Scripts/PackageDocumentTools/Readme.md index dfc2892c41..4f7de7d2c8 100644 --- a/BaseTools/Scripts/PackageDocumentTools/Readme.md +++ b/BaseTools/Scripts/PackageDocumentTools/Readme.md @@ -1,19 +1,19 @@ -Prerequisite Tools:
-1. Install Python 2.7.3 from https://www.python.org/download/releases/2.7.3/
-2. Install wxPython 2.8.12.1 from https://sourceforge.net/projects/wxpython/files/wxPython/2.8.12.1/
- generally the libraries will be installed at python's subfolder, for example in windows: c:\python27\Lib\site-packages\
-3. Install DoxyGen 1.8.6 from https://sourceforge.net/projects/doxygen/files/rel-1.8.6/
-4. (Windows only) Install Htmlhelp tool from https://msdn.microsoft.com/en-us/library/windows/desktop/ms669985(v=vs.85).aspx
-
-Limitation:
-1. Current tool doesn't work on latest wxPython and DoxyGen tool. Please use the sepecific version in above.
-
-Run the Tool:
-a) Run with GUI:
- 1. Enter src folder, double click "packagedocapp.pyw" or run command "python packagedocapp.pyw" to open the GUI.
- 2. Make sure all the information in blank are correct.
- 3. Click "Generate Package Document!"
-b) Run with command line:
- 1. Open command line window
- 2. Enter src folder, for example: "cd C:\PackageDocumentTools\src"
- 3. Run "python packagedoc_cli.py --help" for detail command.
+Prerequisite Tools: +1. Install Python 2.7.3 from https://www.python.org/download/releases/2.7.3/ +2. Install wxPython 2.8.12.1 from https://sourceforge.net/projects/wxpython/files/wxPython/2.8.12.1/ + generally the libraries will be installed at python's subfolder, for example in windows: c:\python27\Lib\site-packages\ +3. Install DoxyGen 1.8.6 from https://sourceforge.net/projects/doxygen/files/rel-1.8.6/ +4. (Windows only) Install Htmlhelp tool from https://msdn.microsoft.com/en-us/library/windows/desktop/ms669985(v=vs.85).aspx + +Limitation: +1. Current tool doesn't work on latest wxPython and DoxyGen tool. Please use the sepecific version in above. + +Run the Tool: +a) Run with GUI: + 1. Enter src folder, double click "packagedocapp.pyw" or run command "python packagedocapp.pyw" to open the GUI. + 2. Make sure all the information in blank are correct. + 3. Click "Generate Package Document!" +b) Run with command line: + 1. Open command line window + 2. Enter src folder, for example: "cd C:\PackageDocumentTools\src" + 3. Run "python packagedoc_cli.py --help" for detail command. diff --git a/BaseTools/Scripts/PackageDocumentTools/__init__.py b/BaseTools/Scripts/PackageDocumentTools/__init__.py index 57dfebde59..a7909346f3 100644 --- a/BaseTools/Scripts/PackageDocumentTools/__init__.py +++ b/BaseTools/Scripts/PackageDocumentTools/__init__.py @@ -1,6 +1,6 @@ -## @file
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
+## @file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# diff --git a/BaseTools/Scripts/PackageDocumentTools/packagedoc_cli.py b/BaseTools/Scripts/PackageDocumentTools/packagedoc_cli.py index eb3164a553..7e7dc1c8eb 100644 --- a/BaseTools/Scripts/PackageDocumentTools/packagedoc_cli.py +++ b/BaseTools/Scripts/PackageDocumentTools/packagedoc_cli.py @@ -1,424 +1,424 @@ -## @file
-# This module provide command line entry for generating package document!
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-
-from __future__ import print_function
-import os, sys, logging, traceback, subprocess
-from optparse import OptionParser
-
-from plugins.EdkPlugins.edk2.model import baseobject
-from plugins.EdkPlugins.edk2.model import doxygengen
-
-gArchMarcoDict = {'ALL' : 'MDE_CPU_IA32 MDE_CPU_X64 MDE_CPU_EBC MDE_CPU_IPF _MSC_EXTENSIONS __GNUC__ __INTEL_COMPILER',
- 'IA32_MSFT': 'MDE_CPU_IA32 _MSC_EXTENSIONS',
- 'IA32_GNU' : 'MDE_CPU_IA32 __GNUC__',
- 'X64_MSFT' : 'MDE_CPU_X64 _MSC_EXTENSIONS ASM_PFX= OPTIONAL= ',
- 'X64_GNU' : 'MDE_CPU_X64 __GNUC__ ASM_PFX= OPTIONAL= ',
- 'IPF_MSFT' : 'MDE_CPU_IPF _MSC_EXTENSIONS ASM_PFX= OPTIONAL= ',
- 'IPF_GNU' : 'MDE_CPU_IPF __GNUC__ ASM_PFX= OPTIONAL= ',
- 'EBC_INTEL': 'MDE_CPU_EBC __INTEL_COMPILER ASM_PFX= OPTIONAL= '}
-
-def parseCmdArgs():
- parser = OptionParser(version="Package Document Generation Tools - Version 0.1")
- parser.add_option('-w', '--workspace', action='store', type='string', dest='WorkspacePath',
- help='Specify workspace absolute path. For example: c:\\tianocore')
- parser.add_option('-p', '--decfile', action='store', dest='PackagePath',
- help='Specify the absolute path for package DEC file. For example: c:\\tianocore\\MdePkg\\MdePkg.dec')
- parser.add_option('-x', '--doxygen', action='store', dest='DoxygenPath',
- help='Specify the absolute path of doxygen tools installation. For example: C:\\Program Files\\doxygen\bin\doxygen.exe')
- parser.add_option('-o', '--output', action='store', dest='OutputPath',
- help='Specify the document output path. For example: c:\\docoutput')
- parser.add_option('-a', '--arch', action='store', dest='Arch', choices=list(gArchMarcoDict.keys()),
- help='Specify the architecture used in preprocess package\'s source. For example: -a IA32_MSFT')
- parser.add_option('-m', '--mode', action='store', dest='DocumentMode', choices=['CHM', 'HTML'],
- help='Specify the document mode from : CHM or HTML')
- parser.add_option('-i', '--includeonly', action='store_true', dest='IncludeOnly',
- help='Only generate document for package\'s public interfaces produced by include folder. ')
- parser.add_option('-c', '--htmlworkshop', dest='HtmlWorkshopPath',
- help='Specify the absolute path for Microsoft HTML Workshop\'s hhc.exe file. For example: C:\\Program Files\\HTML Help Workshop\\hhc.exe')
- (options, args) = parser.parse_args()
-
- # validate the options
- errors = []
- if options.WorkspacePath is None:
- errors.append('- Please specify workspace path via option -w!')
- elif not os.path.exists(options.WorkspacePath):
- errors.append("- Invalid workspace path %s! The workspace path should be exist in absolute path!" % options.WorkspacePath)
-
- if options.PackagePath is None:
- errors.append('- Please specify package DEC file path via option -p!')
- elif not os.path.exists(options.PackagePath):
- errors.append("- Invalid package's DEC file path %s! The DEC path should be exist in absolute path!" % options.PackagePath)
-
- default = "C:\\Program Files\\doxygen\\bin\\doxygen.exe"
- if options.DoxygenPath is None:
- if os.path.exists(default):
- print("Warning: Assume doxygen tool is installed at %s. If not, please specify via -x" % default)
- options.DoxygenPath = default
- else:
- errors.append('- Please specify the path of doxygen tool installation via option -x! or install it in default path %s' % default)
- elif not os.path.exists(options.DoxygenPath):
- errors.append("- Invalid doxygen tool path %s! The doxygen tool path should be exist in absolute path!" % options.DoxygenPath)
-
- if options.OutputPath is not None:
- if not os.path.exists(options.OutputPath):
- # create output
- try:
- os.makedirs(options.OutputPath)
- except:
- errors.append('- Fail to create the output directory %s' % options.OutputPath)
- else:
- if options.PackagePath is not None and os.path.exists(options.PackagePath):
- dirpath = os.path.dirname(options.PackagePath)
- default = os.path.join (dirpath, "Document")
- print('Warning: Assume document output at %s. If not, please specify via option -o' % default)
- options.OutputPath = default
- if not os.path.exists(default):
- try:
- os.makedirs(default)
- except:
- errors.append('- Fail to create default output directory %s! Please specify document output diretory via option -o' % default)
- else:
- errors.append('- Please specify document output path via option -o!')
-
- if options.Arch is None:
- options.Arch = 'ALL'
- print("Warning: Assume arch is \"ALL\". If not, specify via -a")
-
- if options.DocumentMode is None:
- options.DocumentMode = "HTML"
- print("Warning: Assume document mode is \"HTML\". If not, specify via -m")
-
- if options.IncludeOnly is None:
- options.IncludeOnly = False
- print("Warning: Assume generate package document for all package\'s source including publich interfaces and implementation libraries and modules.")
-
- if options.DocumentMode.lower() == 'chm':
- default = "C:\\Program Files\\HTML Help Workshop\\hhc.exe"
- if options.HtmlWorkshopPath is None:
- if os.path.exists(default):
- print('Warning: Assume the installation path of Microsoft HTML Workshop is %s. If not, specify via option -c.' % default)
- options.HtmlWorkshopPath = default
- else:
- errors.append('- Please specify the installation path of Microsoft HTML Workshop via option -c!')
- elif not os.path.exists(options.HtmlWorkshopPath):
- errors.append('- The installation path of Microsoft HTML Workshop %s does not exists. ' % options.HtmlWorkshopPath)
-
- if len(errors) != 0:
- print('\n')
- parser.error('Fail to start due to following reasons: \n%s' %'\n'.join(errors))
- return (options.WorkspacePath, options.PackagePath, options.DoxygenPath, options.OutputPath,
- options.Arch, options.DocumentMode, options.IncludeOnly, options.HtmlWorkshopPath)
-
-def createPackageObject(wsPath, pkgPath):
- try:
- pkgObj = baseobject.Package(None, wsPath)
- pkgObj.Load(pkgPath)
- except:
- logging.getLogger().error ('Fail to create package object!')
- return None
-
- return pkgObj
-
-def callbackLogMessage(msg, level):
- print(msg.strip())
-
-def callbackCreateDoxygenProcess(doxPath, configPath):
- if sys.platform == 'win32':
- cmd = '"%s" %s' % (doxPath, configPath)
- else:
- cmd = '%s %s' % (doxPath, configPath)
- print(cmd)
- subprocess.call(cmd, shell=True)
-
-
-def DocumentFixup(outPath, arch):
- # find BASE_LIBRARY_JUMP_BUFFER structure reference page
-
- print('\n >>> Start fixup document \n')
-
- for root, dirs, files in os.walk(outPath):
- for dir in dirs:
- if dir.lower() in ['.svn', '_svn', 'cvs']:
- dirs.remove(dir)
- for file in files:
- if not file.lower().endswith('.html'): continue
- fullpath = os.path.join(outPath, root, file)
- try:
- f = open(fullpath, 'r')
- text = f.read()
- f.close()
- except:
- logging.getLogger().error('\nFail to open file %s\n' % fullpath)
- continue
- if arch.lower() == 'all':
- if text.find('BASE_LIBRARY_JUMP_BUFFER Struct Reference') != -1:
- FixPageBASE_LIBRARY_JUMP_BUFFER(fullpath, text)
- if text.find('MdePkg/Include/Library/BaseLib.h File Reference') != -1:
- FixPageBaseLib(fullpath, text)
- if text.find('IA32_IDT_GATE_DESCRIPTOR Union Reference') != -1:
- FixPageIA32_IDT_GATE_DESCRIPTOR(fullpath, text)
- if text.find('MdePkg/Include/Library/UefiDriverEntryPoint.h File Reference') != -1:
- FixPageUefiDriverEntryPoint(fullpath, text)
- if text.find('MdePkg/Include/Library/UefiApplicationEntryPoint.h File Reference') != -1:
- FixPageUefiApplicationEntryPoint(fullpath, text)
-
- print(' >>> Finish all document fixing up! \n')
-
-def FixPageBaseLib(path, text):
- print(' >>> Fixup BaseLib file page at file %s \n' % path)
- lines = text.split('\n')
- lastBaseJumpIndex = -1
- lastIdtGateDescriptor = -1
- for index in range(len(lines) - 1, -1, -1):
- line = lines[index]
- if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 4 </td>':
- lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 4 [IA32] </td>'
- if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 0x10 </td>':
- lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 0x10 [IPF] </td>'
- if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 8 </td>':
- lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 9 [EBC, x64] </td>'
- if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 4') != -1:
- lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 4',
- 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 4 [IA32]')
- if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 0x10') != -1:
- lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 0x10',
- 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 0x10 [IPF]')
- if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 8') != -1:
- lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 8',
- 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 8 [x64, EBC]')
- if line.find('>BASE_LIBRARY_JUMP_BUFFER</a>') != -1:
- if lastBaseJumpIndex != -1:
- del lines[lastBaseJumpIndex]
- lastBaseJumpIndex = index
- if line.find('>IA32_IDT_GATE_DESCRIPTOR</a></td>') != -1:
- if lastIdtGateDescriptor != -1:
- del lines[lastIdtGateDescriptor]
- lastIdtGateDescriptor = index
- try:
- f = open(path, 'w')
- f.write('\n'.join(lines))
- f.close()
- except:
- logging.getLogger().error(" <<< Fail to fixup file %s\n" % path)
- return
- print(" <<< Finish to fixup file %s\n" % path)
-
-def FixPageIA32_IDT_GATE_DESCRIPTOR(path, text):
- print(' >>> Fixup structure reference IA32_IDT_GATE_DESCRIPTOR at file %s \n' % path)
- lines = text.split('\n')
- for index in range(len(lines) - 1, -1, -1):
- line = lines[index].strip()
- if line.find('struct {</td>') != -1 and lines[index - 2].find('>Uint64</a></td>') != -1:
- lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>')
- if line.find('struct {</td>') != -1 and lines[index - 1].find('Data Fields') != -1:
- lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>')
- try:
- f = open(path, 'w')
- f.write('\n'.join(lines))
- f.close()
- except:
- logging.getLogger().error(" <<< Fail to fixup file %s\n" % path)
- return
- print(" <<< Finish to fixup file %s\n" % path)
-
-def FixPageBASE_LIBRARY_JUMP_BUFFER(path, text):
- print(' >>> Fixup structure reference BASE_LIBRARY_JUMP_BUFFER at file %s \n' % path)
- lines = text.split('\n')
- bInDetail = True
- bNeedRemove = False
- for index in range(len(lines) - 1, -1, -1):
- line = lines[index]
- if line.find('Detailed Description') != -1:
- bInDetail = False
- if line.startswith('EBC context buffer used by') and lines[index - 1].startswith('x64 context buffer'):
- lines[index] = "IA32/IPF/X64/" + line
- bNeedRemove = True
- if line.startswith("x64 context buffer") or line.startswith('IPF context buffer used by') or \
- line.startswith('IA32 context buffer used by'):
- if bNeedRemove:
- lines.remove(line)
- if line.find('>R0</a>') != -1 and not bInDetail:
- if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For EBC</h2></td></tr>':
- lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For EBC</h2></td></tr>')
- if line.find('>Rbx</a>') != -1 and not bInDetail:
- if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>':
- lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>')
- if line.find('>F2</a>') != -1 and not bInDetail:
- if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For IPF</h2></td></tr>':
- lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IPF</h2></td></tr>')
- if line.find('>Ebx</a>') != -1 and not bInDetail:
- if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>':
- lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>')
- try:
- f = open(path, 'w')
- f.write('\n'.join(lines))
- f.close()
- except:
- logging.getLogger().error(" <<< Fail to fixup file %s" % path)
- return
- print(" <<< Finish to fixup file %s\n" % path)
-
-def FixPageUefiDriverEntryPoint(path, text):
- print(' >>> Fixup file reference MdePkg/Include/Library/UefiDriverEntryPoint.h at file %s \n' % path)
- lines = text.split('\n')
- bInModuleEntry = False
- bInEfiMain = False
- ModuleEntryDlCount = 0
- ModuleEntryDelStart = 0
- ModuleEntryDelEnd = 0
- EfiMainDlCount = 0
- EfiMainDelStart = 0
- EfiMainDelEnd = 0
-
- for index in range(len(lines)):
- line = lines[index].strip()
- if line.find('EFI_STATUS</a> EFIAPI _ModuleEntryPoint </td>') != -1:
- bInModuleEntry = True
- if line.find('EFI_STATUS</a> EFIAPI EfiMain </td>') != -1:
- bInEfiMain = True
- if line.startswith('<p>References <a'):
- if bInModuleEntry:
- ModuleEntryDelEnd = index - 1
- bInModuleEntry = False
- elif bInEfiMain:
- EfiMainDelEnd = index - 1
- bInEfiMain = False
- if bInModuleEntry:
- if line.startswith('</dl>'):
- ModuleEntryDlCount = ModuleEntryDlCount + 1
- if ModuleEntryDlCount == 1:
- ModuleEntryDelStart = index + 1
- if bInEfiMain:
- if line.startswith('</dl>'):
- EfiMainDlCount = EfiMainDlCount + 1
- if EfiMainDlCount == 1:
- EfiMainDelStart = index + 1
-
- if EfiMainDelEnd > EfiMainDelStart:
- for index in range(EfiMainDelEnd, EfiMainDelStart, -1):
- del lines[index]
- if ModuleEntryDelEnd > ModuleEntryDelStart:
- for index in range(ModuleEntryDelEnd, ModuleEntryDelStart, -1):
- del lines[index]
-
- try:
- f = open(path, 'w')
- f.write('\n'.join(lines))
- f.close()
- except:
- logging.getLogger().error(" <<< Fail to fixup file %s" % path)
- return
- print(" <<< Finish to fixup file %s\n" % path)
-
-
-def FixPageUefiApplicationEntryPoint(path, text):
- print(' >>> Fixup file reference MdePkg/Include/Library/UefiApplicationEntryPoint.h at file %s \n' % path)
- lines = text.split('\n')
- bInModuleEntry = False
- bInEfiMain = False
- ModuleEntryDlCount = 0
- ModuleEntryDelStart = 0
- ModuleEntryDelEnd = 0
- EfiMainDlCount = 0
- EfiMainDelStart = 0
- EfiMainDelEnd = 0
-
- for index in range(len(lines)):
- line = lines[index].strip()
- if line.find('EFI_STATUS</a> EFIAPI _ModuleEntryPoint </td>') != -1:
- bInModuleEntry = True
- if line.find('EFI_STATUS</a> EFIAPI EfiMain </td>') != -1:
- bInEfiMain = True
- if line.startswith('<p>References <a'):
- if bInModuleEntry:
- ModuleEntryDelEnd = index - 1
- bInModuleEntry = False
- elif bInEfiMain:
- EfiMainDelEnd = index - 1
- bInEfiMain = False
- if bInModuleEntry:
- if line.startswith('</dl>'):
- ModuleEntryDlCount = ModuleEntryDlCount + 1
- if ModuleEntryDlCount == 1:
- ModuleEntryDelStart = index + 1
- if bInEfiMain:
- if line.startswith('</dl>'):
- EfiMainDlCount = EfiMainDlCount + 1
- if EfiMainDlCount == 1:
- EfiMainDelStart = index + 1
-
- if EfiMainDelEnd > EfiMainDelStart:
- for index in range(EfiMainDelEnd, EfiMainDelStart, -1):
- del lines[index]
- if ModuleEntryDelEnd > ModuleEntryDelStart:
- for index in range(ModuleEntryDelEnd, ModuleEntryDelStart, -1):
- del lines[index]
-
- try:
- f = open(path, 'w')
- f.write('\n'.join(lines))
- f.close()
- except:
- logging.getLogger().error(" <<< Fail to fixup file %s" % path)
- return
- print(" <<< Finish to fixup file %s\n" % path)
-
-if __name__ == '__main__':
- wspath, pkgpath, doxpath, outpath, archtag, docmode, isinc, hwpath = parseCmdArgs()
-
- # configure logging system
- logfilepath = os.path.join(outpath, 'log.txt')
- logging.basicConfig(format='%(levelname)-8s %(message)s', level=logging.DEBUG)
-
- # create package model object firstly
- pkgObj = createPackageObject(wspath, pkgpath)
- if pkgObj is None:
- sys.exit(-1)
-
- # create doxygen action model
- arch = None
- tooltag = None
- if archtag.lower() != 'all':
- arch = archtag.split('_')[0]
- tooltag = archtag.split('_')[1]
- else:
- arch = 'all'
- tooltag = 'all'
-
- # preprocess package and call doxygen
- try:
- action = doxygengen.PackageDocumentAction(doxpath,
- hwpath,
- outpath,
- pkgObj,
- docmode,
- callbackLogMessage,
- arch,
- tooltag,
- isinc,
- True)
- action.RegisterCallbackDoxygenProcess(callbackCreateDoxygenProcess)
- action.Generate()
- except:
- message = traceback.format_exception(*sys.exc_info())
- logging.getLogger().error('Fail to create doxygen action! \n%s' % ''.join(message))
- sys.exit(-1)
-
- DocumentFixup(outpath, arch)
-
- # generate CHM is necessary
- if docmode.lower() == 'chm':
- indexpath = os.path.join(outpath, 'html', 'index.hhp')
- if sys.platform == 'win32':
- cmd = '"%s" %s' % (hwpath, indexpath)
- else:
- cmd = '%s %s' % (hwpath, indexpath)
- subprocess.call(cmd)
- print('\nFinish to generate package document! Please open %s for review' % os.path.join(outpath, 'html', 'index.chm'))
- else:
- print('\nFinish to generate package document! Please open %s for review' % os.path.join(outpath, 'html', 'index.html'))
+## @file +# This module provide command line entry for generating package document! +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +from __future__ import print_function +import os, sys, logging, traceback, subprocess +from optparse import OptionParser + +from plugins.EdkPlugins.edk2.model import baseobject +from plugins.EdkPlugins.edk2.model import doxygengen + +gArchMarcoDict = {'ALL' : 'MDE_CPU_IA32 MDE_CPU_X64 MDE_CPU_EBC MDE_CPU_IPF _MSC_EXTENSIONS __GNUC__ __INTEL_COMPILER', + 'IA32_MSFT': 'MDE_CPU_IA32 _MSC_EXTENSIONS', + 'IA32_GNU' : 'MDE_CPU_IA32 __GNUC__', + 'X64_MSFT' : 'MDE_CPU_X64 _MSC_EXTENSIONS ASM_PFX= OPTIONAL= ', + 'X64_GNU' : 'MDE_CPU_X64 __GNUC__ ASM_PFX= OPTIONAL= ', + 'IPF_MSFT' : 'MDE_CPU_IPF _MSC_EXTENSIONS ASM_PFX= OPTIONAL= ', + 'IPF_GNU' : 'MDE_CPU_IPF __GNUC__ ASM_PFX= OPTIONAL= ', + 'EBC_INTEL': 'MDE_CPU_EBC __INTEL_COMPILER ASM_PFX= OPTIONAL= '} + +def parseCmdArgs(): + parser = OptionParser(version="Package Document Generation Tools - Version 0.1") + parser.add_option('-w', '--workspace', action='store', type='string', dest='WorkspacePath', + help='Specify workspace absolute path. For example: c:\\tianocore') + parser.add_option('-p', '--decfile', action='store', dest='PackagePath', + help='Specify the absolute path for package DEC file. For example: c:\\tianocore\\MdePkg\\MdePkg.dec') + parser.add_option('-x', '--doxygen', action='store', dest='DoxygenPath', + help='Specify the absolute path of doxygen tools installation. For example: C:\\Program Files\\doxygen\bin\doxygen.exe') + parser.add_option('-o', '--output', action='store', dest='OutputPath', + help='Specify the document output path. For example: c:\\docoutput') + parser.add_option('-a', '--arch', action='store', dest='Arch', choices=list(gArchMarcoDict.keys()), + help='Specify the architecture used in preprocess package\'s source. For example: -a IA32_MSFT') + parser.add_option('-m', '--mode', action='store', dest='DocumentMode', choices=['CHM', 'HTML'], + help='Specify the document mode from : CHM or HTML') + parser.add_option('-i', '--includeonly', action='store_true', dest='IncludeOnly', + help='Only generate document for package\'s public interfaces produced by include folder. ') + parser.add_option('-c', '--htmlworkshop', dest='HtmlWorkshopPath', + help='Specify the absolute path for Microsoft HTML Workshop\'s hhc.exe file. For example: C:\\Program Files\\HTML Help Workshop\\hhc.exe') + (options, args) = parser.parse_args() + + # validate the options + errors = [] + if options.WorkspacePath is None: + errors.append('- Please specify workspace path via option -w!') + elif not os.path.exists(options.WorkspacePath): + errors.append("- Invalid workspace path %s! The workspace path should be exist in absolute path!" % options.WorkspacePath) + + if options.PackagePath is None: + errors.append('- Please specify package DEC file path via option -p!') + elif not os.path.exists(options.PackagePath): + errors.append("- Invalid package's DEC file path %s! The DEC path should be exist in absolute path!" % options.PackagePath) + + default = "C:\\Program Files\\doxygen\\bin\\doxygen.exe" + if options.DoxygenPath is None: + if os.path.exists(default): + print("Warning: Assume doxygen tool is installed at %s. If not, please specify via -x" % default) + options.DoxygenPath = default + else: + errors.append('- Please specify the path of doxygen tool installation via option -x! or install it in default path %s' % default) + elif not os.path.exists(options.DoxygenPath): + errors.append("- Invalid doxygen tool path %s! The doxygen tool path should be exist in absolute path!" % options.DoxygenPath) + + if options.OutputPath is not None: + if not os.path.exists(options.OutputPath): + # create output + try: + os.makedirs(options.OutputPath) + except: + errors.append('- Fail to create the output directory %s' % options.OutputPath) + else: + if options.PackagePath is not None and os.path.exists(options.PackagePath): + dirpath = os.path.dirname(options.PackagePath) + default = os.path.join (dirpath, "Document") + print('Warning: Assume document output at %s. If not, please specify via option -o' % default) + options.OutputPath = default + if not os.path.exists(default): + try: + os.makedirs(default) + except: + errors.append('- Fail to create default output directory %s! Please specify document output diretory via option -o' % default) + else: + errors.append('- Please specify document output path via option -o!') + + if options.Arch is None: + options.Arch = 'ALL' + print("Warning: Assume arch is \"ALL\". If not, specify via -a") + + if options.DocumentMode is None: + options.DocumentMode = "HTML" + print("Warning: Assume document mode is \"HTML\". If not, specify via -m") + + if options.IncludeOnly is None: + options.IncludeOnly = False + print("Warning: Assume generate package document for all package\'s source including publich interfaces and implementation libraries and modules.") + + if options.DocumentMode.lower() == 'chm': + default = "C:\\Program Files\\HTML Help Workshop\\hhc.exe" + if options.HtmlWorkshopPath is None: + if os.path.exists(default): + print('Warning: Assume the installation path of Microsoft HTML Workshop is %s. If not, specify via option -c.' % default) + options.HtmlWorkshopPath = default + else: + errors.append('- Please specify the installation path of Microsoft HTML Workshop via option -c!') + elif not os.path.exists(options.HtmlWorkshopPath): + errors.append('- The installation path of Microsoft HTML Workshop %s does not exists. ' % options.HtmlWorkshopPath) + + if len(errors) != 0: + print('\n') + parser.error('Fail to start due to following reasons: \n%s' %'\n'.join(errors)) + return (options.WorkspacePath, options.PackagePath, options.DoxygenPath, options.OutputPath, + options.Arch, options.DocumentMode, options.IncludeOnly, options.HtmlWorkshopPath) + +def createPackageObject(wsPath, pkgPath): + try: + pkgObj = baseobject.Package(None, wsPath) + pkgObj.Load(pkgPath) + except: + logging.getLogger().error ('Fail to create package object!') + return None + + return pkgObj + +def callbackLogMessage(msg, level): + print(msg.strip()) + +def callbackCreateDoxygenProcess(doxPath, configPath): + if sys.platform == 'win32': + cmd = '"%s" %s' % (doxPath, configPath) + else: + cmd = '%s %s' % (doxPath, configPath) + print(cmd) + subprocess.call(cmd, shell=True) + + +def DocumentFixup(outPath, arch): + # find BASE_LIBRARY_JUMP_BUFFER structure reference page + + print('\n >>> Start fixup document \n') + + for root, dirs, files in os.walk(outPath): + for dir in dirs: + if dir.lower() in ['.svn', '_svn', 'cvs']: + dirs.remove(dir) + for file in files: + if not file.lower().endswith('.html'): continue + fullpath = os.path.join(outPath, root, file) + try: + f = open(fullpath, 'r') + text = f.read() + f.close() + except: + logging.getLogger().error('\nFail to open file %s\n' % fullpath) + continue + if arch.lower() == 'all': + if text.find('BASE_LIBRARY_JUMP_BUFFER Struct Reference') != -1: + FixPageBASE_LIBRARY_JUMP_BUFFER(fullpath, text) + if text.find('MdePkg/Include/Library/BaseLib.h File Reference') != -1: + FixPageBaseLib(fullpath, text) + if text.find('IA32_IDT_GATE_DESCRIPTOR Union Reference') != -1: + FixPageIA32_IDT_GATE_DESCRIPTOR(fullpath, text) + if text.find('MdePkg/Include/Library/UefiDriverEntryPoint.h File Reference') != -1: + FixPageUefiDriverEntryPoint(fullpath, text) + if text.find('MdePkg/Include/Library/UefiApplicationEntryPoint.h File Reference') != -1: + FixPageUefiApplicationEntryPoint(fullpath, text) + + print(' >>> Finish all document fixing up! \n') + +def FixPageBaseLib(path, text): + print(' >>> Fixup BaseLib file page at file %s \n' % path) + lines = text.split('\n') + lastBaseJumpIndex = -1 + lastIdtGateDescriptor = -1 + for index in range(len(lines) - 1, -1, -1): + line = lines[index] + if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 4 </td>': + lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 4 [IA32] </td>' + if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 0x10 </td>': + lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 0x10 [IPF] </td>' + if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 8 </td>': + lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 9 [EBC, x64] </td>' + if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 4') != -1: + lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 4', + 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 4 [IA32]') + if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 0x10') != -1: + lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 0x10', + 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 0x10 [IPF]') + if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 8') != -1: + lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 8', + 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 8 [x64, EBC]') + if line.find('>BASE_LIBRARY_JUMP_BUFFER</a>') != -1: + if lastBaseJumpIndex != -1: + del lines[lastBaseJumpIndex] + lastBaseJumpIndex = index + if line.find('>IA32_IDT_GATE_DESCRIPTOR</a></td>') != -1: + if lastIdtGateDescriptor != -1: + del lines[lastIdtGateDescriptor] + lastIdtGateDescriptor = index + try: + f = open(path, 'w') + f.write('\n'.join(lines)) + f.close() + except: + logging.getLogger().error(" <<< Fail to fixup file %s\n" % path) + return + print(" <<< Finish to fixup file %s\n" % path) + +def FixPageIA32_IDT_GATE_DESCRIPTOR(path, text): + print(' >>> Fixup structure reference IA32_IDT_GATE_DESCRIPTOR at file %s \n' % path) + lines = text.split('\n') + for index in range(len(lines) - 1, -1, -1): + line = lines[index].strip() + if line.find('struct {</td>') != -1 and lines[index - 2].find('>Uint64</a></td>') != -1: + lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>') + if line.find('struct {</td>') != -1 and lines[index - 1].find('Data Fields') != -1: + lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>') + try: + f = open(path, 'w') + f.write('\n'.join(lines)) + f.close() + except: + logging.getLogger().error(" <<< Fail to fixup file %s\n" % path) + return + print(" <<< Finish to fixup file %s\n" % path) + +def FixPageBASE_LIBRARY_JUMP_BUFFER(path, text): + print(' >>> Fixup structure reference BASE_LIBRARY_JUMP_BUFFER at file %s \n' % path) + lines = text.split('\n') + bInDetail = True + bNeedRemove = False + for index in range(len(lines) - 1, -1, -1): + line = lines[index] + if line.find('Detailed Description') != -1: + bInDetail = False + if line.startswith('EBC context buffer used by') and lines[index - 1].startswith('x64 context buffer'): + lines[index] = "IA32/IPF/X64/" + line + bNeedRemove = True + if line.startswith("x64 context buffer") or line.startswith('IPF context buffer used by') or \ + line.startswith('IA32 context buffer used by'): + if bNeedRemove: + lines.remove(line) + if line.find('>R0</a>') != -1 and not bInDetail: + if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For EBC</h2></td></tr>': + lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For EBC</h2></td></tr>') + if line.find('>Rbx</a>') != -1 and not bInDetail: + if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>': + lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>') + if line.find('>F2</a>') != -1 and not bInDetail: + if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For IPF</h2></td></tr>': + lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IPF</h2></td></tr>') + if line.find('>Ebx</a>') != -1 and not bInDetail: + if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>': + lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>') + try: + f = open(path, 'w') + f.write('\n'.join(lines)) + f.close() + except: + logging.getLogger().error(" <<< Fail to fixup file %s" % path) + return + print(" <<< Finish to fixup file %s\n" % path) + +def FixPageUefiDriverEntryPoint(path, text): + print(' >>> Fixup file reference MdePkg/Include/Library/UefiDriverEntryPoint.h at file %s \n' % path) + lines = text.split('\n') + bInModuleEntry = False + bInEfiMain = False + ModuleEntryDlCount = 0 + ModuleEntryDelStart = 0 + ModuleEntryDelEnd = 0 + EfiMainDlCount = 0 + EfiMainDelStart = 0 + EfiMainDelEnd = 0 + + for index in range(len(lines)): + line = lines[index].strip() + if line.find('EFI_STATUS</a> EFIAPI _ModuleEntryPoint </td>') != -1: + bInModuleEntry = True + if line.find('EFI_STATUS</a> EFIAPI EfiMain </td>') != -1: + bInEfiMain = True + if line.startswith('<p>References <a'): + if bInModuleEntry: + ModuleEntryDelEnd = index - 1 + bInModuleEntry = False + elif bInEfiMain: + EfiMainDelEnd = index - 1 + bInEfiMain = False + if bInModuleEntry: + if line.startswith('</dl>'): + ModuleEntryDlCount = ModuleEntryDlCount + 1 + if ModuleEntryDlCount == 1: + ModuleEntryDelStart = index + 1 + if bInEfiMain: + if line.startswith('</dl>'): + EfiMainDlCount = EfiMainDlCount + 1 + if EfiMainDlCount == 1: + EfiMainDelStart = index + 1 + + if EfiMainDelEnd > EfiMainDelStart: + for index in range(EfiMainDelEnd, EfiMainDelStart, -1): + del lines[index] + if ModuleEntryDelEnd > ModuleEntryDelStart: + for index in range(ModuleEntryDelEnd, ModuleEntryDelStart, -1): + del lines[index] + + try: + f = open(path, 'w') + f.write('\n'.join(lines)) + f.close() + except: + logging.getLogger().error(" <<< Fail to fixup file %s" % path) + return + print(" <<< Finish to fixup file %s\n" % path) + + +def FixPageUefiApplicationEntryPoint(path, text): + print(' >>> Fixup file reference MdePkg/Include/Library/UefiApplicationEntryPoint.h at file %s \n' % path) + lines = text.split('\n') + bInModuleEntry = False + bInEfiMain = False + ModuleEntryDlCount = 0 + ModuleEntryDelStart = 0 + ModuleEntryDelEnd = 0 + EfiMainDlCount = 0 + EfiMainDelStart = 0 + EfiMainDelEnd = 0 + + for index in range(len(lines)): + line = lines[index].strip() + if line.find('EFI_STATUS</a> EFIAPI _ModuleEntryPoint </td>') != -1: + bInModuleEntry = True + if line.find('EFI_STATUS</a> EFIAPI EfiMain </td>') != -1: + bInEfiMain = True + if line.startswith('<p>References <a'): + if bInModuleEntry: + ModuleEntryDelEnd = index - 1 + bInModuleEntry = False + elif bInEfiMain: + EfiMainDelEnd = index - 1 + bInEfiMain = False + if bInModuleEntry: + if line.startswith('</dl>'): + ModuleEntryDlCount = ModuleEntryDlCount + 1 + if ModuleEntryDlCount == 1: + ModuleEntryDelStart = index + 1 + if bInEfiMain: + if line.startswith('</dl>'): + EfiMainDlCount = EfiMainDlCount + 1 + if EfiMainDlCount == 1: + EfiMainDelStart = index + 1 + + if EfiMainDelEnd > EfiMainDelStart: + for index in range(EfiMainDelEnd, EfiMainDelStart, -1): + del lines[index] + if ModuleEntryDelEnd > ModuleEntryDelStart: + for index in range(ModuleEntryDelEnd, ModuleEntryDelStart, -1): + del lines[index] + + try: + f = open(path, 'w') + f.write('\n'.join(lines)) + f.close() + except: + logging.getLogger().error(" <<< Fail to fixup file %s" % path) + return + print(" <<< Finish to fixup file %s\n" % path) + +if __name__ == '__main__': + wspath, pkgpath, doxpath, outpath, archtag, docmode, isinc, hwpath = parseCmdArgs() + + # configure logging system + logfilepath = os.path.join(outpath, 'log.txt') + logging.basicConfig(format='%(levelname)-8s %(message)s', level=logging.DEBUG) + + # create package model object firstly + pkgObj = createPackageObject(wspath, pkgpath) + if pkgObj is None: + sys.exit(-1) + + # create doxygen action model + arch = None + tooltag = None + if archtag.lower() != 'all': + arch = archtag.split('_')[0] + tooltag = archtag.split('_')[1] + else: + arch = 'all' + tooltag = 'all' + + # preprocess package and call doxygen + try: + action = doxygengen.PackageDocumentAction(doxpath, + hwpath, + outpath, + pkgObj, + docmode, + callbackLogMessage, + arch, + tooltag, + isinc, + True) + action.RegisterCallbackDoxygenProcess(callbackCreateDoxygenProcess) + action.Generate() + except: + message = traceback.format_exception(*sys.exc_info()) + logging.getLogger().error('Fail to create doxygen action! \n%s' % ''.join(message)) + sys.exit(-1) + + DocumentFixup(outpath, arch) + + # generate CHM is necessary + if docmode.lower() == 'chm': + indexpath = os.path.join(outpath, 'html', 'index.hhp') + if sys.platform == 'win32': + cmd = '"%s" %s' % (hwpath, indexpath) + else: + cmd = '%s %s' % (hwpath, indexpath) + subprocess.call(cmd) + print('\nFinish to generate package document! Please open %s for review' % os.path.join(outpath, 'html', 'index.chm')) + else: + print('\nFinish to generate package document! Please open %s for review' % os.path.join(outpath, 'html', 'index.html')) diff --git a/BaseTools/Scripts/PackageDocumentTools/packagedocapp.pyw b/BaseTools/Scripts/PackageDocumentTools/packagedocapp.pyw index e96197a508..d764c1a185 100644 --- a/BaseTools/Scripts/PackageDocumentTools/packagedocapp.pyw +++ b/BaseTools/Scripts/PackageDocumentTools/packagedocapp.pyw @@ -1,1060 +1,1060 @@ -## @file
-# This file is used to define common string related functions used in parsing
-# process
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-
-import os, sys, wx, logging
-
-import wx.stc
-import wx.lib.newevent
-import wx.lib.agw.genericmessagedialog as GMD
-from plugins.EdkPlugins.edk2.model import baseobject
-from plugins.EdkPlugins.edk2.model import doxygengen
-
-if hasattr(sys, "frozen"):
- appPath = os.path.abspath(os.path.dirname(sys.executable))
-else:
- appPath = os.path.abspath(os.path.dirname(__file__))
-
-AppCallBackEvent, EVT_APP_CALLBACK = wx.lib.newevent.NewEvent()
-LogEvent, EVT_LOG = wx.lib.newevent.NewEvent()
-
-class PackageDocApp(wx.App):
-
- def OnInit(self):
- logfile = os.path.join(appPath, 'log.txt')
- logging.basicConfig(format='%(name)-8s %(levelname)-8s %(message)s',
- filename=logfile, level=logging.ERROR)
-
- self.SetAppName('Package Doxygen Generate Application')
- frame = PackageDocMainFrame(None, "Package Document Generation Application!")
- self.SetTopWindow(frame)
-
- frame.Show(True)
-
- EVT_APP_CALLBACK( self, self.OnAppCallBack)
- return True
-
- def GetLogger(self):
- return logging.getLogger('')
-
- def ForegroundProcess(self, function, args):
- wx.PostEvent(self, AppCallBackEvent(callback=function, args=args))
-
- def OnAppCallBack(self, event):
- try:
- event.callback(*event.args)
- except:
- self._logger.exception( 'OnAppCallBack<%s.%s>\n' %
- (event.callback.__module__, event.callback.__name__ ))
-
-class PackageDocMainFrame(wx.Frame):
- def __init__(self, parent, title):
- wx.Frame.__init__(self, parent, -1, title, size=(550, 290), style=wx.MINIMIZE_BOX|wx.SYSTEM_MENU|wx.CAPTION|wx.CLOSE_BOX )
-
- panel = wx.Panel(self)
- sizer = wx.BoxSizer(wx.VERTICAL)
-
- subsizer = wx.GridBagSizer(5, 10)
- subsizer.AddGrowableCol(1)
- subsizer.Add(wx.StaticText(panel, -1, "Workspace Location : "), (0, 0), flag=wx.ALIGN_CENTER_VERTICAL)
- self._workspacePathCtrl = wx.ComboBox(panel, -1)
- list = self.GetConfigure("WorkspacePath")
- if len(list) != 0:
- for item in list:
- self._workspacePathCtrl.Append(item)
- self._workspacePathCtrl.SetValue(list[len(list) - 1])
-
- subsizer.Add(self._workspacePathCtrl, (0, 1), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
- self._workspacePathBt = wx.BitmapButton(panel, -1, bitmap=wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN))
- subsizer.Add(self._workspacePathBt, (0, 2), flag=wx.ALIGN_CENTER_VERTICAL)
- wx.EVT_BUTTON(self._workspacePathBt, self._workspacePathBt.GetId(), self.OnBrowsePath)
-
- subsizer.Add(wx.StaticText(panel, -1, "Package DEC Location : "), (1, 0), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
- self._packagePathCtrl = wx.ComboBox(panel, -1)
- list = self.GetConfigure("PackagePath")
- if len(list) != 0:
- for item in list:
- self._packagePathCtrl.Append(item)
- self._packagePathCtrl.SetValue(list[len(list) - 1])
- subsizer.Add(self._packagePathCtrl, (1, 1), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
- self._packagePathBt = wx.BitmapButton(panel, -1, bitmap=wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN))
- subsizer.Add(self._packagePathBt, (1, 2), flag=wx.ALIGN_CENTER_VERTICAL)
- wx.EVT_BUTTON(self._packagePathBt, self._packagePathBt.GetId(), self.OnBrowsePath)
-
- subsizer.Add(wx.StaticText(panel, -1, "Doxygen Tool Location : "), (2, 0), flag=wx.ALIGN_CENTER_VERTICAL)
- self._doxygenPathCtrl = wx.TextCtrl(panel, -1)
- list = self.GetConfigure('DoxygenPath')
- if len(list) != 0:
- self._doxygenPathCtrl.SetValue(list[0])
- else:
- if wx.Platform == '__WXMSW__':
- self._doxygenPathCtrl.SetValue('C:\\Program Files\\Doxygen\\bin\\doxygen.exe')
- else:
- self._doxygenPathCtrl.SetValue('/usr/bin/doxygen')
-
- self._doxygenPathBt = wx.BitmapButton(panel, -1, bitmap=wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN))
- subsizer.Add(self._doxygenPathCtrl, (2, 1), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
- subsizer.Add(self._doxygenPathBt, (2, 2), flag=wx.ALIGN_CENTER_VERTICAL)
- wx.EVT_BUTTON(self._doxygenPathBt, self._doxygenPathBt.GetId(), self.OnBrowsePath)
-
- subsizer.Add(wx.StaticText(panel, -1, "CHM Tool Location : "), (3, 0), flag=wx.ALIGN_CENTER_VERTICAL)
- self._chmPathCtrl = wx.TextCtrl(panel, -1)
- list = self.GetConfigure('CHMPath')
- if len(list) != 0:
- self._chmPathCtrl.SetValue(list[0])
- else:
- self._chmPathCtrl.SetValue('C:\\Program Files\\HTML Help Workshop\\hhc.exe')
-
- self._chmPathBt = wx.BitmapButton(panel, -1, bitmap=wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN))
- subsizer.Add(self._chmPathCtrl, (3, 1), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
- subsizer.Add(self._chmPathBt, (3, 2), flag=wx.ALIGN_CENTER_VERTICAL)
- wx.EVT_BUTTON(self._chmPathBt, self._chmPathBt.GetId(), self.OnBrowsePath)
-
- subsizer.Add(wx.StaticText(panel, -1, "Output Location : "), (4, 0), flag=wx.ALIGN_CENTER_VERTICAL)
- self._outputPathCtrl = wx.ComboBox(panel, -1)
- list = self.GetConfigure("OutputPath")
- if len(list) != 0:
- for item in list:
- self._outputPathCtrl.Append(item)
- self._outputPathCtrl.SetValue(list[len(list) - 1])
-
- subsizer.Add(self._outputPathCtrl, (4, 1), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
- self._outputPathBt = wx.BitmapButton(panel, -1, bitmap=wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN))
- subsizer.Add(self._outputPathBt, (4, 2), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
- wx.EVT_BUTTON(self._outputPathBt, self._outputPathBt.GetId(), self.OnBrowsePath)
-
- subsizer.Add(wx.StaticText(panel, -1, "Architecture Specified : "), (5, 0), flag=wx.ALIGN_CENTER_VERTICAL)
- self._archCtrl = wx.ComboBox(panel, -1, value='ALL', choices=['ALL', 'IA32/MSFT', 'IA32/GNU', 'X64/INTEL', 'X64/GNU', 'IPF/MSFT', 'IPF/GNU', 'EBC/INTEL'],
- style=wx.CB_READONLY)
- self._archCtrl.Bind(wx.EVT_COMBOBOX, self.OnArchtectureSelectChanged)
- subsizer.Add(self._archCtrl, (5, 1), (1, 2), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
- sizer.Add(subsizer, 0, wx.EXPAND|wx.TOP|wx.BOTTOM|wx.LEFT|wx.RIGHT, 5)
-
- sizer6 = wx.BoxSizer(wx.HORIZONTAL)
- self._modesel = wx.RadioBox(panel, -1, 'Generated Document Mode', majorDimension=2, choices=['CHM', 'HTML'], style=wx.RA_SPECIFY_COLS)
- self._modesel.SetStringSelection('HTML')
-
- self._includeonlysel = wx.CheckBox(panel, -1, 'Only document public include')
-
- sizer6.Add(self._modesel, 0 , wx.EXPAND)
- sizer6.Add(self._includeonlysel, 0, wx.EXPAND|wx.LEFT, 5)
-
- sizer.Add(sizer6, 0, wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, 5)
-
- self._generateBt = wx.Button(panel, -1, "Generate Package Document!")
- self._generateBt.Bind(wx.EVT_BUTTON, self.OnGenerate)
- sizer.Add(self._generateBt, 0, wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, 5)
-
- panel.SetSizer(sizer)
- panel.Layout()
- panel.SetAutoLayout(True)
- self.CenterOnScreen()
-
- def SaveConfigure(self, name, value):
- if value ==None or len(value) == 0:
- return
- config = wx.ConfigBase_Get()
- oldvalues = config.Read(name, '').split(';')
- if len(oldvalues) >= 10:
- oldvalues.remove(oldvalues[0])
- if value not in oldvalues:
- oldvalues.append(value)
- else:
- oldvalues.remove(value)
- oldvalues.append(value)
-
- config.Write(name, ';'.join(oldvalues))
-
- def GetConfigure(self, name):
- config = wx.ConfigBase_Get()
- values = config.Read(name, '').split(';')
- list = []
- for item in values:
- if len(item) != 0:
- list.append(item)
- return list
-
- def OnBrowsePath(self, event):
- id = event.GetId()
- editctrl = None
- startdir = ''
- isFile = False
- if id == self._packagePathBt.GetId():
- dlgTitle = "Choose package path:"
- editctrl = self._packagePathCtrl
- isFile = True
- if os.path.exists(self.GetWorkspace()):
- startdir = self.GetWorkspace()
- elif id == self._workspacePathBt.GetId():
- dlgTitle = "Choose workspace path:"
- editctrl = self._workspacePathCtrl
- startdir = editctrl.GetValue()
- elif id == self._doxygenPathBt.GetId():
- isFile = True
- dlgTitle = "Choose doxygen installation path:"
- editctrl = self._doxygenPathCtrl
- startdir = editctrl.GetValue()
- elif id == self._outputPathBt.GetId():
- dlgTitle = "Choose document output path:"
- editctrl = self._outputPathCtrl
- if os.path.exists(self.GetWorkspace()):
- startdir = self.GetWorkspace()
- startdir = editctrl.GetValue()
- elif id == self._chmPathBt.GetId():
- isFile = True
- dlgTitle = "Choose installation path for Microsoft HTML workshop software"
- editctrl = self._chmPathCtrl
- startdir = editctrl.GetValue()
- else:
- return
-
- if not isFile:
- dlg = wx.DirDialog(self, dlgTitle, defaultPath=startdir)
- else:
- dlg = wx.FileDialog(self, dlgTitle, defaultDir=startdir)
-
- if dlg.ShowModal() == wx.ID_OK:
- editctrl.SetValue(dlg.GetPath())
- dlg.Destroy()
-
- def OnArchtectureSelectChanged(self, event):
- str = ''
- selarch = self._archCtrl.GetValue()
- if selarch == 'ALL':
- str += 'MDE_CPU_IA32 MDE_CPU_X64 MDE_CPU_EBC MDE_CPU_IPF _MSC_EXTENSIONS __GNUC__ __INTEL_COMPILER'
- elif selarch == 'IA32/MSFT':
- str += 'MDE_CPU_IA32 _MSC_EXTENSIONS'
- elif selarch == 'IA32/GNU':
- str += 'MDE_CPU_IA32 __GNUC__'
- elif selarch == 'X64/MSFT':
- str += 'MDE_CPU_X64 _MSC_EXTENSIONS'
- elif selarch == 'X64/GNU':
- str += 'MDE_CPU_X64 __GNUC__'
- elif selarch == 'IPF/MSFT':
- str += 'MDE_CPU_IPF _MSC_EXTENSIONS'
- elif selarch == 'IPF/GNU':
- str += 'MDE_CPU_IPF __GNUC__'
- elif selarch == 'EBC/INTEL':
- str += 'MDE_CPU_EBC __INTEL_COMPILER'
-
- str += ' ASM_PFX= OPTIONAL= '
-
- def OnMacroText(self, event):
- str = ''
- selarch = self._archCtrl.GetValue()
- if selarch == 'ALL':
- str += 'MDE_CPU_IA32 MDE_CPU_X64 MDE_CPU_EBC MDE_CPU_IPF _MSC_EXTENSIONS __GNUC__ __INTEL_COMPILER'
- elif selarch == 'IA32/MSFT':
- str += 'MDE_CPU_IA32 _MSC_EXTENSIONS'
- elif selarch == 'IA32/GNU':
- str += 'MDE_CPU_IA32 __GNUC__'
- elif selarch == 'X64/MSFT':
- str += 'MDE_CPU_X64 _MSC_EXTENSIONS'
- elif selarch == 'X64/GNU':
- str += 'MDE_CPU_X64 __GNUC__'
- elif selarch == 'IPF/MSFT':
- str += 'MDE_CPU_IPF _MSC_EXTENSIONS'
- elif selarch == 'IPF/GNU':
- str += 'MDE_CPU_IPF __GNUC__'
- elif selarch == 'EBC/INTEL':
- str += 'MDE_CPU_EBC __INTEL_COMPILER'
-
- str += ' ASM_PFX= OPTIONAL= '
-
- def OnGenerate(self, event):
- if not self.CheckInput(): return
-
- dlg = ProgressDialog(self)
- dlg.ShowModal()
- dlg.Destroy()
-
- def CheckInput(self):
- pPath = self.GetPackagePath()
- wPath = self.GetWorkspace()
- dPath = self.GetDoxygenToolPath()
- cPath = self.GetChmToolPath()
- oPath = self.GetOutputPath()
-
- if len(wPath) == 0 or not os.path.exists(wPath):
- self._Error("Please input existing workspace path!")
- return False
- else:
- self.SaveConfigure('WorkspacePath', wPath)
-
- if len(pPath) == 0 or not os.path.exists(pPath) or not pPath.lower().endswith('.dec'):
- self._Error("Please input existing package file location!")
- return False
- elif pPath.lower().find(wPath.lower()) == -1:
- self._Error("Package patch should starts with workspace path, such as if workspace path is c:\\edk2, package patch could be c:\\edk2\MdePkg")
- return False
- else:
- self.SaveConfigure('PackagePath', pPath)
-
- if len(dPath) == 0 or not os.path.exists(dPath):
- self._Error("Can not find doxygen tool from path %s! Please download it from www.stack.nl/~dimitri/doxygen/download.html" % dPath)
- return False
- else:
- self.SaveConfigure('DoxygenPath', dPath)
-
- if self._modesel.GetStringSelection() == 'CHM':
- if (len(cPath) == 0 or not os.path.exists(cPath)):
- self._Error("You select CHM mode to generate document, but can not find software of Microsoft HTML Help Workshop.\nPlease\
- download it from http://www.microsoft.com/downloads/details.aspx?FamilyID=00535334-c8a6-452f-9aa0-d597d16580cc&displaylang=en\n\
-and install!")
- return False
- else:
- self.SaveConfigure('CHMPath', cPath)
-
- if len(oPath) == 0:
- self._Error("You must specific document output path")
- return False
- else:
- self.SaveConfigure('OutputPath', oPath)
-
- if os.path.exists(oPath):
- # add checking whether there is old doxygen config file here
- files = os.listdir(oPath)
- for file in files:
- if os.path.isfile(os.path.join(oPath,file)):
- basename, ext = os.path.splitext(file)
- if ext.lower() == '.doxygen_config':
- dlg = GMD.GenericMessageDialog(self, "Existing doxygen document in output directory will be overwritten\n, Are you sure?",
- "Info", wx.ICON_WARNING|wx.YES_NO)
- if dlg.ShowModal() == wx.ID_YES:
- break
- else:
- return False
- else:
- try:
- os.makedirs(oPath)
- except:
- self._Error("Fail to create output directory, please select another output directory!")
- return False
-
- return True
-
- def _Error(self, message):
- dlg = GMD.GenericMessageDialog(self, message,
- "Error", wx.ICON_ERROR|wx.OK)
- dlg.ShowModal()
- dlg.Destroy()
-
- def GetWorkspace(self):
- return os.path.normpath(self._workspacePathCtrl.GetValue())
-
- def GetPackagePath(self):
- return os.path.normpath(self._packagePathCtrl.GetValue())
-
- def GetOutputPath(self):
- return os.path.normpath(self._outputPathCtrl.GetValue())
-
- def GetDoxygenToolPath(self):
- return os.path.normpath(self._doxygenPathCtrl.GetValue())
-
- def GetChmToolPath(self):
- return os.path.normpath(self._chmPathCtrl.GetValue())
-
- def GetDocumentMode(self):
- return self._modesel.GetStringSelection()
-
- def GetArchitecture(self):
- value = self._archCtrl.GetValue()
- return value.split('/')[0]
-
- def GetToolTag(self):
- value = self._archCtrl.GetValue()
- if value == 'ALL':
- return 'ALL'
- return value.split('/')[1]
-
- def GetIsOnlyDocumentInclude(self):
- return self._includeonlysel.IsChecked()
-
-class ProgressDialog(wx.Dialog):
- def __init__(self, parent, id=wx.ID_ANY):
- title = "Generate Document for " + parent.GetPackagePath()
- wx.Dialog.__init__(self, parent, id, title=title, style=wx.CAPTION, size=(600, 300))
- self.Freeze()
- sizer = wx.BoxSizer(wx.VERTICAL)
- self._textCtrl = wx.StaticText(self, -1, "Start launching!")
- self._gaugeCtrl = wx.Gauge(self, -1, 100, size=(-1, 10))
- self._resultCtrl = wx.stc.StyledTextCtrl(self, -1)
- self._closeBt = wx.Button(self, -1, "Close")
- self._gotoOuputBt = wx.Button(self, -1, "Goto Output")
-
- # clear all margin
- self._resultCtrl.SetMarginWidth(0, 0)
- self._resultCtrl.SetMarginWidth(1, 0)
- self._resultCtrl.SetMarginWidth(2, 0)
-
- sizer.Add(self._textCtrl, 0, wx.EXPAND|wx.LEFT|wx.TOP|wx.RIGHT, 5)
- sizer.Add(self._gaugeCtrl, 0, wx.EXPAND|wx.LEFT|wx.TOP|wx.RIGHT, 5)
- sizer.Add(self._resultCtrl, 1, wx.EXPAND|wx.LEFT|wx.TOP|wx.RIGHT, 5)
- btsizer = wx.BoxSizer(wx.HORIZONTAL)
- btsizer.Add(self._gotoOuputBt, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.LEFT|wx.TOP|wx.LEFT|wx.BOTTOM, 5)
- btsizer.Add(self._closeBt, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.LEFT|wx.TOP|wx.LEFT|wx.BOTTOM, 5)
- sizer.Add(btsizer, 0, wx.ALIGN_CENTER_HORIZONTAL)
-
- self.SetSizer(sizer)
- self.CenterOnScreen()
- self.Thaw()
-
- self._logger = logging.getLogger('')
- self._loghandle = ResultHandler(self)
- logging.getLogger('edk').addHandler(self._loghandle)
- logging.getLogger('').addHandler(self._loghandle)
- logging.getLogger('app').addHandler(self._loghandle)
-
- wx.EVT_BUTTON(self._closeBt, self._closeBt.GetId(), self.OnButtonClose)
- wx.EVT_UPDATE_UI(self, self._closeBt.GetId(), self.OnUpdateCloseButton)
- wx.EVT_BUTTON(self._gotoOuputBt, self._gotoOuputBt.GetId(), self.OnGotoOutput)
- EVT_LOG(self, self.OnPostLog)
-
- self._process = None
- self._pid = None
- self._input = None
- self._output = None
- self._error = None
- self._inputThread = None
- self._errorThread = None
- self._isBusy = True
- self._pObj = None
-
- wx.CallAfter(self.GenerateAction)
-
- def OnUpdateCloseButton(self, event):
- self._closeBt.Enable(not self._isBusy)
- return True
-
- def OnButtonClose(self, event):
- if self._isBusy:
- self._InfoDialog("Please don't close in progressing...")
- return
-
- if self._process != None:
- self._process.CloseOutput()
-
- if self._inputThread:
- self._inputThread.Terminate()
- if self._errorThread:
- self._errorThread.Terminate()
-
- if self._pid != None:
- wx.Process.Kill(self._pid, wx.SIGKILL, wx.KILL_CHILDREN)
-
- logging.getLogger('edk').removeHandler(self._loghandle)
- logging.getLogger('').removeHandler(self._loghandle)
- logging.getLogger('app').removeHandler(self._loghandle)
-
- if self._pObj != None:
- self._pObj.Destroy()
-
- self.EndModal(0)
-
- def OnGotoOutput(self, event):
- output = self.GetParent().GetOutputPath()
- if os.path.exists(output):
- if wx.Platform == '__WXMSW__':
- os.startfile(self.GetParent().GetOutputPath())
- else:
- import webbrowser
- webbrowser.open(self.GetParent().GetOutputPath())
- else:
- self._ErrorDialog("Output directory does not exist!")
-
- def _ErrorDialog(self, message):
- dlg = GMD.GenericMessageDialog(self, message,
- "Error", wx.ICON_ERROR|wx.OK)
- dlg.ShowModal()
- dlg.Destroy()
-
- def _InfoDialog(self, message):
- dlg = GMD.GenericMessageDialog(self, message,
- "Info", wx.ICON_INFORMATION|wx.OK)
- dlg.ShowModal()
- dlg.Destroy()
-
- def _LogStep(self, index, message):
- stepstr = "Step %d: %s" % (index, message)
- self._textCtrl.SetLabel(stepstr)
- self.LogMessage(os.linesep + stepstr + os.linesep)
- self._gaugeCtrl.SetValue(index * 100 / 6 )
-
- def OnPostLog(self, event):
- self.LogMessage(event.message)
-
- def GenerateAction(self):
- self._LogStep(1, "Create Package Object Model")
- wsPath = self.GetParent().GetWorkspace()
- pkPath = self.GetParent().GetPackagePath()[len(wsPath) + 1:]
-
- try:
- pObj = baseobject.Package(None, self.GetParent().GetWorkspace())
- pObj.Load(pkPath)
- except:
- self._ErrorDialog("Fail to create package object model! Please check log.txt under this application folder!")
- self._isBusy = False
- return
- self._pObj = pObj
-
- self.LogMessage(str(pObj.GetPcds()))
-
- self._LogStep(2, "Preprocess and Generate Doxygen Config File")
- try:
- action = doxygengen.PackageDocumentAction(self.GetParent().GetDoxygenToolPath(),
- self.GetParent().GetChmToolPath(),
- self.GetParent().GetOutputPath(),
- pObj,
- self.GetParent().GetDocumentMode(),
- self.LogMessage,
- self.GetParent().GetArchitecture(),
- self.GetParent().GetToolTag(),
- self.GetParent().GetIsOnlyDocumentInclude(),
- True)
- except:
- self._ErrorDialog("Fail to preprocess! Please check log.txt under this application folder!")
- self._isBusy = False
- return
-
- action.RegisterCallbackDoxygenProcess(self.CreateDoxygeProcess)
-
- try:
- if not action.Generate():
- self._isBusy = False
- self.LogMessage("Fail to generate package document! Please check log.txt under this application folder!", 'error')
- except:
- import traceback
- message = traceback.format_exception(*sys.exc_info())
- logging.getLogger('').error(''.join(message))
- self._isBusy = False
- self._ErrorDialog("Fail to generate package document! Please check log.txt under this application folder!")
-
- def LogMessage(self, message, level='info'):
- self._resultCtrl.DocumentEnd()
- self._resultCtrl.SetReadOnly(False)
- self._resultCtrl.AppendText(message)
- self._resultCtrl.Home()
- self._resultCtrl.Home()
- self._resultCtrl.SetReadOnly(True)
- if level == 'error':
- wx.GetApp().GetLogger().error(message)
-
- def CreateDoxygeProcess(self, doxPath, configFile):
- self._LogStep(3, "Launch Doxygen Tool and Generate Package Document")
-
- cmd = '"%s" %s' % (doxPath, configFile)
- try:
- self._process = DoxygenProcess()
- self._process.SetParent(self)
- self._process.Redirect()
- self._pid = wx.Execute(cmd, wx.EXEC_ASYNC, self._process)
- self._input = self._process.GetInputStream()
- self._output = self._process.GetOutputStream()
- self._error = self._process.GetErrorStream()
- except:
- self._ErrorDialog('Fail to launch doxygen cmd %s! Please check log.txt under this application folder!' % cmd)
- self._isBusy = False
- return False
-
- self._inputThread = MonitorThread(self._input, self.LogMessage)
- self._errorThread = MonitorThread(self._error, self.LogMessage)
- self._inputThread.start()
- self._errorThread.start()
- return True
-
- def OnTerminateDoxygenProcess(self):
- if self._inputThread:
- self._inputThread.Terminate()
- self._inputThread = None
- if self._errorThread:
- self._errorThread.Terminate()
- self._errorThread = None
-
- if self._error:
- while self._error.CanRead():
- text = self._error.read()
- self.LogMessage(text)
-
- if self._input:
- while self._input.CanRead():
- text = self._input.read()
- self.LogMessage(text)
- self._process.Detach()
-
- self._process.CloseOutput()
- self._process = None
- self._pid = None
-
- self.DocumentFixup()
-
- if self.GetParent().GetDocumentMode().lower() == 'chm':
- hhcfile = os.path.join(self.GetParent().GetOutputPath(), 'html', 'index.hhc')
- hhpfile = os.path.join(self.GetParent().GetOutputPath(), 'html', 'index.hhp')
- self.FixDecDoxygenFileLink(hhcfile, None)
- if not self.CreateCHMProcess(self.GetParent().GetChmToolPath(), hhpfile):
- self._ErrorDialog("Fail to Create %s process for %s" % (self.GetParent().GetChmToolPath(), hhpfile))
- self._isBusy = False
- else:
- self._LogStep(6, "Finished Document Generation!")
- self._isBusy = False
- indexpath = os.path.realpath(os.path.join(self.GetParent().GetOutputPath(), 'html', 'index.html'))
- if wx.Platform == '__WXMSW__':
- os.startfile(indexpath)
- else:
- import webbrowser
- webbrowser.open(indexpath)
-
- self._InfoDialog('Success create HTML doxgen document %s' % indexpath)
-
- def CreateCHMProcess(self, chmPath, hhpfile):
- self.LogMessage(" >>>>>> Start Microsoft HTML workshop process...Zzz...\n")
- cmd = '"%s" %s' % (chmPath, hhpfile)
- try:
- self._process = CHMProcess()
- self._process.SetParent(self)
- self._process.Redirect()
- self._pid = wx.Execute(cmd, wx.EXEC_ASYNC, self._process)
- self._input = self._process.GetInputStream()
- self._output = self._process.GetOutputStream()
- self._error = self._process.GetErrorStream()
- except:
- self.LogMessage('\nFail to launch hhp cmd %s!\n' % cmd)
- self._isBusy = False
- return False
- self._inputThread = MonitorThread(self._input, self.LogMessage)
- self._errorThread = MonitorThread(self._error, self.LogMessage)
- self._inputThread.start()
- self._errorThread.start()
- return True
-
- def OnTerminateCHMProcess(self):
- if self._inputThread:
- self._inputThread.Terminate()
- self._inputThread = None
- if self._errorThread:
- self._errorThread.Terminate()
- self._errorThread = None
-
- if self._error:
- while self._error.CanRead():
- text = self._error.read()
- self.LogMessage(text)
- if self._input:
- while self._input.CanRead():
- text = self._input.read()
- self.LogMessage(text)
- self._process.Detach()
-
- self._process.CloseOutput()
- self._process = None
- self._pid = None
- self._isBusy = False
- indexpath = os.path.realpath(os.path.join(self.GetParent().GetOutputPath(), 'html', 'index.chm'))
- if os.path.exists(indexpath):
- if wx.Platform == '__WXMSW__':
- os.startfile(indexpath)
- else:
- import webbrowser
- webbrowser.open(indexpath)
-
- self._LogStep(6, "Finished Document Generation!")
- self.LogMessage('\nSuccess create CHM doxgen document %s\n' % indexpath)
- self._InfoDialog('Success create CHM doxgen document %s' % indexpath)
-
- def DocumentFixup(self):
- # find BASE_LIBRARY_JUMP_BUFFER structure reference page
- self._LogStep(4, "Fixup Package Document!")
- self.LogMessage('\n >>> Start fixup document \n')
-
- for root, dirs, files in os.walk(os.path.join(self.GetParent().GetOutputPath(), 'html')):
- for dir in dirs:
- if dir.lower() in ['.svn', '_svn', 'cvs']:
- dirs.remove(dir)
- for file in files:
- wx.YieldIfNeeded()
- if not file.lower().endswith('.html'): continue
- fullpath = os.path.join(self.GetParent().GetOutputPath(), root, file)
- try:
- f = open(fullpath, 'r')
- text = f.read()
- f.close()
- except:
- self.LogMessage('\nFail to open file %s\n' % fullpath)
- continue
- if text.find('BASE_LIBRARY_JUMP_BUFFER Struct Reference') != -1 and self.GetParent().GetArchitecture() == 'ALL':
- self.FixPageBASE_LIBRARY_JUMP_BUFFER(fullpath, text)
- if text.find('MdePkg/Include/Library/BaseLib.h File Reference') != -1 and self.GetParent().GetArchitecture() == 'ALL':
- self.FixPageBaseLib(fullpath, text)
- if text.find('IA32_IDT_GATE_DESCRIPTOR Union Reference') != -1 and self.GetParent().GetArchitecture() == 'ALL':
- self.FixPageIA32_IDT_GATE_DESCRIPTOR(fullpath, text)
- if text.find('MdePkg/Include/Library/UefiDriverEntryPoint.h File Reference') != -1:
- self.FixPageUefiDriverEntryPoint(fullpath, text)
- if text.find('MdePkg/Include/Library/UefiApplicationEntryPoint.h File Reference') != -1:
- self.FixPageUefiApplicationEntryPoint(fullpath, text)
- if text.lower().find('.s.dox') != -1 or \
- text.lower().find('.asm.dox') != -1 or \
- text.lower().find('.uni.dox') != -1:
- self.FixDoxFileLink(fullpath, text)
-
- self.RemoveFileList()
- self.LogMessage(' >>> Finish all document fixing up! \n')
-
- def RemoveFileList(self):
- path_html = os.path.join(self.GetParent().GetOutputPath(), "html", "tree.html")
- path_chm = os.path.join(self.GetParent().GetOutputPath(), "html", "index.hhc")
- if os.path.exists(path_html):
- self.LogMessage(' >>>Remove FileList item from generated HTML document.\n');
- lines = []
- f = open (path_html, "r")
- lines = f.readlines()
- f.close()
- bfound = False
- for index in range(len(lines)):
- if lines[index].find('<a class="el" href="files.html" target="basefrm">File List</a>') != -1:
- lines[index] = "<!-- %s" % lines[index]
- bfound = True
- continue
- if bfound:
- if lines[index].find('</div>') != -1:
- lines[index] = "%s -->" % lines[index]
- break
- if bfound:
- f = open(path_html, "w")
- f.write("".join(lines))
- f.close()
- else:
- self.LogMessage (' !!!Can not found FileList item in HTML document!\n')
-
- if os.path.exists(path_chm):
- self.LogMessage(" >>>Warning: Can not remove FileList for CHM files!\n");
- """
- self.LogMessage(' >>>Remove FileList item from generated CHM document!\n');
- lines = []
- f = open (path_chm, "r")
- lines = f.readlines()
- f.close()
- bfound = False
- for index in xrange(len(lines)):
- if not bfound:
- if lines[index].find('<param name="Local" value="files.html">') != -1:
- lines[index] = '<!-- %s' % lines[index]
- bfound = True
- continue
- if bfound:
- if lines[index].find('</UL>') != -1:
- lines[index] = '%s -->\n' % lines[index].rstrip()
- break
- if bfound:
- f = open(path_chm, "w")
- f.write("".join(lines))
- f.close()
- import time
- time.sleep(2)
- else:
- self.LogMessage(' !!!Can not found the FileList item in CHM document!')
- """
- def FixPageBaseLib(self, path, text):
- self.LogMessage(' >>> Fixup BaseLib file page at file %s \n' % path)
- lines = text.split('\n')
- lastBaseJumpIndex = -1
- lastIdtGateDescriptor = -1
- for index in range(len(lines) - 1, -1, -1):
- line = lines[index]
- if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 4 </td>':
- lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 4 [IA32] </td>'
- if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 0x10 </td>':
- lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 0x10 [IPF] </td>'
- if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 8 </td>':
- lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 9 [EBC, x64] </td>'
- if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 4') != -1:
- lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 4',
- 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 4 [IA32]')
- if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 0x10') != -1:
- lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 0x10',
- 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 0x10 [IPF]')
- if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 8') != -1:
- lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 8',
- 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 8 [x64, EBC]')
- if line.find('>BASE_LIBRARY_JUMP_BUFFER</a>') != -1:
- if lastBaseJumpIndex != -1:
- del lines[lastBaseJumpIndex]
- lastBaseJumpIndex = index
- if line.find('>IA32_IDT_GATE_DESCRIPTOR</a></td>') != -1:
- if lastIdtGateDescriptor != -1:
- del lines[lastIdtGateDescriptor]
- lastIdtGateDescriptor = index
- try:
- f = open(path, 'w')
- f.write('\n'.join(lines))
- f.close()
- except:
- self._isBusy = False
- self.LogMessage(" <<< Fail to fixup file %s\n" % path)
- self.LogMessage(" <<< Finish to fixup file %s\n" % path)
-
- def FixPageIA32_IDT_GATE_DESCRIPTOR(self, path, text):
- self.LogMessage(' >>> Fixup structure reference IA32_IDT_GATE_DESCRIPTOR at file %s \n' % path)
- lines = text.split('\n')
- for index in range(len(lines) - 1, -1, -1):
- line = lines[index].strip()
- if line.find('struct {</td>') != -1 and lines[index - 2].find('>Uint64</a></td>') != -1:
- lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>')
- if line.find('struct {</td>') != -1 and lines[index - 1].find('Data Fields') != -1:
- lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>')
- try:
- f = open(path, 'w')
- f.write('\n'.join(lines))
- f.close()
- except:
- self._isBusy = False
- self.LogMessage(" <<< Fail to fixup file %s\n" % path)
- self.LogMessage(" <<< Finish to fixup file %s\n" % path)
-
- def FixPageBASE_LIBRARY_JUMP_BUFFER(self, path, text):
- self.LogMessage(' >>> Fixup structure reference BASE_LIBRARY_JUMP_BUFFER at file %s \n' % path)
- lines = text.split('\n')
- bInDetail = True
- bNeedRemove = False
- for index in range(len(lines) - 1, -1, -1):
- line = lines[index]
- if line.find('Detailed Description') != -1:
- bInDetail = False
- if line.startswith('EBC context buffer used by') and lines[index - 1].startswith('x64 context buffer'):
- lines[index] = "IA32/IPF/X64/" + line
- bNeedRemove = True
- if line.startswith("x64 context buffer") or line.startswith('IPF context buffer used by') or \
- line.startswith('IA32 context buffer used by'):
- if bNeedRemove:
- lines.remove(line)
- if line.find('>R0</a>') != -1 and not bInDetail:
- if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For EBC</h2></td></tr>':
- lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For EBC</h2></td></tr>')
- if line.find('>Rbx</a>') != -1 and not bInDetail:
- if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>':
- lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>')
- if line.find('>F2</a>') != -1 and not bInDetail:
- if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For IPF</h2></td></tr>':
- lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IPF</h2></td></tr>')
- if line.find('>Ebx</a>') != -1 and not bInDetail:
- if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>':
- lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>')
- try:
- f = open(path, 'w')
- f.write('\n'.join(lines))
- f.close()
- except:
- self._isBusy = False
- self.LogMessage(" <<< Fail to fixup file %s" % path)
- self.LogMessage(" <<< Finish to fixup file %s\n" % path)
-
- def FixPageUefiDriverEntryPoint(self, path, text):
- self.LogMessage(' >>> Fixup file reference MdePkg/Include/Library/UefiDriverEntryPoint.h at file %s \n' % path)
- lines = text.split('\n')
- bInModuleEntry = False
- bInEfiMain = False
- ModuleEntryDlCount = 0
- ModuleEntryDelStart = 0
- ModuleEntryDelEnd = 0
- EfiMainDlCount = 0
- EfiMainDelStart = 0
- EfiMainDelEnd = 0
-
- for index in range(len(lines)):
- line = lines[index].strip()
- if line.find('EFI_STATUS</a> EFIAPI _ModuleEntryPoint </td>') != -1:
- bInModuleEntry = True
- if line.find('EFI_STATUS</a> EFIAPI EfiMain </td>') != -1:
- bInEfiMain = True
- if line.startswith('<p>References <a'):
- if bInModuleEntry:
- ModuleEntryDelEnd = index - 1
- bInModuleEntry = False
- elif bInEfiMain:
- EfiMainDelEnd = index - 1
- bInEfiMain = False
- if bInModuleEntry:
- if line.startswith('</dl>'):
- ModuleEntryDlCount = ModuleEntryDlCount + 1
- if ModuleEntryDlCount == 1:
- ModuleEntryDelStart = index + 1
- if bInEfiMain:
- if line.startswith('</dl>'):
- EfiMainDlCount = EfiMainDlCount + 1
- if EfiMainDlCount == 1:
- EfiMainDelStart = index + 1
-
- if EfiMainDelEnd > EfiMainDelStart:
- for index in range(EfiMainDelEnd, EfiMainDelStart, -1):
- del lines[index]
- if ModuleEntryDelEnd > ModuleEntryDelStart:
- for index in range(ModuleEntryDelEnd, ModuleEntryDelStart, -1):
- del lines[index]
-
- try:
- f = open(path, 'w')
- f.write('\n'.join(lines))
- f.close()
- except:
- self._isBusy = False
- self.LogMessage(" <<< Fail to fixup file %s" % path)
- self.LogMessage(" <<< Finish to fixup file %s\n" % path)
-
- def FixPageUefiApplicationEntryPoint(self, path, text):
- self.LogMessage(' >>> Fixup file reference MdePkg/Include/Library/UefiApplicationEntryPoint.h at file %s \n' % path)
- lines = text.split('\n')
- bInModuleEntry = False
- bInEfiMain = False
- ModuleEntryDlCount = 0
- ModuleEntryDelStart = 0
- ModuleEntryDelEnd = 0
- EfiMainDlCount = 0
- EfiMainDelStart = 0
- EfiMainDelEnd = 0
-
- for index in range(len(lines)):
- line = lines[index].strip()
- if line.find('EFI_STATUS</a> EFIAPI _ModuleEntryPoint </td>') != -1:
- bInModuleEntry = True
- if line.find('EFI_STATUS</a> EFIAPI EfiMain </td>') != -1:
- bInEfiMain = True
- if line.startswith('<p>References <a'):
- if bInModuleEntry:
- ModuleEntryDelEnd = index - 1
- bInModuleEntry = False
- elif bInEfiMain:
- EfiMainDelEnd = index - 1
- bInEfiMain = False
- if bInModuleEntry:
- if line.startswith('</dl>'):
- ModuleEntryDlCount = ModuleEntryDlCount + 1
- if ModuleEntryDlCount == 1:
- ModuleEntryDelStart = index + 1
- if bInEfiMain:
- if line.startswith('</dl>'):
- EfiMainDlCount = EfiMainDlCount + 1
- if EfiMainDlCount == 1:
- EfiMainDelStart = index + 1
-
- if EfiMainDelEnd > EfiMainDelStart:
- for index in range(EfiMainDelEnd, EfiMainDelStart, -1):
- del lines[index]
- if ModuleEntryDelEnd > ModuleEntryDelStart:
- for index in range(ModuleEntryDelEnd, ModuleEntryDelStart, -1):
- del lines[index]
-
- try:
- f = open(path, 'w')
- f.write('\n'.join(lines))
- f.close()
- except:
- self._isBusy = False
- self.LogMessage(" <<< Fail to fixup file %s" % path)
- self.LogMessage(" <<< Finish to fixup file %s\n" % path)
-
-
- def FixDoxFileLink(self, path, text):
- self.LogMessage(' >>> Fixup .dox postfix for file %s \n' % path)
- try:
- fd = open(path, 'r')
- text = fd.read()
- fd.close()
- except Exception as e:
- self.LogMessage (" <<<Fail to open file %s" % path)
- return
- text = text.replace ('.s.dox', '.s')
- text = text.replace ('.S.dox', '.S')
- text = text.replace ('.asm.dox', '.asm')
- text = text.replace ('.Asm.dox', '.Asm')
- text = text.replace ('.uni.dox', '.uni')
- text = text.replace ('.Uni.dox', '.Uni')
- try:
- fd = open(path, 'w')
- fd.write(text)
- fd.close()
- except Exception as e:
- self.LogMessage (" <<<Fail to fixup file %s" % path)
- return
- self.LogMessage(' >>> Finish to fixup .dox postfix for file %s \n' % path)
-
- def FixDecDoxygenFileLink(self, path, text):
- self.LogMessage(' >>> Fixup .decdoxygen postfix for file %s \n' % path)
- try:
- fd = open(path, 'r')
- lines = fd.readlines()
- fd.close()
- except Exception as e:
- self.LogMessage (" <<<Fail to open file %s" % path)
- return
- for line in lines:
- if line.find('.decdoxygen') != -1:
- lines.remove(line)
- break
- try:
- fd = open(path, 'w')
- fd.write("".join(lines))
- fd.close()
- except Exception as e:
- self.LogMessage (" <<<Fail to fixup file %s" % path)
- return
- self.LogMessage(' >>> Finish to fixup .decdoxygen postfix for file %s \n' % path)
-
-import threading
-class MonitorThread(threading.Thread):
- def __init__(self, pipe, callback):
- threading.Thread.__init__(self)
- self._pipe = pipe
- self._callback = callback
- self._isCancel = False
-
- def run(self):
- while (not self._isCancel):
- self._pipe.Peek()
- if self._pipe.LastRead() == 0:
- break
- text = self._pipe.read()
- if len(text.strip()) != 0:
- wx.GetApp().ForegroundProcess(self._callback, (text,))
-
- def Terminate(self):
- self._pipe.flush()
- self._isCancel = True
-
-class DoxygenProcess(wx.Process):
- def OnTerminate(self, id, status):
- self._parent.OnTerminateDoxygenProcess()
-
- def SetParent(self, parent):
- self._parent = parent
-
-class CHMProcess(wx.Process):
- def OnTerminate(self, id, status):
- self._parent.OnTerminateCHMProcess()
-
- def SetParent(self, parent):
- self._parent = parent
-
-class ResultHandler:
- def __init__(self, parent):
- self._parent = parent
- self.level = 0
-
- def emit(self, record):
- self._parent.LogMessage(record)
-
- def handle(self, record):
- wx.PostEvent(self._parent, LogEvent(message=record.getMessage()))
-
- def acquire(self):
- pass
-
- def release(self):
- pass
-
-if __name__ == '__main__':
- app = PackageDocApp(redirect=False)
- app.MainLoop()
+## @file +# This file is used to define common string related functions used in parsing +# process +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +import os, sys, wx, logging + +import wx.stc +import wx.lib.newevent +import wx.lib.agw.genericmessagedialog as GMD +from plugins.EdkPlugins.edk2.model import baseobject +from plugins.EdkPlugins.edk2.model import doxygengen + +if hasattr(sys, "frozen"): + appPath = os.path.abspath(os.path.dirname(sys.executable)) +else: + appPath = os.path.abspath(os.path.dirname(__file__)) + +AppCallBackEvent, EVT_APP_CALLBACK = wx.lib.newevent.NewEvent() +LogEvent, EVT_LOG = wx.lib.newevent.NewEvent() + +class PackageDocApp(wx.App): + + def OnInit(self): + logfile = os.path.join(appPath, 'log.txt') + logging.basicConfig(format='%(name)-8s %(levelname)-8s %(message)s', + filename=logfile, level=logging.ERROR) + + self.SetAppName('Package Doxygen Generate Application') + frame = PackageDocMainFrame(None, "Package Document Generation Application!") + self.SetTopWindow(frame) + + frame.Show(True) + + EVT_APP_CALLBACK( self, self.OnAppCallBack) + return True + + def GetLogger(self): + return logging.getLogger('') + + def ForegroundProcess(self, function, args): + wx.PostEvent(self, AppCallBackEvent(callback=function, args=args)) + + def OnAppCallBack(self, event): + try: + event.callback(*event.args) + except: + self._logger.exception( 'OnAppCallBack<%s.%s>\n' % + (event.callback.__module__, event.callback.__name__ )) + +class PackageDocMainFrame(wx.Frame): + def __init__(self, parent, title): + wx.Frame.__init__(self, parent, -1, title, size=(550, 290), style=wx.MINIMIZE_BOX|wx.SYSTEM_MENU|wx.CAPTION|wx.CLOSE_BOX ) + + panel = wx.Panel(self) + sizer = wx.BoxSizer(wx.VERTICAL) + + subsizer = wx.GridBagSizer(5, 10) + subsizer.AddGrowableCol(1) + subsizer.Add(wx.StaticText(panel, -1, "Workspace Location : "), (0, 0), flag=wx.ALIGN_CENTER_VERTICAL) + self._workspacePathCtrl = wx.ComboBox(panel, -1) + list = self.GetConfigure("WorkspacePath") + if len(list) != 0: + for item in list: + self._workspacePathCtrl.Append(item) + self._workspacePathCtrl.SetValue(list[len(list) - 1]) + + subsizer.Add(self._workspacePathCtrl, (0, 1), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND) + self._workspacePathBt = wx.BitmapButton(panel, -1, bitmap=wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN)) + subsizer.Add(self._workspacePathBt, (0, 2), flag=wx.ALIGN_CENTER_VERTICAL) + wx.EVT_BUTTON(self._workspacePathBt, self._workspacePathBt.GetId(), self.OnBrowsePath) + + subsizer.Add(wx.StaticText(panel, -1, "Package DEC Location : "), (1, 0), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND) + self._packagePathCtrl = wx.ComboBox(panel, -1) + list = self.GetConfigure("PackagePath") + if len(list) != 0: + for item in list: + self._packagePathCtrl.Append(item) + self._packagePathCtrl.SetValue(list[len(list) - 1]) + subsizer.Add(self._packagePathCtrl, (1, 1), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND) + self._packagePathBt = wx.BitmapButton(panel, -1, bitmap=wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN)) + subsizer.Add(self._packagePathBt, (1, 2), flag=wx.ALIGN_CENTER_VERTICAL) + wx.EVT_BUTTON(self._packagePathBt, self._packagePathBt.GetId(), self.OnBrowsePath) + + subsizer.Add(wx.StaticText(panel, -1, "Doxygen Tool Location : "), (2, 0), flag=wx.ALIGN_CENTER_VERTICAL) + self._doxygenPathCtrl = wx.TextCtrl(panel, -1) + list = self.GetConfigure('DoxygenPath') + if len(list) != 0: + self._doxygenPathCtrl.SetValue(list[0]) + else: + if wx.Platform == '__WXMSW__': + self._doxygenPathCtrl.SetValue('C:\\Program Files\\Doxygen\\bin\\doxygen.exe') + else: + self._doxygenPathCtrl.SetValue('/usr/bin/doxygen') + + self._doxygenPathBt = wx.BitmapButton(panel, -1, bitmap=wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN)) + subsizer.Add(self._doxygenPathCtrl, (2, 1), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND) + subsizer.Add(self._doxygenPathBt, (2, 2), flag=wx.ALIGN_CENTER_VERTICAL) + wx.EVT_BUTTON(self._doxygenPathBt, self._doxygenPathBt.GetId(), self.OnBrowsePath) + + subsizer.Add(wx.StaticText(panel, -1, "CHM Tool Location : "), (3, 0), flag=wx.ALIGN_CENTER_VERTICAL) + self._chmPathCtrl = wx.TextCtrl(panel, -1) + list = self.GetConfigure('CHMPath') + if len(list) != 0: + self._chmPathCtrl.SetValue(list[0]) + else: + self._chmPathCtrl.SetValue('C:\\Program Files\\HTML Help Workshop\\hhc.exe') + + self._chmPathBt = wx.BitmapButton(panel, -1, bitmap=wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN)) + subsizer.Add(self._chmPathCtrl, (3, 1), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND) + subsizer.Add(self._chmPathBt, (3, 2), flag=wx.ALIGN_CENTER_VERTICAL) + wx.EVT_BUTTON(self._chmPathBt, self._chmPathBt.GetId(), self.OnBrowsePath) + + subsizer.Add(wx.StaticText(panel, -1, "Output Location : "), (4, 0), flag=wx.ALIGN_CENTER_VERTICAL) + self._outputPathCtrl = wx.ComboBox(panel, -1) + list = self.GetConfigure("OutputPath") + if len(list) != 0: + for item in list: + self._outputPathCtrl.Append(item) + self._outputPathCtrl.SetValue(list[len(list) - 1]) + + subsizer.Add(self._outputPathCtrl, (4, 1), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND) + self._outputPathBt = wx.BitmapButton(panel, -1, bitmap=wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN)) + subsizer.Add(self._outputPathBt, (4, 2), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND) + wx.EVT_BUTTON(self._outputPathBt, self._outputPathBt.GetId(), self.OnBrowsePath) + + subsizer.Add(wx.StaticText(panel, -1, "Architecture Specified : "), (5, 0), flag=wx.ALIGN_CENTER_VERTICAL) + self._archCtrl = wx.ComboBox(panel, -1, value='ALL', choices=['ALL', 'IA32/MSFT', 'IA32/GNU', 'X64/INTEL', 'X64/GNU', 'IPF/MSFT', 'IPF/GNU', 'EBC/INTEL'], + style=wx.CB_READONLY) + self._archCtrl.Bind(wx.EVT_COMBOBOX, self.OnArchtectureSelectChanged) + subsizer.Add(self._archCtrl, (5, 1), (1, 2), flag=wx.ALIGN_CENTER_VERTICAL|wx.EXPAND) + sizer.Add(subsizer, 0, wx.EXPAND|wx.TOP|wx.BOTTOM|wx.LEFT|wx.RIGHT, 5) + + sizer6 = wx.BoxSizer(wx.HORIZONTAL) + self._modesel = wx.RadioBox(panel, -1, 'Generated Document Mode', majorDimension=2, choices=['CHM', 'HTML'], style=wx.RA_SPECIFY_COLS) + self._modesel.SetStringSelection('HTML') + + self._includeonlysel = wx.CheckBox(panel, -1, 'Only document public include') + + sizer6.Add(self._modesel, 0 , wx.EXPAND) + sizer6.Add(self._includeonlysel, 0, wx.EXPAND|wx.LEFT, 5) + + sizer.Add(sizer6, 0, wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, 5) + + self._generateBt = wx.Button(panel, -1, "Generate Package Document!") + self._generateBt.Bind(wx.EVT_BUTTON, self.OnGenerate) + sizer.Add(self._generateBt, 0, wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, 5) + + panel.SetSizer(sizer) + panel.Layout() + panel.SetAutoLayout(True) + self.CenterOnScreen() + + def SaveConfigure(self, name, value): + if value ==None or len(value) == 0: + return + config = wx.ConfigBase_Get() + oldvalues = config.Read(name, '').split(';') + if len(oldvalues) >= 10: + oldvalues.remove(oldvalues[0]) + if value not in oldvalues: + oldvalues.append(value) + else: + oldvalues.remove(value) + oldvalues.append(value) + + config.Write(name, ';'.join(oldvalues)) + + def GetConfigure(self, name): + config = wx.ConfigBase_Get() + values = config.Read(name, '').split(';') + list = [] + for item in values: + if len(item) != 0: + list.append(item) + return list + + def OnBrowsePath(self, event): + id = event.GetId() + editctrl = None + startdir = '' + isFile = False + if id == self._packagePathBt.GetId(): + dlgTitle = "Choose package path:" + editctrl = self._packagePathCtrl + isFile = True + if os.path.exists(self.GetWorkspace()): + startdir = self.GetWorkspace() + elif id == self._workspacePathBt.GetId(): + dlgTitle = "Choose workspace path:" + editctrl = self._workspacePathCtrl + startdir = editctrl.GetValue() + elif id == self._doxygenPathBt.GetId(): + isFile = True + dlgTitle = "Choose doxygen installation path:" + editctrl = self._doxygenPathCtrl + startdir = editctrl.GetValue() + elif id == self._outputPathBt.GetId(): + dlgTitle = "Choose document output path:" + editctrl = self._outputPathCtrl + if os.path.exists(self.GetWorkspace()): + startdir = self.GetWorkspace() + startdir = editctrl.GetValue() + elif id == self._chmPathBt.GetId(): + isFile = True + dlgTitle = "Choose installation path for Microsoft HTML workshop software" + editctrl = self._chmPathCtrl + startdir = editctrl.GetValue() + else: + return + + if not isFile: + dlg = wx.DirDialog(self, dlgTitle, defaultPath=startdir) + else: + dlg = wx.FileDialog(self, dlgTitle, defaultDir=startdir) + + if dlg.ShowModal() == wx.ID_OK: + editctrl.SetValue(dlg.GetPath()) + dlg.Destroy() + + def OnArchtectureSelectChanged(self, event): + str = '' + selarch = self._archCtrl.GetValue() + if selarch == 'ALL': + str += 'MDE_CPU_IA32 MDE_CPU_X64 MDE_CPU_EBC MDE_CPU_IPF _MSC_EXTENSIONS __GNUC__ __INTEL_COMPILER' + elif selarch == 'IA32/MSFT': + str += 'MDE_CPU_IA32 _MSC_EXTENSIONS' + elif selarch == 'IA32/GNU': + str += 'MDE_CPU_IA32 __GNUC__' + elif selarch == 'X64/MSFT': + str += 'MDE_CPU_X64 _MSC_EXTENSIONS' + elif selarch == 'X64/GNU': + str += 'MDE_CPU_X64 __GNUC__' + elif selarch == 'IPF/MSFT': + str += 'MDE_CPU_IPF _MSC_EXTENSIONS' + elif selarch == 'IPF/GNU': + str += 'MDE_CPU_IPF __GNUC__' + elif selarch == 'EBC/INTEL': + str += 'MDE_CPU_EBC __INTEL_COMPILER' + + str += ' ASM_PFX= OPTIONAL= ' + + def OnMacroText(self, event): + str = '' + selarch = self._archCtrl.GetValue() + if selarch == 'ALL': + str += 'MDE_CPU_IA32 MDE_CPU_X64 MDE_CPU_EBC MDE_CPU_IPF _MSC_EXTENSIONS __GNUC__ __INTEL_COMPILER' + elif selarch == 'IA32/MSFT': + str += 'MDE_CPU_IA32 _MSC_EXTENSIONS' + elif selarch == 'IA32/GNU': + str += 'MDE_CPU_IA32 __GNUC__' + elif selarch == 'X64/MSFT': + str += 'MDE_CPU_X64 _MSC_EXTENSIONS' + elif selarch == 'X64/GNU': + str += 'MDE_CPU_X64 __GNUC__' + elif selarch == 'IPF/MSFT': + str += 'MDE_CPU_IPF _MSC_EXTENSIONS' + elif selarch == 'IPF/GNU': + str += 'MDE_CPU_IPF __GNUC__' + elif selarch == 'EBC/INTEL': + str += 'MDE_CPU_EBC __INTEL_COMPILER' + + str += ' ASM_PFX= OPTIONAL= ' + + def OnGenerate(self, event): + if not self.CheckInput(): return + + dlg = ProgressDialog(self) + dlg.ShowModal() + dlg.Destroy() + + def CheckInput(self): + pPath = self.GetPackagePath() + wPath = self.GetWorkspace() + dPath = self.GetDoxygenToolPath() + cPath = self.GetChmToolPath() + oPath = self.GetOutputPath() + + if len(wPath) == 0 or not os.path.exists(wPath): + self._Error("Please input existing workspace path!") + return False + else: + self.SaveConfigure('WorkspacePath', wPath) + + if len(pPath) == 0 or not os.path.exists(pPath) or not pPath.lower().endswith('.dec'): + self._Error("Please input existing package file location!") + return False + elif pPath.lower().find(wPath.lower()) == -1: + self._Error("Package patch should starts with workspace path, such as if workspace path is c:\\edk2, package patch could be c:\\edk2\MdePkg") + return False + else: + self.SaveConfigure('PackagePath', pPath) + + if len(dPath) == 0 or not os.path.exists(dPath): + self._Error("Can not find doxygen tool from path %s! Please download it from www.stack.nl/~dimitri/doxygen/download.html" % dPath) + return False + else: + self.SaveConfigure('DoxygenPath', dPath) + + if self._modesel.GetStringSelection() == 'CHM': + if (len(cPath) == 0 or not os.path.exists(cPath)): + self._Error("You select CHM mode to generate document, but can not find software of Microsoft HTML Help Workshop.\nPlease\ + download it from http://www.microsoft.com/downloads/details.aspx?FamilyID=00535334-c8a6-452f-9aa0-d597d16580cc&displaylang=en\n\ +and install!") + return False + else: + self.SaveConfigure('CHMPath', cPath) + + if len(oPath) == 0: + self._Error("You must specific document output path") + return False + else: + self.SaveConfigure('OutputPath', oPath) + + if os.path.exists(oPath): + # add checking whether there is old doxygen config file here + files = os.listdir(oPath) + for file in files: + if os.path.isfile(os.path.join(oPath,file)): + basename, ext = os.path.splitext(file) + if ext.lower() == '.doxygen_config': + dlg = GMD.GenericMessageDialog(self, "Existing doxygen document in output directory will be overwritten\n, Are you sure?", + "Info", wx.ICON_WARNING|wx.YES_NO) + if dlg.ShowModal() == wx.ID_YES: + break + else: + return False + else: + try: + os.makedirs(oPath) + except: + self._Error("Fail to create output directory, please select another output directory!") + return False + + return True + + def _Error(self, message): + dlg = GMD.GenericMessageDialog(self, message, + "Error", wx.ICON_ERROR|wx.OK) + dlg.ShowModal() + dlg.Destroy() + + def GetWorkspace(self): + return os.path.normpath(self._workspacePathCtrl.GetValue()) + + def GetPackagePath(self): + return os.path.normpath(self._packagePathCtrl.GetValue()) + + def GetOutputPath(self): + return os.path.normpath(self._outputPathCtrl.GetValue()) + + def GetDoxygenToolPath(self): + return os.path.normpath(self._doxygenPathCtrl.GetValue()) + + def GetChmToolPath(self): + return os.path.normpath(self._chmPathCtrl.GetValue()) + + def GetDocumentMode(self): + return self._modesel.GetStringSelection() + + def GetArchitecture(self): + value = self._archCtrl.GetValue() + return value.split('/')[0] + + def GetToolTag(self): + value = self._archCtrl.GetValue() + if value == 'ALL': + return 'ALL' + return value.split('/')[1] + + def GetIsOnlyDocumentInclude(self): + return self._includeonlysel.IsChecked() + +class ProgressDialog(wx.Dialog): + def __init__(self, parent, id=wx.ID_ANY): + title = "Generate Document for " + parent.GetPackagePath() + wx.Dialog.__init__(self, parent, id, title=title, style=wx.CAPTION, size=(600, 300)) + self.Freeze() + sizer = wx.BoxSizer(wx.VERTICAL) + self._textCtrl = wx.StaticText(self, -1, "Start launching!") + self._gaugeCtrl = wx.Gauge(self, -1, 100, size=(-1, 10)) + self._resultCtrl = wx.stc.StyledTextCtrl(self, -1) + self._closeBt = wx.Button(self, -1, "Close") + self._gotoOuputBt = wx.Button(self, -1, "Goto Output") + + # clear all margin + self._resultCtrl.SetMarginWidth(0, 0) + self._resultCtrl.SetMarginWidth(1, 0) + self._resultCtrl.SetMarginWidth(2, 0) + + sizer.Add(self._textCtrl, 0, wx.EXPAND|wx.LEFT|wx.TOP|wx.RIGHT, 5) + sizer.Add(self._gaugeCtrl, 0, wx.EXPAND|wx.LEFT|wx.TOP|wx.RIGHT, 5) + sizer.Add(self._resultCtrl, 1, wx.EXPAND|wx.LEFT|wx.TOP|wx.RIGHT, 5) + btsizer = wx.BoxSizer(wx.HORIZONTAL) + btsizer.Add(self._gotoOuputBt, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.LEFT|wx.TOP|wx.LEFT|wx.BOTTOM, 5) + btsizer.Add(self._closeBt, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.LEFT|wx.TOP|wx.LEFT|wx.BOTTOM, 5) + sizer.Add(btsizer, 0, wx.ALIGN_CENTER_HORIZONTAL) + + self.SetSizer(sizer) + self.CenterOnScreen() + self.Thaw() + + self._logger = logging.getLogger('') + self._loghandle = ResultHandler(self) + logging.getLogger('edk').addHandler(self._loghandle) + logging.getLogger('').addHandler(self._loghandle) + logging.getLogger('app').addHandler(self._loghandle) + + wx.EVT_BUTTON(self._closeBt, self._closeBt.GetId(), self.OnButtonClose) + wx.EVT_UPDATE_UI(self, self._closeBt.GetId(), self.OnUpdateCloseButton) + wx.EVT_BUTTON(self._gotoOuputBt, self._gotoOuputBt.GetId(), self.OnGotoOutput) + EVT_LOG(self, self.OnPostLog) + + self._process = None + self._pid = None + self._input = None + self._output = None + self._error = None + self._inputThread = None + self._errorThread = None + self._isBusy = True + self._pObj = None + + wx.CallAfter(self.GenerateAction) + + def OnUpdateCloseButton(self, event): + self._closeBt.Enable(not self._isBusy) + return True + + def OnButtonClose(self, event): + if self._isBusy: + self._InfoDialog("Please don't close in progressing...") + return + + if self._process != None: + self._process.CloseOutput() + + if self._inputThread: + self._inputThread.Terminate() + if self._errorThread: + self._errorThread.Terminate() + + if self._pid != None: + wx.Process.Kill(self._pid, wx.SIGKILL, wx.KILL_CHILDREN) + + logging.getLogger('edk').removeHandler(self._loghandle) + logging.getLogger('').removeHandler(self._loghandle) + logging.getLogger('app').removeHandler(self._loghandle) + + if self._pObj != None: + self._pObj.Destroy() + + self.EndModal(0) + + def OnGotoOutput(self, event): + output = self.GetParent().GetOutputPath() + if os.path.exists(output): + if wx.Platform == '__WXMSW__': + os.startfile(self.GetParent().GetOutputPath()) + else: + import webbrowser + webbrowser.open(self.GetParent().GetOutputPath()) + else: + self._ErrorDialog("Output directory does not exist!") + + def _ErrorDialog(self, message): + dlg = GMD.GenericMessageDialog(self, message, + "Error", wx.ICON_ERROR|wx.OK) + dlg.ShowModal() + dlg.Destroy() + + def _InfoDialog(self, message): + dlg = GMD.GenericMessageDialog(self, message, + "Info", wx.ICON_INFORMATION|wx.OK) + dlg.ShowModal() + dlg.Destroy() + + def _LogStep(self, index, message): + stepstr = "Step %d: %s" % (index, message) + self._textCtrl.SetLabel(stepstr) + self.LogMessage(os.linesep + stepstr + os.linesep) + self._gaugeCtrl.SetValue(index * 100 / 6 ) + + def OnPostLog(self, event): + self.LogMessage(event.message) + + def GenerateAction(self): + self._LogStep(1, "Create Package Object Model") + wsPath = self.GetParent().GetWorkspace() + pkPath = self.GetParent().GetPackagePath()[len(wsPath) + 1:] + + try: + pObj = baseobject.Package(None, self.GetParent().GetWorkspace()) + pObj.Load(pkPath) + except: + self._ErrorDialog("Fail to create package object model! Please check log.txt under this application folder!") + self._isBusy = False + return + self._pObj = pObj + + self.LogMessage(str(pObj.GetPcds())) + + self._LogStep(2, "Preprocess and Generate Doxygen Config File") + try: + action = doxygengen.PackageDocumentAction(self.GetParent().GetDoxygenToolPath(), + self.GetParent().GetChmToolPath(), + self.GetParent().GetOutputPath(), + pObj, + self.GetParent().GetDocumentMode(), + self.LogMessage, + self.GetParent().GetArchitecture(), + self.GetParent().GetToolTag(), + self.GetParent().GetIsOnlyDocumentInclude(), + True) + except: + self._ErrorDialog("Fail to preprocess! Please check log.txt under this application folder!") + self._isBusy = False + return + + action.RegisterCallbackDoxygenProcess(self.CreateDoxygeProcess) + + try: + if not action.Generate(): + self._isBusy = False + self.LogMessage("Fail to generate package document! Please check log.txt under this application folder!", 'error') + except: + import traceback + message = traceback.format_exception(*sys.exc_info()) + logging.getLogger('').error(''.join(message)) + self._isBusy = False + self._ErrorDialog("Fail to generate package document! Please check log.txt under this application folder!") + + def LogMessage(self, message, level='info'): + self._resultCtrl.DocumentEnd() + self._resultCtrl.SetReadOnly(False) + self._resultCtrl.AppendText(message) + self._resultCtrl.Home() + self._resultCtrl.Home() + self._resultCtrl.SetReadOnly(True) + if level == 'error': + wx.GetApp().GetLogger().error(message) + + def CreateDoxygeProcess(self, doxPath, configFile): + self._LogStep(3, "Launch Doxygen Tool and Generate Package Document") + + cmd = '"%s" %s' % (doxPath, configFile) + try: + self._process = DoxygenProcess() + self._process.SetParent(self) + self._process.Redirect() + self._pid = wx.Execute(cmd, wx.EXEC_ASYNC, self._process) + self._input = self._process.GetInputStream() + self._output = self._process.GetOutputStream() + self._error = self._process.GetErrorStream() + except: + self._ErrorDialog('Fail to launch doxygen cmd %s! Please check log.txt under this application folder!' % cmd) + self._isBusy = False + return False + + self._inputThread = MonitorThread(self._input, self.LogMessage) + self._errorThread = MonitorThread(self._error, self.LogMessage) + self._inputThread.start() + self._errorThread.start() + return True + + def OnTerminateDoxygenProcess(self): + if self._inputThread: + self._inputThread.Terminate() + self._inputThread = None + if self._errorThread: + self._errorThread.Terminate() + self._errorThread = None + + if self._error: + while self._error.CanRead(): + text = self._error.read() + self.LogMessage(text) + + if self._input: + while self._input.CanRead(): + text = self._input.read() + self.LogMessage(text) + self._process.Detach() + + self._process.CloseOutput() + self._process = None + self._pid = None + + self.DocumentFixup() + + if self.GetParent().GetDocumentMode().lower() == 'chm': + hhcfile = os.path.join(self.GetParent().GetOutputPath(), 'html', 'index.hhc') + hhpfile = os.path.join(self.GetParent().GetOutputPath(), 'html', 'index.hhp') + self.FixDecDoxygenFileLink(hhcfile, None) + if not self.CreateCHMProcess(self.GetParent().GetChmToolPath(), hhpfile): + self._ErrorDialog("Fail to Create %s process for %s" % (self.GetParent().GetChmToolPath(), hhpfile)) + self._isBusy = False + else: + self._LogStep(6, "Finished Document Generation!") + self._isBusy = False + indexpath = os.path.realpath(os.path.join(self.GetParent().GetOutputPath(), 'html', 'index.html')) + if wx.Platform == '__WXMSW__': + os.startfile(indexpath) + else: + import webbrowser + webbrowser.open(indexpath) + + self._InfoDialog('Success create HTML doxgen document %s' % indexpath) + + def CreateCHMProcess(self, chmPath, hhpfile): + self.LogMessage(" >>>>>> Start Microsoft HTML workshop process...Zzz...\n") + cmd = '"%s" %s' % (chmPath, hhpfile) + try: + self._process = CHMProcess() + self._process.SetParent(self) + self._process.Redirect() + self._pid = wx.Execute(cmd, wx.EXEC_ASYNC, self._process) + self._input = self._process.GetInputStream() + self._output = self._process.GetOutputStream() + self._error = self._process.GetErrorStream() + except: + self.LogMessage('\nFail to launch hhp cmd %s!\n' % cmd) + self._isBusy = False + return False + self._inputThread = MonitorThread(self._input, self.LogMessage) + self._errorThread = MonitorThread(self._error, self.LogMessage) + self._inputThread.start() + self._errorThread.start() + return True + + def OnTerminateCHMProcess(self): + if self._inputThread: + self._inputThread.Terminate() + self._inputThread = None + if self._errorThread: + self._errorThread.Terminate() + self._errorThread = None + + if self._error: + while self._error.CanRead(): + text = self._error.read() + self.LogMessage(text) + if self._input: + while self._input.CanRead(): + text = self._input.read() + self.LogMessage(text) + self._process.Detach() + + self._process.CloseOutput() + self._process = None + self._pid = None + self._isBusy = False + indexpath = os.path.realpath(os.path.join(self.GetParent().GetOutputPath(), 'html', 'index.chm')) + if os.path.exists(indexpath): + if wx.Platform == '__WXMSW__': + os.startfile(indexpath) + else: + import webbrowser + webbrowser.open(indexpath) + + self._LogStep(6, "Finished Document Generation!") + self.LogMessage('\nSuccess create CHM doxgen document %s\n' % indexpath) + self._InfoDialog('Success create CHM doxgen document %s' % indexpath) + + def DocumentFixup(self): + # find BASE_LIBRARY_JUMP_BUFFER structure reference page + self._LogStep(4, "Fixup Package Document!") + self.LogMessage('\n >>> Start fixup document \n') + + for root, dirs, files in os.walk(os.path.join(self.GetParent().GetOutputPath(), 'html')): + for dir in dirs: + if dir.lower() in ['.svn', '_svn', 'cvs']: + dirs.remove(dir) + for file in files: + wx.YieldIfNeeded() + if not file.lower().endswith('.html'): continue + fullpath = os.path.join(self.GetParent().GetOutputPath(), root, file) + try: + f = open(fullpath, 'r') + text = f.read() + f.close() + except: + self.LogMessage('\nFail to open file %s\n' % fullpath) + continue + if text.find('BASE_LIBRARY_JUMP_BUFFER Struct Reference') != -1 and self.GetParent().GetArchitecture() == 'ALL': + self.FixPageBASE_LIBRARY_JUMP_BUFFER(fullpath, text) + if text.find('MdePkg/Include/Library/BaseLib.h File Reference') != -1 and self.GetParent().GetArchitecture() == 'ALL': + self.FixPageBaseLib(fullpath, text) + if text.find('IA32_IDT_GATE_DESCRIPTOR Union Reference') != -1 and self.GetParent().GetArchitecture() == 'ALL': + self.FixPageIA32_IDT_GATE_DESCRIPTOR(fullpath, text) + if text.find('MdePkg/Include/Library/UefiDriverEntryPoint.h File Reference') != -1: + self.FixPageUefiDriverEntryPoint(fullpath, text) + if text.find('MdePkg/Include/Library/UefiApplicationEntryPoint.h File Reference') != -1: + self.FixPageUefiApplicationEntryPoint(fullpath, text) + if text.lower().find('.s.dox') != -1 or \ + text.lower().find('.asm.dox') != -1 or \ + text.lower().find('.uni.dox') != -1: + self.FixDoxFileLink(fullpath, text) + + self.RemoveFileList() + self.LogMessage(' >>> Finish all document fixing up! \n') + + def RemoveFileList(self): + path_html = os.path.join(self.GetParent().GetOutputPath(), "html", "tree.html") + path_chm = os.path.join(self.GetParent().GetOutputPath(), "html", "index.hhc") + if os.path.exists(path_html): + self.LogMessage(' >>>Remove FileList item from generated HTML document.\n'); + lines = [] + f = open (path_html, "r") + lines = f.readlines() + f.close() + bfound = False + for index in range(len(lines)): + if lines[index].find('<a class="el" href="files.html" target="basefrm">File List</a>') != -1: + lines[index] = "<!-- %s" % lines[index] + bfound = True + continue + if bfound: + if lines[index].find('</div>') != -1: + lines[index] = "%s -->" % lines[index] + break + if bfound: + f = open(path_html, "w") + f.write("".join(lines)) + f.close() + else: + self.LogMessage (' !!!Can not found FileList item in HTML document!\n') + + if os.path.exists(path_chm): + self.LogMessage(" >>>Warning: Can not remove FileList for CHM files!\n"); + """ + self.LogMessage(' >>>Remove FileList item from generated CHM document!\n'); + lines = [] + f = open (path_chm, "r") + lines = f.readlines() + f.close() + bfound = False + for index in xrange(len(lines)): + if not bfound: + if lines[index].find('<param name="Local" value="files.html">') != -1: + lines[index] = '<!-- %s' % lines[index] + bfound = True + continue + if bfound: + if lines[index].find('</UL>') != -1: + lines[index] = '%s -->\n' % lines[index].rstrip() + break + if bfound: + f = open(path_chm, "w") + f.write("".join(lines)) + f.close() + import time + time.sleep(2) + else: + self.LogMessage(' !!!Can not found the FileList item in CHM document!') + """ + def FixPageBaseLib(self, path, text): + self.LogMessage(' >>> Fixup BaseLib file page at file %s \n' % path) + lines = text.split('\n') + lastBaseJumpIndex = -1 + lastIdtGateDescriptor = -1 + for index in range(len(lines) - 1, -1, -1): + line = lines[index] + if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 4 </td>': + lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 4 [IA32] </td>' + if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 0x10 </td>': + lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 0x10 [IPF] </td>' + if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 8 </td>': + lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 9 [EBC, x64] </td>' + if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 4') != -1: + lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 4', + 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 4 [IA32]') + if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 0x10') != -1: + lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 0x10', + 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 0x10 [IPF]') + if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 8') != -1: + lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 8', + 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a> 8 [x64, EBC]') + if line.find('>BASE_LIBRARY_JUMP_BUFFER</a>') != -1: + if lastBaseJumpIndex != -1: + del lines[lastBaseJumpIndex] + lastBaseJumpIndex = index + if line.find('>IA32_IDT_GATE_DESCRIPTOR</a></td>') != -1: + if lastIdtGateDescriptor != -1: + del lines[lastIdtGateDescriptor] + lastIdtGateDescriptor = index + try: + f = open(path, 'w') + f.write('\n'.join(lines)) + f.close() + except: + self._isBusy = False + self.LogMessage(" <<< Fail to fixup file %s\n" % path) + self.LogMessage(" <<< Finish to fixup file %s\n" % path) + + def FixPageIA32_IDT_GATE_DESCRIPTOR(self, path, text): + self.LogMessage(' >>> Fixup structure reference IA32_IDT_GATE_DESCRIPTOR at file %s \n' % path) + lines = text.split('\n') + for index in range(len(lines) - 1, -1, -1): + line = lines[index].strip() + if line.find('struct {</td>') != -1 and lines[index - 2].find('>Uint64</a></td>') != -1: + lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>') + if line.find('struct {</td>') != -1 and lines[index - 1].find('Data Fields') != -1: + lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>') + try: + f = open(path, 'w') + f.write('\n'.join(lines)) + f.close() + except: + self._isBusy = False + self.LogMessage(" <<< Fail to fixup file %s\n" % path) + self.LogMessage(" <<< Finish to fixup file %s\n" % path) + + def FixPageBASE_LIBRARY_JUMP_BUFFER(self, path, text): + self.LogMessage(' >>> Fixup structure reference BASE_LIBRARY_JUMP_BUFFER at file %s \n' % path) + lines = text.split('\n') + bInDetail = True + bNeedRemove = False + for index in range(len(lines) - 1, -1, -1): + line = lines[index] + if line.find('Detailed Description') != -1: + bInDetail = False + if line.startswith('EBC context buffer used by') and lines[index - 1].startswith('x64 context buffer'): + lines[index] = "IA32/IPF/X64/" + line + bNeedRemove = True + if line.startswith("x64 context buffer") or line.startswith('IPF context buffer used by') or \ + line.startswith('IA32 context buffer used by'): + if bNeedRemove: + lines.remove(line) + if line.find('>R0</a>') != -1 and not bInDetail: + if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For EBC</h2></td></tr>': + lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For EBC</h2></td></tr>') + if line.find('>Rbx</a>') != -1 and not bInDetail: + if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>': + lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>') + if line.find('>F2</a>') != -1 and not bInDetail: + if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For IPF</h2></td></tr>': + lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IPF</h2></td></tr>') + if line.find('>Ebx</a>') != -1 and not bInDetail: + if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>': + lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>') + try: + f = open(path, 'w') + f.write('\n'.join(lines)) + f.close() + except: + self._isBusy = False + self.LogMessage(" <<< Fail to fixup file %s" % path) + self.LogMessage(" <<< Finish to fixup file %s\n" % path) + + def FixPageUefiDriverEntryPoint(self, path, text): + self.LogMessage(' >>> Fixup file reference MdePkg/Include/Library/UefiDriverEntryPoint.h at file %s \n' % path) + lines = text.split('\n') + bInModuleEntry = False + bInEfiMain = False + ModuleEntryDlCount = 0 + ModuleEntryDelStart = 0 + ModuleEntryDelEnd = 0 + EfiMainDlCount = 0 + EfiMainDelStart = 0 + EfiMainDelEnd = 0 + + for index in range(len(lines)): + line = lines[index].strip() + if line.find('EFI_STATUS</a> EFIAPI _ModuleEntryPoint </td>') != -1: + bInModuleEntry = True + if line.find('EFI_STATUS</a> EFIAPI EfiMain </td>') != -1: + bInEfiMain = True + if line.startswith('<p>References <a'): + if bInModuleEntry: + ModuleEntryDelEnd = index - 1 + bInModuleEntry = False + elif bInEfiMain: + EfiMainDelEnd = index - 1 + bInEfiMain = False + if bInModuleEntry: + if line.startswith('</dl>'): + ModuleEntryDlCount = ModuleEntryDlCount + 1 + if ModuleEntryDlCount == 1: + ModuleEntryDelStart = index + 1 + if bInEfiMain: + if line.startswith('</dl>'): + EfiMainDlCount = EfiMainDlCount + 1 + if EfiMainDlCount == 1: + EfiMainDelStart = index + 1 + + if EfiMainDelEnd > EfiMainDelStart: + for index in range(EfiMainDelEnd, EfiMainDelStart, -1): + del lines[index] + if ModuleEntryDelEnd > ModuleEntryDelStart: + for index in range(ModuleEntryDelEnd, ModuleEntryDelStart, -1): + del lines[index] + + try: + f = open(path, 'w') + f.write('\n'.join(lines)) + f.close() + except: + self._isBusy = False + self.LogMessage(" <<< Fail to fixup file %s" % path) + self.LogMessage(" <<< Finish to fixup file %s\n" % path) + + def FixPageUefiApplicationEntryPoint(self, path, text): + self.LogMessage(' >>> Fixup file reference MdePkg/Include/Library/UefiApplicationEntryPoint.h at file %s \n' % path) + lines = text.split('\n') + bInModuleEntry = False + bInEfiMain = False + ModuleEntryDlCount = 0 + ModuleEntryDelStart = 0 + ModuleEntryDelEnd = 0 + EfiMainDlCount = 0 + EfiMainDelStart = 0 + EfiMainDelEnd = 0 + + for index in range(len(lines)): + line = lines[index].strip() + if line.find('EFI_STATUS</a> EFIAPI _ModuleEntryPoint </td>') != -1: + bInModuleEntry = True + if line.find('EFI_STATUS</a> EFIAPI EfiMain </td>') != -1: + bInEfiMain = True + if line.startswith('<p>References <a'): + if bInModuleEntry: + ModuleEntryDelEnd = index - 1 + bInModuleEntry = False + elif bInEfiMain: + EfiMainDelEnd = index - 1 + bInEfiMain = False + if bInModuleEntry: + if line.startswith('</dl>'): + ModuleEntryDlCount = ModuleEntryDlCount + 1 + if ModuleEntryDlCount == 1: + ModuleEntryDelStart = index + 1 + if bInEfiMain: + if line.startswith('</dl>'): + EfiMainDlCount = EfiMainDlCount + 1 + if EfiMainDlCount == 1: + EfiMainDelStart = index + 1 + + if EfiMainDelEnd > EfiMainDelStart: + for index in range(EfiMainDelEnd, EfiMainDelStart, -1): + del lines[index] + if ModuleEntryDelEnd > ModuleEntryDelStart: + for index in range(ModuleEntryDelEnd, ModuleEntryDelStart, -1): + del lines[index] + + try: + f = open(path, 'w') + f.write('\n'.join(lines)) + f.close() + except: + self._isBusy = False + self.LogMessage(" <<< Fail to fixup file %s" % path) + self.LogMessage(" <<< Finish to fixup file %s\n" % path) + + + def FixDoxFileLink(self, path, text): + self.LogMessage(' >>> Fixup .dox postfix for file %s \n' % path) + try: + fd = open(path, 'r') + text = fd.read() + fd.close() + except Exception as e: + self.LogMessage (" <<<Fail to open file %s" % path) + return + text = text.replace ('.s.dox', '.s') + text = text.replace ('.S.dox', '.S') + text = text.replace ('.asm.dox', '.asm') + text = text.replace ('.Asm.dox', '.Asm') + text = text.replace ('.uni.dox', '.uni') + text = text.replace ('.Uni.dox', '.Uni') + try: + fd = open(path, 'w') + fd.write(text) + fd.close() + except Exception as e: + self.LogMessage (" <<<Fail to fixup file %s" % path) + return + self.LogMessage(' >>> Finish to fixup .dox postfix for file %s \n' % path) + + def FixDecDoxygenFileLink(self, path, text): + self.LogMessage(' >>> Fixup .decdoxygen postfix for file %s \n' % path) + try: + fd = open(path, 'r') + lines = fd.readlines() + fd.close() + except Exception as e: + self.LogMessage (" <<<Fail to open file %s" % path) + return + for line in lines: + if line.find('.decdoxygen') != -1: + lines.remove(line) + break + try: + fd = open(path, 'w') + fd.write("".join(lines)) + fd.close() + except Exception as e: + self.LogMessage (" <<<Fail to fixup file %s" % path) + return + self.LogMessage(' >>> Finish to fixup .decdoxygen postfix for file %s \n' % path) + +import threading +class MonitorThread(threading.Thread): + def __init__(self, pipe, callback): + threading.Thread.__init__(self) + self._pipe = pipe + self._callback = callback + self._isCancel = False + + def run(self): + while (not self._isCancel): + self._pipe.Peek() + if self._pipe.LastRead() == 0: + break + text = self._pipe.read() + if len(text.strip()) != 0: + wx.GetApp().ForegroundProcess(self._callback, (text,)) + + def Terminate(self): + self._pipe.flush() + self._isCancel = True + +class DoxygenProcess(wx.Process): + def OnTerminate(self, id, status): + self._parent.OnTerminateDoxygenProcess() + + def SetParent(self, parent): + self._parent = parent + +class CHMProcess(wx.Process): + def OnTerminate(self, id, status): + self._parent.OnTerminateCHMProcess() + + def SetParent(self, parent): + self._parent = parent + +class ResultHandler: + def __init__(self, parent): + self._parent = parent + self.level = 0 + + def emit(self, record): + self._parent.LogMessage(record) + + def handle(self, record): + wx.PostEvent(self._parent, LogEvent(message=record.getMessage())) + + def acquire(self): + pass + + def release(self): + pass + +if __name__ == '__main__': + app = PackageDocApp(redirect=False) + app.MainLoop() diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/__init__.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/__init__.py index 57dfebde59..a7909346f3 100644 --- a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/__init__.py +++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/__init__.py @@ -1,6 +1,6 @@ -## @file
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
+## @file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/__init__.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/__init__.py index 57dfebde59..a7909346f3 100644 --- a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/__init__.py +++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/__init__.py @@ -1,6 +1,6 @@ -## @file
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
+## @file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/doxygen.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/doxygen.py index a8f87751a0..b3198d5bc9 100644 --- a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/doxygen.py +++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/doxygen.py @@ -1,445 +1,445 @@ -## @file
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-
-from __future__ import print_function
-from __future__ import absolute_import
-import os
-
-from .message import *
-
-class BaseDoxygeItem:
- def __init__(self, name, tag=''):
- self.mName = name
- self.mTag = tag
- self.mDescription = ''
- self.mText = []
-
- def AddDescription(self, desc):
- self.mDescription = '%s%s' % (self.mDescription, desc)
-
- def __str__(self):
- return '\n'.join(self.mText)
-
- def Generate(self):
- """This interface need to be override"""
-
-class Section(BaseDoxygeItem):
- def Generate(self):
- """This interface need to be override"""
- if len(self.mTag) != 0:
- self.mText.append(' \section %s %s' % (self.mName, self.mTag))
- else:
- self.mText.append(' \section %s' % self.mName)
-
- self.mText.append(self.mDescription)
- return self.mText
-
-class Page(BaseDoxygeItem):
- def __init__(self, name, tag=None, isSort=True):
- BaseDoxygeItem.__init__(self, name, tag)
- self.mSubPages = []
- self.mIsMainPage = False
- self.mSections = []
- self.mIsSort = isSort
-
- def GetSubpageCount(self):
- return len(self.mSubPages)
-
- def AddPage(self, subpage):
- self.mSubPages.append(subpage)
- return subpage
-
- def AddPages(self, pageArray):
- if pageArray is None:
- return
- for page in pageArray:
- self.AddPage(page)
-
- def AddSection(self, section):
- self.mSections.append(section)
- self.mSections.sort(key=lambda x: x.mName.lower())
-
- def Generate(self):
- if self.mIsMainPage:
- self.mText.append('/** \mainpage %s' % self.mName)
- self.mIsSort = False
- else:
- self.mText.append('/** \page %s %s' % (self.mTag, self.mName))
-
- if len(self.mDescription) != 0:
- self.mText.append(self.mDescription)
- endIndex = len(self.mText)
-
- self.mSections.sort(key=lambda x: x.mName.lower())
- for sect in self.mSections:
- self.mText += sect.Generate()
-
- endIndex = len(self.mText)
-
- if len(self.mSubPages) != 0:
- self.mText.insert(endIndex, "<p> \section content_index INDEX")
- endIndex = len(self.mText)
- self.mText.insert(endIndex, '<ul>')
- endIndex += 1
- if self.mIsSort:
- self.mSubPages.sort(key=lambda x: x.mName.lower())
- for page in self.mSubPages:
- self.mText.insert(endIndex, '<li>\subpage %s \"%s\" </li>' % (page.mTag, page.mName))
- endIndex += 1
- self.mText += page.Generate()
- self.mText.insert(endIndex, '</ul>')
- endIndex += 1
- self.mText.insert(endIndex, ' **/')
- return self.mText
-
-class DoxygenFile(Page):
- def __init__(self, name, file):
- Page.__init__(self, name)
- self.mFilename = file
- self.mIsMainPage = True
-
- def GetFilename(self):
- return self.mFilename.replace('/', '\\')
-
- def Save(self):
- str = self.Generate()
- try:
- f = open(self.mFilename, 'w')
- f.write('\n'.join(str))
- f.close()
- except IOError as e:
- ErrorMsg ('Fail to write file %s' % self.mFilename)
- return False
-
- return True
-
-doxygenConfigTemplate = """
-DOXYFILE_ENCODING = UTF-8
-PROJECT_NAME = %(ProjectName)s
-PROJECT_NUMBER = %(ProjectVersion)s
-OUTPUT_DIRECTORY = %(OutputDir)s
-CREATE_SUBDIRS = YES
-OUTPUT_LANGUAGE = English
-BRIEF_MEMBER_DESC = YES
-REPEAT_BRIEF = YES
-ABBREVIATE_BRIEF = "The $name class " \\
- "The $name widget " \\
- "The $name file " \\
- is \\
- provides \\
- specifies \\
- contains \\
- represents \\
- a \\
- an \\
- the
-ALWAYS_DETAILED_SEC = NO
-INLINE_INHERITED_MEMB = NO
-FULL_PATH_NAMES = YES
-STRIP_FROM_PATH = %(StripPath)s
-STRIP_FROM_INC_PATH =
-SHORT_NAMES = YES
-JAVADOC_AUTOBRIEF = NO
-QT_AUTOBRIEF = NO
-MULTILINE_CPP_IS_BRIEF = NO
-DETAILS_AT_TOP = YES
-INHERIT_DOCS = YES
-SEPARATE_MEMBER_PAGES = NO
-TAB_SIZE = 1
-ALIASES =
-OPTIMIZE_OUTPUT_FOR_C = YES
-OPTIMIZE_OUTPUT_JAVA = NO
-BUILTIN_STL_SUPPORT = NO
-CPP_CLI_SUPPORT = NO
-SIP_SUPPORT = NO
-DISTRIBUTE_GROUP_DOC = YES
-SUBGROUPING = YES
-TYPEDEF_HIDES_STRUCT = NO
-
-EXTRACT_ALL = YES
-EXTRACT_PRIVATE = NO
-EXTRACT_STATIC = NO
-EXTRACT_LOCAL_CLASSES = NO
-EXTRACT_LOCAL_METHODS = NO
-EXTRACT_ANON_NSPACES = NO
-HIDE_UNDOC_MEMBERS = NO
-HIDE_UNDOC_CLASSES = NO
-HIDE_FRIEND_COMPOUNDS = NO
-HIDE_IN_BODY_DOCS = NO
-INTERNAL_DOCS = NO
-CASE_SENSE_NAMES = NO
-HIDE_SCOPE_NAMES = NO
-SHOW_INCLUDE_FILES = NO
-INLINE_INFO = YES
-SORT_MEMBER_DOCS = YES
-SORT_BRIEF_DOCS = NO
-SORT_BY_SCOPE_NAME = YES
-GENERATE_TODOLIST = YES
-GENERATE_TESTLIST = YES
-GENERATE_BUGLIST = YES
-GENERATE_DEPRECATEDLIST= YES
-ENABLED_SECTIONS =
-MAX_INITIALIZER_LINES = 30
-SHOW_USED_FILES = NO
-SHOW_DIRECTORIES = NO
-FILE_VERSION_FILTER =
-
-QUIET = NO
-WARNINGS = YES
-WARN_IF_UNDOCUMENTED = YES
-WARN_IF_DOC_ERROR = YES
-WARN_NO_PARAMDOC = YES
-WARN_FORMAT = "$file:$line: $text "
-WARN_LOGFILE = %(WarningFile)s
-
-INPUT = %(FileList)s
-INPUT_ENCODING = UTF-8
-FILE_PATTERNS = %(Pattern)s
-RECURSIVE = NO
-EXCLUDE = *.svn
-EXCLUDE_SYMLINKS = NO
-EXCLUDE_PATTERNS = .svn
-EXCLUDE_SYMBOLS =
-EXAMPLE_PATH = %(ExamplePath)s
-EXAMPLE_PATTERNS = *
-EXAMPLE_RECURSIVE = NO
-IMAGE_PATH =
-INPUT_FILTER =
-FILTER_PATTERNS =
-FILTER_SOURCE_FILES = NO
-
-SOURCE_BROWSER = NO
-INLINE_SOURCES = NO
-STRIP_CODE_COMMENTS = YES
-REFERENCED_BY_RELATION = YES
-REFERENCES_RELATION = YES
-REFERENCES_LINK_SOURCE = NO
-USE_HTAGS = NO
-VERBATIM_HEADERS = NO
-
-ALPHABETICAL_INDEX = NO
-COLS_IN_ALPHA_INDEX = 5
-IGNORE_PREFIX =
-
-GENERATE_HTML = YES
-HTML_OUTPUT = html
-HTML_FILE_EXTENSION = .html
-HTML_HEADER =
-HTML_FOOTER =
-HTML_STYLESHEET =
-HTML_ALIGN_MEMBERS = YES
-GENERATE_HTMLHELP = %(WhetherGenerateHtmlHelp)s
-HTML_DYNAMIC_SECTIONS = NO
-CHM_FILE = index.chm
-HHC_LOCATION =
-GENERATE_CHI = NO
-BINARY_TOC = NO
-TOC_EXPAND = NO
-DISABLE_INDEX = NO
-ENUM_VALUES_PER_LINE = 4
-GENERATE_TREEVIEW = %(WhetherGenerateTreeView)s
-TREEVIEW_WIDTH = 250
-
-GENERATE_LATEX = NO
-LATEX_OUTPUT = latex
-LATEX_CMD_NAME = latex
-MAKEINDEX_CMD_NAME = makeindex
-COMPACT_LATEX = NO
-PAPER_TYPE = a4wide
-EXTRA_PACKAGES =
-LATEX_HEADER =
-PDF_HYPERLINKS = YES
-USE_PDFLATEX = YES
-LATEX_BATCHMODE = NO
-LATEX_HIDE_INDICES = NO
-
-GENERATE_RTF = NO
-RTF_OUTPUT = rtf
-COMPACT_RTF = NO
-RTF_HYPERLINKS = NO
-RTF_STYLESHEET_FILE =
-RTF_EXTENSIONS_FILE =
-
-GENERATE_MAN = NO
-MAN_OUTPUT = man
-MAN_EXTENSION = .3
-MAN_LINKS = NO
-
-GENERATE_XML = NO
-XML_OUTPUT = xml
-XML_SCHEMA =
-XML_DTD =
-XML_PROGRAMLISTING = YES
-
-GENERATE_AUTOGEN_DEF = NO
-
-GENERATE_PERLMOD = NO
-PERLMOD_LATEX = NO
-PERLMOD_PRETTY = YES
-PERLMOD_MAKEVAR_PREFIX =
-
-ENABLE_PREPROCESSING = YES
-MACRO_EXPANSION = YES
-EXPAND_ONLY_PREDEF = YES
-SEARCH_INCLUDES = YES
-INCLUDE_PATH = %(IncludePath)s
-INCLUDE_FILE_PATTERNS = *.h
-PREDEFINED = %(PreDefined)s
-EXPAND_AS_DEFINED =
-SKIP_FUNCTION_MACROS = NO
-
-TAGFILES =
-GENERATE_TAGFILE =
-ALLEXTERNALS = NO
-EXTERNAL_GROUPS = YES
-PERL_PATH = /usr/bin/perl
-
-CLASS_DIAGRAMS = NO
-MSCGEN_PATH =
-HIDE_UNDOC_RELATIONS = YES
-HAVE_DOT = NO
-CLASS_GRAPH = YES
-COLLABORATION_GRAPH = YES
-GROUP_GRAPHS = YES
-UML_LOOK = NO
-TEMPLATE_RELATIONS = NO
-INCLUDE_GRAPH = YES
-INCLUDED_BY_GRAPH = YES
-CALL_GRAPH = NO
-CALLER_GRAPH = NO
-GRAPHICAL_HIERARCHY = YES
-DIRECTORY_GRAPH = YES
-DOT_IMAGE_FORMAT = png
-DOT_PATH =
-DOTFILE_DIRS =
-DOT_GRAPH_MAX_NODES = 50
-MAX_DOT_GRAPH_DEPTH = 1000
-DOT_TRANSPARENT = YES
-DOT_MULTI_TARGETS = NO
-GENERATE_LEGEND = YES
-DOT_CLEANUP = YES
-
-SEARCHENGINE = NO
-
-"""
-class DoxygenConfigFile:
- def __init__(self):
- self.mProjectName = ''
- self.mOutputDir = ''
- self.mFileList = []
- self.mIncludeList = []
- self.mStripPath = ''
- self.mExamplePath = ''
- self.mPattern = ['*.c', '*.h',
- '*.asm', '*.s', '.nasm', '*.html', '*.dox']
- self.mMode = 'HTML'
- self.mWarningFile = ''
- self.mPreDefined = []
- self.mProjectVersion = 0.1
-
- def SetChmMode(self):
- self.mMode = 'CHM'
-
- def SetHtmlMode(self):
- self.mMode = 'HTML'
-
- def SetProjectName(self, str):
- self.mProjectName = str
-
- def SetProjectVersion(self, str):
- self.mProjectVersion = str
-
- def SetOutputDir(self, str):
- self.mOutputDir = str
-
- def SetStripPath(self, str):
- self.mStripPath = str
-
- def SetExamplePath(self, str):
- self.mExamplePath = str
-
- def SetWarningFilePath(self, str):
- self.mWarningFile = str.replace('\\', '/')
-
- def FileExists(self, path):
- if path is None:
- return False
- if len(path) == 0:
- return False
-
- for p in self.mFileList:
- if path.lower() == p.lower():
- return True
-
- return False
-
- def AddFile(self, path):
- if path is None:
- return
-
- if len(path) == 0:
- return
- path = path.replace('\\', '/')
- if not self.FileExists(path):
- self.mFileList.append(path)
-
- def AddIncludePath(self, path):
- path = path.replace('\\', '/')
- if path not in self.mIncludeList:
- self.mIncludeList.append(path)
-
- def AddPattern(self, pattern):
- self.mPattern.append(pattern)
-
- def AddPreDefined(self, macro):
- self.mPreDefined.append(macro)
-
- def Generate(self, path):
- files = ' \\\n'.join(self.mFileList)
- includes = ' \\\n'.join(self.mIncludeList)
- patterns = ' \\\n'.join(self.mPattern)
- if self.mMode.lower() == 'html':
- sHtmlHelp = 'NO'
- sTreeView = 'YES'
- else:
- sHtmlHelp = 'YES'
- sTreeView = 'NO'
-
- text = doxygenConfigTemplate % {'ProjectName':self.mProjectName,
- 'OutputDir':self.mOutputDir,
- 'StripPath':self.mStripPath,
- 'ExamplePath':self.mExamplePath,
- 'FileList':files,
- 'Pattern':patterns,
- 'WhetherGenerateHtmlHelp':sHtmlHelp,
- 'WhetherGenerateTreeView':sTreeView,
- 'IncludePath':includes,
- 'WarningFile':self.mWarningFile,
- 'PreDefined':' '.join(self.mPreDefined),
- 'ProjectVersion':self.mProjectVersion}
- try:
- f = open(path, 'w')
- f.write(text)
- f.close()
- except IOError as e:
- ErrorMsg ('Fail to generate doxygen config file %s' % path)
- return False
-
- return True
-
-########################################################################
-# TEST CODE
-########################################################################
-if __name__== '__main__':
- df = DoxygenFile('Platform Document', 'm:\tree')
- df.AddPage(Page('Module', 'module'))
- p = df.AddPage(Page('Library', 'library'))
- p.AddDescription(desc)
- p.AddPage(Page('PCD', 'pcds'))
-
- df.Generate()
- print(df)
+## @file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +from __future__ import print_function +from __future__ import absolute_import +import os + +from .message import * + +class BaseDoxygeItem: + def __init__(self, name, tag=''): + self.mName = name + self.mTag = tag + self.mDescription = '' + self.mText = [] + + def AddDescription(self, desc): + self.mDescription = '%s%s' % (self.mDescription, desc) + + def __str__(self): + return '\n'.join(self.mText) + + def Generate(self): + """This interface need to be override""" + +class Section(BaseDoxygeItem): + def Generate(self): + """This interface need to be override""" + if len(self.mTag) != 0: + self.mText.append(' \section %s %s' % (self.mName, self.mTag)) + else: + self.mText.append(' \section %s' % self.mName) + + self.mText.append(self.mDescription) + return self.mText + +class Page(BaseDoxygeItem): + def __init__(self, name, tag=None, isSort=True): + BaseDoxygeItem.__init__(self, name, tag) + self.mSubPages = [] + self.mIsMainPage = False + self.mSections = [] + self.mIsSort = isSort + + def GetSubpageCount(self): + return len(self.mSubPages) + + def AddPage(self, subpage): + self.mSubPages.append(subpage) + return subpage + + def AddPages(self, pageArray): + if pageArray is None: + return + for page in pageArray: + self.AddPage(page) + + def AddSection(self, section): + self.mSections.append(section) + self.mSections.sort(key=lambda x: x.mName.lower()) + + def Generate(self): + if self.mIsMainPage: + self.mText.append('/** \mainpage %s' % self.mName) + self.mIsSort = False + else: + self.mText.append('/** \page %s %s' % (self.mTag, self.mName)) + + if len(self.mDescription) != 0: + self.mText.append(self.mDescription) + endIndex = len(self.mText) + + self.mSections.sort(key=lambda x: x.mName.lower()) + for sect in self.mSections: + self.mText += sect.Generate() + + endIndex = len(self.mText) + + if len(self.mSubPages) != 0: + self.mText.insert(endIndex, "<p> \section content_index INDEX") + endIndex = len(self.mText) + self.mText.insert(endIndex, '<ul>') + endIndex += 1 + if self.mIsSort: + self.mSubPages.sort(key=lambda x: x.mName.lower()) + for page in self.mSubPages: + self.mText.insert(endIndex, '<li>\subpage %s \"%s\" </li>' % (page.mTag, page.mName)) + endIndex += 1 + self.mText += page.Generate() + self.mText.insert(endIndex, '</ul>') + endIndex += 1 + self.mText.insert(endIndex, ' **/') + return self.mText + +class DoxygenFile(Page): + def __init__(self, name, file): + Page.__init__(self, name) + self.mFilename = file + self.mIsMainPage = True + + def GetFilename(self): + return self.mFilename.replace('/', '\\') + + def Save(self): + str = self.Generate() + try: + f = open(self.mFilename, 'w') + f.write('\n'.join(str)) + f.close() + except IOError as e: + ErrorMsg ('Fail to write file %s' % self.mFilename) + return False + + return True + +doxygenConfigTemplate = """ +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = %(ProjectName)s +PROJECT_NUMBER = %(ProjectVersion)s +OUTPUT_DIRECTORY = %(OutputDir)s +CREATE_SUBDIRS = YES +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class " \\ + "The $name widget " \\ + "The $name file " \\ + is \\ + provides \\ + specifies \\ + contains \\ + represents \\ + a \\ + an \\ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = %(StripPath)s +STRIP_FROM_INC_PATH = +SHORT_NAMES = YES +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = YES +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 1 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = YES +SUBGROUPING = YES +TYPEDEF_HIDES_STRUCT = NO + +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = NO +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = YES +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = NO +SHOW_DIRECTORIES = NO +FILE_VERSION_FILTER = + +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = YES +WARN_FORMAT = "$file:$line: $text " +WARN_LOGFILE = %(WarningFile)s + +INPUT = %(FileList)s +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = %(Pattern)s +RECURSIVE = NO +EXCLUDE = *.svn +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = .svn +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = %(ExamplePath)s +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO + +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +REFERENCES_LINK_SOURCE = NO +USE_HTAGS = NO +VERBATIM_HEADERS = NO + +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = + +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = %(WhetherGenerateHtmlHelp)s +HTML_DYNAMIC_SECTIONS = NO +CHM_FILE = index.chm +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = %(WhetherGenerateTreeView)s +TREEVIEW_WIDTH = 250 + +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO + +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = + +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO + +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES + +GENERATE_AUTOGEN_DEF = NO + +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = + +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +SEARCH_INCLUDES = YES +INCLUDE_PATH = %(IncludePath)s +INCLUDE_FILE_PATTERNS = *.h +PREDEFINED = %(PreDefined)s +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = NO + +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl + +CLASS_DIAGRAMS = NO +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = YES +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES + +SEARCHENGINE = NO + +""" +class DoxygenConfigFile: + def __init__(self): + self.mProjectName = '' + self.mOutputDir = '' + self.mFileList = [] + self.mIncludeList = [] + self.mStripPath = '' + self.mExamplePath = '' + self.mPattern = ['*.c', '*.h', + '*.asm', '*.s', '.nasm', '*.html', '*.dox'] + self.mMode = 'HTML' + self.mWarningFile = '' + self.mPreDefined = [] + self.mProjectVersion = 0.1 + + def SetChmMode(self): + self.mMode = 'CHM' + + def SetHtmlMode(self): + self.mMode = 'HTML' + + def SetProjectName(self, str): + self.mProjectName = str + + def SetProjectVersion(self, str): + self.mProjectVersion = str + + def SetOutputDir(self, str): + self.mOutputDir = str + + def SetStripPath(self, str): + self.mStripPath = str + + def SetExamplePath(self, str): + self.mExamplePath = str + + def SetWarningFilePath(self, str): + self.mWarningFile = str.replace('\\', '/') + + def FileExists(self, path): + if path is None: + return False + if len(path) == 0: + return False + + for p in self.mFileList: + if path.lower() == p.lower(): + return True + + return False + + def AddFile(self, path): + if path is None: + return + + if len(path) == 0: + return + path = path.replace('\\', '/') + if not self.FileExists(path): + self.mFileList.append(path) + + def AddIncludePath(self, path): + path = path.replace('\\', '/') + if path not in self.mIncludeList: + self.mIncludeList.append(path) + + def AddPattern(self, pattern): + self.mPattern.append(pattern) + + def AddPreDefined(self, macro): + self.mPreDefined.append(macro) + + def Generate(self, path): + files = ' \\\n'.join(self.mFileList) + includes = ' \\\n'.join(self.mIncludeList) + patterns = ' \\\n'.join(self.mPattern) + if self.mMode.lower() == 'html': + sHtmlHelp = 'NO' + sTreeView = 'YES' + else: + sHtmlHelp = 'YES' + sTreeView = 'NO' + + text = doxygenConfigTemplate % {'ProjectName':self.mProjectName, + 'OutputDir':self.mOutputDir, + 'StripPath':self.mStripPath, + 'ExamplePath':self.mExamplePath, + 'FileList':files, + 'Pattern':patterns, + 'WhetherGenerateHtmlHelp':sHtmlHelp, + 'WhetherGenerateTreeView':sTreeView, + 'IncludePath':includes, + 'WarningFile':self.mWarningFile, + 'PreDefined':' '.join(self.mPreDefined), + 'ProjectVersion':self.mProjectVersion} + try: + f = open(path, 'w') + f.write(text) + f.close() + except IOError as e: + ErrorMsg ('Fail to generate doxygen config file %s' % path) + return False + + return True + +######################################################################## +# TEST CODE +######################################################################## +if __name__== '__main__': + df = DoxygenFile('Platform Document', 'm:\tree') + df.AddPage(Page('Module', 'module')) + p = df.AddPage(Page('Library', 'library')) + p.AddDescription(desc) + p.AddPage(Page('PCD', 'pcds')) + + df.Generate() + print(df) diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/efibinary.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/efibinary.py index 1bc4938bfc..44ab75114b 100644 --- a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/efibinary.py +++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/efibinary.py @@ -1,606 +1,606 @@ -## @file
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-
-from __future__ import print_function
-import array
-import uuid
-import re
-import os
-import logging
-import core.pe as pe
-
-def GetLogger():
- return logging.getLogger('EFI Binary File')
-
-class EFIBinaryError(Exception):
- def __init__(self, message):
- Exception.__init__(self)
- self._message = message
-
- def GetMessage(self):
- return self._message
-
-class EfiFd(object):
- EFI_FV_HEADER_SIZE = 0x48
-
- def __init__(self):
- self._fvs = []
-
- def Load(self, fd, size):
- index = fd.tell()
- while (index + self.EFI_FV_HEADER_SIZE < size):
- fv = EfiFv(self)
- fv.Load(fd)
- self._fvs.append(fv)
- index += fv.GetHeader().GetFvLength()
- index = align(index, 8)
- fd.seek(index)
-
- def GetFvs(self):
- return self._fvs
-
-class EfiFv(object):
- FILE_SYSTEM_GUID = uuid.UUID('{8c8ce578-8a3d-4f1c-9935-896185c32dd3}')
-
- def __init__(self, parent=None):
- self._size = 0
- self._filename = None
- self._fvheader = None
- self._blockentries = []
- self._ffs = []
-
- # following field is for FV in FD
- self._parent = parent
- self._offset = 0
- self._raw = array.array('B')
-
- def Load(self, fd):
- self._offset = fd.tell()
- self._filename = fd.name
-
- # get file header
- self._fvheader = EfiFirmwareVolumeHeader.Read(fd)
- #self._fvheader.Dump()
-
- self._size = self._fvheader.GetFvLength()
-
- if self._fvheader.GetFileSystemGuid() != self.FILE_SYSTEM_GUID:
- fd.seek(self._offset)
- self._raw.fromfile(fd, self.GetHeader().GetFvLength())
- return
-
- # read block map
- blockentry = BlockMapEntry.Read(fd)
- self._blockentries.append(blockentry)
- while (blockentry.GetNumberBlocks() != 0 and blockentry.GetLength() != 0):
- self._blockentries.append(blockentry)
- blockentry = BlockMapEntry.Read(fd)
-
-
- if self._fvheader.GetSize() + (len(self._blockentries)) * 8 != \
- self._fvheader.GetHeaderLength():
- raise EFIBinaryError("Volume Header length not consistent with block map!")
-
- index = align(fd.tell(), 8)
- count = 0
- while ((index + EfiFfs.FFS_HEADER_SIZE) < self._size):
- ffs = EfiFfs.Read(fd, self)
- if not isValidGuid(ffs.GetNameGuid()):
- break
- self._ffs.append(ffs)
- count += 1
- index = align(fd.tell(), 8)
-
- fd.seek(self._offset)
- self._raw.fromfile(fd, self.GetHeader().GetFvLength())
-
- def GetFfs(self):
- return self._ffs
-
- def GetHeader(self):
- return self._fvheader
-
- def GetBlockEntries(self):
- return self._blockentries
-
- def GetHeaderRawData(self):
- ret = []
- ret += self._fvheader.GetRawData()
- for block in self._blockentries:
- ret += block.GetRawData()
- return ret
-
- def GetOffset(self):
- return 0
-
- def GetRawData(self):
- return self._raw.tolist()
-
-class BinaryItem(object):
- def __init__(self, parent=None):
- self._size = 0
- self._arr = array.array('B')
- self._parent = parent
-
- @classmethod
- def Read(cls, fd, parent=None):
- item = cls(parent)
- item.fromfile(fd)
- return item
-
- def Load(self, fd):
- self.fromfile(fd)
-
- def GetSize(self):
- """should be implemented by inherited class"""
-
- def fromfile(self, fd):
- self._arr.fromfile(fd, self.GetSize())
-
- def GetParent(self):
- return self._parent
-
-class EfiFirmwareVolumeHeader(BinaryItem):
- def GetSize(self):
- return 56
-
- def GetSigunature(self):
- list = self._arr.tolist()
- sig = ''
- for x in list[40:44]:
- sig += chr(x)
- return sig
-
- def GetAttribute(self):
- return list2int(self._arr.tolist()[44:48])
-
- def GetErasePolarity(self):
- list = self.GetAttrStrings()
- if 'EFI_FVB2_ERASE_POLARITY' in list:
- return True
- return False
-
- def GetAttrStrings(self):
- list = []
- value = self.GetAttribute()
- if (value & 0x01) != 0:
- list.append('EFI_FVB2_READ_DISABLED_CAP')
- if (value & 0x02) != 0:
- list.append('EFI_FVB2_READ_ENABLED_CAP')
- if (value & 0x04) != 0:
- list.append('EFI_FVB2_READ_STATUS')
- if (value & 0x08) != 0:
- list.append('EFI_FVB2_WRITE_DISABLED_CAP')
- if (value & 0x10) != 0:
- list.append('EFI_FVB2_WRITE_ENABLED_CAP')
- if (value & 0x20) != 0:
- list.append('EFI_FVB2_WRITE_STATUS')
- if (value & 0x40) != 0:
- list.append('EFI_FVB2_LOCK_CAP')
- if (value & 0x80) != 0:
- list.append('EFI_FVB2_LOCK_STATUS')
- if (value & 0x200) != 0:
- list.append('EFI_FVB2_STICKY_WRITE')
- if (value & 0x400) != 0:
- list.append('EFI_FVB2_MEMORY_MAPPED')
- if (value & 0x800) != 0:
- list.append('EFI_FVB2_ERASE_POLARITY')
- if (value & 0x1000) != 0:
- list.append('EFI_FVB2_READ_LOCK_CAP')
- if (value & 0x00002000) != 0:
- list.append('EFI_FVB2_READ_LOCK_STATUS')
- if (value & 0x00004000) != 0:
- list.append('EFI_FVB2_WRITE_LOCK_CAP')
- if (value & 0x00008000) != 0:
- list.append('EFI_FVB2_WRITE_LOCK_STATUS')
-
- if (value == 0):
- list.append('EFI_FVB2_ALIGNMENT_1')
- if (value & 0x001F0000) == 0x00010000:
- list.append('EFI_FVB2_ALIGNMENT_2')
- if (value & 0x001F0000) == 0x00020000:
- list.append('EFI_FVB2_ALIGNMENT_4')
- if (value & 0x001F0000) == 0x00030000:
- list.append('EFI_FVB2_ALIGNMENT_8')
- if (value & 0x001F0000) == 0x00040000:
- list.append('EFI_FVB2_ALIGNMENT_16')
- if (value & 0x001F0000) == 0x00050000:
- list.append('EFI_FVB2_ALIGNMENT_32')
- if (value & 0x001F0000) == 0x00060000:
- list.append('EFI_FVB2_ALIGNMENT_64')
- if (value & 0x001F0000) == 0x00070000:
- list.append('EFI_FVB2_ALIGNMENT_128')
- if (value & 0x001F0000) == 0x00080000:
- list.append('EFI_FVB2_ALIGNMENT_256')
- if (value & 0x001F0000) == 0x00090000:
- list.append('EFI_FVB2_ALIGNMENT_512')
- if (value & 0x001F0000) == 0x000A0000:
- list.append('EFI_FVB2_ALIGNMENT_1K')
- if (value & 0x001F0000) == 0x000B0000:
- list.append('EFI_FVB2_ALIGNMENT_2K')
- if (value & 0x001F0000) == 0x000C0000:
- list.append('EFI_FVB2_ALIGNMENT_4K')
- if (value & 0x001F0000) == 0x000D0000:
- list.append('EFI_FVB2_ALIGNMENT_8K')
- if (value & 0x001F0000) == 0x000E0000:
- list.append('EFI_FVB2_ALIGNMENT_16K')
- if (value & 0x001F0000) == 0x000F0000:
- list.append('EFI_FVB2_ALIGNMENT_32K')
- if (value & 0x001F0000) == 0x00100000:
- list.append('EFI_FVB2_ALIGNMENT_64K')
- if (value & 0x001F0000) == 0x00110000:
- list.append('EFI_FVB2_ALIGNMENT_128K')
- if (value & 0x001F0000) == 0x00120000:
- list.append('EFI_FVB2_ALIGNMENT_256K')
- if (value & 0x001F0000) == 0x00130000:
- list.append('EFI_FVB2_ALIGNMENT_512K')
-
- return list
-
- def GetHeaderLength(self):
- return list2int(self._arr.tolist()[48:50])
-
- def Dump(self):
- print('Signature: %s' % self.GetSigunature())
- print('Attribute: 0x%X' % self.GetAttribute())
- print('Header Length: 0x%X' % self.GetHeaderLength())
- print('File system Guid: ', self.GetFileSystemGuid())
- print('Revision: 0x%X' % self.GetRevision())
- print('FvLength: 0x%X' % self.GetFvLength())
-
- def GetFileSystemGuid(self):
- list = self._arr.tolist()
- return list2guid(list[16:32])
-
- def GetRevision(self):
- list = self._arr.tolist()
- return int(list[55])
-
- def GetFvLength(self):
- list = self._arr.tolist()
- return list2int(list[32:40])
-
- def GetRawData(self):
- return self._arr.tolist()
-
-class BlockMapEntry(BinaryItem):
- def GetSize(self):
- return 8
-
- def GetNumberBlocks(self):
- list = self._arr.tolist()
- return list2int(list[0:4])
-
- def GetLength(self):
- list = self._arr.tolist()
- return list2int(list[4:8])
-
- def GetRawData(self):
- return self._arr.tolist()
-
- def __str__(self):
- return '[BlockEntry] Number = 0x%X, length=0x%X' % (self.GetNumberBlocks(), self.GetLength())
-
-class EfiFfs(object):
- FFS_HEADER_SIZE = 24
-
- def __init__(self, parent=None):
- self._header = None
-
- # following field is for FFS in FV file.
- self._parent = parent
- self._offset = 0
- self._sections = []
-
- def Load(self, fd):
- self._offset = align(fd.tell(), 8)
-
- self._header = EfiFfsHeader.Read(fd, self)
-
- if not isValidGuid(self.GetNameGuid()):
- return
-
- index = self._offset
- fileend = self._offset + self.GetSize()
- while (index + EfiSection.EFI_SECTION_HEADER_SIZE < fileend):
- section = EfiSection(self)
- section.Load(fd)
- if section.GetSize() == 0 and section.GetHeader().GetType() == 0:
- break
- self._sections.append(section)
- index = fd.tell()
-
- # rebase file pointer to next ffs file
- index = self._offset + self._header.GetFfsSize()
- index = align(index, 8)
- fd.seek(index)
-
- def GetOffset(self):
- return self._offset
-
- def GetSize(self):
- return self._header.GetFfsSize()
-
- @classmethod
- def Read(cls, fd, parent=None):
- item = cls(parent)
- item.Load(fd)
- return item
-
- def GetNameGuid(self):
- return self._header.GetNameGuid()
-
- def DumpContent(self):
- list = self._content.tolist()
- line = []
- count = 0
- for item in list:
- if count < 32:
- line.append('0x%X' % int(item))
- count += 1
- else:
- print(' '.join(line))
- count = 0
- line = []
- line.append('0x%X' % int(item))
- count += 1
-
- def GetHeader(self):
- return self._header
-
- def GetParent(self):
- return self._parent
-
- def GetSections(self):
- return self._sections
-
-class EfiFfsHeader(BinaryItem):
- ffs_state_map = {0x01:'EFI_FILE_HEADER_CONSTRUCTION',
- 0x02:'EFI_FILE_HEADER_VALID',
- 0x04:'EFI_FILE_DATA_VALID',
- 0x08:'EFI_FILE_MARKED_FOR_UPDATE',
- 0x10:'EFI_FILE_DELETED',
- 0x20:'EFI_FILE_HEADER_INVALID'}
-
- def GetSize(self):
- return 24
-
- def GetNameGuid(self):
- list = self._arr.tolist()
- return list2guid(list[0:16])
-
- def GetType(self):
- list = self._arr.tolist()
- return int(list[18])
-
-
- def GetTypeString(self):
- value = self.GetType()
- if value == 0x01:
- return 'EFI_FV_FILETYPE_RAW'
- if value == 0x02:
- return 'EFI_FV_FILETYPE_FREEFORM'
- if value == 0x03:
- return 'EFI_FV_FILETYPE_SECURITY_CORE'
- if value == 0x04:
- return 'EFI_FV_FILETYPE_PEI_CORE'
- if value == 0x05:
- return 'EFI_FV_FILETYPE_DXE_CORE'
- if value == 0x06:
- return 'EFI_FV_FILETYPE_PEIM'
- if value == 0x07:
- return 'EFI_FV_FILETYPE_DRIVER'
- if value == 0x08:
- return 'EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER'
- if value == 0x09:
- return 'EFI_FV_FILETYPE_APPLICATION'
- if value == 0x0B:
- return 'EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE'
- if value == 0xc0:
- return 'EFI_FV_FILETYPE_OEM_MIN'
- if value == 0xdf:
- return 'EFI_FV_FILETYPE_OEM_MAX'
- if value == 0xe0:
- return 'EFI_FV_FILETYPE_DEBUG_MIN'
- if value == 0xef:
- return 'EFI_FV_FILETYPE_DEBUG_MAX'
- if value == 0xf0:
- return 'EFI_FV_FILETYPE_FFS_PAD'
- if value == 0xff:
- return 'EFI_FV_FILETYPE_FFS_MAX'
- return 'Unknown FFS Type'
-
- def GetAttributes(self):
- list = self._arr.tolist()
- return int(list[19])
-
- def GetFfsSize(self):
- list = self._arr.tolist()
- return list2int(list[20:23])
-
- def GetState(self):
- list = self._arr.tolist()
- state = int(list[23])
- polarity = self.GetParent().GetParent().GetHeader().GetErasePolarity()
- if polarity:
- state = (~state) & 0xFF
- HighestBit = 0x80
- while (HighestBit != 0) and (HighestBit & state) == 0:
- HighestBit = HighestBit >> 1
- return HighestBit
-
- def GetStateString(self):
- state = self.GetState()
- if state in self.ffs_state_map.keys():
- return self.ffs_state_map[state]
- return 'Unknown Ffs State'
-
- def Dump(self):
- print("FFS name: ", self.GetNameGuid())
- print("FFS type: ", self.GetType())
- print("FFS attr: 0x%X" % self.GetAttributes())
- print("FFS size: 0x%X" % self.GetFfsSize())
- print("FFS state: 0x%X" % self.GetState())
-
- def GetRawData(self):
- return self._arr.tolist()
-
-
-class EfiSection(object):
- EFI_SECTION_HEADER_SIZE = 4
-
- def __init__(self, parent=None):
- self._size = 0
- self._parent = parent
- self._offset = 0
- self._contents = array.array('B')
-
- def Load(self, fd):
- self._offset = align(fd.tell(), 4)
-
- self._header = EfiSectionHeader.Read(fd, self)
-
- if self._header.GetTypeString() == "EFI_SECTION_PE32":
- pefile = pe.PEFile(self)
- pefile.Load(fd, self.GetContentSize())
-
- fd.seek(self._offset)
- self._contents.fromfile(fd, self.GetContentSize())
-
- # rebase file pointer to next section
- index = self._offset + self.GetSize()
- index = align(index, 4)
- fd.seek(index)
-
- def GetContentSize(self):
- return self.GetSize() - self.EFI_SECTION_HEADER_SIZE
-
- def GetContent(self):
- return self._contents.tolist()
-
- def GetSize(self):
- return self._header.GetSectionSize()
-
- def GetHeader(self):
- return self._header
-
- def GetSectionOffset(self):
- return self._offset + self.EFI_SECTION_HEADER_SIZE
-
-class EfiSectionHeader(BinaryItem):
- section_type_map = {0x01: 'EFI_SECTION_COMPRESSION',
- 0x02: 'EFI_SECTION_GUID_DEFINED',
- 0x10: 'EFI_SECTION_PE32',
- 0x11: 'EFI_SECTION_PIC',
- 0x12: 'EFI_SECTION_TE',
- 0x13: 'EFI_SECTION_DXE_DEPEX',
- 0x14: 'EFI_SECTION_VERSION',
- 0x15: 'EFI_SECTION_USER_INTERFACE',
- 0x16: 'EFI_SECTION_COMPATIBILITY16',
- 0x17: 'EFI_SECTION_FIRMWARE_VOLUME_IMAGE',
- 0x18: 'EFI_SECTION_FREEFORM_SUBTYPE_GUID',
- 0x19: 'EFI_SECTION_RAW',
- 0x1B: 'EFI_SECTION_PEI_DEPEX'}
- def GetSize(self):
- return 4
-
- def GetSectionSize(self):
- list = self._arr.tolist()
- return list2int(list[0:3])
-
- def GetType(self):
- list = self._arr.tolist()
- return int(list[3])
-
- def GetTypeString(self):
- type = self.GetType()
- if type not in self.section_type_map.keys():
- return 'Unknown Section Type'
- return self.section_type_map[type]
-
- def Dump(self):
- print('size = 0x%X' % self.GetSectionSize())
- print('type = 0x%X' % self.GetType())
-
-
-
-rMapEntry = re.compile('^(\w+)[ \(\w\)]* \(BaseAddress=([0-9a-fA-F]+), EntryPoint=([0-9a-fA-F]+), GUID=([0-9a-fA-F\-]+)')
-class EfiFvMapFile(object):
- def __init__(self):
- self._mapentries = {}
-
- def Load(self, path):
- if not os.path.exists(path):
- return False
-
- try:
- file = open(path, 'r')
- lines = file.readlines()
- file.close()
- except:
- return False
-
- for line in lines:
- if line[0] != ' ':
- # new entry
- ret = rMapEntry.match(line)
- if ret is not None:
- name = ret.groups()[0]
- baseaddr = int(ret.groups()[1], 16)
- entry = int(ret.groups()[2], 16)
- guidstr = '{' + ret.groups()[3] + '}'
- guid = uuid.UUID(guidstr)
- self._mapentries[guid] = EfiFvMapFileEntry(name, baseaddr, entry, guid)
- return True
-
- def GetEntry(self, guid):
- if guid in self._mapentries.keys():
- return self._mapentries[guid]
- return None
-
-class EfiFvMapFileEntry(object):
- def __init__(self, name, baseaddr, entry, guid):
- self._name = name
- self._baseaddr = baseaddr
- self._entry = entry
- self._guid = guid
-
- def GetName(self):
- return self._name
-
- def GetBaseAddress(self):
- return self._baseaddr
-
- def GetEntryPoint(self):
- return self._entry
-
-def list2guid(list):
- val1 = list2int(list[0:4])
- val2 = list2int(list[4:6])
- val3 = list2int(list[6:8])
- val4 = 0
- for item in list[8:16]:
- val4 = (val4 << 8) | int(item)
-
- val = val1 << 12 * 8 | val2 << 10 * 8 | val3 << 8 * 8 | val4
- guid = uuid.UUID(int=val)
- return guid
-
-def list2int(list):
- val = 0
- for index in range(len(list) - 1, -1, -1):
- val = (val << 8) | int(list[index])
- return val
-
-def align(value, alignment):
- return (value + ((alignment - value) & (alignment - 1)))
-
-gInvalidGuid = uuid.UUID(int=0xffffffffffffffffffffffffffffffff)
-def isValidGuid(guid):
- if guid == gInvalidGuid:
- return False
- return True
+## @file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +from __future__ import print_function +import array +import uuid +import re +import os +import logging +import core.pe as pe + +def GetLogger(): + return logging.getLogger('EFI Binary File') + +class EFIBinaryError(Exception): + def __init__(self, message): + Exception.__init__(self) + self._message = message + + def GetMessage(self): + return self._message + +class EfiFd(object): + EFI_FV_HEADER_SIZE = 0x48 + + def __init__(self): + self._fvs = [] + + def Load(self, fd, size): + index = fd.tell() + while (index + self.EFI_FV_HEADER_SIZE < size): + fv = EfiFv(self) + fv.Load(fd) + self._fvs.append(fv) + index += fv.GetHeader().GetFvLength() + index = align(index, 8) + fd.seek(index) + + def GetFvs(self): + return self._fvs + +class EfiFv(object): + FILE_SYSTEM_GUID = uuid.UUID('{8c8ce578-8a3d-4f1c-9935-896185c32dd3}') + + def __init__(self, parent=None): + self._size = 0 + self._filename = None + self._fvheader = None + self._blockentries = [] + self._ffs = [] + + # following field is for FV in FD + self._parent = parent + self._offset = 0 + self._raw = array.array('B') + + def Load(self, fd): + self._offset = fd.tell() + self._filename = fd.name + + # get file header + self._fvheader = EfiFirmwareVolumeHeader.Read(fd) + #self._fvheader.Dump() + + self._size = self._fvheader.GetFvLength() + + if self._fvheader.GetFileSystemGuid() != self.FILE_SYSTEM_GUID: + fd.seek(self._offset) + self._raw.fromfile(fd, self.GetHeader().GetFvLength()) + return + + # read block map + blockentry = BlockMapEntry.Read(fd) + self._blockentries.append(blockentry) + while (blockentry.GetNumberBlocks() != 0 and blockentry.GetLength() != 0): + self._blockentries.append(blockentry) + blockentry = BlockMapEntry.Read(fd) + + + if self._fvheader.GetSize() + (len(self._blockentries)) * 8 != \ + self._fvheader.GetHeaderLength(): + raise EFIBinaryError("Volume Header length not consistent with block map!") + + index = align(fd.tell(), 8) + count = 0 + while ((index + EfiFfs.FFS_HEADER_SIZE) < self._size): + ffs = EfiFfs.Read(fd, self) + if not isValidGuid(ffs.GetNameGuid()): + break + self._ffs.append(ffs) + count += 1 + index = align(fd.tell(), 8) + + fd.seek(self._offset) + self._raw.fromfile(fd, self.GetHeader().GetFvLength()) + + def GetFfs(self): + return self._ffs + + def GetHeader(self): + return self._fvheader + + def GetBlockEntries(self): + return self._blockentries + + def GetHeaderRawData(self): + ret = [] + ret += self._fvheader.GetRawData() + for block in self._blockentries: + ret += block.GetRawData() + return ret + + def GetOffset(self): + return 0 + + def GetRawData(self): + return self._raw.tolist() + +class BinaryItem(object): + def __init__(self, parent=None): + self._size = 0 + self._arr = array.array('B') + self._parent = parent + + @classmethod + def Read(cls, fd, parent=None): + item = cls(parent) + item.fromfile(fd) + return item + + def Load(self, fd): + self.fromfile(fd) + + def GetSize(self): + """should be implemented by inherited class""" + + def fromfile(self, fd): + self._arr.fromfile(fd, self.GetSize()) + + def GetParent(self): + return self._parent + +class EfiFirmwareVolumeHeader(BinaryItem): + def GetSize(self): + return 56 + + def GetSigunature(self): + list = self._arr.tolist() + sig = '' + for x in list[40:44]: + sig += chr(x) + return sig + + def GetAttribute(self): + return list2int(self._arr.tolist()[44:48]) + + def GetErasePolarity(self): + list = self.GetAttrStrings() + if 'EFI_FVB2_ERASE_POLARITY' in list: + return True + return False + + def GetAttrStrings(self): + list = [] + value = self.GetAttribute() + if (value & 0x01) != 0: + list.append('EFI_FVB2_READ_DISABLED_CAP') + if (value & 0x02) != 0: + list.append('EFI_FVB2_READ_ENABLED_CAP') + if (value & 0x04) != 0: + list.append('EFI_FVB2_READ_STATUS') + if (value & 0x08) != 0: + list.append('EFI_FVB2_WRITE_DISABLED_CAP') + if (value & 0x10) != 0: + list.append('EFI_FVB2_WRITE_ENABLED_CAP') + if (value & 0x20) != 0: + list.append('EFI_FVB2_WRITE_STATUS') + if (value & 0x40) != 0: + list.append('EFI_FVB2_LOCK_CAP') + if (value & 0x80) != 0: + list.append('EFI_FVB2_LOCK_STATUS') + if (value & 0x200) != 0: + list.append('EFI_FVB2_STICKY_WRITE') + if (value & 0x400) != 0: + list.append('EFI_FVB2_MEMORY_MAPPED') + if (value & 0x800) != 0: + list.append('EFI_FVB2_ERASE_POLARITY') + if (value & 0x1000) != 0: + list.append('EFI_FVB2_READ_LOCK_CAP') + if (value & 0x00002000) != 0: + list.append('EFI_FVB2_READ_LOCK_STATUS') + if (value & 0x00004000) != 0: + list.append('EFI_FVB2_WRITE_LOCK_CAP') + if (value & 0x00008000) != 0: + list.append('EFI_FVB2_WRITE_LOCK_STATUS') + + if (value == 0): + list.append('EFI_FVB2_ALIGNMENT_1') + if (value & 0x001F0000) == 0x00010000: + list.append('EFI_FVB2_ALIGNMENT_2') + if (value & 0x001F0000) == 0x00020000: + list.append('EFI_FVB2_ALIGNMENT_4') + if (value & 0x001F0000) == 0x00030000: + list.append('EFI_FVB2_ALIGNMENT_8') + if (value & 0x001F0000) == 0x00040000: + list.append('EFI_FVB2_ALIGNMENT_16') + if (value & 0x001F0000) == 0x00050000: + list.append('EFI_FVB2_ALIGNMENT_32') + if (value & 0x001F0000) == 0x00060000: + list.append('EFI_FVB2_ALIGNMENT_64') + if (value & 0x001F0000) == 0x00070000: + list.append('EFI_FVB2_ALIGNMENT_128') + if (value & 0x001F0000) == 0x00080000: + list.append('EFI_FVB2_ALIGNMENT_256') + if (value & 0x001F0000) == 0x00090000: + list.append('EFI_FVB2_ALIGNMENT_512') + if (value & 0x001F0000) == 0x000A0000: + list.append('EFI_FVB2_ALIGNMENT_1K') + if (value & 0x001F0000) == 0x000B0000: + list.append('EFI_FVB2_ALIGNMENT_2K') + if (value & 0x001F0000) == 0x000C0000: + list.append('EFI_FVB2_ALIGNMENT_4K') + if (value & 0x001F0000) == 0x000D0000: + list.append('EFI_FVB2_ALIGNMENT_8K') + if (value & 0x001F0000) == 0x000E0000: + list.append('EFI_FVB2_ALIGNMENT_16K') + if (value & 0x001F0000) == 0x000F0000: + list.append('EFI_FVB2_ALIGNMENT_32K') + if (value & 0x001F0000) == 0x00100000: + list.append('EFI_FVB2_ALIGNMENT_64K') + if (value & 0x001F0000) == 0x00110000: + list.append('EFI_FVB2_ALIGNMENT_128K') + if (value & 0x001F0000) == 0x00120000: + list.append('EFI_FVB2_ALIGNMENT_256K') + if (value & 0x001F0000) == 0x00130000: + list.append('EFI_FVB2_ALIGNMENT_512K') + + return list + + def GetHeaderLength(self): + return list2int(self._arr.tolist()[48:50]) + + def Dump(self): + print('Signature: %s' % self.GetSigunature()) + print('Attribute: 0x%X' % self.GetAttribute()) + print('Header Length: 0x%X' % self.GetHeaderLength()) + print('File system Guid: ', self.GetFileSystemGuid()) + print('Revision: 0x%X' % self.GetRevision()) + print('FvLength: 0x%X' % self.GetFvLength()) + + def GetFileSystemGuid(self): + list = self._arr.tolist() + return list2guid(list[16:32]) + + def GetRevision(self): + list = self._arr.tolist() + return int(list[55]) + + def GetFvLength(self): + list = self._arr.tolist() + return list2int(list[32:40]) + + def GetRawData(self): + return self._arr.tolist() + +class BlockMapEntry(BinaryItem): + def GetSize(self): + return 8 + + def GetNumberBlocks(self): + list = self._arr.tolist() + return list2int(list[0:4]) + + def GetLength(self): + list = self._arr.tolist() + return list2int(list[4:8]) + + def GetRawData(self): + return self._arr.tolist() + + def __str__(self): + return '[BlockEntry] Number = 0x%X, length=0x%X' % (self.GetNumberBlocks(), self.GetLength()) + +class EfiFfs(object): + FFS_HEADER_SIZE = 24 + + def __init__(self, parent=None): + self._header = None + + # following field is for FFS in FV file. + self._parent = parent + self._offset = 0 + self._sections = [] + + def Load(self, fd): + self._offset = align(fd.tell(), 8) + + self._header = EfiFfsHeader.Read(fd, self) + + if not isValidGuid(self.GetNameGuid()): + return + + index = self._offset + fileend = self._offset + self.GetSize() + while (index + EfiSection.EFI_SECTION_HEADER_SIZE < fileend): + section = EfiSection(self) + section.Load(fd) + if section.GetSize() == 0 and section.GetHeader().GetType() == 0: + break + self._sections.append(section) + index = fd.tell() + + # rebase file pointer to next ffs file + index = self._offset + self._header.GetFfsSize() + index = align(index, 8) + fd.seek(index) + + def GetOffset(self): + return self._offset + + def GetSize(self): + return self._header.GetFfsSize() + + @classmethod + def Read(cls, fd, parent=None): + item = cls(parent) + item.Load(fd) + return item + + def GetNameGuid(self): + return self._header.GetNameGuid() + + def DumpContent(self): + list = self._content.tolist() + line = [] + count = 0 + for item in list: + if count < 32: + line.append('0x%X' % int(item)) + count += 1 + else: + print(' '.join(line)) + count = 0 + line = [] + line.append('0x%X' % int(item)) + count += 1 + + def GetHeader(self): + return self._header + + def GetParent(self): + return self._parent + + def GetSections(self): + return self._sections + +class EfiFfsHeader(BinaryItem): + ffs_state_map = {0x01:'EFI_FILE_HEADER_CONSTRUCTION', + 0x02:'EFI_FILE_HEADER_VALID', + 0x04:'EFI_FILE_DATA_VALID', + 0x08:'EFI_FILE_MARKED_FOR_UPDATE', + 0x10:'EFI_FILE_DELETED', + 0x20:'EFI_FILE_HEADER_INVALID'} + + def GetSize(self): + return 24 + + def GetNameGuid(self): + list = self._arr.tolist() + return list2guid(list[0:16]) + + def GetType(self): + list = self._arr.tolist() + return int(list[18]) + + + def GetTypeString(self): + value = self.GetType() + if value == 0x01: + return 'EFI_FV_FILETYPE_RAW' + if value == 0x02: + return 'EFI_FV_FILETYPE_FREEFORM' + if value == 0x03: + return 'EFI_FV_FILETYPE_SECURITY_CORE' + if value == 0x04: + return 'EFI_FV_FILETYPE_PEI_CORE' + if value == 0x05: + return 'EFI_FV_FILETYPE_DXE_CORE' + if value == 0x06: + return 'EFI_FV_FILETYPE_PEIM' + if value == 0x07: + return 'EFI_FV_FILETYPE_DRIVER' + if value == 0x08: + return 'EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER' + if value == 0x09: + return 'EFI_FV_FILETYPE_APPLICATION' + if value == 0x0B: + return 'EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE' + if value == 0xc0: + return 'EFI_FV_FILETYPE_OEM_MIN' + if value == 0xdf: + return 'EFI_FV_FILETYPE_OEM_MAX' + if value == 0xe0: + return 'EFI_FV_FILETYPE_DEBUG_MIN' + if value == 0xef: + return 'EFI_FV_FILETYPE_DEBUG_MAX' + if value == 0xf0: + return 'EFI_FV_FILETYPE_FFS_PAD' + if value == 0xff: + return 'EFI_FV_FILETYPE_FFS_MAX' + return 'Unknown FFS Type' + + def GetAttributes(self): + list = self._arr.tolist() + return int(list[19]) + + def GetFfsSize(self): + list = self._arr.tolist() + return list2int(list[20:23]) + + def GetState(self): + list = self._arr.tolist() + state = int(list[23]) + polarity = self.GetParent().GetParent().GetHeader().GetErasePolarity() + if polarity: + state = (~state) & 0xFF + HighestBit = 0x80 + while (HighestBit != 0) and (HighestBit & state) == 0: + HighestBit = HighestBit >> 1 + return HighestBit + + def GetStateString(self): + state = self.GetState() + if state in self.ffs_state_map.keys(): + return self.ffs_state_map[state] + return 'Unknown Ffs State' + + def Dump(self): + print("FFS name: ", self.GetNameGuid()) + print("FFS type: ", self.GetType()) + print("FFS attr: 0x%X" % self.GetAttributes()) + print("FFS size: 0x%X" % self.GetFfsSize()) + print("FFS state: 0x%X" % self.GetState()) + + def GetRawData(self): + return self._arr.tolist() + + +class EfiSection(object): + EFI_SECTION_HEADER_SIZE = 4 + + def __init__(self, parent=None): + self._size = 0 + self._parent = parent + self._offset = 0 + self._contents = array.array('B') + + def Load(self, fd): + self._offset = align(fd.tell(), 4) + + self._header = EfiSectionHeader.Read(fd, self) + + if self._header.GetTypeString() == "EFI_SECTION_PE32": + pefile = pe.PEFile(self) + pefile.Load(fd, self.GetContentSize()) + + fd.seek(self._offset) + self._contents.fromfile(fd, self.GetContentSize()) + + # rebase file pointer to next section + index = self._offset + self.GetSize() + index = align(index, 4) + fd.seek(index) + + def GetContentSize(self): + return self.GetSize() - self.EFI_SECTION_HEADER_SIZE + + def GetContent(self): + return self._contents.tolist() + + def GetSize(self): + return self._header.GetSectionSize() + + def GetHeader(self): + return self._header + + def GetSectionOffset(self): + return self._offset + self.EFI_SECTION_HEADER_SIZE + +class EfiSectionHeader(BinaryItem): + section_type_map = {0x01: 'EFI_SECTION_COMPRESSION', + 0x02: 'EFI_SECTION_GUID_DEFINED', + 0x10: 'EFI_SECTION_PE32', + 0x11: 'EFI_SECTION_PIC', + 0x12: 'EFI_SECTION_TE', + 0x13: 'EFI_SECTION_DXE_DEPEX', + 0x14: 'EFI_SECTION_VERSION', + 0x15: 'EFI_SECTION_USER_INTERFACE', + 0x16: 'EFI_SECTION_COMPATIBILITY16', + 0x17: 'EFI_SECTION_FIRMWARE_VOLUME_IMAGE', + 0x18: 'EFI_SECTION_FREEFORM_SUBTYPE_GUID', + 0x19: 'EFI_SECTION_RAW', + 0x1B: 'EFI_SECTION_PEI_DEPEX'} + def GetSize(self): + return 4 + + def GetSectionSize(self): + list = self._arr.tolist() + return list2int(list[0:3]) + + def GetType(self): + list = self._arr.tolist() + return int(list[3]) + + def GetTypeString(self): + type = self.GetType() + if type not in self.section_type_map.keys(): + return 'Unknown Section Type' + return self.section_type_map[type] + + def Dump(self): + print('size = 0x%X' % self.GetSectionSize()) + print('type = 0x%X' % self.GetType()) + + + +rMapEntry = re.compile('^(\w+)[ \(\w\)]* \(BaseAddress=([0-9a-fA-F]+), EntryPoint=([0-9a-fA-F]+), GUID=([0-9a-fA-F\-]+)') +class EfiFvMapFile(object): + def __init__(self): + self._mapentries = {} + + def Load(self, path): + if not os.path.exists(path): + return False + + try: + file = open(path, 'r') + lines = file.readlines() + file.close() + except: + return False + + for line in lines: + if line[0] != ' ': + # new entry + ret = rMapEntry.match(line) + if ret is not None: + name = ret.groups()[0] + baseaddr = int(ret.groups()[1], 16) + entry = int(ret.groups()[2], 16) + guidstr = '{' + ret.groups()[3] + '}' + guid = uuid.UUID(guidstr) + self._mapentries[guid] = EfiFvMapFileEntry(name, baseaddr, entry, guid) + return True + + def GetEntry(self, guid): + if guid in self._mapentries.keys(): + return self._mapentries[guid] + return None + +class EfiFvMapFileEntry(object): + def __init__(self, name, baseaddr, entry, guid): + self._name = name + self._baseaddr = baseaddr + self._entry = entry + self._guid = guid + + def GetName(self): + return self._name + + def GetBaseAddress(self): + return self._baseaddr + + def GetEntryPoint(self): + return self._entry + +def list2guid(list): + val1 = list2int(list[0:4]) + val2 = list2int(list[4:6]) + val3 = list2int(list[6:8]) + val4 = 0 + for item in list[8:16]: + val4 = (val4 << 8) | int(item) + + val = val1 << 12 * 8 | val2 << 10 * 8 | val3 << 8 * 8 | val4 + guid = uuid.UUID(int=val) + return guid + +def list2int(list): + val = 0 + for index in range(len(list) - 1, -1, -1): + val = (val << 8) | int(list[index]) + return val + +def align(value, alignment): + return (value + ((alignment - value) & (alignment - 1))) + +gInvalidGuid = uuid.UUID(int=0xffffffffffffffffffffffffffffffff) +def isValidGuid(guid): + if guid == gInvalidGuid: + return False + return True diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/ini.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/ini.py index 7facb9aa24..6d61b7a289 100644 --- a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/ini.py +++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/ini.py @@ -1,475 +1,475 @@ -## @file
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-
-from __future__ import absolute_import
-from .message import *
-import re
-import os
-
-section_re = re.compile(r'^\[([\w., "]+)\]')
-
-class BaseINIFile(object):
- _objs = {}
- def __new__(cls, *args, **kwargs):
- """Maintain only a single instance of this object
- @return: instance of this class
-
- """
- if len(args) == 0: return object.__new__(cls)
- filename = args[0]
- parent = None
- if len(args) > 1:
- parent = args[1]
-
- key = os.path.normpath(filename)
- if key not in cls._objs.keys():
- cls._objs[key] = object.__new__(cls)
-
- if parent is not None:
- cls._objs[key].AddParent(parent)
-
- return cls._objs[key]
-
- def __init__(self, filename=None, parent=None):
- self._lines = []
- self._sections = {}
- self._filename = filename
- self._globals = []
- self._isModify = True
-
- def AddParent(self, parent):
- if parent is None: return
- if not hasattr(self, "_parents"):
- self._parents = []
-
- if parent in self._parents:
- ErrorMsg("Duplicate parent is found for INI file %s" % self._filename)
- return
- self._parents.append(parent)
-
- def GetFilename(self):
- return os.path.normpath(self._filename)
-
- def IsModified(self):
- return self._isModify
-
- def Modify(self, modify=True, obj=None):
- if modify == self._isModify: return
- self._isModify = modify
- if modify:
- for parent in self._parents:
- parent.Modify(True, self)
-
- def _ReadLines(self, filename):
- #
- # try to open file
- #
- if not os.path.exists(filename):
- return False
-
- try:
- handle = open(filename, 'r')
- self._lines = handle.readlines()
- handle.close()
- except:
- raise EdkException("Fail to open file %s" % filename)
-
- return True
-
- def GetSectionInstance(self, parent, name, isCombined=False):
- return BaseINISection(parent, name, isCombined)
-
- def GetSectionByName(self, name):
- arr = []
- for key in self._sections.keys():
- if '.private' in key:
- continue
- for item in self._sections[key]:
- if item.GetBaseName().lower().find(name.lower()) != -1:
- arr.append(item)
- return arr
-
- def GetSectionObjectsByName(self, name):
- arr = []
- sects = self.GetSectionByName(name)
- for sect in sects:
- for obj in sect.GetObjects():
- arr.append(obj)
- return arr
-
- def Parse(self):
- if not self._isModify: return True
- if not self._ReadLines(self._filename): return False
-
- sObjs = []
- inGlobal = True
- # process line
- for index in range(len(self._lines)):
- templine = self._lines[index].strip()
- # skip comments
- if len(templine) == 0: continue
- if re.match("^\[=*\]", templine) or re.match("^#", templine) or \
- re.match("\*+/", templine):
- continue
-
- m = section_re.match(templine)
- if m is not None: # found a section
- inGlobal = False
- # Finish the latest section first
- if len(sObjs) != 0:
- for sObj in sObjs:
- sObj._end = index - 1
- if not sObj.Parse():
- ErrorMsg("Fail to parse section %s" % sObj.GetBaseName(),
- self._filename,
- sObj._start)
-
- # start new section
- sname_arr = m.groups()[0].split(',')
- sObjs = []
- for name in sname_arr:
- sObj = self.GetSectionInstance(self, name, (len(sname_arr) > 1))
- sObj._start = index
- sObjs.append(sObj)
- if name.lower() not in self._sections:
- self._sections[name.lower()] = [sObj]
- else:
- self._sections[name.lower()].append(sObj)
- elif inGlobal: # not start any section and find global object
- gObj = BaseINIGlobalObject(self)
- gObj._start = index
- gObj.Parse()
- self._globals.append(gObj)
-
- # Finish the last section
- if len(sObjs) != 0:
- for sObj in sObjs:
- sObj._end = index
- if not sObj.Parse():
- ErrorMsg("Fail to parse section %s" % sObj.GetBaseName(),
- self._filename,
- sObj._start)
-
- self._isModify = False
- return True
-
- def Destroy(self, parent):
-
- # check referenced parent
- if parent is not None:
- assert parent in self._parents, "when destory ini object, can not found parent reference!"
- self._parents.remove(parent)
-
- if len(self._parents) != 0: return
-
- for sects in self._sections.values():
- for sect in sects:
- sect.Destroy()
-
- # dereference from _objs array
- assert self.GetFilename() in self._objs.keys(), "When destroy ini object, can not find obj reference!"
- assert self in self._objs.values(), "When destroy ini object, can not find obj reference!"
- del self._objs[self.GetFilename()]
-
- # dereference self
- self.Clear()
-
- def GetDefine(self, name):
- sects = self.GetSectionByName('Defines')
- for sect in sects:
- for obj in sect.GetObjects():
- line = obj.GetLineByOffset(obj._start).split('#')[0].strip()
- arr = line.split('=')
- if arr[0].strip().lower() == name.strip().lower():
- return arr[1].strip()
- return None
-
- def Clear(self):
- for sects in self._sections.values():
- for sect in sects:
- del sect
- self._sections.clear()
- for gObj in self._globals:
- del gObj
-
- del self._globals[:]
- del self._lines[:]
-
- def Reload(self):
- self.Clear()
- ret = self.Parse()
- if ret:
- self._isModify = False
- return ret
-
- def AddNewSection(self, sectName):
- if sectName.lower() in self._sections.keys():
- ErrorMsg('Section %s can not be created for conflict with existing section')
- return None
-
- sectionObj = self.GetSectionInstance(self, sectName)
- sectionObj._start = len(self._lines)
- sectionObj._end = len(self._lines) + 1
- self._lines.append('[%s]\n' % sectName)
- self._lines.append('\n\n')
- self._sections[sectName.lower()] = sectionObj
- return sectionObj
-
- def CopySectionsByName(self, oldDscObj, nameStr):
- sects = oldDscObj.GetSectionByName(nameStr)
- for sect in sects:
- sectObj = self.AddNewSection(sect.GetName())
- sectObj.Copy(sect)
-
- def __str__(self):
- return ''.join(self._lines)
-
- ## Get file header's comment from basic INI file.
- # The file comments has two style:
- # 1) #/** @file
- # 2) ## @file
- #
- def GetFileHeader(self):
- desc = []
- lineArr = self._lines
- inHeader = False
- for num in range(len(self._lines)):
- line = lineArr[num].strip()
- if not inHeader and (line.startswith("#/**") or line.startswith("##")) and \
- line.find("@file") != -1:
- inHeader = True
- continue
- if inHeader and (line.startswith("#**/") or line.startswith('##')):
- inHeader = False
- break
- if inHeader:
- prefixIndex = line.find('#')
- if prefixIndex == -1:
- desc.append(line)
- else:
- desc.append(line[prefixIndex + 1:])
- return '<br>\n'.join(desc)
-
-class BaseINISection(object):
- def __init__(self, parent, name, isCombined=False):
- self._parent = parent
- self._name = name
- self._isCombined = isCombined
- self._start = 0
- self._end = 0
- self._objs = []
-
- def __del__(self):
- for obj in self._objs:
- del obj
- del self._objs[:]
-
- def GetName(self):
- return self._name
-
- def GetObjects(self):
- return self._objs
-
- def GetParent(self):
- return self._parent
-
- def GetStartLinenumber(self):
- return self._start
-
- def GetEndLinenumber(self):
- return self._end
-
- def GetLine(self, linenumber):
- return self._parent._lines[linenumber]
-
- def GetFilename(self):
- return self._parent.GetFilename()
-
- def GetSectionINIObject(self, parent):
- return BaseINISectionObject(parent)
-
- def Parse(self):
- # skip first line in section, it is used by section name
- visit = self._start + 1
- iniObj = None
- while (visit <= self._end):
- line = self.GetLine(visit).strip()
- if re.match("^\[=*\]", line) or re.match("^#", line) or len(line) == 0:
- visit += 1
- continue
- line = line.split('#')[0].strip()
- if iniObj is not None:
- if line.endswith('}'):
- iniObj._end = visit - self._start
- if not iniObj.Parse():
- ErrorMsg("Fail to parse ini object",
- self.GetFilename(),
- iniObj.GetStartLinenumber())
- else:
- self._objs.append(iniObj)
- iniObj = None
- else:
- iniObj = self.GetSectionINIObject(self)
- iniObj._start = visit - self._start
- if not line.endswith('{'):
- iniObj._end = visit - self._start
- if not iniObj.Parse():
- ErrorMsg("Fail to parse ini object",
- self.GetFilename(),
- iniObj.GetStartLinenumber())
- else:
- self._objs.append(iniObj)
- iniObj = None
- visit += 1
- return True
-
- def Destroy(self):
- for obj in self._objs:
- obj.Destroy()
-
- def GetBaseName(self):
- return self._name
-
- def AddLine(self, line):
- end = self.GetEndLinenumber()
- self._parent._lines.insert(end, line)
- self._end += 1
-
- def Copy(self, sectObj):
- index = sectObj.GetStartLinenumber() + 1
- while index < sectObj.GetEndLinenumber():
- line = sectObj.GetLine(index)
- if not line.strip().startswith('#'):
- self.AddLine(line)
- index += 1
-
- def AddObject(self, obj):
- lines = obj.GenerateLines()
- for line in lines:
- self.AddLine(line)
-
- def GetComment(self):
- comments = []
- start = self._start - 1
- bFound = False
-
- while (start > 0):
- line = self.GetLine(start).strip()
- if len(line) == 0:
- start -= 1
- continue
- if line.startswith('##'):
- bFound = True
- index = line.rfind('#')
- if (index + 1) < len(line):
- comments.append(line[index + 1:])
- break
- if line.startswith('#'):
- start -= 1
- continue
- break
- if bFound:
- end = start + 1
- while (end < self._start):
- line = self.GetLine(end).strip()
- if len(line) == 0: break
- if not line.startswith('#'): break
- index = line.rfind('#')
- if (index + 1) < len(line):
- comments.append(line[index + 1:])
- end += 1
- return comments
-
-class BaseINIGlobalObject(object):
- def __init__(self, parent):
- self._start = 0
- self._end = 0
-
- def Parse(self):
- return True
-
- def __str__(self):
- return parent._lines[self._start]
-
- def __del__(self):
- pass
-
-class BaseINISectionObject(object):
- def __init__(self, parent):
- self._start = 0
- self._end = 0
- self._parent = parent
-
- def __del__(self):
- self._parent = None
-
- def GetParent(self):
- return self._parent
-
- def GetFilename(self):
- return self.GetParent().GetFilename()
-
- def GetPackageName(self):
- return self.GetFilename()
-
- def GetFileObj(self):
- return self.GetParent().GetParent()
-
- def GetStartLinenumber(self):
- return self.GetParent()._start + self._start
-
- def GetLineByOffset(self, offset):
- sect_start = self._parent.GetStartLinenumber()
- linenumber = sect_start + offset
- return self._parent.GetLine(linenumber)
-
- def GetLinenumberByOffset(self, offset):
- return offset + self._parent.GetStartLinenumber()
-
- def Parse(self):
- return True
-
- def Destroy(self):
- pass
-
- def __str__(self):
- return self.GetLineByOffset(self._start).strip()
-
- def GenerateLines(self):
- return ['default setion object string\n']
-
- def GetComment(self):
- comments = []
- start = self.GetStartLinenumber() - 1
- bFound = False
-
- while (start > 0):
- line = self.GetParent().GetLine(start).strip()
- if len(line) == 0:
- start -= 1
- continue
- if line.startswith('##'):
- bFound = True
- index = line.rfind('#')
- if (index + 1) < len(line):
- comments.append(line[index + 1:])
- break
- if line.startswith('#'):
- start -= 1
- continue
- break
- if bFound:
- end = start + 1
- while (end <= self.GetStartLinenumber() - 1):
- line = self.GetParent().GetLine(end).strip()
- if len(line) == 0: break
- if not line.startswith('#'): break
- index = line.rfind('#')
- if (index + 1) < len(line):
- comments.append(line[index + 1:])
- end += 1
- return comments
+## @file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +from __future__ import absolute_import +from .message import * +import re +import os + +section_re = re.compile(r'^\[([\w., "]+)\]') + +class BaseINIFile(object): + _objs = {} + def __new__(cls, *args, **kwargs): + """Maintain only a single instance of this object + @return: instance of this class + + """ + if len(args) == 0: return object.__new__(cls) + filename = args[0] + parent = None + if len(args) > 1: + parent = args[1] + + key = os.path.normpath(filename) + if key not in cls._objs.keys(): + cls._objs[key] = object.__new__(cls) + + if parent is not None: + cls._objs[key].AddParent(parent) + + return cls._objs[key] + + def __init__(self, filename=None, parent=None): + self._lines = [] + self._sections = {} + self._filename = filename + self._globals = [] + self._isModify = True + + def AddParent(self, parent): + if parent is None: return + if not hasattr(self, "_parents"): + self._parents = [] + + if parent in self._parents: + ErrorMsg("Duplicate parent is found for INI file %s" % self._filename) + return + self._parents.append(parent) + + def GetFilename(self): + return os.path.normpath(self._filename) + + def IsModified(self): + return self._isModify + + def Modify(self, modify=True, obj=None): + if modify == self._isModify: return + self._isModify = modify + if modify: + for parent in self._parents: + parent.Modify(True, self) + + def _ReadLines(self, filename): + # + # try to open file + # + if not os.path.exists(filename): + return False + + try: + handle = open(filename, 'r') + self._lines = handle.readlines() + handle.close() + except: + raise EdkException("Fail to open file %s" % filename) + + return True + + def GetSectionInstance(self, parent, name, isCombined=False): + return BaseINISection(parent, name, isCombined) + + def GetSectionByName(self, name): + arr = [] + for key in self._sections.keys(): + if '.private' in key: + continue + for item in self._sections[key]: + if item.GetBaseName().lower().find(name.lower()) != -1: + arr.append(item) + return arr + + def GetSectionObjectsByName(self, name): + arr = [] + sects = self.GetSectionByName(name) + for sect in sects: + for obj in sect.GetObjects(): + arr.append(obj) + return arr + + def Parse(self): + if not self._isModify: return True + if not self._ReadLines(self._filename): return False + + sObjs = [] + inGlobal = True + # process line + for index in range(len(self._lines)): + templine = self._lines[index].strip() + # skip comments + if len(templine) == 0: continue + if re.match("^\[=*\]", templine) or re.match("^#", templine) or \ + re.match("\*+/", templine): + continue + + m = section_re.match(templine) + if m is not None: # found a section + inGlobal = False + # Finish the latest section first + if len(sObjs) != 0: + for sObj in sObjs: + sObj._end = index - 1 + if not sObj.Parse(): + ErrorMsg("Fail to parse section %s" % sObj.GetBaseName(), + self._filename, + sObj._start) + + # start new section + sname_arr = m.groups()[0].split(',') + sObjs = [] + for name in sname_arr: + sObj = self.GetSectionInstance(self, name, (len(sname_arr) > 1)) + sObj._start = index + sObjs.append(sObj) + if name.lower() not in self._sections: + self._sections[name.lower()] = [sObj] + else: + self._sections[name.lower()].append(sObj) + elif inGlobal: # not start any section and find global object + gObj = BaseINIGlobalObject(self) + gObj._start = index + gObj.Parse() + self._globals.append(gObj) + + # Finish the last section + if len(sObjs) != 0: + for sObj in sObjs: + sObj._end = index + if not sObj.Parse(): + ErrorMsg("Fail to parse section %s" % sObj.GetBaseName(), + self._filename, + sObj._start) + + self._isModify = False + return True + + def Destroy(self, parent): + + # check referenced parent + if parent is not None: + assert parent in self._parents, "when destory ini object, can not found parent reference!" + self._parents.remove(parent) + + if len(self._parents) != 0: return + + for sects in self._sections.values(): + for sect in sects: + sect.Destroy() + + # dereference from _objs array + assert self.GetFilename() in self._objs.keys(), "When destroy ini object, can not find obj reference!" + assert self in self._objs.values(), "When destroy ini object, can not find obj reference!" + del self._objs[self.GetFilename()] + + # dereference self + self.Clear() + + def GetDefine(self, name): + sects = self.GetSectionByName('Defines') + for sect in sects: + for obj in sect.GetObjects(): + line = obj.GetLineByOffset(obj._start).split('#')[0].strip() + arr = line.split('=') + if arr[0].strip().lower() == name.strip().lower(): + return arr[1].strip() + return None + + def Clear(self): + for sects in self._sections.values(): + for sect in sects: + del sect + self._sections.clear() + for gObj in self._globals: + del gObj + + del self._globals[:] + del self._lines[:] + + def Reload(self): + self.Clear() + ret = self.Parse() + if ret: + self._isModify = False + return ret + + def AddNewSection(self, sectName): + if sectName.lower() in self._sections.keys(): + ErrorMsg('Section %s can not be created for conflict with existing section') + return None + + sectionObj = self.GetSectionInstance(self, sectName) + sectionObj._start = len(self._lines) + sectionObj._end = len(self._lines) + 1 + self._lines.append('[%s]\n' % sectName) + self._lines.append('\n\n') + self._sections[sectName.lower()] = sectionObj + return sectionObj + + def CopySectionsByName(self, oldDscObj, nameStr): + sects = oldDscObj.GetSectionByName(nameStr) + for sect in sects: + sectObj = self.AddNewSection(sect.GetName()) + sectObj.Copy(sect) + + def __str__(self): + return ''.join(self._lines) + + ## Get file header's comment from basic INI file. + # The file comments has two style: + # 1) #/** @file + # 2) ## @file + # + def GetFileHeader(self): + desc = [] + lineArr = self._lines + inHeader = False + for num in range(len(self._lines)): + line = lineArr[num].strip() + if not inHeader and (line.startswith("#/**") or line.startswith("##")) and \ + line.find("@file") != -1: + inHeader = True + continue + if inHeader and (line.startswith("#**/") or line.startswith('##')): + inHeader = False + break + if inHeader: + prefixIndex = line.find('#') + if prefixIndex == -1: + desc.append(line) + else: + desc.append(line[prefixIndex + 1:]) + return '<br>\n'.join(desc) + +class BaseINISection(object): + def __init__(self, parent, name, isCombined=False): + self._parent = parent + self._name = name + self._isCombined = isCombined + self._start = 0 + self._end = 0 + self._objs = [] + + def __del__(self): + for obj in self._objs: + del obj + del self._objs[:] + + def GetName(self): + return self._name + + def GetObjects(self): + return self._objs + + def GetParent(self): + return self._parent + + def GetStartLinenumber(self): + return self._start + + def GetEndLinenumber(self): + return self._end + + def GetLine(self, linenumber): + return self._parent._lines[linenumber] + + def GetFilename(self): + return self._parent.GetFilename() + + def GetSectionINIObject(self, parent): + return BaseINISectionObject(parent) + + def Parse(self): + # skip first line in section, it is used by section name + visit = self._start + 1 + iniObj = None + while (visit <= self._end): + line = self.GetLine(visit).strip() + if re.match("^\[=*\]", line) or re.match("^#", line) or len(line) == 0: + visit += 1 + continue + line = line.split('#')[0].strip() + if iniObj is not None: + if line.endswith('}'): + iniObj._end = visit - self._start + if not iniObj.Parse(): + ErrorMsg("Fail to parse ini object", + self.GetFilename(), + iniObj.GetStartLinenumber()) + else: + self._objs.append(iniObj) + iniObj = None + else: + iniObj = self.GetSectionINIObject(self) + iniObj._start = visit - self._start + if not line.endswith('{'): + iniObj._end = visit - self._start + if not iniObj.Parse(): + ErrorMsg("Fail to parse ini object", + self.GetFilename(), + iniObj.GetStartLinenumber()) + else: + self._objs.append(iniObj) + iniObj = None + visit += 1 + return True + + def Destroy(self): + for obj in self._objs: + obj.Destroy() + + def GetBaseName(self): + return self._name + + def AddLine(self, line): + end = self.GetEndLinenumber() + self._parent._lines.insert(end, line) + self._end += 1 + + def Copy(self, sectObj): + index = sectObj.GetStartLinenumber() + 1 + while index < sectObj.GetEndLinenumber(): + line = sectObj.GetLine(index) + if not line.strip().startswith('#'): + self.AddLine(line) + index += 1 + + def AddObject(self, obj): + lines = obj.GenerateLines() + for line in lines: + self.AddLine(line) + + def GetComment(self): + comments = [] + start = self._start - 1 + bFound = False + + while (start > 0): + line = self.GetLine(start).strip() + if len(line) == 0: + start -= 1 + continue + if line.startswith('##'): + bFound = True + index = line.rfind('#') + if (index + 1) < len(line): + comments.append(line[index + 1:]) + break + if line.startswith('#'): + start -= 1 + continue + break + if bFound: + end = start + 1 + while (end < self._start): + line = self.GetLine(end).strip() + if len(line) == 0: break + if not line.startswith('#'): break + index = line.rfind('#') + if (index + 1) < len(line): + comments.append(line[index + 1:]) + end += 1 + return comments + +class BaseINIGlobalObject(object): + def __init__(self, parent): + self._start = 0 + self._end = 0 + + def Parse(self): + return True + + def __str__(self): + return parent._lines[self._start] + + def __del__(self): + pass + +class BaseINISectionObject(object): + def __init__(self, parent): + self._start = 0 + self._end = 0 + self._parent = parent + + def __del__(self): + self._parent = None + + def GetParent(self): + return self._parent + + def GetFilename(self): + return self.GetParent().GetFilename() + + def GetPackageName(self): + return self.GetFilename() + + def GetFileObj(self): + return self.GetParent().GetParent() + + def GetStartLinenumber(self): + return self.GetParent()._start + self._start + + def GetLineByOffset(self, offset): + sect_start = self._parent.GetStartLinenumber() + linenumber = sect_start + offset + return self._parent.GetLine(linenumber) + + def GetLinenumberByOffset(self, offset): + return offset + self._parent.GetStartLinenumber() + + def Parse(self): + return True + + def Destroy(self): + pass + + def __str__(self): + return self.GetLineByOffset(self._start).strip() + + def GenerateLines(self): + return ['default setion object string\n'] + + def GetComment(self): + comments = [] + start = self.GetStartLinenumber() - 1 + bFound = False + + while (start > 0): + line = self.GetParent().GetLine(start).strip() + if len(line) == 0: + start -= 1 + continue + if line.startswith('##'): + bFound = True + index = line.rfind('#') + if (index + 1) < len(line): + comments.append(line[index + 1:]) + break + if line.startswith('#'): + start -= 1 + continue + break + if bFound: + end = start + 1 + while (end <= self.GetStartLinenumber() - 1): + line = self.GetParent().GetLine(end).strip() + if len(line) == 0: break + if not line.startswith('#'): break + index = line.rfind('#') + if (index + 1) < len(line): + comments.append(line[index + 1:]) + end += 1 + return comments diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/inidocview.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/inidocview.py index 849d0fc91a..46015d54e5 100644 --- a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/inidocview.py +++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/inidocview.py @@ -1,17 +1,17 @@ -## @file
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-
-import core.editor
-
-class INIDoc(core.editor.EditorDocument):
- def __init__(self):
- core.editor.EditorDocument.__init__(self)
- self._iniobj = None
-
-
-class INIView(core.editor.EditorView):
- pass
+## @file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +import core.editor + +class INIDoc(core.editor.EditorDocument): + def __init__(self): + core.editor.EditorDocument.__init__(self) + self._iniobj = None + + +class INIView(core.editor.EditorView): + pass diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/message.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/message.py index 882538a171..e36930ef61 100644 --- a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/message.py +++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/message.py @@ -1,46 +1,46 @@ -## @file
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-
-def GetEdkLogger():
- import logging
- return logging.getLogger('edk')
-
-class EdkException(Exception):
- def __init__(self, message, fName=None, fNo=None):
- self._message = message
- ErrorMsg(message, fName, fNo)
-
- def GetMessage(self):
- return '[EDK Failure]: %s' %self._message
-
-def ErrorMsg(mess, fName=None, fNo=None):
- GetEdkLogger().error(NormalMessage('#ERR#', mess, fName, fNo))
-
-def LogMsg(mess, fName=None, fNo=None):
- GetEdkLogger().info(NormalMessage('@LOG@', mess, fName, fNo))
-
-def WarnMsg(mess, fName=None, fNo=None):
- GetEdkLogger().warning(NormalMessage('!WAR!', mess, fName, fNo))
-
-def NormalMessage(type, mess, fName=None, fNo=None):
- strMsg = type
-
- if fName is not None:
- strMsg += ' %s' % fName.replace('/', '\\')
- if fNo is not None:
- strMsg += '(%d):' % fNo
- else:
- strMsg += ' :'
-
- if fName is None and fNo is None:
- strMsg += ' '
- strMsg += mess
-
- return strMsg
-
-
-
+## @file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +def GetEdkLogger(): + import logging + return logging.getLogger('edk') + +class EdkException(Exception): + def __init__(self, message, fName=None, fNo=None): + self._message = message + ErrorMsg(message, fName, fNo) + + def GetMessage(self): + return '[EDK Failure]: %s' %self._message + +def ErrorMsg(mess, fName=None, fNo=None): + GetEdkLogger().error(NormalMessage('#ERR#', mess, fName, fNo)) + +def LogMsg(mess, fName=None, fNo=None): + GetEdkLogger().info(NormalMessage('@LOG@', mess, fName, fNo)) + +def WarnMsg(mess, fName=None, fNo=None): + GetEdkLogger().warning(NormalMessage('!WAR!', mess, fName, fNo)) + +def NormalMessage(type, mess, fName=None, fNo=None): + strMsg = type + + if fName is not None: + strMsg += ' %s' % fName.replace('/', '\\') + if fNo is not None: + strMsg += '(%d):' % fNo + else: + strMsg += ' :' + + if fName is None and fNo is None: + strMsg += ' ' + strMsg += mess + + return strMsg + + + diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/__init__.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/__init__.py index 57dfebde59..a7909346f3 100644 --- a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/__init__.py +++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/__init__.py @@ -1,6 +1,6 @@ -## @file
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
+## @file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/__init__.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/__init__.py index 57dfebde59..a7909346f3 100644 --- a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/__init__.py +++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/__init__.py @@ -1,6 +1,6 @@ -## @file
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
+## @file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/baseobject.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/baseobject.py index ee00529f46..0bafe2dce2 100644 --- a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/baseobject.py +++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/baseobject.py @@ -1,928 +1,928 @@ -## @file
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-
-from plugins.EdkPlugins.basemodel import ini
-from plugins.EdkPlugins.edk2.model import dsc
-from plugins.EdkPlugins.edk2.model import inf
-from plugins.EdkPlugins.edk2.model import dec
-import os
-from plugins.EdkPlugins.basemodel.message import *
-
-class SurfaceObject(object):
- _objs = {}
-
- def __new__(cls, *args, **kwargs):
- """Maintain only a single instance of this object
- @return: instance of this class
-
- """
- obj = object.__new__(cls)
- if "None" not in cls._objs:
- cls._objs["None"] = []
- cls._objs["None"].append(obj)
-
- return obj
-
- def __init__(self, parent, workspace):
- self._parent = parent
- self._fileObj = None
- self._workspace = workspace
- self._isModify = False
- self._modifiedObjs = []
-
- def __del__(self):
- pass
-
- def Destroy(self):
- key = self.GetRelativeFilename()
- self.GetFileObj().Destroy(self)
- del self._fileObj
- # dereference self from _objs arrary
- assert key in self._objs, "when destory, object is not in obj list"
- assert self in self._objs[key], "when destory, object is not in obj list"
- self._objs[key].remove(self)
- if len(self._objs[key]) == 0:
- del self._objs[key]
-
- def GetParent(self):
- return self._parent
-
- def GetWorkspace(self):
- return self._workspace
-
- def GetFileObjectClass(self):
- return ini.BaseINIFile
-
- def GetFilename(self):
- return self.GetFileObj().GetFilename()
-
- def GetFileObj(self):
- return self._fileObj
-
- def GetRelativeFilename(self):
- fullPath = self.GetFilename()
- return fullPath[len(self._workspace) + 1:]
-
- def Load(self, relativePath):
- # if has been loaded, directly return
- if self._fileObj is not None: return True
-
- relativePath = os.path.normpath(relativePath)
- fullPath = os.path.join(self._workspace, relativePath)
- fullPath = os.path.normpath(fullPath)
-
- if not os.path.exists(fullPath):
- ErrorMsg("file does not exist!", fullPath)
- return False
-
- self._fileObj = self.GetFileObjectClass()(fullPath, self)
-
- if not self._fileObj.Parse():
- ErrorMsg("Fail to parse file!", fullPath)
- return False
-
- # remove self from None list to list with filename as key
- cls = self.__class__
- if self not in cls._objs["None"]:
- ErrorMsg("Sufrace object does not be create into None list")
- cls._objs["None"].remove(self)
- if relativePath not in cls._objs:
- cls._objs[relativePath] = []
- cls._objs[relativePath].append(self)
-
- return True
-
- def Reload(self, force=False):
- ret = True
- # whether require must be update
- if force:
- ret = self.GetFileObj().Reload(True)
- else:
- if self.IsModified():
- if self.GetFileObj().IsModified():
- ret = self.GetFileObj().Reload()
- return ret
-
- def Modify(self, modify=True, modifiedObj=None):
- if modify:
- #LogMsg("%s is modified, modified object is %s" % (self.GetFilename(), modifiedObj))
- if issubclass(modifiedObj.__class__, ini.BaseINIFile) and self._isModify:
- return
- self._isModify = modify
- self.GetParent().Modify(modify, self)
- else:
- self._isModify = modify
-
- def IsModified(self):
- return self._isModify
-
- def GetModifiedObjs(self):
- return self._modifiedObjs
-
- def FilterObjsByArch(self, objs, arch):
- arr = []
- for obj in objs:
- if obj.GetArch().lower() == 'common':
- arr.append(obj)
- continue
- if obj.GetArch().lower() == arch.lower():
- arr.append(obj)
- continue
- return arr
-
-class Platform(SurfaceObject):
- def __init__(self, parent, workspace):
- SurfaceObject.__init__(self, parent, workspace)
- self._modules = []
- self._packages = []
-
- def Destroy(self):
- for module in self._modules:
- module.Destroy()
- del self._modules[:]
-
- del self._packages[:]
- SurfaceObject.Destroy(self)
-
- def GetName(self):
- return self.GetFileObj().GetDefine("PLATFORM_NAME")
-
- def GetFileObjectClass(self):
- return dsc.DSCFile
-
- def GetModuleCount(self):
- if self.GetFileObj() is None:
- ErrorMsg("Fail to get module count because DSC file has not been load!")
-
- return len(self.GetFileObj().GetComponents())
-
- def GetSupportArchs(self):
- return self.GetFileObj().GetDefine("SUPPORTED_ARCHITECTURES").strip().split('#')[0].split('|')
-
- def LoadModules(self, precallback=None, postcallback=None):
- for obj in self.GetFileObj().GetComponents():
- mFilename = obj.GetFilename()
- if precallback is not None:
- precallback(self, mFilename)
- arch = obj.GetArch()
- if arch.lower() == 'common':
- archarr = self.GetSupportArchs()
- else:
- archarr = [arch]
- for arch in archarr:
- module = Module(self, self.GetWorkspace())
- if module.Load(mFilename, arch, obj.GetOveridePcds(), obj.GetOverideLibs()):
- self._modules.append(module)
- if postcallback is not None:
- postcallback(self, module)
- else:
- del module
- ErrorMsg("Fail to load module %s" % mFilename)
-
- def GetModules(self):
- return self._modules
-
- def GetLibraryPath(self, classname, arch, type):
- objs = self.GetFileObj().GetSectionObjectsByName("libraryclasses")
-
- for obj in objs:
- if classname.lower() != obj.GetClass().lower():
- continue
- if obj.GetArch().lower() != 'common' and \
- obj.GetArch().lower() != arch.lower():
- continue
-
- if obj.GetModuleType().lower() != 'common' and \
- obj.GetModuleType().lower() != type.lower():
- continue
-
- return obj.GetInstance()
-
- ErrorMsg("Fail to get library class %s [%s][%s] from platform %s" % (classname, arch, type, self.GetFilename()))
- return None
-
- def GetPackage(self, path):
- package = self.GetParent().GetPackage(path)
- if package not in self._packages:
- self._packages.append(package)
- return package
-
- def GetPcdBuildObjs(self, name, arch=None):
- arr = []
- objs = self.GetFileObj().GetSectionObjectsByName('pcds')
- for obj in objs:
- if obj.GetPcdName().lower() == name.lower():
- arr.append(obj)
- if arch is not None:
- arr = self.FilterObjsByArch(arr, arch)
- return arr
-
- def Reload(self, callback=None):
- # do not care force paramter for platform object
- isFileChanged = self.GetFileObj().IsModified()
- ret = SurfaceObject.Reload(self, False)
- if not ret: return False
- if isFileChanged:
- # destroy all modules and reload them again
- for obj in self._modules:
- obj.Destroy()
- del self._modules[:]
- del self._packages[:]
- self.LoadModules(callback)
- else:
- for obj in self._modules:
- callback(self, obj.GetFilename())
- obj.Reload()
-
- self.Modify(False)
- return True
-
- def Modify(self, modify=True, modifiedObj=None):
- if modify:
- #LogMsg("%s is modified, modified object is %s" % (self.GetFilename(), modifiedObj))
- if issubclass(modifiedObj.__class__, ini.BaseINIFile) and self._isModify:
- return
- self._isModify = modify
- self.GetParent().Modify(modify, self)
- else:
- if self.GetFileObj().IsModified():
- return
- for obj in self._modules:
- if obj.IsModified():
- return
-
- self._isModify = modify
- self.GetParent().Modify(modify, self)
-
- def GetModuleObject(self, relativePath, arch):
- path = os.path.normpath(relativePath)
- for obj in self._modules:
- if obj.GetRelativeFilename() == path:
- if arch.lower() == 'common':
- return obj
- if obj.GetArch() == arch:
- return obj
- return None
-
- def GenerateFullReferenceDsc(self):
- oldDsc = self.GetFileObj()
- newDsc = dsc.DSCFile()
- newDsc.CopySectionsByName(oldDsc, 'defines')
- newDsc.CopySectionsByName(oldDsc, 'SkuIds')
-
- #
- # Dynamic common section should also be copied
- #
- newDsc.CopySectionsByName(oldDsc, 'PcdsDynamicDefault')
- newDsc.CopySectionsByName(oldDsc, 'PcdsDynamicHii')
- newDsc.CopySectionsByName(oldDsc, 'PcdsDynamicVpd')
- newDsc.CopySectionsByName(oldDsc, 'PcdsDynamicEx')
-
- sects = oldDsc.GetSectionByName('Components')
- for oldSect in sects:
- newSect = newDsc.AddNewSection(oldSect.GetName())
- for oldComObj in oldSect.GetObjects():
- module = self.GetModuleObject(oldComObj.GetFilename(), oldSect.GetArch())
- if module is None: continue
-
- newComObj = dsc.DSCComponentObject(newSect)
- newComObj.SetFilename(oldComObj.GetFilename())
-
- # add all library instance for override section
- libdict = module.GetLibraries()
- for libclass in libdict.keys():
- if libdict[libclass] is not None:
- newComObj.AddOverideLib(libclass, libdict[libclass].GetRelativeFilename().replace('\\', '/'))
-
- # add all pcds for override section
- pcddict = module.GetPcds()
- for pcd in pcddict.values():
- buildPcd = pcd.GetBuildObj()
- buildType = buildPcd.GetPcdType()
- buildValue = None
- if buildType.lower() == 'pcdsdynamichii' or \
- buildType.lower() == 'pcdsdynamicvpd' or \
- buildType.lower() == 'pcdsdynamicdefault':
- buildType = 'PcdsDynamic'
- if buildType != 'PcdsDynamic':
- buildValue = buildPcd.GetPcdValue()
- newComObj.AddOveridePcd(buildPcd.GetPcdName(),
- buildType,
- buildValue)
- newSect.AddObject(newComObj)
- return newDsc
-
-class Module(SurfaceObject):
- def __init__(self, parent, workspace):
- SurfaceObject.__init__(self, parent, workspace)
- self._arch = 'common'
- self._parent = parent
- self._overidePcds = {}
- self._overideLibs = {}
- self._libs = {}
- self._pcds = {}
- self._ppis = []
- self._protocols = []
- self._depexs = []
- self._guids = []
- self._packages = []
-
- def Destroy(self):
- for lib in self._libs.values():
- if lib is not None:
- lib.Destroy()
- self._libs.clear()
-
- for pcd in self._pcds.values():
- pcd.Destroy()
- self._pcds.clear()
-
- for ppi in self._ppis:
- ppi.DeRef(self)
- del self._ppis[:]
-
- for protocol in self._protocols:
- if protocol is not None:
- protocol.DeRef(self)
- del self._protocols[:]
-
- for guid in self._guids:
- if guid is not None:
- guid.DeRef(self)
- del self._guids[:]
-
- del self._packages[:]
- del self._depexs[:]
- SurfaceObject.Destroy(self)
-
- def GetFileObjectClass(self):
- return inf.INFFile
-
- def GetLibraries(self):
- return self._libs
-
- def Load(self, filename, arch='common', overidePcds=None, overideLibs=None):
- if not SurfaceObject.Load(self, filename):
- return False
-
- self._arch = arch
- if overidePcds is not None:
- self._overideLibs = overideLibs
- if overideLibs is not None:
- self._overidePcds = overidePcds
-
- self._SearchLibraries()
- self._SearchPackage()
- self._SearchSurfaceItems()
- return True
-
- def GetArch(self):
- return self._arch
-
- def GetModuleName(self):
- return self.GetFileObj().GetDefine("BASE_NAME")
-
- def GetModuleType(self):
- return self.GetFileObj().GetDefine("MODULE_TYPE")
-
- def GetPlatform(self):
- return self.GetParent()
-
- def GetModuleObj(self):
- return self
-
- def GetPcds(self):
- pcds = self._pcds.copy()
- for lib in self._libs.values():
- if lib is None: continue
- for name in lib._pcds.keys():
- pcds[name] = lib._pcds[name]
- return pcds
-
- def GetPpis(self):
- ppis = []
- ppis += self._ppis
- for lib in self._libs.values():
- if lib is None: continue
- ppis += lib._ppis
- return ppis
-
- def GetProtocols(self):
- pros = []
- pros = self._protocols
- for lib in self._libs.values():
- if lib is None: continue
- pros += lib._protocols
- return pros
-
- def GetGuids(self):
- guids = []
- guids += self._guids
- for lib in self._libs.values():
- if lib is None: continue
- guids += lib._guids
- return guids
-
- def GetDepexs(self):
- deps = []
- deps += self._depexs
- for lib in self._libs.values():
- if lib is None: continue
- deps += lib._depexs
- return deps
-
- def IsLibrary(self):
- return self.GetFileObj().GetDefine("LIBRARY_CLASS") is not None
-
- def GetLibraryInstance(self, classname, arch, type):
- if classname not in self._libs.keys():
- # find in overide lib firstly
- if classname in self._overideLibs.keys():
- self._libs[classname] = Library(self, self.GetWorkspace())
- self._libs[classname].Load(self._overideLibs[classname])
- return self._libs[classname]
-
- parent = self.GetParent()
- if issubclass(parent.__class__, Platform):
- path = parent.GetLibraryPath(classname, arch, type)
- if path is None:
- ErrorMsg('Fail to get library instance for %s' % classname, self.GetFilename())
- return None
- self._libs[classname] = Library(self, self.GetWorkspace())
- if not self._libs[classname].Load(path, self.GetArch()):
- self._libs[classname] = None
- else:
- self._libs[classname] = parent.GetLibraryInstance(classname, arch, type)
- return self._libs[classname]
-
- def GetSourceObjs(self):
- return self.GetFileObj().GetSectionObjectsByName('source')
-
- def _SearchLibraries(self):
- objs = self.GetFileObj().GetSectionObjectsByName('libraryclasses')
- arch = self.GetArch()
- type = self.GetModuleType()
- for obj in objs:
- if obj.GetArch().lower() != 'common' and \
- obj.GetArch().lower() not in self.GetPlatform().GetSupportArchs():
- continue
- classname = obj.GetClass()
- instance = self.GetLibraryInstance(classname, arch, type)
- if not self.IsLibrary() and instance is not None:
- instance._isInherit = False
-
- if classname not in self._libs.keys():
- self._libs[classname] = instance
-
- def _SearchSurfaceItems(self):
- # get surface item from self's inf
- pcds = []
- ppis = []
- pros = []
- deps = []
- guids = []
- if self.GetFileObj() is not None:
- pcds = self.FilterObjsByArch(self.GetFileObj().GetSectionObjectsByName('pcd'),
- self.GetArch())
- for pcd in pcds:
- if pcd.GetPcdName() not in self._pcds.keys():
- pcdItem = PcdItem(pcd.GetPcdName(), self, pcd)
- self._pcds[pcd.GetPcdName()] = ModulePcd(self,
- pcd.GetPcdName(),
- pcd,
- pcdItem)
-
- ppis += self.FilterObjsByArch(self.GetFileObj().GetSectionObjectsByName('ppis'),
- self.GetArch())
-
- for ppi in ppis:
- item = PpiItem(ppi.GetName(), self, ppi)
- if item not in self._ppis:
- self._ppis.append(item)
-
- pros += self.FilterObjsByArch(self.GetFileObj().GetSectionObjectsByName('protocols'),
- self.GetArch())
-
- for pro in pros:
- item = ProtocolItem(pro.GetName(), self, pro)
- if item not in self._protocols:
- self._protocols.append(item)
-
- deps += self.FilterObjsByArch(self.GetFileObj().GetSectionObjectsByName('depex'),
- self.GetArch())
- for dep in deps:
- item = DepexItem(self, dep)
- self._depexs.append(item)
-
- guids += self.FilterObjsByArch(self.GetFileObj().GetSectionObjectsByName('guids'),
- self.GetArch())
- for guid in guids:
- item = GuidItem(guid.GetName(), self, guid)
- if item not in self._guids:
- self._guids.append(item)
-
- def _SearchPackage(self):
- objs = self.GetFileObj().GetSectionObjectsByName('packages')
- for obj in objs:
- package = self.GetPlatform().GetPackage(obj.GetPath())
- if package is not None:
- self._packages.append(package)
-
- def GetPackages(self):
- return self._packages
-
- def GetPcdObjects(self):
- if self.GetFileObj() is None:
- return []
-
- return self.GetFileObj().GetSectionObjectsByName('pcd')
-
- def GetLibraryClassHeaderFilePath(self):
- lcname = self.GetFileObj().GetProduceLibraryClass()
- if lcname is None: return None
-
- pkgs = self.GetPackages()
- for package in pkgs:
- path = package.GetLibraryClassHeaderPathByName(lcname)
- if path is not None:
- return os.path.realpath(os.path.join(package.GetFileObj().GetPackageRootPath(), path))
- return None
-
- def Reload(self, force=False, callback=None):
- if callback is not None:
- callback(self, "Starting reload...")
-
- ret = SurfaceObject.Reload(self, force)
- if not ret: return False
-
- if not force and not self.IsModified():
- return True
-
- for lib in self._libs.values():
- if lib is not None:
- lib.Destroy()
- self._libs.clear()
-
- for pcd in self._pcds.values():
- pcd.Destroy()
- self._pcds.clear()
-
- for ppi in self._ppis:
- ppi.DeRef(self)
- del self._ppis[:]
-
- for protocol in self._protocols:
- protocol.DeRef(self)
- del self._protocols[:]
-
- for guid in self._guids:
- guid.DeRef(self)
- del self._guids[:]
-
- del self._packages[:]
- del self._depexs[:]
-
- if callback is not None:
- callback(self, "Searching libraries...")
- self._SearchLibraries()
- if callback is not None:
- callback(self, "Searching packages...")
- self._SearchPackage()
- if callback is not None:
- callback(self, "Searching surface items...")
- self._SearchSurfaceItems()
-
- self.Modify(False)
- return True
-
- def Modify(self, modify=True, modifiedObj=None):
- if modify:
- #LogMsg("%s is modified, modified object is %s" % (self.GetFilename(), modifiedObj))
- if issubclass(modifiedObj.__class__, ini.BaseINIFile) and self._isModify:
- return
- self._isModify = modify
- self.GetParent().Modify(modify, self)
- else:
- if self.GetFileObj().IsModified():
- return
-
- self._isModify = modify
- self.GetParent().Modify(modify, self)
-
-class Library(Module):
- def __init__(self, parent, workspace):
- Module.__init__(self, parent, workspace)
- self._isInherit = True
-
- def IsInherit(self):
- return self._isInherit
-
- def GetModuleType(self):
- return self.GetParent().GetModuleType()
-
- def GetPlatform(self):
- return self.GetParent().GetParent()
-
- def GetModuleObj(self):
- return self.GetParent()
-
- def GetArch(self):
- return self.GetParent().GetArch()
-
- def Destroy(self):
- self._libs.clear()
- self._pcds.clear()
- SurfaceObject.Destroy(self)
-
-class Package(SurfaceObject):
- def __init__(self, parent, workspace):
- SurfaceObject.__init__(self, parent, workspace)
- self._pcds = {}
- self._guids = {}
- self._protocols = {}
- self._ppis = {}
-
- def GetPcds(self):
- return self._pcds
-
- def GetPpis(self):
- return list(self._ppis.values())
-
- def GetProtocols(self):
- return list(self._protocols.values())
-
- def GetGuids(self):
- return list(self._guids.values())
-
- def Destroy(self):
- for pcd in self._pcds.values():
- if pcd is not None:
- pcd.Destroy()
- for guid in self._guids.values():
- if guid is not None:
- guid.Destroy()
- for protocol in self._protocols.values():
- if protocol is not None:
- protocol.Destroy()
- for ppi in self._ppis.values():
- if ppi is not None:
- ppi.Destroy()
- self._pcds.clear()
- self._guids.clear()
- self._protocols.clear()
- self._ppis.clear()
- self._pcds.clear()
- SurfaceObject.Destroy(self)
-
- def Load(self, relativePath):
- ret = SurfaceObject.Load(self, relativePath)
- if not ret: return False
- pcds = self.GetFileObj().GetSectionObjectsByName('pcds')
- for pcd in pcds:
- if pcd.GetPcdName() in self._pcds.keys():
- if self._pcds[pcd.GetPcdName()] is not None:
- self._pcds[pcd.GetPcdName()].AddDecObj(pcd)
- else:
- self._pcds[pcd.GetPcdName()] = PcdItem(pcd.GetPcdName(), self, pcd)
-
- guids = self.GetFileObj().GetSectionObjectsByName('guids')
- for guid in guids:
- if guid.GetName() not in self._guids.keys():
- self._guids[guid.GetName()] = GuidItem(guid.GetName(), self, guid)
- else:
- WarnMsg("Duplicate definition for %s" % guid.GetName())
-
- ppis = self.GetFileObj().GetSectionObjectsByName('ppis')
- for ppi in ppis:
- if ppi.GetName() not in self._ppis.keys():
- self._ppis[ppi.GetName()] = PpiItem(ppi.GetName(), self, ppi)
- else:
- WarnMsg("Duplicate definition for %s" % ppi.GetName())
-
- protocols = self.GetFileObj().GetSectionObjectsByName('protocols')
- for protocol in protocols:
- if protocol.GetName() not in self._protocols.keys():
- self._protocols[protocol.GetName()] = ProtocolItem(protocol.GetName(), self, protocol)
- else:
- WarnMsg("Duplicate definition for %s" % protocol.GetName())
-
- return True
-
- def GetFileObjectClass(self):
- return dec.DECFile
-
- def GetName(self):
- return self.GetFileObj().GetDefine("PACKAGE_NAME")
-
- def GetPcdDefineObjs(self, name=None):
- arr = []
- objs = self.GetFileObj().GetSectionObjectsByName('pcds')
- if name is None: return objs
-
- for obj in objs:
- if obj.GetPcdName().lower() == name.lower():
- arr.append(obj)
- return arr
-
- def GetLibraryClassObjs(self):
- return self.GetFileObj().GetSectionObjectsByName('libraryclasses')
-
- def Modify(self, modify=True, modifiedObj=None):
- if modify:
- self._isModify = modify
- self.GetParent().Modify(modify, self)
- else:
- if self.GetFileObj().IsModified():
- return
-
- self._isModify = modify
- self.GetParent().Modify(modify, self)
-
- def GetLibraryClassHeaderPathByName(self, clsname):
- objs = self.GetLibraryClassObjs()
- for obj in objs:
- if obj.GetClassName() == clsname:
- return obj.GetHeaderFile()
- return None
-
-class DepexItem(object):
- def __init__(self, parent, infObj):
- self._parent = parent
- self._infObj = infObj
-
- def GetDepexString(self):
- return str(self._infObj)
-
- def GetInfObject(self):
- return self._infObj
-
-class ModulePcd(object):
- _type_mapping = {'FeaturePcd': 'PcdsFeatureFlag',
- 'FixedPcd': 'PcdsFixedAtBuild',
- 'PatchPcd': 'PcdsPatchableInModule'}
-
- def __init__(self, parent, name, infObj, pcdItem):
- assert issubclass(parent.__class__, Module), "Module's PCD's parent must be module!"
- assert pcdItem is not None, 'Pcd %s does not in some package!' % name
-
- self._name = name
- self._parent = parent
- self._pcdItem = pcdItem
- self._infObj = infObj
-
- def GetName(self):
- return self._name
-
- def GetParent(self):
- return self._name
-
- def GetArch(self):
- return self._parent.GetArch()
-
- def Destroy(self):
- self._pcdItem.DeRef(self._parent)
- self._infObj = None
-
- def GetBuildObj(self):
- platformInfos = self._parent.GetPlatform().GetPcdBuildObjs(self._name, self.GetArch())
- modulePcdType = self._infObj.GetPcdType()
-
- # if platform do not gives pcd's value, get default value from package
- if len(platformInfos) == 0:
- if modulePcdType.lower() == 'pcd':
- return self._pcdItem.GetDecObject()
- else:
- for obj in self._pcdItem.GetDecObjects():
- if modulePcdType not in self._type_mapping.keys():
- ErrorMsg("Invalid PCD type %s" % modulePcdType)
- return None
-
- if self._type_mapping[modulePcdType] == obj.GetPcdType():
- return obj
- ErrorMsg ('Module PCD type %s does not in valied range [%s] in package!' % \
- (modulePcdType))
- else:
- if modulePcdType.lower() == 'pcd':
- if len(platformInfos) > 1:
- WarnMsg("Find more than one value for PCD %s in platform %s" % \
- (self._name, self._parent.GetPlatform().GetFilename()))
- return platformInfos[0]
- else:
- for obj in platformInfos:
- if modulePcdType not in self._type_mapping.keys():
- ErrorMsg("Invalid PCD type %s" % modulePcdType)
- return None
-
- if self._type_mapping[modulePcdType] == obj.GetPcdType():
- return obj
-
- ErrorMsg('Can not find value for pcd %s in pcd type %s' % \
- (self._name, modulePcdType))
- return None
-
-
-class SurfaceItem(object):
- _objs = {}
-
- def __new__(cls, *args, **kwargs):
- """Maintain only a single instance of this object
- @return: instance of this class
-
- """
- name = args[0]
- parent = args[1]
- fileObj = args[2]
- if issubclass(parent.__class__, Package):
- if name in cls._objs.keys():
- ErrorMsg("%s item is duplicated defined in packages: %s and %s" %
- (name, parent.GetFilename(), cls._objs[name].GetParent().GetFilename()))
- return None
- obj = object.__new__(cls)
- cls._objs[name] = obj
- return obj
- elif issubclass(parent.__class__, Module):
- if name not in cls._objs.keys():
- ErrorMsg("%s item does not defined in any package! It is used by module %s" % \
- (name, parent.GetFilename()))
- return None
- return cls._objs[name]
-
- return None
-
-
- def __init__(self, name, parent, fileObj):
- if issubclass(parent.__class__, Package):
- self._name = name
- self._parent = parent
- self._decObj = [fileObj]
- self._refMods = {}
- else:
- self.RefModule(parent, fileObj)
-
- @classmethod
- def GetObjectDict(cls):
- return cls._objs
-
- def GetParent(self):
- return self._parent
-
- def GetReference(self):
- return self._refMods
-
- def RefModule(self, mObj, infObj):
- if mObj in self._refMods.keys():
- return
- self._refMods[mObj] = infObj
-
- def DeRef(self, mObj):
- if mObj not in self._refMods.keys():
- WarnMsg("%s is not referenced by module %s" % (self._name, mObj.GetFilename()))
- return
- del self._refMods[mObj]
-
- def Destroy(self):
- self._refMods.clear()
- cls = self.__class__
- del cls._objs[self._name]
-
- def GetName(self):
- return self._name
-
- def GetDecObject(self):
- return self._decObj[0]
-
- def GetDecObjects(self):
- return self._decObj
-
-class PcdItem(SurfaceItem):
- def AddDecObj(self, fileObj):
- for decObj in self._decObj:
- if decObj.GetFilename() != fileObj.GetFilename():
- ErrorMsg("Pcd %s defined in more than one packages : %s and %s" % \
- (self._name, decObj.GetFilename(), fileObj.GetFilename()))
- return
- if decObj.GetPcdType() == fileObj.GetPcdType() and \
- decObj.GetArch().lower() == fileObj.GetArch():
- ErrorMsg("Pcd %s is duplicated defined in pcd type %s in package %s" % \
- (self._name, decObj.GetPcdType(), decObj.GetFilename()))
- return
- self._decObj.append(fileObj)
-
- def GetValidPcdType(self):
- types = []
- for obj in self._decObj:
- if obj.GetPcdType() not in types:
- types += obj.GetPcdType()
- return types
-
-class GuidItem(SurfaceItem):
- pass
-
-class PpiItem(SurfaceItem):
- pass
-
-class ProtocolItem(SurfaceItem):
- pass
+## @file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent + +from plugins.EdkPlugins.basemodel import ini +from plugins.EdkPlugins.edk2.model import dsc +from plugins.EdkPlugins.edk2.model import inf +from plugins.EdkPlugins.edk2.model import dec +import os +from plugins.EdkPlugins.basemodel.message import * + +class SurfaceObject(object): + _objs = {} + + def __new__(cls, *args, **kwargs): + """Maintain only a single instance of this object + @return: instance of this class + + """ + obj = object.__new__(cls) + if "None" not in cls._objs: + cls._objs["None"] = [] + cls._objs["None"].append(obj) + + return obj + + def __init__(self, parent, workspace): + self._parent = parent + self._fileObj = None + self._workspace = workspace + self._isModify = False + self._modifiedObjs = [] + + def __del__(self): + pass + + def Destroy(self): + key = self.GetRelativeFilename() + self.GetFileObj().Destroy(self) + del self._fileObj + # dereference self from _objs arrary + assert key in self._objs, "when destory, object is not in obj list" + assert self in self._objs[key], "when destory, object is not in obj list" + self._objs[key].remove(self) + if len(self._objs[key]) == 0: + del self._objs[key] + + def GetParent(self): + return self._parent + + def GetWorkspace(self): + return self._workspace + + def GetFileObjectClass(self): + return ini.BaseINIFile + + def GetFilename(self): + return self.GetFileObj().GetFilename() + + def GetFileObj(self): + return self._fileObj + + def GetRelativeFilename(self): + fullPath = self.GetFilename() + return fullPath[len(self._workspace) + 1:] + + def Load(self, relativePath): + # if has been loaded, directly return + if self._fileObj is not None: return True + + relativePath = os.path.normpath(relativePath) + fullPath = os.path.join(self._workspace, relativePath) + fullPath = os.path.normpath(fullPath) + + if not os.path.exists(fullPath): + ErrorMsg("file does not exist!", fullPath) + return False + + self._fileObj = self.GetFileObjectClass()(fullPath, self) + + if not self._fileObj.Parse(): + ErrorMsg("Fail to parse file!", fullPath) + return False + + # remove self from None list to list with filename as key + cls = self.__class__ + if self not in cls._objs["None"]: + ErrorMsg("Sufrace object does not be create into None list") + cls._objs["None"].remove(self) + if relativePath not in cls._objs: + cls._objs[relativePath] = [] + cls._objs[relativePath].append(self) + + return True + + def Reload(self, force=False): + ret = True + # whether require must be update + if force: + ret = self.GetFileObj().Reload(True) + else: + if self.IsModified(): + if self.GetFileObj().IsModified(): + ret = self.GetFileObj().Reload() + return ret + + def Modify(self, modify=True, modifiedObj=None): + if modify: + #LogMsg("%s is modified, modified object is %s" % (self.GetFilename(), modifiedObj)) + if issubclass(modifiedObj.__class__, ini.BaseINIFile) and self._isModify: + return + self._isModify = modify + self.GetParent().Modify(modify, self) + else: + self._isModify = modify + + def IsModified(self): + return self._isModify + + def GetModifiedObjs(self): + return self._modifiedObjs + + def FilterObjsByArch(self, objs, arch): + arr = [] + for obj in objs: + if obj.GetArch().lower() == 'common': + arr.append(obj) + continue + if obj.GetArch().lower() == arch.lower(): + arr.append(obj) + continue + return arr + +class Platform(SurfaceObject): + def __init__(self, parent, workspace): + SurfaceObject.__init__(self, parent, workspace) + self._modules = [] + self._packages = [] + + def Destroy(self): + for module in self._modules: + module.Destroy() + del self._modules[:] + + del self._packages[:] + SurfaceObject.Destroy(self) + + def GetName(self): + return self.GetFileObj().GetDefine("PLATFORM_NAME") + + def GetFileObjectClass(self): + return dsc.DSCFile + + def GetModuleCount(self): + if self.GetFileObj() is None: + ErrorMsg("Fail to get module count because DSC file has not been load!") + + return len(self.GetFileObj().GetComponents()) + + def GetSupportArchs(self): + return self.GetFileObj().GetDefine("SUPPORTED_ARCHITECTURES").strip().split('#')[0].split('|') + + def LoadModules(self, precallback=None, postcallback=None): + for obj in self.GetFileObj().GetComponents(): + mFilename = obj.GetFilename() + if precallback is not None: + precallback(self, mFilename) + arch = obj.GetArch() + if arch.lower() == 'common': + archarr = self.GetSupportArchs() + else: + archarr = [arch] + for arch in archarr: + module = Module(self, self.GetWorkspace()) + if module.Load(mFilename, arch, obj.GetOveridePcds(), obj.GetOverideLibs()): + self._modules.append(module) + if postcallback is not None: + postcallback(self, module) + else: + del module + ErrorMsg("Fail to load module %s" % mFilename) + + def GetModules(self): + return self._modules + + def GetLibraryPath(self, classname, arch, type): + objs = self.GetFileObj().GetSectionObjectsByName("libraryclasses") + + for obj in objs: + if classname.lower() != obj.GetClass().lower(): + continue + if obj.GetArch().lower() != 'common' and \ + obj.GetArch().lower() != arch.lower(): + continue + + if obj.GetModuleType().lower() != 'common' and \ + obj.GetModuleType().lower() != type.lower(): + continue + + return obj.GetInstance() + + ErrorMsg("Fail to get library class %s [%s][%s] from platform %s" % (classname, arch, type, self.GetFilename())) + return None + + def GetPackage(self, path): + package = self.GetParent().GetPackage(path) + if package not in self._packages: + self._packages.append(package) + return package + + def GetPcdBuildObjs(self, name, arch=None): + arr = [] + objs = self.GetFileObj().GetSectionObjectsByName('pcds') + for obj in objs: + if obj.GetPcdName().lower() == name.lower(): + arr.append(obj) + if arch is not None: + arr = self.FilterObjsByArch(arr, arch) + return arr + + def Reload(self, callback=None): + # do not care force paramter for platform object + isFileChanged = self.GetFileObj().IsModified() + ret = SurfaceObject.Reload(self, False) + if not ret: return False + if isFileChanged: + # destroy all modules and reload them again + for obj in self._modules: + obj.Destroy() + del self._modules[:] + del self._packages[:] + self.LoadModules(callback) + else: + for obj in self._modules: + callback(self, obj.GetFilename()) + obj.Reload() + + self.Modify(False) + return True + + def Modify(self, modify=True, modifiedObj=None): + if modify: + #LogMsg("%s is modified, modified object is %s" % (self.GetFilename(), modifiedObj)) + if issubclass(modifiedObj.__class__, ini.BaseINIFile) and self._isModify: + return + self._isModify = modify + self.GetParent().Modify(modify, self) + else: + if self.GetFileObj().IsModified(): + return + for obj in self._modules: + if obj.IsModified(): + return + + self._isModify = modify + self.GetParent().Modify(modify, self) + + def GetModuleObject(self, relativePath, arch): + path = os.path.normpath(relativePath) + for obj in self._modules: + if obj.GetRelativeFilename() == path: + if arch.lower() == 'common': + return obj + if obj.GetArch() == arch: + return obj + return None + + def GenerateFullReferenceDsc(self): + oldDsc = self.GetFileObj() + newDsc = dsc.DSCFile() + newDsc.CopySectionsByName(oldDsc, 'defines') + newDsc.CopySectionsByName(oldDsc, 'SkuIds') + + # + # Dynamic common section should also be copied + # + newDsc.CopySectionsByName(oldDsc, 'PcdsDynamicDefault') + newDsc.CopySectionsByName(oldDsc, 'PcdsDynamicHii') + newDsc.CopySectionsByName(oldDsc, 'PcdsDynamicVpd') + newDsc.CopySectionsByName(oldDsc, 'PcdsDynamicEx') + + sects = oldDsc.GetSectionByName('Components') + for oldSect in sects: + newSect = newDsc.AddNewSection(oldSect.GetName()) + for oldComObj in oldSect.GetObjects(): + module = self.GetModuleObject(oldComObj.GetFilename(), oldSect.GetArch()) + if module is None: continue + + newComObj = dsc.DSCComponentObject(newSect) + newComObj.SetFilename(oldComObj.GetFilename()) + + # add all library instance for override section + libdict = module.GetLibraries() + for libclass in libdict.keys(): + if libdict[libclass] is not None: + newComObj.AddOverideLib(libclass, libdict[libclass].GetRelativeFilename().replace('\\', '/')) + + # add all pcds for override section + pcddict = module.GetPcds() + for pcd in pcddict.values(): + buildPcd = pcd.GetBuildObj() + buildType = buildPcd.GetPcdType() + buildValue = None + if buildType.lower() == 'pcdsdynamichii' or \ + buildType.lower() == 'pcdsdynamicvpd' or \ + buildType.lower() == 'pcdsdynamicdefault': + buildType = 'PcdsDynamic' + if buildType != 'PcdsDynamic': + buildValue = buildPcd.GetPcdValue() + newComObj.AddOveridePcd(buildPcd.GetPcdName(), + buildType, + buildValue) + newSect.AddObject(newComObj) + return newDsc + +class Module(SurfaceObject): + def __init__(self, parent, workspace): + SurfaceObject.__init__(self, parent, workspace) + self._arch = 'common' + self._parent = parent + self._overidePcds = {} + self._overideLibs = {} + self._libs = {} + self._pcds = {} + self._ppis = [] + self._protocols = [] + self._depexs = [] + self._guids = [] + self._packages = [] + + def Destroy(self): + for lib in self._libs.values(): + if lib is not None: + lib.Destroy() + self._libs.clear() + + for pcd in self._pcds.values(): + pcd.Destroy() + self._pcds.clear() + + for ppi in self._ppis: + ppi.DeRef(self) + del self._ppis[:] + + for protocol in self._protocols: + if protocol is not None: + protocol.DeRef(self) + del self._protocols[:] + + for guid in self._guids: + if guid is not None: + guid.DeRef(self) + del self._guids[:] + + del self._packages[:] + del self._depexs[:] + SurfaceObject.Destroy(self) + + def GetFileObjectClass(self): + return inf.INFFile + + def GetLibraries(self): + return self._libs + + def Load(self, filename, arch='common', overidePcds=None, overideLibs=None): + if not SurfaceObject.Load(self, filename): + return False + + self._arch = arch + if overidePcds is not None: + self._overideLibs = overideLibs + if overideLibs is not None: + self._overidePcds = overidePcds + + self._SearchLibraries() + self._SearchPackage() + self._SearchSurfaceItems() + return True + + def GetArch(self): + return self._arch + + def GetModuleName(self): + return self.GetFileObj().GetDefine("BASE_NAME") + + def GetModuleType(self): + return self.GetFileObj().GetDefine("MODULE_TYPE") + + def GetPlatform(self): + return self.GetParent() + + def GetModuleObj(self): + return self + + def GetPcds(self): + pcds = self._pcds.copy() + for lib in self._libs.values(): + if lib is None: continue + for name in lib._pcds.keys(): + pcds[name] = lib._pcds[name] + return pcds + + def GetPpis(self): + ppis = [] + ppis += self._ppis + for lib in self._libs.values(): + if lib is None: continue + ppis += lib._ppis + return ppis + + def GetProtocols(self): + pros = [] + pros = self._protocols + for lib in self._libs.values(): + if lib is None: continue + pros += lib._protocols + return pros + + def GetGuids(self): + guids = [] + guids += self._guids + for lib in self._libs.values(): + if lib is None: continue + guids += lib._guids + return guids + + def GetDepexs(self): + deps = [] + deps += self._depexs + for lib in self._libs.values(): + if lib is None: continue + deps += lib._depexs + return deps + + def IsLibrary(self): + return self.GetFileObj().GetDefine("LIBRARY_CLASS") is not None + + def GetLibraryInstance(self, classname, arch, type): + if classname not in self._libs.keys(): + # find in overide lib firstly + if classname in self._overideLibs.keys(): + self._libs[classname] = Library(self, self.GetWorkspace()) + self._libs[classname].Load(self._overideLibs[classname]) + return self._libs[classname] + + parent = self.GetParent() + if issubclass(parent.__class__, Platform): + path = parent.GetLibraryPath(classname, arch, type) + if path is None: + ErrorMsg('Fail to get library instance for %s' % classname, self.GetFilename()) + return None + self._libs[classname] = Library(self, self.GetWorkspace()) + if not self._libs[classname].Load(path, self.GetArch()): + self._libs[classname] = None + else: + self._libs[classname] = parent.GetLibraryInstance(classname, arch, type) + return self._libs[classname] + + def GetSourceObjs(self): + return self.GetFileObj().GetSectionObjectsByName('source') + + def _SearchLibraries(self): + objs = self.GetFileObj().GetSectionObjectsByName('libraryclasses') + arch = self.GetArch() + type = self.GetModuleType() + for obj in objs: + if obj.GetArch().lower() != 'common' and \ + obj.GetArch().lower() not in self.GetPlatform().GetSupportArchs(): + continue + classname = obj.GetClass() + instance = self.GetLibraryInstance(classname, arch, type) + if not self.IsLibrary() and instance is not None: + instance._isInherit = False + + if classname not in self._libs.keys(): + self._libs[classname] = instance + + def _SearchSurfaceItems(self): + # get surface item from self's inf + pcds = [] + ppis = [] + pros = [] + deps = [] + guids = [] + if self.GetFileObj() is not None: + pcds = self.FilterObjsByArch(self.GetFileObj().GetSectionObjectsByName('pcd'), + self.GetArch()) + for pcd in pcds: + if pcd.GetPcdName() not in self._pcds.keys(): + pcdItem = PcdItem(pcd.GetPcdName(), self, pcd) + self._pcds[pcd.GetPcdName()] = ModulePcd(self, + pcd.GetPcdName(), + pcd, + pcdItem) + + ppis += self.FilterObjsByArch(self.GetFileObj().GetSectionObjectsByName('ppis'), + self.GetArch()) + + for ppi in ppis: + item = PpiItem(ppi.GetName(), self, ppi) + if item not in self._ppis: + self._ppis.append(item) + + pros += self.FilterObjsByArch(self.GetFileObj().GetSectionObjectsByName('protocols'), + self.GetArch()) + + for pro in pros: + item = ProtocolItem(pro.GetName(), self, pro) + if item not in self._protocols: + self._protocols.append(item) + + deps += self.FilterObjsByArch(self.GetFileObj().GetSectionObjectsByName('depex'), + self.GetArch()) + for dep in deps: + item = DepexItem(self, dep) + self._depexs.append(item) + + guids += self.FilterObjsByArch(self.GetFileObj().GetSectionObjectsByName('guids'), + self.GetArch()) + for guid in guids: + item = GuidItem(guid.GetName(), self, guid) + if item not in self._guids: + self._guids.append(item) + + def _SearchPackage(self): + objs = self.GetFileObj().GetSectionObjectsByName('packages') + for obj in objs: + package = self.GetPlatform().GetPackage(obj.GetPath()) + if package is not None: + self._packages.append(package) + + def GetPackages(self): + return self._packages + + def GetPcdObjects(self): + if self.GetFileObj() is None: + return [] + + return self.GetFileObj().GetSectionObjectsByName('pcd') + + def GetLibraryClassHeaderFilePath(self): + lcname = self.GetFileObj().GetProduceLibraryClass() + if lcname is None: return None + + pkgs = self.GetPackages() + for package in pkgs: + path = package.GetLibraryClassHeaderPathByName(lcname) + if path is not None: + return os.path.realpath(os.path.join(package.GetFileObj().GetPackageRootPath(), path)) + return None + + def Reload(self, force=False, callback=None): + if callback is not None: + callback(self, "Starting reload...") + + ret = SurfaceObject.Reload(self, force) + if not ret: return False + + if not force and not self.IsModified(): + return True + + for lib in self._libs.values(): + if lib is not None: + lib.Destroy() + self._libs.clear() + + for pcd in self._pcds.values(): + pcd.Destroy() + self._pcds.clear() + + for ppi in self._ppis: + ppi.DeRef(self) + del self._ppis[:] + + for protocol in self._protocols: + protocol.DeRef(self) + del self._protocols[:] + + for guid in self._guids: + guid.DeRef(self) + del self._guids[:] + + del self._packages[:] + del self._depexs[:] + + if callback is not None: + callback(self, "Searching libraries...") + self._SearchLibraries() + if callback is not None: + callback(self, "Searching packages...") + self._SearchPackage() + if callback is not None: + callback(self, "Searching surface items...") + self._SearchSurfaceItems() + + self.Modify(False) + return True + + def Modify(self, modify=True, modifiedObj=None): + if modify: + #LogMsg("%s is modified, modified object is %s" % (self.GetFilename(), modifiedObj)) + if issubclass(modifiedObj.__class__, ini.BaseINIFile) and self._isModify: + return + self._isModify = modify + self.GetParent().Modify(modify, self) + else: + if self.GetFileObj().IsModified(): + return + + self._isModify = modify + self.GetParent().Modify(modify, self) + +class Library(Module): + def __init__(self, parent, workspace): + Module.__init__(self, parent, workspace) + self._isInherit = True + + def IsInherit(self): + return self._isInherit + + def GetModuleType(self): + return self.GetParent().GetModuleType() + + def GetPlatform(self): + return self.GetParent().GetParent() + + def GetModuleObj(self): + return self.GetParent() + + def GetArch(self): + return self.GetParent().GetArch() + + def Destroy(self): + self._libs.clear() + self._pcds.clear() + SurfaceObject.Destroy(self) + +class Package(SurfaceObject): + def __init__(self, parent, workspace): + SurfaceObject.__init__(self, parent, workspace) + self._pcds = {} + self._guids = {} + self._protocols = {} + self._ppis = {} + + def GetPcds(self): + return self._pcds + + def GetPpis(self): + return list(self._ppis.values()) + + def GetProtocols(self): + return list(self._protocols.values()) + + def GetGuids(self): + return list(self._guids.values()) + + def Destroy(self): + for pcd in self._pcds.values(): + if pcd is not None: + pcd.Destroy() + for guid in self._guids.values(): + if guid is not None: + guid.Destroy() + for protocol in self._protocols.values(): + if protocol is not None: + protocol.Destroy() + for ppi in self._ppis.values(): + if ppi is not None: + ppi.Destroy() + self._pcds.clear() + self._guids.clear() + self._protocols.clear() + self._ppis.clear() + self._pcds.clear() + SurfaceObject.Destroy(self) + + def Load(self, relativePath): + ret = SurfaceObject.Load(self, relativePath) + if not ret: return False + pcds = self.GetFileObj().GetSectionObjectsByName('pcds') + for pcd in pcds: + if pcd.GetPcdName() in self._pcds.keys(): + if self._pcds[pcd.GetPcdName()] is not None: + self._pcds[pcd.GetPcdName()].AddDecObj(pcd) + else: + self._pcds[pcd.GetPcdName()] = PcdItem(pcd.GetPcdName(), self, pcd) + + guids = self.GetFileObj().GetSectionObjectsByName('guids') + for guid in guids: + if guid.GetName() not in self._guids.keys(): + self._guids[guid.GetName()] = GuidItem(guid.GetName(), self, guid) + else: + WarnMsg("Duplicate definition for %s" % guid.GetName()) + + ppis = self.GetFileObj().GetSectionObjectsByName('ppis') + for ppi in ppis: + if ppi.GetName() not in self._ppis.keys(): + self._ppis[ppi.GetName()] = PpiItem(ppi.GetName(), self, ppi) + else: + WarnMsg("Duplicate definition for %s" % ppi.GetName()) + + protocols = self.GetFileObj().GetSectionObjectsByName('protocols') + for protocol in protocols: + if protocol.GetName() not in self._protocols.keys(): + self._protocols[protocol.GetName()] = ProtocolItem(protocol.GetName(), self, protocol) + else: + WarnMsg("Duplicate definition for %s" % protocol.GetName()) + + return True + + def GetFileObjectClass(self): + return dec.DECFile + + def GetName(self): + return self.GetFileObj().GetDefine("PACKAGE_NAME") + + def GetPcdDefineObjs(self, name=None): + arr = [] + objs = self.GetFileObj().GetSectionObjectsByName('pcds') + if name is None: return objs + + for obj in objs: + if obj.GetPcdName().lower() == name.lower(): + arr.append(obj) + return arr + + def GetLibraryClassObjs(self): + return self.GetFileObj().GetSectionObjectsByName('libraryclasses') + + def Modify(self, modify=True, modifiedObj=None): + if modify: + self._isModify = modify + self.GetParent().Modify(modify, self) + else: + if self.GetFileObj().IsModified(): + return + + self._isModify = modify + self.GetParent().Modify(modify, self) + + def GetLibraryClassHeaderPathByName(self, clsname): + objs = self.GetLibraryClassObjs() + for obj in objs: + if obj.GetClassName() == clsname: + return obj.GetHeaderFile() + return None + +class DepexItem(object): + def __init__(self, parent, infObj): + self._parent = parent + self._infObj = infObj + + def GetDepexString(self): + return str(self._infObj) + + def GetInfObject(self): + return self._infObj + +class ModulePcd(object): + _type_mapping = {'FeaturePcd': 'PcdsFeatureFlag', + 'FixedPcd': 'PcdsFixedAtBuild', + 'PatchPcd': 'PcdsPatchableInModule'} + + def __init__(self, parent, name, infObj, pcdItem): + assert issubclass(parent.__class__, Module), "Module's PCD's parent must be module!" + assert pcdItem is not None, 'Pcd %s does not in some package!' % name + + self._name = name + self._parent = parent + self._pcdItem = pcdItem + self._infObj = infObj + + def GetName(self): + return self._name + + def GetParent(self): + return self._name + + def GetArch(self): + return self._parent.GetArch() + + def Destroy(self): + self._pcdItem.DeRef(self._parent) + self._infObj = None + + def GetBuildObj(self): + platformInfos = self._parent.GetPlatform().GetPcdBuildObjs(self._name, self.GetArch()) + modulePcdType = self._infObj.GetPcdType() + + # if platform do not gives pcd's value, get default value from package + if len(platformInfos) == 0: + if modulePcdType.lower() == 'pcd': + return self._pcdItem.GetDecObject() + else: + for obj in self._pcdItem.GetDecObjects(): + if modulePcdType not in self._type_mapping.keys(): + ErrorMsg("Invalid PCD type %s" % modulePcdType) + return None + + if self._type_mapping[modulePcdType] == obj.GetPcdType(): + return obj + ErrorMsg ('Module PCD type %s does not in valied range [%s] in package!' % \ + (modulePcdType)) + else: + if modulePcdType.lower() == 'pcd': + if len(platformInfos) > 1: + WarnMsg("Find more than one value for PCD %s in platform %s" % \ + (self._name, self._parent.GetPlatform().GetFilename())) + return platformInfos[0] + else: + for obj in platformInfos: + if modulePcdType not in self._type_mapping.keys(): + ErrorMsg("Invalid PCD type %s" % modulePcdType) + return None + + if self._type_mapping[modulePcdType] == obj.GetPcdType(): + return obj + + ErrorMsg('Can not find value for pcd %s in pcd type %s' % \ + (self._name, modulePcdType)) + return None + + +class SurfaceItem(object): + _objs = {} + + def __new__(cls, *args, **kwargs): + """Maintain only a single instance of this object + @return: instance of this class + + """ + name = args[0] + parent = args[1] + fileObj = args[2] + if issubclass(parent.__class__, Package): + if name in cls._objs.keys(): + ErrorMsg("%s item is duplicated defined in packages: %s and %s" % + (name, parent.GetFilename(), cls._objs[name].GetParent().GetFilename())) + return None + obj = object.__new__(cls) + cls._objs[name] = obj + return obj + elif issubclass(parent.__class__, Module): + if name not in cls._objs.keys(): + ErrorMsg("%s item does not defined in any package! It is used by module %s" % \ + (name, parent.GetFilename())) + return None + return cls._objs[name] + + return None + + + def __init__(self, name, parent, fileObj): + if issubclass(parent.__class__, Package): + self._name = name + self._parent = parent + self._decObj = [fileObj] + self._refMods = {} + else: + self.RefModule(parent, fileObj) + + @classmethod + def GetObjectDict(cls): + return cls._objs + + def GetParent(self): + return self._parent + + def GetReference(self): + return self._refMods + + def RefModule(self, mObj, infObj): + if mObj in self._refMods.keys(): + return + self._refMods[mObj] = infObj + + def DeRef(self, mObj): + if mObj not in self._refMods.keys(): + WarnMsg("%s is not referenced by module %s" % (self._name, mObj.GetFilename())) + return + del self._refMods[mObj] + + def Destroy(self): + self._refMods.clear() + cls = self.__class__ + del cls._objs[self._name] + + def GetName(self): + return self._name + + def GetDecObject(self): + return self._decObj[0] + + def GetDecObjects(self): + return self._decObj + +class PcdItem(SurfaceItem): + def AddDecObj(self, fileObj): + for decObj in self._decObj: + if decObj.GetFilename() != fileObj.GetFilename(): + ErrorMsg("Pcd %s defined in more than one packages : %s and %s" % \ + (self._name, decObj.GetFilename(), fileObj.GetFilename())) + return + if decObj.GetPcdType() == fileObj.GetPcdType() and \ + decObj.GetArch().lower() == fileObj.GetArch(): + ErrorMsg("Pcd %s is duplicated defined in pcd type %s in package %s" % \ + (self._name, decObj.GetPcdType(), decObj.GetFilename())) + return + self._decObj.append(fileObj) + + def GetValidPcdType(self): + types = [] + for obj in self._decObj: + if obj.GetPcdType() not in types: + types += obj.GetPcdType() + return types + +class GuidItem(SurfaceItem): + pass + +class PpiItem(SurfaceItem): + pass + +class ProtocolItem(SurfaceItem): + pass diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/dec.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/dec.py index c25ab322ef..cff2f1278a 100644 --- a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/dec.py +++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/dec.py @@ -1,313 +1,313 @@ -## @file
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-
-from plugins.EdkPlugins.basemodel import ini
-import re, os
-from plugins.EdkPlugins.basemodel.message import *
-
-class DECFile(ini.BaseINIFile):
-
- def GetSectionInstance(self, parent, name, isCombined=False):
- return DECSection(parent, name, isCombined)
-
- def GetComponents(self):
- return self.GetSectionByName('Components')
-
- def GetPackageRootPath(self):
- return os.path.dirname(self.GetFilename()).strip()
-
- def GetBaseName(self):
- return self.GetDefine("PACKAGE_NAME").strip()
-
- def GetVersion(self):
- return self.GetDefine("PACKAGE_VERSION").strip()
-
- def GetSectionObjectsByName(self, name, arch=None):
- arr = []
- sects = self.GetSectionByName(name)
- for sect in sects:
- # skip unmatched archtecture content
- if not sect.IsArchMatch(arch):
- continue
-
- for obj in sect.GetObjects():
- arr.append(obj)
-
- return arr
-
-class DECSection(ini.BaseINISection):
- def GetSectionINIObject(self, parent):
- type = self.GetType()
-
- if type.lower().find('defines') != -1:
- return DECDefineSectionObject(self)
- if type.lower().find('includes') != -1:
- return DECIncludeObject(self)
- if type.lower().find('pcd') != -1:
- return DECPcdObject(self)
- if type.lower() == 'libraryclasses':
- return DECLibraryClassObject(self)
- if type.lower() == 'guids':
- return DECGuidObject(self)
- if type.lower() == 'ppis':
- return DECPpiObject(self)
- if type.lower() == 'protocols':
- return DECProtocolObject(self)
-
- return DECSectionObject(self)
-
- def GetType(self):
- arr = self._name.split('.')
- return arr[0].strip()
-
- def GetArch(self):
- arr = self._name.split('.')
- if len(arr) == 1:
- return 'common'
- return arr[1]
-
- def IsArchMatch(self, arch):
- if arch is None or self.GetArch() == 'common':
- return True
-
- if self.GetArch().lower() != arch.lower():
- return False
-
- return True
-
-class DECSectionObject(ini.BaseINISectionObject):
- def GetArch(self):
- return self.GetParent().GetArch()
-
-class DECDefineSectionObject(DECSectionObject):
- def __init__(self, parent):
- DECSectionObject.__init__(self, parent)
- self._key = None
- self._value = None
-
- def Parse(self):
- assert (self._start == self._end), 'The object in define section must be in single line'
-
- line = self.GetLineByOffset(self._start).strip()
-
- line = line.split('#')[0]
- arr = line.split('=')
- if len(arr) != 2:
- ErrorMsg('Invalid define section object',
- self.GetFilename(),
- self.GetParent().GetName()
- )
- return False
-
- self._key = arr[0].strip()
- self._value = arr[1].strip()
-
- return True
-
- def GetKey(self):
- return self._key
-
- def GetValue(self):
- return self._value
-
-class DECGuidObject(DECSectionObject):
- _objs = {}
-
- def __init__(self, parent):
- DECSectionObject.__init__(self, parent)
- self._name = None
-
- def Parse(self):
- line = self.GetLineByOffset(self._start).strip().split('#')[0]
- self._name = line.split('=')[0].strip()
- self._guid = line.split('=')[1].strip()
- objdict = DECGuidObject._objs
- if self._name not in objdict.keys():
- objdict[self._name] = [self]
- else:
- objdict[self._name].append(self)
-
- return True
-
- def GetName(self):
- return self._name
-
- def GetGuid(self):
- return self._guid
-
- def Destroy(self):
- objdict = DECGuidObject._objs
- objdict[self._name].remove(self)
- if len(objdict[self._name]) == 0:
- del objdict[self._name]
-
- @staticmethod
- def GetObjectDict():
- return DECGuidObject._objs
-
-class DECPpiObject(DECSectionObject):
- _objs = {}
- def __init__(self, parent):
- DECSectionObject.__init__(self, parent)
- self._name = None
-
- def Parse(self):
- line = self.GetLineByOffset(self._start).strip().split('#')[0]
- self._name = line.split('=')[0].strip()
- self._guid = line.split('=')[1].strip()
- objdict = DECPpiObject._objs
- if self._name not in objdict.keys():
- objdict[self._name] = [self]
- else:
- objdict[self._name].append(self)
-
- return True
-
- def GetName(self):
- return self._name
-
- def GetGuid(self):
- return self._guid
-
- def Destroy(self):
- objdict = DECPpiObject._objs
- objdict[self._name].remove(self)
- if len(objdict[self._name]) == 0:
- del objdict[self._name]
-
- @staticmethod
- def GetObjectDict():
- return DECPpiObject._objs
-
-class DECProtocolObject(DECSectionObject):
- _objs = {}
-
- def __init__(self, parent):
- DECSectionObject.__init__(self, parent)
- self._name = None
-
- def Parse(self):
- line = self.GetLineByOffset(self._start).strip().split('#')[0]
- self._name = line.split('=')[0].strip()
- self._guid = line.split('=')[1].strip()
- objdict = DECProtocolObject._objs
- if self._name not in objdict.keys():
- objdict[self._name] = [self]
- else:
- objdict[self._name].append(self)
-
- return True
-
- def GetName(self):
- return self._name
-
- def GetGuid(self):
- return self._guid
-
- def Destroy(self):
- objdict = DECProtocolObject._objs
- objdict[self._name].remove(self)
- if len(objdict[self._name]) == 0:
- del objdict[self._name]
-
-
- @staticmethod
- def GetObjectDict():
- return DECProtocolObject._objs
-
-class DECLibraryClassObject(DECSectionObject):
- _objs = {}
-
- def __init__(self, parent):
- DECSectionObject.__init__(self, parent)
- self.mClassName = None
- self.mHeaderFile = None
-
- def Parse(self):
- line = self.GetLineByOffset(self._start).strip().split('#')[0]
- self.mClassName, self.mHeaderFile = line.split('|')
- objdict = DECLibraryClassObject._objs
- if self.mClassName not in objdict.keys():
- objdict[self.mClassName] = [self]
- else:
- objdict[self.mClassName].append(self)
- return True
-
- def GetClassName(self):
- return self.mClassName
-
- def GetName(self):
- return self.mClassName
-
- def GetHeaderFile(self):
- return self.mHeaderFile
-
- def Destroy(self):
- objdict = DECLibraryClassObject._objs
- objdict[self.mClassName].remove(self)
- if len(objdict[self.mClassName]) == 0:
- del objdict[self.mClassName]
-
- @staticmethod
- def GetObjectDict():
- return DECLibraryClassObject._objs
-
-class DECIncludeObject(DECSectionObject):
- def __init__(self, parent):
- DECSectionObject.__init__(self, parent)
-
- def GetPath(self):
- return self.GetLineByOffset(self._start).split('#')[0].strip()
-
-class DECPcdObject(DECSectionObject):
- _objs = {}
-
- def __init__(self, parent):
- DECSectionObject.__init__(self, parent)
- self.mPcdName = None
- self.mPcdDefaultValue = None
- self.mPcdDataType = None
- self.mPcdToken = None
-
- def Parse(self):
- line = self.GetLineByOffset(self._start).strip().split('#')[0]
- (self.mPcdName, self.mPcdDefaultValue, self.mPcdDataType, self.mPcdToken) = line.split('|')
- objdict = DECPcdObject._objs
- if self.mPcdName not in objdict.keys():
- objdict[self.mPcdName] = [self]
- else:
- objdict[self.mPcdName].append(self)
-
- return True
-
- def Destroy(self):
- objdict = DECPcdObject._objs
- objdict[self.mPcdName].remove(self)
- if len(objdict[self.mPcdName]) == 0:
- del objdict[self.mPcdName]
-
- def GetPcdType(self):
- return self.GetParent().GetType()
-
- def GetPcdName(self):
- return self.mPcdName
-
- def GetPcdValue(self):
- return self.mPcdDefaultValue
-
- def GetPcdDataType(self):
- return self.mPcdDataType
-
- def GetPcdToken(self):
- return self.mPcdToken
-
- def GetName(self):
- return self.GetPcdName().split('.')[1]
-
- @staticmethod
- def GetObjectDict():
- return DECPcdObject._objs
+## @file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +from plugins.EdkPlugins.basemodel import ini +import re, os +from plugins.EdkPlugins.basemodel.message import * + +class DECFile(ini.BaseINIFile): + + def GetSectionInstance(self, parent, name, isCombined=False): + return DECSection(parent, name, isCombined) + + def GetComponents(self): + return self.GetSectionByName('Components') + + def GetPackageRootPath(self): + return os.path.dirname(self.GetFilename()).strip() + + def GetBaseName(self): + return self.GetDefine("PACKAGE_NAME").strip() + + def GetVersion(self): + return self.GetDefine("PACKAGE_VERSION").strip() + + def GetSectionObjectsByName(self, name, arch=None): + arr = [] + sects = self.GetSectionByName(name) + for sect in sects: + # skip unmatched archtecture content + if not sect.IsArchMatch(arch): + continue + + for obj in sect.GetObjects(): + arr.append(obj) + + return arr + +class DECSection(ini.BaseINISection): + def GetSectionINIObject(self, parent): + type = self.GetType() + + if type.lower().find('defines') != -1: + return DECDefineSectionObject(self) + if type.lower().find('includes') != -1: + return DECIncludeObject(self) + if type.lower().find('pcd') != -1: + return DECPcdObject(self) + if type.lower() == 'libraryclasses': + return DECLibraryClassObject(self) + if type.lower() == 'guids': + return DECGuidObject(self) + if type.lower() == 'ppis': + return DECPpiObject(self) + if type.lower() == 'protocols': + return DECProtocolObject(self) + + return DECSectionObject(self) + + def GetType(self): + arr = self._name.split('.') + return arr[0].strip() + + def GetArch(self): + arr = self._name.split('.') + if len(arr) == 1: + return 'common' + return arr[1] + + def IsArchMatch(self, arch): + if arch is None or self.GetArch() == 'common': + return True + + if self.GetArch().lower() != arch.lower(): + return False + + return True + +class DECSectionObject(ini.BaseINISectionObject): + def GetArch(self): + return self.GetParent().GetArch() + +class DECDefineSectionObject(DECSectionObject): + def __init__(self, parent): + DECSectionObject.__init__(self, parent) + self._key = None + self._value = None + + def Parse(self): + assert (self._start == self._end), 'The object in define section must be in single line' + + line = self.GetLineByOffset(self._start).strip() + + line = line.split('#')[0] + arr = line.split('=') + if len(arr) != 2: + ErrorMsg('Invalid define section object', + self.GetFilename(), + self.GetParent().GetName() + ) + return False + + self._key = arr[0].strip() + self._value = arr[1].strip() + + return True + + def GetKey(self): + return self._key + + def GetValue(self): + return self._value + +class DECGuidObject(DECSectionObject): + _objs = {} + + def __init__(self, parent): + DECSectionObject.__init__(self, parent) + self._name = None + + def Parse(self): + line = self.GetLineByOffset(self._start).strip().split('#')[0] + self._name = line.split('=')[0].strip() + self._guid = line.split('=')[1].strip() + objdict = DECGuidObject._objs + if self._name not in objdict.keys(): + objdict[self._name] = [self] + else: + objdict[self._name].append(self) + + return True + + def GetName(self): + return self._name + + def GetGuid(self): + return self._guid + + def Destroy(self): + objdict = DECGuidObject._objs + objdict[self._name].remove(self) + if len(objdict[self._name]) == 0: + del objdict[self._name] + + @staticmethod + def GetObjectDict(): + return DECGuidObject._objs + +class DECPpiObject(DECSectionObject): + _objs = {} + def __init__(self, parent): + DECSectionObject.__init__(self, parent) + self._name = None + + def Parse(self): + line = self.GetLineByOffset(self._start).strip().split('#')[0] + self._name = line.split('=')[0].strip() + self._guid = line.split('=')[1].strip() + objdict = DECPpiObject._objs + if self._name not in objdict.keys(): + objdict[self._name] = [self] + else: + objdict[self._name].append(self) + + return True + + def GetName(self): + return self._name + + def GetGuid(self): + return self._guid + + def Destroy(self): + objdict = DECPpiObject._objs + objdict[self._name].remove(self) + if len(objdict[self._name]) == 0: + del objdict[self._name] + + @staticmethod + def GetObjectDict(): + return DECPpiObject._objs + +class DECProtocolObject(DECSectionObject): + _objs = {} + + def __init__(self, parent): + DECSectionObject.__init__(self, parent) + self._name = None + + def Parse(self): + line = self.GetLineByOffset(self._start).strip().split('#')[0] + self._name = line.split('=')[0].strip() + self._guid = line.split('=')[1].strip() + objdict = DECProtocolObject._objs + if self._name not in objdict.keys(): + objdict[self._name] = [self] + else: + objdict[self._name].append(self) + + return True + + def GetName(self): + return self._name + + def GetGuid(self): + return self._guid + + def Destroy(self): + objdict = DECProtocolObject._objs + objdict[self._name].remove(self) + if len(objdict[self._name]) == 0: + del objdict[self._name] + + + @staticmethod + def GetObjectDict(): + return DECProtocolObject._objs + +class DECLibraryClassObject(DECSectionObject): + _objs = {} + + def __init__(self, parent): + DECSectionObject.__init__(self, parent) + self.mClassName = None + self.mHeaderFile = None + + def Parse(self): + line = self.GetLineByOffset(self._start).strip().split('#')[0] + self.mClassName, self.mHeaderFile = line.split('|') + objdict = DECLibraryClassObject._objs + if self.mClassName not in objdict.keys(): + objdict[self.mClassName] = [self] + else: + objdict[self.mClassName].append(self) + return True + + def GetClassName(self): + return self.mClassName + + def GetName(self): + return self.mClassName + + def GetHeaderFile(self): + return self.mHeaderFile + + def Destroy(self): + objdict = DECLibraryClassObject._objs + objdict[self.mClassName].remove(self) + if len(objdict[self.mClassName]) == 0: + del objdict[self.mClassName] + + @staticmethod + def GetObjectDict(): + return DECLibraryClassObject._objs + +class DECIncludeObject(DECSectionObject): + def __init__(self, parent): + DECSectionObject.__init__(self, parent) + + def GetPath(self): + return self.GetLineByOffset(self._start).split('#')[0].strip() + +class DECPcdObject(DECSectionObject): + _objs = {} + + def __init__(self, parent): + DECSectionObject.__init__(self, parent) + self.mPcdName = None + self.mPcdDefaultValue = None + self.mPcdDataType = None + self.mPcdToken = None + + def Parse(self): + line = self.GetLineByOffset(self._start).strip().split('#')[0] + (self.mPcdName, self.mPcdDefaultValue, self.mPcdDataType, self.mPcdToken) = line.split('|') + objdict = DECPcdObject._objs + if self.mPcdName not in objdict.keys(): + objdict[self.mPcdName] = [self] + else: + objdict[self.mPcdName].append(self) + + return True + + def Destroy(self): + objdict = DECPcdObject._objs + objdict[self.mPcdName].remove(self) + if len(objdict[self.mPcdName]) == 0: + del objdict[self.mPcdName] + + def GetPcdType(self): + return self.GetParent().GetType() + + def GetPcdName(self): + return self.mPcdName + + def GetPcdValue(self): + return self.mPcdDefaultValue + + def GetPcdDataType(self): + return self.mPcdDataType + + def GetPcdToken(self): + return self.mPcdToken + + def GetName(self): + return self.GetPcdName().split('.')[1] + + @staticmethod + def GetObjectDict(): + return DECPcdObject._objs diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/doxygengen.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/doxygengen.py index 89833043c6..829ac803df 100644 --- a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/doxygengen.py +++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/doxygengen.py @@ -1,1084 +1,1084 @@ -## @file
-#
-# This file produce action class to generate doxygen document for edk2 codebase.
-# The action classes are shared by GUI and command line tools.
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-
-"""This file produce action class to generate doxygen document for edk2 codebase.
- The action classes are shared by GUI and command line tools.
-"""
-from plugins.EdkPlugins.basemodel import doxygen
-import os
-try:
- import wx
- gInGui = True
-except:
- gInGui = False
-import re
-from plugins.EdkPlugins.edk2.model import inf
-from plugins.EdkPlugins.edk2.model import dec
-from plugins.EdkPlugins.basemodel.message import *
-
-_ignore_dir = ['.svn', '_svn', 'cvs']
-_inf_key_description_mapping_table = {
- 'INF_VERSION':'Version of INF file specification',
- #'BASE_NAME':'Module Name',
- 'FILE_GUID':'Module Guid',
- 'MODULE_TYPE': 'Module Type',
- 'VERSION_STRING': 'Module Version',
- 'LIBRARY_CLASS': 'Produced Library Class',
- 'EFI_SPECIFICATION_VERSION': 'UEFI Specification Version',
- 'PI_SPECIFICATION_VERSION': 'PI Specification Version',
- 'ENTRY_POINT': 'Module Entry Point Function',
- 'CONSTRUCTOR': 'Library Constructor Function'
-}
-
-_dec_key_description_mapping_table = {
- 'DEC_SPECIFICATION': 'Version of DEC file specification',
- 'PACKAGE_GUID': 'Package Guid'
-}
-class DoxygenAction:
- """This is base class for all doxygen action.
- """
-
- def __init__(self, doxPath, chmPath, outputPath, projname, mode='html', log=None, verbose=False):
- """Constructor function.
- @param doxPath the obosolution path of doxygen execute file.
- @param outputPath the obosolution output path.
- @param log log function for output message
- """
- self._doxPath = doxPath
- self._chmPath = chmPath
- self._outputPath = outputPath
- self._projname = projname
- self._configFile = None # doxygen config file is used by doxygen exe file
- self._indexPageFile = None # doxygen page file for index page.
- self._log = log
- self._mode = mode
- self._verbose = verbose
- self._doxygenCallback = None
- self._chmCallback = None
-
- def Log(self, message, level='info'):
- if self._log is not None:
- self._log(message, level)
-
- def IsVerbose(self):
- return self._verbose
-
- def Generate(self):
- """Generate interface called by outer directly"""
- self.Log(">>>>>> Start generate doxygen document for %s... Zzz....\n" % self._projname)
-
- # create doxygen config file at first
- self._configFile = doxygen.DoxygenConfigFile()
- self._configFile.SetOutputDir(self._outputPath)
-
- self._configFile.SetWarningFilePath(os.path.join(self._outputPath, 'warning.txt'))
- if self._mode.lower() == 'html':
- self._configFile.SetHtmlMode()
- else:
- self._configFile.SetChmMode()
-
- self.Log(" >>>>>> Initialize doxygen config file...Zzz...\n")
- self.InitializeConfigFile()
-
- self.Log(" >>>>>> Generate doxygen index page file...Zzz...\n")
- indexPagePath = self.GenerateIndexPage()
- if indexPagePath is None:
- self.Log("Fail to generate index page!\n", 'error')
- return False
- else:
- self.Log("Success to create doxygen index page file %s \n" % indexPagePath)
-
- # Add index page doxygen file to file list.
- self._configFile.AddFile(indexPagePath)
-
- # save config file to output path
- configFilePath = os.path.join(self._outputPath, self._projname + '.doxygen_config')
- self._configFile.Generate(configFilePath)
- self.Log(" <<<<<< Success Save doxygen config file to %s...\n" % configFilePath)
-
- # launch doxygen tool to generate document
- if self._doxygenCallback is not None:
- self.Log(" >>>>>> Start doxygen process...Zzz...\n")
- if not self._doxygenCallback(self._doxPath, configFilePath):
- return False
- else:
- self.Log("Fail to create doxygen process!", 'error')
- return False
-
- return True
-
- def InitializeConfigFile(self):
- """Initialize config setting for doxygen project. It will be invoked after config file
- object is created. Inherited class should implement it.
- """
-
- def GenerateIndexPage(self):
- """Generate doxygen index page. Inherited class should implement it."""
- return None
-
- def RegisterCallbackDoxygenProcess(self, callback):
- self._doxygenCallback = callback
-
- def RegisterCallbackCHMProcess(self, callback):
- self._chmCallback = callback
-
-class PlatformDocumentAction(DoxygenAction):
- """Generate platform doxygen document, will be implement at future."""
-
-class PackageDocumentAction(DoxygenAction):
- """Generate package reference document"""
-
- def __init__(self, doxPath, chmPath, outputPath, pObj, mode='html', log=None, arch=None, tooltag=None,
- onlyInclude=False, verbose=False):
- DoxygenAction.__init__(self, doxPath, chmPath, outputPath, pObj.GetName(), mode, log, verbose)
- self._pObj = pObj
- self._arch = arch
- self._tooltag = tooltag
- self._onlyIncludeDocument = onlyInclude
-
- def InitializeConfigFile(self):
- if self._arch == 'IA32':
- self._configFile.AddPreDefined('MDE_CPU_IA32')
- elif self._arch == 'X64':
- self._configFile.AddPreDefined('MDE_CPU_X64')
- elif self._arch == 'IPF':
- self._configFile.AddPreDefined('MDE_CPU_IPF')
- elif self._arch == 'EBC':
- self._configFile.AddPreDefined('MDE_CPU_EBC')
- else:
- self._arch = None
- self._configFile.AddPreDefined('MDE_CPU_IA32')
- self._configFile.AddPreDefined('MDE_CPU_X64')
- self._configFile.AddPreDefined('MDE_CPU_IPF')
- self._configFile.AddPreDefined('MDE_CPU_EBC')
- self._configFile.AddPreDefined('MDE_CPU_ARM')
-
- namestr = self._pObj.GetName()
- if self._arch is not None:
- namestr += '[%s]' % self._arch
- if self._tooltag is not None:
- namestr += '[%s]' % self._tooltag
- self._configFile.SetProjectName(namestr)
- self._configFile.SetStripPath(self._pObj.GetWorkspace())
- self._configFile.SetProjectVersion(self._pObj.GetFileObj().GetVersion())
- self._configFile.AddPattern('*.decdoxygen')
-
- if self._tooltag.lower() == 'msft':
- self._configFile.AddPreDefined('_MSC_EXTENSIONS')
- elif self._tooltag.lower() == 'gnu':
- self._configFile.AddPreDefined('__GNUC__')
- elif self._tooltag.lower() == 'intel':
- self._configFile.AddPreDefined('__INTEL_COMPILER')
- else:
- self._tooltag = None
- self._configFile.AddPreDefined('_MSC_EXTENSIONS')
- self._configFile.AddPreDefined('__GNUC__')
- self._configFile.AddPreDefined('__INTEL_COMPILER')
-
- self._configFile.AddPreDefined('ASM_PFX= ')
- self._configFile.AddPreDefined('OPTIONAL= ')
-
- def GenerateIndexPage(self):
- """Generate doxygen index page. Inherited class should implement it."""
- fObj = self._pObj.GetFileObj()
- pdObj = doxygen.DoxygenFile('%s Package Document' % self._pObj.GetName(),
- '%s.decdoxygen' % self._pObj.GetFilename())
- self._configFile.AddFile(pdObj.GetFilename())
- pdObj.AddDescription(fObj.GetFileHeader())
-
- defSection = fObj.GetSectionByName('defines')[0]
- baseSection = doxygen.Section('PackageBasicInformation', 'Package Basic Information')
- descr = '<TABLE>'
- for obj in defSection.GetObjects():
- if obj.GetKey() in _dec_key_description_mapping_table.keys():
- descr += '<TR>'
- descr += '<TD><B>%s</B></TD>' % _dec_key_description_mapping_table[obj.GetKey()]
- descr += '<TD>%s</TD>' % obj.GetValue()
- descr += '</TR>'
- descr += '</TABLE><br>'
- baseSection.AddDescription(descr)
- pdObj.AddSection(baseSection)
-
- knownIssueSection = doxygen.Section('Known_Issue_section', 'Known Issue')
- knownIssueSection.AddDescription('<ul>')
- knownIssueSection.AddDescription('<li> OPTIONAL macro for function parameter can not be dealed with doxygen, so it disapear in this document! </li>')
- knownIssueSection.AddDescription('</ul>')
- pdObj.AddSection(knownIssueSection)
-
- self.AddAllIncludeFiles(self._pObj, self._configFile)
- pages = self.GenerateIncludesSubPage(self._pObj, self._configFile)
- if len(pages) != 0:
- pdObj.AddPages(pages)
- pages = self.GenerateLibraryClassesSubPage(self._pObj, self._configFile)
- if len(pages) != 0:
- pdObj.AddPages(pages)
- pages = self.GeneratePcdSubPages(self._pObj, self._configFile)
- if len(pages) != 0:
- pdObj.AddPages(pages)
- pages = self.GenerateGuidSubPages(self._pObj, self._configFile)
- if len(pages) != 0:
- pdObj.AddPages(pages)
- pages = self.GeneratePpiSubPages(self._pObj, self._configFile)
- if len(pages) != 0:
- pdObj.AddPages(pages)
- pages = self.GenerateProtocolSubPages(self._pObj, self._configFile)
- if len(pages) != 0:
- pdObj.AddPages(pages)
- if not self._onlyIncludeDocument:
- pdObj.AddPages(self.GenerateModulePages(self._pObj, self._configFile))
-
- pdObj.Save()
- return pdObj.GetFilename()
-
- def GenerateIncludesSubPage(self, pObj, configFile):
- # by default add following path as include path to config file
- pkpath = pObj.GetFileObj().GetPackageRootPath()
- configFile.AddIncludePath(os.path.join(pkpath, 'Include'))
- configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Library'))
- configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Protocol'))
- configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Ppi'))
- configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Guid'))
- configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'IndustryStandard'))
-
- rootArray = []
- pageRoot = doxygen.Page("Public Includes", "%s_public_includes" % pObj.GetName())
- objs = pObj.GetFileObj().GetSectionObjectsByName('includes')
- if len(objs) == 0: return []
-
- for obj in objs:
- # Add path to include path
- path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetPath())
- configFile.AddIncludePath(path)
-
- # only list common folder's include file
- if obj.GetArch().lower() != 'common':
- continue
-
- bNeedAddIncludePage = False
- topPage = doxygen.Page(self._ConvertPathToDoxygen(path, pObj), 'public_include_top')
-
- topPage.AddDescription('<ul>\n')
- for file in os.listdir(path):
- if file.lower() in _ignore_dir: continue
- fullpath = os.path.join(path, file)
- if os.path.isfile(fullpath):
- self.ProcessSourceFileForInclude(fullpath, pObj, configFile)
- topPage.AddDescription('<li> \link %s\endlink </li>\n' % self._ConvertPathToDoxygen(fullpath, pObj))
- else:
- if file.lower() in ['library', 'protocol', 'guid', 'ppi', 'ia32', 'x64', 'ipf', 'ebc', 'arm', 'pi', 'uefi', 'aarch64']:
- continue
- bNeedAddSubPage = False
- subpage = doxygen.Page(self._ConvertPathToDoxygen(fullpath, pObj), 'public_include_%s' % file)
- subpage.AddDescription('<ul>\n')
- for subfile in os.listdir(fullpath):
- if subfile.lower() in _ignore_dir: continue
- bNeedAddSubPage = True
- subfullpath = os.path.join(fullpath, subfile)
- self.ProcessSourceFileForInclude(subfullpath, pObj, configFile)
- subpage.AddDescription('<li> \link %s \endlink </li>\n' % self._ConvertPathToDoxygen(subfullpath, pObj))
- subpage.AddDescription('</ul>\n')
- if bNeedAddSubPage:
- bNeedAddIncludePage = True
- pageRoot.AddPage(subpage)
- topPage.AddDescription('</ul>\n')
- if bNeedAddIncludePage:
- pageRoot.AddPage(topPage)
-
- if pageRoot.GetSubpageCount() != 0:
- return [pageRoot]
- else:
- return []
-
- def GenerateLibraryClassesSubPage(self, pObj, configFile):
- """
- Generate sub page for library class for package.
- One DEC file maybe contains many library class sections
- for different architecture.
-
- @param fObj DEC file object.
- """
- rootArray = []
- pageRoot = doxygen.Page("Library Class", "%s_libraryclass" % pObj.GetName())
- objs = pObj.GetFileObj().GetSectionObjectsByName('libraryclass', self._arch)
- if len(objs) == 0: return []
-
- if self._arch is not None:
- for obj in objs:
- classPage = doxygen.Page(obj.GetClassName(),
- "lc_%s" % obj.GetClassName())
- comments = obj.GetComment()
- if len(comments) != 0:
- classPage.AddDescription('<br>\n'.join(comments) + '<br>\n')
- pageRoot.AddPage(classPage)
- path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile())
- path = path[len(pObj.GetWorkspace()) + 1:]
- if len(comments) == 0:
- classPage.AddDescription('\copydoc %s<p>' % obj.GetHeaderFile())
- section = doxygen.Section('ref', 'Refer to Header File')
- section.AddDescription('\link %s\n' % obj.GetHeaderFile())
- section.AddDescription(' \endlink<p>\n')
- classPage.AddSection(section)
- fullPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile())
- self.ProcessSourceFileForInclude(fullPath, pObj, configFile)
- else:
- archPageDict = {}
- for obj in objs:
- if obj.GetArch() not in archPageDict.keys():
- archPageDict[obj.GetArch()] = doxygen.Page(obj.GetArch(),
- 'lc_%s' % obj.GetArch())
- pageRoot.AddPage(archPageDict[obj.GetArch()])
- subArchRoot = archPageDict[obj.GetArch()]
- classPage = doxygen.Page(obj.GetClassName(),
- "lc_%s" % obj.GetClassName())
- comments = obj.GetComment()
- if len(comments) != 0:
- classPage.AddDescription('<br>\n'.join(comments) + '<br>\n')
- subArchRoot.AddPage(classPage)
- path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile())
- path = path[len(pObj.GetWorkspace()) + 1:]
- if len(comments) == 0:
- classPage.AddDescription('\copydoc %s<p>' % obj.GetHeaderFile())
- section = doxygen.Section('ref', 'Refer to Header File')
- section.AddDescription('\link %s\n' % obj.GetHeaderFile())
- section.AddDescription(' \endlink<p>\n')
- classPage.AddSection(section)
- fullPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile())
-
- self.ProcessSourceFileForInclude(fullPath, pObj, configFile)
- rootArray.append(pageRoot)
- return rootArray
-
- def ProcessSourceFileForInclude(self, path, pObj, configFile, infObj=None):
- """
- @param path the analysising file full path
- @param pObj package object
- @param configFile doxygen config file.
- """
- if gInGui:
- wx.Yield()
- if not os.path.exists(path):
- ErrorMsg('Source file path %s does not exist!' % path)
- return
-
- if configFile.FileExists(path):
- return
-
- try:
- with open(path, 'r') as f:
- lines = f.readlines()
- except UnicodeDecodeError:
- return
- except IOError:
- ErrorMsg('Fail to open file %s' % path)
- return
-
- configFile.AddFile(path)
-
- no = 0
- for no in range(len(lines)):
- if len(lines[no].strip()) == 0:
- continue
- if lines[no].strip()[:2] in ['##', '//', '/*', '*/']:
- continue
- index = lines[no].lower().find('include')
- #mo = IncludePattern.finditer(lines[no].lower())
- mo = re.match(r"^#\s*include\s+[<\"]([\\/\w.]+)[>\"]$", lines[no].strip().lower())
- if not mo:
- continue
- mo = re.match(r"^[#\w\s]+[<\"]([\\/\w.]+)[>\"]$", lines[no].strip())
- filePath = mo.groups()[0]
-
- if filePath is None or len(filePath) == 0:
- continue
-
- # find header file in module's path firstly.
- fullPath = None
-
- if os.path.exists(os.path.join(os.path.dirname(path), filePath)):
- # Find the file in current directory
- fullPath = os.path.join(os.path.dirname(path), filePath).replace('\\', '/')
- else:
- # find in depedent package's include path
- incObjs = pObj.GetFileObj().GetSectionObjectsByName('includes')
- for incObj in incObjs:
- incPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), incObj.GetPath()).strip()
- incPath = os.path.realpath(os.path.join(incPath, filePath))
- if os.path.exists(incPath):
- fullPath = incPath
- break
- if infObj is not None:
- pkgInfObjs = infObj.GetSectionObjectsByName('packages')
- for obj in pkgInfObjs:
- decObj = dec.DECFile(os.path.join(pObj.GetWorkspace(), obj.GetPath()))
- if not decObj:
- ErrorMsg ('Fail to create pacakge object for %s' % obj.GetPackageName())
- continue
- if not decObj.Parse():
- ErrorMsg ('Fail to load package object for %s' % obj.GetPackageName())
- continue
- incObjs = decObj.GetSectionObjectsByName('includes')
- for incObj in incObjs:
- incPath = os.path.join(decObj.GetPackageRootPath(), incObj.GetPath()).replace('\\', '/')
- if os.path.exists(os.path.join(incPath, filePath)):
- fullPath = os.path.join(os.path.join(incPath, filePath))
- break
- if fullPath is not None:
- break
-
- if fullPath is None and self.IsVerbose():
- self.Log('Can not resolve header file %s for file %s in package %s\n' % (filePath, path, pObj.GetFileObj().GetFilename()), 'error')
- return
- else:
- fullPath = fullPath.replace('\\', '/')
- if self.IsVerbose():
- self.Log('Preprocessing: Add include file %s for file %s\n' % (fullPath, path))
- #LogMsg ('Preprocessing: Add include file %s for file %s' % (fullPath, path))
- self.ProcessSourceFileForInclude(fullPath, pObj, configFile, infObj)
-
- def AddAllIncludeFiles(self, pObj, configFile):
- objs = pObj.GetFileObj().GetSectionObjectsByName('includes')
- for obj in objs:
- incPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetPath())
- for root, dirs, files in os.walk(incPath):
- for dir in dirs:
- if dir.lower() in _ignore_dir:
- dirs.remove(dir)
- for file in files:
- path = os.path.normpath(os.path.join(root, file))
- configFile.AddFile(path.replace('/', '\\'))
-
- def GeneratePcdSubPages(self, pObj, configFile):
- """
- Generate sub pages for package's PCD definition.
- @param pObj package object
- @param configFile config file object
- """
- rootArray = []
- objs = pObj.GetFileObj().GetSectionObjectsByName('pcd')
- if len(objs) == 0:
- return []
-
- pcdRootPage = doxygen.Page('PCD', 'pcd_root_page')
- typeRootPageDict = {}
- typeArchRootPageDict = {}
- for obj in objs:
- if obj.GetPcdType() not in typeRootPageDict.keys():
- typeRootPageDict[obj.GetPcdType()] = doxygen.Page(obj.GetPcdType(), 'pcd_%s_root_page' % obj.GetPcdType())
- pcdRootPage.AddPage(typeRootPageDict[obj.GetPcdType()])
- typeRoot = typeRootPageDict[obj.GetPcdType()]
- if self._arch is not None:
- pcdPage = doxygen.Page('%s' % obj.GetPcdName(),
- 'pcd_%s_%s_%s' % (obj.GetPcdType(), obj.GetArch(), obj.GetPcdName().split('.')[1]))
- pcdPage.AddDescription('<br>\n'.join(obj.GetComment()) + '<br>\n')
- section = doxygen.Section('PCDinformation', 'PCD Information')
- desc = '<TABLE>'
- desc += '<TR>'
- desc += '<TD><CAPTION>Name</CAPTION></TD>'
- desc += '<TD><CAPTION>Token Space</CAPTION></TD>'
- desc += '<TD><CAPTION>Token number</CAPTION></TD>'
- desc += '<TD><CAPTION>Data Type</CAPTION></TD>'
- desc += '<TD><CAPTION>Default Value</CAPTION></TD>'
- desc += '</TR>'
- desc += '<TR>'
- desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[1]
- desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[0]
- desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdToken()
- desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdDataType()
- desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdValue()
- desc += '</TR>'
- desc += '</TABLE>'
- section.AddDescription(desc)
- pcdPage.AddSection(section)
- typeRoot.AddPage(pcdPage)
- else:
- keystr = obj.GetPcdType() + obj.GetArch()
- if keystr not in typeArchRootPageDict.keys():
- typeArchRootPage = doxygen.Page(obj.GetArch(), 'pcd_%s_%s_root_page' % (obj.GetPcdType(), obj.GetArch()))
- typeArchRootPageDict[keystr] = typeArchRootPage
- typeRoot.AddPage(typeArchRootPage)
- typeArchRoot = typeArchRootPageDict[keystr]
- pcdPage = doxygen.Page('%s' % obj.GetPcdName(),
- 'pcd_%s_%s_%s' % (obj.GetPcdType(), obj.GetArch(), obj.GetPcdName().split('.')[1]))
- pcdPage.AddDescription('<br>\n'.join(obj.GetComment()) + '<br>\n')
- section = doxygen.Section('PCDinformation', 'PCD Information')
- desc = '<TABLE>'
- desc += '<TR>'
- desc += '<TD><CAPTION>Name</CAPTION></TD>'
- desc += '<TD><CAPTION>Token Space</CAPTION></TD>'
- desc += '<TD><CAPTION>Token number</CAPTION></TD>'
- desc += '<TD><CAPTION>Data Type</CAPTION></TD>'
- desc += '<TD><CAPTION>Default Value</CAPTION></TD>'
- desc += '</TR>'
- desc += '<TR>'
- desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[1]
- desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[0]
- desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdToken()
- desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdDataType()
- desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdValue()
- desc += '</TR>'
- desc += '</TABLE>'
- section.AddDescription(desc)
- pcdPage.AddSection(section)
- typeArchRoot.AddPage(pcdPage)
- return [pcdRootPage]
-
- def _GenerateGuidSubPage(self, pObj, obj, configFile):
- guidPage = doxygen.Page('%s' % obj.GetName(),
- 'guid_%s_%s' % (obj.GetArch(), obj.GetName()))
- comments = obj.GetComment()
- if len(comments) != 0:
- guidPage.AddDescription('<br>'.join(obj.GetComment()) + '<br>')
- section = doxygen.Section('BasicGuidInfo', 'GUID Information')
- desc = '<TABLE>'
- desc += '<TR>'
- desc += '<TD><CAPTION>GUID\'s Guid Name</CAPTION></TD><TD><CAPTION>GUID\'s Guid</CAPTION></TD>'
- desc += '</TR>'
- desc += '<TR>'
- desc += '<TD>%s</TD>' % obj.GetName()
- desc += '<TD>%s</TD>' % obj.GetGuid()
- desc += '</TR>'
- desc += '</TABLE>'
- section.AddDescription(desc)
- guidPage.AddSection(section)
- refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile)
- if refFile:
- relPath = refFile[len(pObj.GetWorkspace()) + 1:]
- if len(comments) == 0:
- guidPage.AddDescription(' \\copydoc %s <br>' % relPath)
-
- section = doxygen.Section('ref', 'Refer to Header File')
- section.AddDescription('\link %s\n' % relPath)
- section.AddDescription('\endlink\n')
- self.ProcessSourceFileForInclude(refFile, pObj, configFile)
- guidPage.AddSection(section)
- return guidPage
-
- def GenerateGuidSubPages(self, pObj, configFile):
- """
- Generate sub pages for package's GUID definition.
- @param pObj package object
- @param configFilf doxygen config file object
- """
- pageRoot = doxygen.Page('GUID', 'guid_root_page')
- objs = pObj.GetFileObj().GetSectionObjectsByName('guids', self._arch)
- if len(objs) == 0: return []
- if self._arch is not None:
- for obj in objs:
- pageRoot.AddPage(self._GenerateGuidSubPage(pObj, obj, configFile))
- else:
- guidArchRootPageDict = {}
- for obj in objs:
- if obj.GetArch() not in guidArchRootPageDict.keys():
- guidArchRoot = doxygen.Page(obj.GetArch(), 'guid_arch_root_%s' % obj.GetArch())
- pageRoot.AddPage(guidArchRoot)
- guidArchRootPageDict[obj.GetArch()] = guidArchRoot
- guidArchRoot = guidArchRootPageDict[obj.GetArch()]
- guidArchRoot.AddPage(self._GenerateGuidSubPage(pObj, obj, configFile))
- return [pageRoot]
-
- def _GeneratePpiSubPage(self, pObj, obj, configFile):
- guidPage = doxygen.Page(obj.GetName(), 'ppi_page_%s' % obj.GetName())
- comments = obj.GetComment()
- if len(comments) != 0:
- guidPage.AddDescription('<br>'.join(obj.GetComment()) + '<br>')
- section = doxygen.Section('BasicPpiInfo', 'PPI Information')
- desc = '<TABLE>'
- desc += '<TR>'
- desc += '<TD><CAPTION>PPI\'s Guid Name</CAPTION></TD><TD><CAPTION>PPI\'s Guid</CAPTION></TD>'
- desc += '</TR>'
- desc += '<TR>'
- desc += '<TD>%s</TD>' % obj.GetName()
- desc += '<TD>%s</TD>' % obj.GetGuid()
- desc += '</TR>'
- desc += '</TABLE>'
- section.AddDescription(desc)
- guidPage.AddSection(section)
- refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile)
- if refFile:
- relPath = refFile[len(pObj.GetWorkspace()) + 1:]
- if len(comments) == 0:
- guidPage.AddDescription(' \\copydoc %s <br>' % relPath)
- section = doxygen.Section('ref', 'Refer to Header File')
- section.AddDescription('\link %s\n' % relPath)
- section.AddDescription('\endlink\n')
- self.ProcessSourceFileForInclude(refFile, pObj, configFile)
- guidPage.AddSection(section)
-
- return guidPage
-
- def GeneratePpiSubPages(self, pObj, configFile):
- """
- Generate sub pages for package's GUID definition.
- @param pObj package object
- @param configFilf doxygen config file object
- """
- pageRoot = doxygen.Page('PPI', 'ppi_root_page')
- objs = pObj.GetFileObj().GetSectionObjectsByName('ppis', self._arch)
- if len(objs) == 0: return []
- if self._arch is not None:
- for obj in objs:
- pageRoot.AddPage(self._GeneratePpiSubPage(pObj, obj, configFile))
- else:
- guidArchRootPageDict = {}
- for obj in objs:
- if obj.GetArch() not in guidArchRootPageDict.keys():
- guidArchRoot = doxygen.Page(obj.GetArch(), 'ppi_arch_root_%s' % obj.GetArch())
- pageRoot.AddPage(guidArchRoot)
- guidArchRootPageDict[obj.GetArch()] = guidArchRoot
- guidArchRoot = guidArchRootPageDict[obj.GetArch()]
- guidArchRoot.AddPage(self._GeneratePpiSubPage(pObj, obj, configFile))
- return [pageRoot]
-
- def _GenerateProtocolSubPage(self, pObj, obj, configFile):
- guidPage = doxygen.Page(obj.GetName(), 'protocol_page_%s' % obj.GetName())
- comments = obj.GetComment()
- if len(comments) != 0:
- guidPage.AddDescription('<br>'.join(obj.GetComment()) + '<br>')
- section = doxygen.Section('BasicProtocolInfo', 'PROTOCOL Information')
- desc = '<TABLE>'
- desc += '<TR>'
- desc += '<TD><CAPTION>PROTOCOL\'s Guid Name</CAPTION></TD><TD><CAPTION>PROTOCOL\'s Guid</CAPTION></TD>'
- desc += '</TR>'
- desc += '<TR>'
- desc += '<TD>%s</TD>' % obj.GetName()
- desc += '<TD>%s</TD>' % obj.GetGuid()
- desc += '</TR>'
- desc += '</TABLE>'
- section.AddDescription(desc)
- guidPage.AddSection(section)
-
- refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile)
- if refFile:
- relPath = refFile[len(pObj.GetWorkspace()) + 1:]
- if len(comments) == 0:
- guidPage.AddDescription(' \\copydoc %s <br>' % relPath)
- section = doxygen.Section('ref', 'Refer to Header File')
- section.AddDescription('\link %s\n' % relPath)
- section.AddDescription('\endlink\n')
- self.ProcessSourceFileForInclude(refFile, pObj, configFile)
- guidPage.AddSection(section)
-
- return guidPage
-
- def GenerateProtocolSubPages(self, pObj, configFile):
- """
- Generate sub pages for package's GUID definition.
- @param pObj package object
- @param configFilf doxygen config file object
- """
- pageRoot = doxygen.Page('PROTOCOL', 'protocol_root_page')
- objs = pObj.GetFileObj().GetSectionObjectsByName('protocols', self._arch)
- if len(objs) == 0: return []
- if self._arch is not None:
- for obj in objs:
- pageRoot.AddPage(self._GenerateProtocolSubPage(pObj, obj, configFile))
- else:
- guidArchRootPageDict = {}
- for obj in objs:
- if obj.GetArch() not in guidArchRootPageDict.keys():
- guidArchRoot = doxygen.Page(obj.GetArch(), 'protocol_arch_root_%s' % obj.GetArch())
- pageRoot.AddPage(guidArchRoot)
- guidArchRootPageDict[obj.GetArch()] = guidArchRoot
- guidArchRoot = guidArchRootPageDict[obj.GetArch()]
- guidArchRoot.AddPage(self._GenerateProtocolSubPage(pObj, obj, configFile))
- return [pageRoot]
-
- def FindHeaderFileForGuid(self, pObj, name, configFile):
- """
- For declaration header file for GUID/PPI/Protocol.
-
- @param pObj package object
- @param name guid/ppi/protocol's name
- @param configFile config file object
-
- @return full path of header file and None if not found.
- """
- startPath = pObj.GetFileObj().GetPackageRootPath()
- incPath = os.path.join(startPath, 'Include').replace('\\', '/')
- # if <PackagePath>/include exist, then search header under it.
- if os.path.exists(incPath):
- startPath = incPath
-
- for root, dirs, files in os.walk(startPath):
- for dir in dirs:
- if dir.lower() in _ignore_dir:
- dirs.remove(dir)
- for file in files:
- fPath = os.path.join(root, file)
- if not IsCHeaderFile(fPath):
- continue
- try:
- f = open(fPath, 'r')
- lines = f.readlines()
- f.close()
- except IOError:
- self.Log('Fail to open file %s\n' % fPath)
- continue
- for line in lines:
- if line.find(name) != -1 and \
- line.find('extern') != -1:
- return fPath.replace('\\', '/')
- return None
-
- def GetPackageModuleList(self, pObj):
- """
- Get all module's INF path under package's root path
- @param pObj package object
- @return arrary of INF full path
- """
- mArray = []
- packPath = pObj.GetFileObj().GetPackageRootPath()
- if not os.path.exists:
- return None
- for root, dirs, files in os.walk(packPath):
- for dir in dirs:
- if dir.lower() in _ignore_dir:
- dirs.remove(dir)
- for file in files:
- if CheckPathPostfix(file, 'inf'):
- fPath = os.path.join(root, file).replace('\\', '/')
- mArray.append(fPath)
- return mArray
-
- def GenerateModulePages(self, pObj, configFile):
- """
- Generate sub pages for package's module which is under the package
- root directory.
-
- @param pObj package object
- @param configFilf doxygen config file object
- """
- infList = self.GetPackageModuleList(pObj)
- rootPages = []
- libObjs = []
- modObjs = []
- for infpath in infList:
- infObj = inf.INFFile(infpath)
- #infObj = INFFileObject.INFFile (pObj.GetWorkspacePath(),
- # inf)
- if not infObj:
- self.Log('Fail create INF object for %s' % inf)
- continue
- if not infObj.Parse():
- self.Log('Fail to load INF file %s' % inf)
- continue
- if infObj.GetProduceLibraryClass() is not None:
- libObjs.append(infObj)
- else:
- modObjs.append(infObj)
-
- if len(libObjs) != 0:
- libRootPage = doxygen.Page('Libraries', 'lib_root_page')
- rootPages.append(libRootPage)
- for libInf in libObjs:
- libRootPage.AddPage(self.GenerateModulePage(pObj, libInf, configFile, True))
-
- if len(modObjs) != 0:
- modRootPage = doxygen.Page('Modules', 'module_root_page')
- rootPages.append(modRootPage)
- for modInf in modObjs:
- modRootPage.AddPage(self.GenerateModulePage(pObj, modInf, configFile, False))
-
- return rootPages
-
- def GenerateModulePage(self, pObj, infObj, configFile, isLib):
- """
- Generate page for a module/library.
- @param infObj INF file object for module/library
- @param configFile doxygen config file object
- @param isLib Whether this module is library
-
- @param module doxygen page object
- """
- workspace = pObj.GetWorkspace()
- refDecObjs = []
- for obj in infObj.GetSectionObjectsByName('packages'):
- decObj = dec.DECFile(os.path.join(workspace, obj.GetPath()))
- if not decObj:
- ErrorMsg ('Fail to create pacakge object for %s' % obj.GetPackageName())
- continue
- if not decObj.Parse():
- ErrorMsg ('Fail to load package object for %s' % obj.GetPackageName())
- continue
- refDecObjs.append(decObj)
-
- modPage = doxygen.Page('%s' % infObj.GetBaseName(),
- 'module_%s' % infObj.GetBaseName())
- modPage.AddDescription(infObj.GetFileHeader())
-
- basicInfSection = doxygen.Section('BasicModuleInformation', 'Basic Module Information')
- desc = "<TABLE>"
- for obj in infObj.GetSectionObjectsByName('defines'):
- key = obj.GetKey()
- value = obj.GetValue()
- if key not in _inf_key_description_mapping_table.keys(): continue
- if key == 'LIBRARY_CLASS' and value.find('|') != -1:
- clsname, types = value.split('|')
- desc += '<TR>'
- desc += '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table[key]
- desc += '<TD>%s</TD>' % clsname
- desc += '</TR>'
-
- desc += '<TR>'
- desc += '<TD><B>Supported Module Types</B></TD>'
- desc += '<TD>%s</TD>' % types
- desc += '</TR>'
- else:
- desc += '<TR>'
- desc += '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table[key]
- if key == 'EFI_SPECIFICATION_VERSION' and value == '0x00020000':
- value = '2.0'
- desc += '<TD>%s</TD>' % value
- desc += '</TR>'
- desc += '</TABLE>'
- basicInfSection.AddDescription(desc)
- modPage.AddSection(basicInfSection)
-
- # Add protocol section
- data = []
- for obj in infObj.GetSectionObjectsByName('pcd', self._arch):
- data.append(obj.GetPcdName().strip())
- if len(data) != 0:
- s = doxygen.Section('Pcds', 'Pcds')
- desc = "<TABLE>"
- desc += '<TR><TD><B>PCD Name</B></TD><TD><B>TokenSpace</B></TD><TD><B>Package</B></TD></TR>'
- for item in data:
- desc += '<TR>'
- desc += '<TD>%s</TD>' % item.split('.')[1]
- desc += '<TD>%s</TD>' % item.split('.')[0]
- pkgbasename = self.SearchPcdPackage(item, workspace, refDecObjs)
- desc += '<TD>%s</TD>' % pkgbasename
- desc += '</TR>'
- desc += "</TABLE>"
- s.AddDescription(desc)
- modPage.AddSection(s)
-
- # Add protocol section
- #sects = infObj.GetSectionByString('protocol')
- data = []
- #for sect in sects:
- for obj in infObj.GetSectionObjectsByName('protocol', self._arch):
- data.append(obj.GetName().strip())
- if len(data) != 0:
- s = doxygen.Section('Protocols', 'Protocols')
- desc = "<TABLE>"
- desc += '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
- for item in data:
- desc += '<TR>'
- desc += '<TD>%s</TD>' % item
- pkgbasename = self.SearchProtocolPackage(item, workspace, refDecObjs)
- desc += '<TD>%s</TD>' % pkgbasename
- desc += '</TR>'
- desc += "</TABLE>"
- s.AddDescription(desc)
- modPage.AddSection(s)
-
- # Add ppi section
- #sects = infObj.GetSectionByString('ppi')
- data = []
- #for sect in sects:
- for obj in infObj.GetSectionObjectsByName('ppi', self._arch):
- data.append(obj.GetName().strip())
- if len(data) != 0:
- s = doxygen.Section('Ppis', 'Ppis')
- desc = "<TABLE>"
- desc += '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
- for item in data:
- desc += '<TR>'
- desc += '<TD>%s</TD>' % item
- pkgbasename = self.SearchPpiPackage(item, workspace, refDecObjs)
- desc += '<TD>%s</TD>' % pkgbasename
- desc += '</TR>'
- desc += "</TABLE>"
- s.AddDescription(desc)
- modPage.AddSection(s)
-
- # Add guid section
- #sects = infObj.GetSectionByString('guid')
- data = []
- #for sect in sects:
- for obj in infObj.GetSectionObjectsByName('guid', self._arch):
- data.append(obj.GetName().strip())
- if len(data) != 0:
- s = doxygen.Section('Guids', 'Guids')
- desc = "<TABLE>"
- desc += '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
- for item in data:
- desc += '<TR>'
- desc += '<TD>%s</TD>' % item
- pkgbasename = self.SearchGuidPackage(item, workspace, refDecObjs)
- desc += '<TD>%s</TD>' % pkgbasename
- desc += '</TR>'
- desc += "</TABLE>"
- s.AddDescription(desc)
- modPage.AddSection(s)
-
- section = doxygen.Section('LibraryClasses', 'Library Classes')
- desc = "<TABLE>"
- desc += '<TR><TD><B>Name</B></TD><TD><B>Type</B></TD><TD><B>Package</B></TD><TD><B>Header File</B></TD></TR>'
- if isLib:
- desc += '<TR>'
- desc += '<TD>%s</TD>' % infObj.GetProduceLibraryClass()
- desc += '<TD>Produce</TD>'
- try:
- pkgname, hPath = self.SearchLibraryClassHeaderFile(infObj.GetProduceLibraryClass(),
- workspace,
- refDecObjs)
- except:
- self.Log ('fail to get package header file for lib class %s' % infObj.GetProduceLibraryClass())
- pkgname = 'NULL'
- hPath = 'NULL'
- desc += '<TD>%s</TD>' % pkgname
- if hPath != "NULL":
- desc += '<TD>\link %s \endlink</TD>' % hPath
- else:
- desc += '<TD>%s</TD>' % hPath
- desc += '</TR>'
- for lcObj in infObj.GetSectionObjectsByName('libraryclasses', self._arch):
- desc += '<TR>'
- desc += '<TD>%s</TD>' % lcObj.GetClass()
- retarr = self.SearchLibraryClassHeaderFile(lcObj.GetClass(),
- workspace,
- refDecObjs)
- if retarr is not None:
- pkgname, hPath = retarr
- else:
- self.Log('Fail find the library class %s definition from module %s dependent package!' % (lcObj.GetClass(), infObj.GetFilename()), 'error')
- pkgname = 'NULL'
- hPath = 'NULL'
- desc += '<TD>Consume</TD>'
- desc += '<TD>%s</TD>' % pkgname
- desc += '<TD>\link %s \endlink</TD>' % hPath
- desc += '</TR>'
- desc += "</TABLE>"
- section.AddDescription(desc)
- modPage.AddSection(section)
-
- section = doxygen.Section('SourceFiles', 'Source Files')
- section.AddDescription('<ul>\n')
- for obj in infObj.GetSourceObjects(self._arch, self._tooltag):
- sPath = infObj.GetModuleRootPath()
- sPath = os.path.join(sPath, obj.GetSourcePath()).replace('\\', '/').strip()
- if sPath.lower().endswith('.uni') or sPath.lower().endswith('.s') or sPath.lower().endswith('.asm') or sPath.lower().endswith('.nasm'):
- newPath = self.TranslateUniFile(sPath)
- configFile.AddFile(newPath)
- newPath = newPath[len(pObj.GetWorkspace()) + 1:]
- section.AddDescription('<li> \link %s \endlink </li>' % newPath)
- else:
- self.ProcessSourceFileForInclude(sPath, pObj, configFile, infObj)
- sPath = sPath[len(pObj.GetWorkspace()) + 1:]
- section.AddDescription('<li>\link %s \endlink </li>' % sPath)
- section.AddDescription('</ul>\n')
- modPage.AddSection(section)
-
- #sects = infObj.GetSectionByString('depex')
- data = []
- #for sect in sects:
- for obj in infObj.GetSectionObjectsByName('depex'):
- data.append(str(obj))
- if len(data) != 0:
- s = doxygen.Section('DependentSection', 'Module Dependencies')
- s.AddDescription('<br>'.join(data))
- modPage.AddSection(s)
-
- return modPage
-
- def TranslateUniFile(self, path):
- newpath = path + '.dox'
- #import core.textfile as textfile
- #file = textfile.TextFile(path)
-
- try:
- file = open(path, 'r')
- except (IOError, OSError) as msg:
- return None
-
- t = file.read()
- file.close()
-
- output = '/** @file \n'
- #output = '<html><body>'
- arr = t.split('\r\n')
- for line in arr:
- if line.find('@file') != -1:
- continue
- if line.find('*/') != -1:
- continue
- line = line.strip()
- if line.strip().startswith('/'):
- arr = line.split(' ')
- if len(arr) > 1:
- line = ' '.join(arr[1:])
- else:
- continue
- output += '%s<br>\n' % line
- output += '**/'
-
- if os.path.exists(newpath):
- os.remove(newpath)
-
- file = open(newpath, "w")
- file.write(output)
- file.close()
- return newpath
-
- def SearchPcdPackage(self, pcdname, workspace, decObjs):
- for decObj in decObjs:
- for pcd in decObj.GetSectionObjectsByName('pcd'):
- if pcdname == pcd.GetPcdName():
- return decObj.GetBaseName()
- return None
-
- def SearchProtocolPackage(self, protname, workspace, decObjs):
- for decObj in decObjs:
- for proto in decObj.GetSectionObjectsByName('protocol'):
- if protname == proto.GetName():
- return decObj.GetBaseName()
- return None
-
- def SearchPpiPackage(self, ppiname, workspace, decObjs):
- for decObj in decObjs:
- for ppi in decObj.GetSectionObjectsByName('ppi'):
- if ppiname == ppi.GetName():
- return decObj.GetBaseName()
- return None
-
- def SearchGuidPackage(self, guidname, workspace, decObjs):
- for decObj in decObjs:
- for guid in decObj.GetSectionObjectsByName('guid'):
- if guidname == guid.GetName():
- return decObj.GetBaseName()
- return None
-
- def SearchLibraryClassHeaderFile(self, className, workspace, decObjs):
- for decObj in decObjs:
- for cls in decObj.GetSectionObjectsByName('libraryclasses'):
- if cls.GetClassName().strip() == className:
- path = cls.GetHeaderFile().strip()
- path = os.path.join(decObj.GetPackageRootPath(), path)
- path = path[len(workspace) + 1:]
- return decObj.GetBaseName(), path.replace('\\', '/')
-
- return None
-
- def _ConvertPathToDoxygen(self, path, pObj):
- pRootPath = pObj.GetWorkspace()
- path = path[len(pRootPath) + 1:]
- return path.replace('\\', '/')
-
-def IsCHeaderFile(path):
- return CheckPathPostfix(path, 'h')
-
-def CheckPathPostfix(path, str):
- index = path.rfind('.')
- if index == -1:
- return False
- if path[index + 1:].lower() == str.lower():
- return True
- return False
+## @file +# +# This file produce action class to generate doxygen document for edk2 codebase. +# The action classes are shared by GUI and command line tools. +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent + +"""This file produce action class to generate doxygen document for edk2 codebase. + The action classes are shared by GUI and command line tools. +""" +from plugins.EdkPlugins.basemodel import doxygen +import os +try: + import wx + gInGui = True +except: + gInGui = False +import re +from plugins.EdkPlugins.edk2.model import inf +from plugins.EdkPlugins.edk2.model import dec +from plugins.EdkPlugins.basemodel.message import * + +_ignore_dir = ['.svn', '_svn', 'cvs'] +_inf_key_description_mapping_table = { + 'INF_VERSION':'Version of INF file specification', + #'BASE_NAME':'Module Name', + 'FILE_GUID':'Module Guid', + 'MODULE_TYPE': 'Module Type', + 'VERSION_STRING': 'Module Version', + 'LIBRARY_CLASS': 'Produced Library Class', + 'EFI_SPECIFICATION_VERSION': 'UEFI Specification Version', + 'PI_SPECIFICATION_VERSION': 'PI Specification Version', + 'ENTRY_POINT': 'Module Entry Point Function', + 'CONSTRUCTOR': 'Library Constructor Function' +} + +_dec_key_description_mapping_table = { + 'DEC_SPECIFICATION': 'Version of DEC file specification', + 'PACKAGE_GUID': 'Package Guid' +} +class DoxygenAction: + """This is base class for all doxygen action. + """ + + def __init__(self, doxPath, chmPath, outputPath, projname, mode='html', log=None, verbose=False): + """Constructor function. + @param doxPath the obosolution path of doxygen execute file. + @param outputPath the obosolution output path. + @param log log function for output message + """ + self._doxPath = doxPath + self._chmPath = chmPath + self._outputPath = outputPath + self._projname = projname + self._configFile = None # doxygen config file is used by doxygen exe file + self._indexPageFile = None # doxygen page file for index page. + self._log = log + self._mode = mode + self._verbose = verbose + self._doxygenCallback = None + self._chmCallback = None + + def Log(self, message, level='info'): + if self._log is not None: + self._log(message, level) + + def IsVerbose(self): + return self._verbose + + def Generate(self): + """Generate interface called by outer directly""" + self.Log(">>>>>> Start generate doxygen document for %s... Zzz....\n" % self._projname) + + # create doxygen config file at first + self._configFile = doxygen.DoxygenConfigFile() + self._configFile.SetOutputDir(self._outputPath) + + self._configFile.SetWarningFilePath(os.path.join(self._outputPath, 'warning.txt')) + if self._mode.lower() == 'html': + self._configFile.SetHtmlMode() + else: + self._configFile.SetChmMode() + + self.Log(" >>>>>> Initialize doxygen config file...Zzz...\n") + self.InitializeConfigFile() + + self.Log(" >>>>>> Generate doxygen index page file...Zzz...\n") + indexPagePath = self.GenerateIndexPage() + if indexPagePath is None: + self.Log("Fail to generate index page!\n", 'error') + return False + else: + self.Log("Success to create doxygen index page file %s \n" % indexPagePath) + + # Add index page doxygen file to file list. + self._configFile.AddFile(indexPagePath) + + # save config file to output path + configFilePath = os.path.join(self._outputPath, self._projname + '.doxygen_config') + self._configFile.Generate(configFilePath) + self.Log(" <<<<<< Success Save doxygen config file to %s...\n" % configFilePath) + + # launch doxygen tool to generate document + if self._doxygenCallback is not None: + self.Log(" >>>>>> Start doxygen process...Zzz...\n") + if not self._doxygenCallback(self._doxPath, configFilePath): + return False + else: + self.Log("Fail to create doxygen process!", 'error') + return False + + return True + + def InitializeConfigFile(self): + """Initialize config setting for doxygen project. It will be invoked after config file + object is created. Inherited class should implement it. + """ + + def GenerateIndexPage(self): + """Generate doxygen index page. Inherited class should implement it.""" + return None + + def RegisterCallbackDoxygenProcess(self, callback): + self._doxygenCallback = callback + + def RegisterCallbackCHMProcess(self, callback): + self._chmCallback = callback + +class PlatformDocumentAction(DoxygenAction): + """Generate platform doxygen document, will be implement at future.""" + +class PackageDocumentAction(DoxygenAction): + """Generate package reference document""" + + def __init__(self, doxPath, chmPath, outputPath, pObj, mode='html', log=None, arch=None, tooltag=None, + onlyInclude=False, verbose=False): + DoxygenAction.__init__(self, doxPath, chmPath, outputPath, pObj.GetName(), mode, log, verbose) + self._pObj = pObj + self._arch = arch + self._tooltag = tooltag + self._onlyIncludeDocument = onlyInclude + + def InitializeConfigFile(self): + if self._arch == 'IA32': + self._configFile.AddPreDefined('MDE_CPU_IA32') + elif self._arch == 'X64': + self._configFile.AddPreDefined('MDE_CPU_X64') + elif self._arch == 'IPF': + self._configFile.AddPreDefined('MDE_CPU_IPF') + elif self._arch == 'EBC': + self._configFile.AddPreDefined('MDE_CPU_EBC') + else: + self._arch = None + self._configFile.AddPreDefined('MDE_CPU_IA32') + self._configFile.AddPreDefined('MDE_CPU_X64') + self._configFile.AddPreDefined('MDE_CPU_IPF') + self._configFile.AddPreDefined('MDE_CPU_EBC') + self._configFile.AddPreDefined('MDE_CPU_ARM') + + namestr = self._pObj.GetName() + if self._arch is not None: + namestr += '[%s]' % self._arch + if self._tooltag is not None: + namestr += '[%s]' % self._tooltag + self._configFile.SetProjectName(namestr) + self._configFile.SetStripPath(self._pObj.GetWorkspace()) + self._configFile.SetProjectVersion(self._pObj.GetFileObj().GetVersion()) + self._configFile.AddPattern('*.decdoxygen') + + if self._tooltag.lower() == 'msft': + self._configFile.AddPreDefined('_MSC_EXTENSIONS') + elif self._tooltag.lower() == 'gnu': + self._configFile.AddPreDefined('__GNUC__') + elif self._tooltag.lower() == 'intel': + self._configFile.AddPreDefined('__INTEL_COMPILER') + else: + self._tooltag = None + self._configFile.AddPreDefined('_MSC_EXTENSIONS') + self._configFile.AddPreDefined('__GNUC__') + self._configFile.AddPreDefined('__INTEL_COMPILER') + + self._configFile.AddPreDefined('ASM_PFX= ') + self._configFile.AddPreDefined('OPTIONAL= ') + + def GenerateIndexPage(self): + """Generate doxygen index page. Inherited class should implement it.""" + fObj = self._pObj.GetFileObj() + pdObj = doxygen.DoxygenFile('%s Package Document' % self._pObj.GetName(), + '%s.decdoxygen' % self._pObj.GetFilename()) + self._configFile.AddFile(pdObj.GetFilename()) + pdObj.AddDescription(fObj.GetFileHeader()) + + defSection = fObj.GetSectionByName('defines')[0] + baseSection = doxygen.Section('PackageBasicInformation', 'Package Basic Information') + descr = '<TABLE>' + for obj in defSection.GetObjects(): + if obj.GetKey() in _dec_key_description_mapping_table.keys(): + descr += '<TR>' + descr += '<TD><B>%s</B></TD>' % _dec_key_description_mapping_table[obj.GetKey()] + descr += '<TD>%s</TD>' % obj.GetValue() + descr += '</TR>' + descr += '</TABLE><br>' + baseSection.AddDescription(descr) + pdObj.AddSection(baseSection) + + knownIssueSection = doxygen.Section('Known_Issue_section', 'Known Issue') + knownIssueSection.AddDescription('<ul>') + knownIssueSection.AddDescription('<li> OPTIONAL macro for function parameter can not be dealed with doxygen, so it disapear in this document! </li>') + knownIssueSection.AddDescription('</ul>') + pdObj.AddSection(knownIssueSection) + + self.AddAllIncludeFiles(self._pObj, self._configFile) + pages = self.GenerateIncludesSubPage(self._pObj, self._configFile) + if len(pages) != 0: + pdObj.AddPages(pages) + pages = self.GenerateLibraryClassesSubPage(self._pObj, self._configFile) + if len(pages) != 0: + pdObj.AddPages(pages) + pages = self.GeneratePcdSubPages(self._pObj, self._configFile) + if len(pages) != 0: + pdObj.AddPages(pages) + pages = self.GenerateGuidSubPages(self._pObj, self._configFile) + if len(pages) != 0: + pdObj.AddPages(pages) + pages = self.GeneratePpiSubPages(self._pObj, self._configFile) + if len(pages) != 0: + pdObj.AddPages(pages) + pages = self.GenerateProtocolSubPages(self._pObj, self._configFile) + if len(pages) != 0: + pdObj.AddPages(pages) + if not self._onlyIncludeDocument: + pdObj.AddPages(self.GenerateModulePages(self._pObj, self._configFile)) + + pdObj.Save() + return pdObj.GetFilename() + + def GenerateIncludesSubPage(self, pObj, configFile): + # by default add following path as include path to config file + pkpath = pObj.GetFileObj().GetPackageRootPath() + configFile.AddIncludePath(os.path.join(pkpath, 'Include')) + configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Library')) + configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Protocol')) + configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Ppi')) + configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Guid')) + configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'IndustryStandard')) + + rootArray = [] + pageRoot = doxygen.Page("Public Includes", "%s_public_includes" % pObj.GetName()) + objs = pObj.GetFileObj().GetSectionObjectsByName('includes') + if len(objs) == 0: return [] + + for obj in objs: + # Add path to include path + path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetPath()) + configFile.AddIncludePath(path) + + # only list common folder's include file + if obj.GetArch().lower() != 'common': + continue + + bNeedAddIncludePage = False + topPage = doxygen.Page(self._ConvertPathToDoxygen(path, pObj), 'public_include_top') + + topPage.AddDescription('<ul>\n') + for file in os.listdir(path): + if file.lower() in _ignore_dir: continue + fullpath = os.path.join(path, file) + if os.path.isfile(fullpath): + self.ProcessSourceFileForInclude(fullpath, pObj, configFile) + topPage.AddDescription('<li> \link %s\endlink </li>\n' % self._ConvertPathToDoxygen(fullpath, pObj)) + else: + if file.lower() in ['library', 'protocol', 'guid', 'ppi', 'ia32', 'x64', 'ipf', 'ebc', 'arm', 'pi', 'uefi', 'aarch64']: + continue + bNeedAddSubPage = False + subpage = doxygen.Page(self._ConvertPathToDoxygen(fullpath, pObj), 'public_include_%s' % file) + subpage.AddDescription('<ul>\n') + for subfile in os.listdir(fullpath): + if subfile.lower() in _ignore_dir: continue + bNeedAddSubPage = True + subfullpath = os.path.join(fullpath, subfile) + self.ProcessSourceFileForInclude(subfullpath, pObj, configFile) + subpage.AddDescription('<li> \link %s \endlink </li>\n' % self._ConvertPathToDoxygen(subfullpath, pObj)) + subpage.AddDescription('</ul>\n') + if bNeedAddSubPage: + bNeedAddIncludePage = True + pageRoot.AddPage(subpage) + topPage.AddDescription('</ul>\n') + if bNeedAddIncludePage: + pageRoot.AddPage(topPage) + + if pageRoot.GetSubpageCount() != 0: + return [pageRoot] + else: + return [] + + def GenerateLibraryClassesSubPage(self, pObj, configFile): + """ + Generate sub page for library class for package. + One DEC file maybe contains many library class sections + for different architecture. + + @param fObj DEC file object. + """ + rootArray = [] + pageRoot = doxygen.Page("Library Class", "%s_libraryclass" % pObj.GetName()) + objs = pObj.GetFileObj().GetSectionObjectsByName('libraryclass', self._arch) + if len(objs) == 0: return [] + + if self._arch is not None: + for obj in objs: + classPage = doxygen.Page(obj.GetClassName(), + "lc_%s" % obj.GetClassName()) + comments = obj.GetComment() + if len(comments) != 0: + classPage.AddDescription('<br>\n'.join(comments) + '<br>\n') + pageRoot.AddPage(classPage) + path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile()) + path = path[len(pObj.GetWorkspace()) + 1:] + if len(comments) == 0: + classPage.AddDescription('\copydoc %s<p>' % obj.GetHeaderFile()) + section = doxygen.Section('ref', 'Refer to Header File') + section.AddDescription('\link %s\n' % obj.GetHeaderFile()) + section.AddDescription(' \endlink<p>\n') + classPage.AddSection(section) + fullPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile()) + self.ProcessSourceFileForInclude(fullPath, pObj, configFile) + else: + archPageDict = {} + for obj in objs: + if obj.GetArch() not in archPageDict.keys(): + archPageDict[obj.GetArch()] = doxygen.Page(obj.GetArch(), + 'lc_%s' % obj.GetArch()) + pageRoot.AddPage(archPageDict[obj.GetArch()]) + subArchRoot = archPageDict[obj.GetArch()] + classPage = doxygen.Page(obj.GetClassName(), + "lc_%s" % obj.GetClassName()) + comments = obj.GetComment() + if len(comments) != 0: + classPage.AddDescription('<br>\n'.join(comments) + '<br>\n') + subArchRoot.AddPage(classPage) + path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile()) + path = path[len(pObj.GetWorkspace()) + 1:] + if len(comments) == 0: + classPage.AddDescription('\copydoc %s<p>' % obj.GetHeaderFile()) + section = doxygen.Section('ref', 'Refer to Header File') + section.AddDescription('\link %s\n' % obj.GetHeaderFile()) + section.AddDescription(' \endlink<p>\n') + classPage.AddSection(section) + fullPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile()) + + self.ProcessSourceFileForInclude(fullPath, pObj, configFile) + rootArray.append(pageRoot) + return rootArray + + def ProcessSourceFileForInclude(self, path, pObj, configFile, infObj=None): + """ + @param path the analysising file full path + @param pObj package object + @param configFile doxygen config file. + """ + if gInGui: + wx.Yield() + if not os.path.exists(path): + ErrorMsg('Source file path %s does not exist!' % path) + return + + if configFile.FileExists(path): + return + + try: + with open(path, 'r') as f: + lines = f.readlines() + except UnicodeDecodeError: + return + except IOError: + ErrorMsg('Fail to open file %s' % path) + return + + configFile.AddFile(path) + + no = 0 + for no in range(len(lines)): + if len(lines[no].strip()) == 0: + continue + if lines[no].strip()[:2] in ['##', '//', '/*', '*/']: + continue + index = lines[no].lower().find('include') + #mo = IncludePattern.finditer(lines[no].lower()) + mo = re.match(r"^#\s*include\s+[<\"]([\\/\w.]+)[>\"]$", lines[no].strip().lower()) + if not mo: + continue + mo = re.match(r"^[#\w\s]+[<\"]([\\/\w.]+)[>\"]$", lines[no].strip()) + filePath = mo.groups()[0] + + if filePath is None or len(filePath) == 0: + continue + + # find header file in module's path firstly. + fullPath = None + + if os.path.exists(os.path.join(os.path.dirname(path), filePath)): + # Find the file in current directory + fullPath = os.path.join(os.path.dirname(path), filePath).replace('\\', '/') + else: + # find in depedent package's include path + incObjs = pObj.GetFileObj().GetSectionObjectsByName('includes') + for incObj in incObjs: + incPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), incObj.GetPath()).strip() + incPath = os.path.realpath(os.path.join(incPath, filePath)) + if os.path.exists(incPath): + fullPath = incPath + break + if infObj is not None: + pkgInfObjs = infObj.GetSectionObjectsByName('packages') + for obj in pkgInfObjs: + decObj = dec.DECFile(os.path.join(pObj.GetWorkspace(), obj.GetPath())) + if not decObj: + ErrorMsg ('Fail to create pacakge object for %s' % obj.GetPackageName()) + continue + if not decObj.Parse(): + ErrorMsg ('Fail to load package object for %s' % obj.GetPackageName()) + continue + incObjs = decObj.GetSectionObjectsByName('includes') + for incObj in incObjs: + incPath = os.path.join(decObj.GetPackageRootPath(), incObj.GetPath()).replace('\\', '/') + if os.path.exists(os.path.join(incPath, filePath)): + fullPath = os.path.join(os.path.join(incPath, filePath)) + break + if fullPath is not None: + break + + if fullPath is None and self.IsVerbose(): + self.Log('Can not resolve header file %s for file %s in package %s\n' % (filePath, path, pObj.GetFileObj().GetFilename()), 'error') + return + else: + fullPath = fullPath.replace('\\', '/') + if self.IsVerbose(): + self.Log('Preprocessing: Add include file %s for file %s\n' % (fullPath, path)) + #LogMsg ('Preprocessing: Add include file %s for file %s' % (fullPath, path)) + self.ProcessSourceFileForInclude(fullPath, pObj, configFile, infObj) + + def AddAllIncludeFiles(self, pObj, configFile): + objs = pObj.GetFileObj().GetSectionObjectsByName('includes') + for obj in objs: + incPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetPath()) + for root, dirs, files in os.walk(incPath): + for dir in dirs: + if dir.lower() in _ignore_dir: + dirs.remove(dir) + for file in files: + path = os.path.normpath(os.path.join(root, file)) + configFile.AddFile(path.replace('/', '\\')) + + def GeneratePcdSubPages(self, pObj, configFile): + """ + Generate sub pages for package's PCD definition. + @param pObj package object + @param configFile config file object + """ + rootArray = [] + objs = pObj.GetFileObj().GetSectionObjectsByName('pcd') + if len(objs) == 0: + return [] + + pcdRootPage = doxygen.Page('PCD', 'pcd_root_page') + typeRootPageDict = {} + typeArchRootPageDict = {} + for obj in objs: + if obj.GetPcdType() not in typeRootPageDict.keys(): + typeRootPageDict[obj.GetPcdType()] = doxygen.Page(obj.GetPcdType(), 'pcd_%s_root_page' % obj.GetPcdType()) + pcdRootPage.AddPage(typeRootPageDict[obj.GetPcdType()]) + typeRoot = typeRootPageDict[obj.GetPcdType()] + if self._arch is not None: + pcdPage = doxygen.Page('%s' % obj.GetPcdName(), + 'pcd_%s_%s_%s' % (obj.GetPcdType(), obj.GetArch(), obj.GetPcdName().split('.')[1])) + pcdPage.AddDescription('<br>\n'.join(obj.GetComment()) + '<br>\n') + section = doxygen.Section('PCDinformation', 'PCD Information') + desc = '<TABLE>' + desc += '<TR>' + desc += '<TD><CAPTION>Name</CAPTION></TD>' + desc += '<TD><CAPTION>Token Space</CAPTION></TD>' + desc += '<TD><CAPTION>Token number</CAPTION></TD>' + desc += '<TD><CAPTION>Data Type</CAPTION></TD>' + desc += '<TD><CAPTION>Default Value</CAPTION></TD>' + desc += '</TR>' + desc += '<TR>' + desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[1] + desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[0] + desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdToken() + desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdDataType() + desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdValue() + desc += '</TR>' + desc += '</TABLE>' + section.AddDescription(desc) + pcdPage.AddSection(section) + typeRoot.AddPage(pcdPage) + else: + keystr = obj.GetPcdType() + obj.GetArch() + if keystr not in typeArchRootPageDict.keys(): + typeArchRootPage = doxygen.Page(obj.GetArch(), 'pcd_%s_%s_root_page' % (obj.GetPcdType(), obj.GetArch())) + typeArchRootPageDict[keystr] = typeArchRootPage + typeRoot.AddPage(typeArchRootPage) + typeArchRoot = typeArchRootPageDict[keystr] + pcdPage = doxygen.Page('%s' % obj.GetPcdName(), + 'pcd_%s_%s_%s' % (obj.GetPcdType(), obj.GetArch(), obj.GetPcdName().split('.')[1])) + pcdPage.AddDescription('<br>\n'.join(obj.GetComment()) + '<br>\n') + section = doxygen.Section('PCDinformation', 'PCD Information') + desc = '<TABLE>' + desc += '<TR>' + desc += '<TD><CAPTION>Name</CAPTION></TD>' + desc += '<TD><CAPTION>Token Space</CAPTION></TD>' + desc += '<TD><CAPTION>Token number</CAPTION></TD>' + desc += '<TD><CAPTION>Data Type</CAPTION></TD>' + desc += '<TD><CAPTION>Default Value</CAPTION></TD>' + desc += '</TR>' + desc += '<TR>' + desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[1] + desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[0] + desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdToken() + desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdDataType() + desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdValue() + desc += '</TR>' + desc += '</TABLE>' + section.AddDescription(desc) + pcdPage.AddSection(section) + typeArchRoot.AddPage(pcdPage) + return [pcdRootPage] + + def _GenerateGuidSubPage(self, pObj, obj, configFile): + guidPage = doxygen.Page('%s' % obj.GetName(), + 'guid_%s_%s' % (obj.GetArch(), obj.GetName())) + comments = obj.GetComment() + if len(comments) != 0: + guidPage.AddDescription('<br>'.join(obj.GetComment()) + '<br>') + section = doxygen.Section('BasicGuidInfo', 'GUID Information') + desc = '<TABLE>' + desc += '<TR>' + desc += '<TD><CAPTION>GUID\'s Guid Name</CAPTION></TD><TD><CAPTION>GUID\'s Guid</CAPTION></TD>' + desc += '</TR>' + desc += '<TR>' + desc += '<TD>%s</TD>' % obj.GetName() + desc += '<TD>%s</TD>' % obj.GetGuid() + desc += '</TR>' + desc += '</TABLE>' + section.AddDescription(desc) + guidPage.AddSection(section) + refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile) + if refFile: + relPath = refFile[len(pObj.GetWorkspace()) + 1:] + if len(comments) == 0: + guidPage.AddDescription(' \\copydoc %s <br>' % relPath) + + section = doxygen.Section('ref', 'Refer to Header File') + section.AddDescription('\link %s\n' % relPath) + section.AddDescription('\endlink\n') + self.ProcessSourceFileForInclude(refFile, pObj, configFile) + guidPage.AddSection(section) + return guidPage + + def GenerateGuidSubPages(self, pObj, configFile): + """ + Generate sub pages for package's GUID definition. + @param pObj package object + @param configFilf doxygen config file object + """ + pageRoot = doxygen.Page('GUID', 'guid_root_page') + objs = pObj.GetFileObj().GetSectionObjectsByName('guids', self._arch) + if len(objs) == 0: return [] + if self._arch is not None: + for obj in objs: + pageRoot.AddPage(self._GenerateGuidSubPage(pObj, obj, configFile)) + else: + guidArchRootPageDict = {} + for obj in objs: + if obj.GetArch() not in guidArchRootPageDict.keys(): + guidArchRoot = doxygen.Page(obj.GetArch(), 'guid_arch_root_%s' % obj.GetArch()) + pageRoot.AddPage(guidArchRoot) + guidArchRootPageDict[obj.GetArch()] = guidArchRoot + guidArchRoot = guidArchRootPageDict[obj.GetArch()] + guidArchRoot.AddPage(self._GenerateGuidSubPage(pObj, obj, configFile)) + return [pageRoot] + + def _GeneratePpiSubPage(self, pObj, obj, configFile): + guidPage = doxygen.Page(obj.GetName(), 'ppi_page_%s' % obj.GetName()) + comments = obj.GetComment() + if len(comments) != 0: + guidPage.AddDescription('<br>'.join(obj.GetComment()) + '<br>') + section = doxygen.Section('BasicPpiInfo', 'PPI Information') + desc = '<TABLE>' + desc += '<TR>' + desc += '<TD><CAPTION>PPI\'s Guid Name</CAPTION></TD><TD><CAPTION>PPI\'s Guid</CAPTION></TD>' + desc += '</TR>' + desc += '<TR>' + desc += '<TD>%s</TD>' % obj.GetName() + desc += '<TD>%s</TD>' % obj.GetGuid() + desc += '</TR>' + desc += '</TABLE>' + section.AddDescription(desc) + guidPage.AddSection(section) + refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile) + if refFile: + relPath = refFile[len(pObj.GetWorkspace()) + 1:] + if len(comments) == 0: + guidPage.AddDescription(' \\copydoc %s <br>' % relPath) + section = doxygen.Section('ref', 'Refer to Header File') + section.AddDescription('\link %s\n' % relPath) + section.AddDescription('\endlink\n') + self.ProcessSourceFileForInclude(refFile, pObj, configFile) + guidPage.AddSection(section) + + return guidPage + + def GeneratePpiSubPages(self, pObj, configFile): + """ + Generate sub pages for package's GUID definition. + @param pObj package object + @param configFilf doxygen config file object + """ + pageRoot = doxygen.Page('PPI', 'ppi_root_page') + objs = pObj.GetFileObj().GetSectionObjectsByName('ppis', self._arch) + if len(objs) == 0: return [] + if self._arch is not None: + for obj in objs: + pageRoot.AddPage(self._GeneratePpiSubPage(pObj, obj, configFile)) + else: + guidArchRootPageDict = {} + for obj in objs: + if obj.GetArch() not in guidArchRootPageDict.keys(): + guidArchRoot = doxygen.Page(obj.GetArch(), 'ppi_arch_root_%s' % obj.GetArch()) + pageRoot.AddPage(guidArchRoot) + guidArchRootPageDict[obj.GetArch()] = guidArchRoot + guidArchRoot = guidArchRootPageDict[obj.GetArch()] + guidArchRoot.AddPage(self._GeneratePpiSubPage(pObj, obj, configFile)) + return [pageRoot] + + def _GenerateProtocolSubPage(self, pObj, obj, configFile): + guidPage = doxygen.Page(obj.GetName(), 'protocol_page_%s' % obj.GetName()) + comments = obj.GetComment() + if len(comments) != 0: + guidPage.AddDescription('<br>'.join(obj.GetComment()) + '<br>') + section = doxygen.Section('BasicProtocolInfo', 'PROTOCOL Information') + desc = '<TABLE>' + desc += '<TR>' + desc += '<TD><CAPTION>PROTOCOL\'s Guid Name</CAPTION></TD><TD><CAPTION>PROTOCOL\'s Guid</CAPTION></TD>' + desc += '</TR>' + desc += '<TR>' + desc += '<TD>%s</TD>' % obj.GetName() + desc += '<TD>%s</TD>' % obj.GetGuid() + desc += '</TR>' + desc += '</TABLE>' + section.AddDescription(desc) + guidPage.AddSection(section) + + refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile) + if refFile: + relPath = refFile[len(pObj.GetWorkspace()) + 1:] + if len(comments) == 0: + guidPage.AddDescription(' \\copydoc %s <br>' % relPath) + section = doxygen.Section('ref', 'Refer to Header File') + section.AddDescription('\link %s\n' % relPath) + section.AddDescription('\endlink\n') + self.ProcessSourceFileForInclude(refFile, pObj, configFile) + guidPage.AddSection(section) + + return guidPage + + def GenerateProtocolSubPages(self, pObj, configFile): + """ + Generate sub pages for package's GUID definition. + @param pObj package object + @param configFilf doxygen config file object + """ + pageRoot = doxygen.Page('PROTOCOL', 'protocol_root_page') + objs = pObj.GetFileObj().GetSectionObjectsByName('protocols', self._arch) + if len(objs) == 0: return [] + if self._arch is not None: + for obj in objs: + pageRoot.AddPage(self._GenerateProtocolSubPage(pObj, obj, configFile)) + else: + guidArchRootPageDict = {} + for obj in objs: + if obj.GetArch() not in guidArchRootPageDict.keys(): + guidArchRoot = doxygen.Page(obj.GetArch(), 'protocol_arch_root_%s' % obj.GetArch()) + pageRoot.AddPage(guidArchRoot) + guidArchRootPageDict[obj.GetArch()] = guidArchRoot + guidArchRoot = guidArchRootPageDict[obj.GetArch()] + guidArchRoot.AddPage(self._GenerateProtocolSubPage(pObj, obj, configFile)) + return [pageRoot] + + def FindHeaderFileForGuid(self, pObj, name, configFile): + """ + For declaration header file for GUID/PPI/Protocol. + + @param pObj package object + @param name guid/ppi/protocol's name + @param configFile config file object + + @return full path of header file and None if not found. + """ + startPath = pObj.GetFileObj().GetPackageRootPath() + incPath = os.path.join(startPath, 'Include').replace('\\', '/') + # if <PackagePath>/include exist, then search header under it. + if os.path.exists(incPath): + startPath = incPath + + for root, dirs, files in os.walk(startPath): + for dir in dirs: + if dir.lower() in _ignore_dir: + dirs.remove(dir) + for file in files: + fPath = os.path.join(root, file) + if not IsCHeaderFile(fPath): + continue + try: + f = open(fPath, 'r') + lines = f.readlines() + f.close() + except IOError: + self.Log('Fail to open file %s\n' % fPath) + continue + for line in lines: + if line.find(name) != -1 and \ + line.find('extern') != -1: + return fPath.replace('\\', '/') + return None + + def GetPackageModuleList(self, pObj): + """ + Get all module's INF path under package's root path + @param pObj package object + @return arrary of INF full path + """ + mArray = [] + packPath = pObj.GetFileObj().GetPackageRootPath() + if not os.path.exists: + return None + for root, dirs, files in os.walk(packPath): + for dir in dirs: + if dir.lower() in _ignore_dir: + dirs.remove(dir) + for file in files: + if CheckPathPostfix(file, 'inf'): + fPath = os.path.join(root, file).replace('\\', '/') + mArray.append(fPath) + return mArray + + def GenerateModulePages(self, pObj, configFile): + """ + Generate sub pages for package's module which is under the package + root directory. + + @param pObj package object + @param configFilf doxygen config file object + """ + infList = self.GetPackageModuleList(pObj) + rootPages = [] + libObjs = [] + modObjs = [] + for infpath in infList: + infObj = inf.INFFile(infpath) + #infObj = INFFileObject.INFFile (pObj.GetWorkspacePath(), + # inf) + if not infObj: + self.Log('Fail create INF object for %s' % inf) + continue + if not infObj.Parse(): + self.Log('Fail to load INF file %s' % inf) + continue + if infObj.GetProduceLibraryClass() is not None: + libObjs.append(infObj) + else: + modObjs.append(infObj) + + if len(libObjs) != 0: + libRootPage = doxygen.Page('Libraries', 'lib_root_page') + rootPages.append(libRootPage) + for libInf in libObjs: + libRootPage.AddPage(self.GenerateModulePage(pObj, libInf, configFile, True)) + + if len(modObjs) != 0: + modRootPage = doxygen.Page('Modules', 'module_root_page') + rootPages.append(modRootPage) + for modInf in modObjs: + modRootPage.AddPage(self.GenerateModulePage(pObj, modInf, configFile, False)) + + return rootPages + + def GenerateModulePage(self, pObj, infObj, configFile, isLib): + """ + Generate page for a module/library. + @param infObj INF file object for module/library + @param configFile doxygen config file object + @param isLib Whether this module is library + + @param module doxygen page object + """ + workspace = pObj.GetWorkspace() + refDecObjs = [] + for obj in infObj.GetSectionObjectsByName('packages'): + decObj = dec.DECFile(os.path.join(workspace, obj.GetPath())) + if not decObj: + ErrorMsg ('Fail to create pacakge object for %s' % obj.GetPackageName()) + continue + if not decObj.Parse(): + ErrorMsg ('Fail to load package object for %s' % obj.GetPackageName()) + continue + refDecObjs.append(decObj) + + modPage = doxygen.Page('%s' % infObj.GetBaseName(), + 'module_%s' % infObj.GetBaseName()) + modPage.AddDescription(infObj.GetFileHeader()) + + basicInfSection = doxygen.Section('BasicModuleInformation', 'Basic Module Information') + desc = "<TABLE>" + for obj in infObj.GetSectionObjectsByName('defines'): + key = obj.GetKey() + value = obj.GetValue() + if key not in _inf_key_description_mapping_table.keys(): continue + if key == 'LIBRARY_CLASS' and value.find('|') != -1: + clsname, types = value.split('|') + desc += '<TR>' + desc += '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table[key] + desc += '<TD>%s</TD>' % clsname + desc += '</TR>' + + desc += '<TR>' + desc += '<TD><B>Supported Module Types</B></TD>' + desc += '<TD>%s</TD>' % types + desc += '</TR>' + else: + desc += '<TR>' + desc += '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table[key] + if key == 'EFI_SPECIFICATION_VERSION' and value == '0x00020000': + value = '2.0' + desc += '<TD>%s</TD>' % value + desc += '</TR>' + desc += '</TABLE>' + basicInfSection.AddDescription(desc) + modPage.AddSection(basicInfSection) + + # Add protocol section + data = [] + for obj in infObj.GetSectionObjectsByName('pcd', self._arch): + data.append(obj.GetPcdName().strip()) + if len(data) != 0: + s = doxygen.Section('Pcds', 'Pcds') + desc = "<TABLE>" + desc += '<TR><TD><B>PCD Name</B></TD><TD><B>TokenSpace</B></TD><TD><B>Package</B></TD></TR>' + for item in data: + desc += '<TR>' + desc += '<TD>%s</TD>' % item.split('.')[1] + desc += '<TD>%s</TD>' % item.split('.')[0] + pkgbasename = self.SearchPcdPackage(item, workspace, refDecObjs) + desc += '<TD>%s</TD>' % pkgbasename + desc += '</TR>' + desc += "</TABLE>" + s.AddDescription(desc) + modPage.AddSection(s) + + # Add protocol section + #sects = infObj.GetSectionByString('protocol') + data = [] + #for sect in sects: + for obj in infObj.GetSectionObjectsByName('protocol', self._arch): + data.append(obj.GetName().strip()) + if len(data) != 0: + s = doxygen.Section('Protocols', 'Protocols') + desc = "<TABLE>" + desc += '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>' + for item in data: + desc += '<TR>' + desc += '<TD>%s</TD>' % item + pkgbasename = self.SearchProtocolPackage(item, workspace, refDecObjs) + desc += '<TD>%s</TD>' % pkgbasename + desc += '</TR>' + desc += "</TABLE>" + s.AddDescription(desc) + modPage.AddSection(s) + + # Add ppi section + #sects = infObj.GetSectionByString('ppi') + data = [] + #for sect in sects: + for obj in infObj.GetSectionObjectsByName('ppi', self._arch): + data.append(obj.GetName().strip()) + if len(data) != 0: + s = doxygen.Section('Ppis', 'Ppis') + desc = "<TABLE>" + desc += '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>' + for item in data: + desc += '<TR>' + desc += '<TD>%s</TD>' % item + pkgbasename = self.SearchPpiPackage(item, workspace, refDecObjs) + desc += '<TD>%s</TD>' % pkgbasename + desc += '</TR>' + desc += "</TABLE>" + s.AddDescription(desc) + modPage.AddSection(s) + + # Add guid section + #sects = infObj.GetSectionByString('guid') + data = [] + #for sect in sects: + for obj in infObj.GetSectionObjectsByName('guid', self._arch): + data.append(obj.GetName().strip()) + if len(data) != 0: + s = doxygen.Section('Guids', 'Guids') + desc = "<TABLE>" + desc += '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>' + for item in data: + desc += '<TR>' + desc += '<TD>%s</TD>' % item + pkgbasename = self.SearchGuidPackage(item, workspace, refDecObjs) + desc += '<TD>%s</TD>' % pkgbasename + desc += '</TR>' + desc += "</TABLE>" + s.AddDescription(desc) + modPage.AddSection(s) + + section = doxygen.Section('LibraryClasses', 'Library Classes') + desc = "<TABLE>" + desc += '<TR><TD><B>Name</B></TD><TD><B>Type</B></TD><TD><B>Package</B></TD><TD><B>Header File</B></TD></TR>' + if isLib: + desc += '<TR>' + desc += '<TD>%s</TD>' % infObj.GetProduceLibraryClass() + desc += '<TD>Produce</TD>' + try: + pkgname, hPath = self.SearchLibraryClassHeaderFile(infObj.GetProduceLibraryClass(), + workspace, + refDecObjs) + except: + self.Log ('fail to get package header file for lib class %s' % infObj.GetProduceLibraryClass()) + pkgname = 'NULL' + hPath = 'NULL' + desc += '<TD>%s</TD>' % pkgname + if hPath != "NULL": + desc += '<TD>\link %s \endlink</TD>' % hPath + else: + desc += '<TD>%s</TD>' % hPath + desc += '</TR>' + for lcObj in infObj.GetSectionObjectsByName('libraryclasses', self._arch): + desc += '<TR>' + desc += '<TD>%s</TD>' % lcObj.GetClass() + retarr = self.SearchLibraryClassHeaderFile(lcObj.GetClass(), + workspace, + refDecObjs) + if retarr is not None: + pkgname, hPath = retarr + else: + self.Log('Fail find the library class %s definition from module %s dependent package!' % (lcObj.GetClass(), infObj.GetFilename()), 'error') + pkgname = 'NULL' + hPath = 'NULL' + desc += '<TD>Consume</TD>' + desc += '<TD>%s</TD>' % pkgname + desc += '<TD>\link %s \endlink</TD>' % hPath + desc += '</TR>' + desc += "</TABLE>" + section.AddDescription(desc) + modPage.AddSection(section) + + section = doxygen.Section('SourceFiles', 'Source Files') + section.AddDescription('<ul>\n') + for obj in infObj.GetSourceObjects(self._arch, self._tooltag): + sPath = infObj.GetModuleRootPath() + sPath = os.path.join(sPath, obj.GetSourcePath()).replace('\\', '/').strip() + if sPath.lower().endswith('.uni') or sPath.lower().endswith('.s') or sPath.lower().endswith('.asm') or sPath.lower().endswith('.nasm'): + newPath = self.TranslateUniFile(sPath) + configFile.AddFile(newPath) + newPath = newPath[len(pObj.GetWorkspace()) + 1:] + section.AddDescription('<li> \link %s \endlink </li>' % newPath) + else: + self.ProcessSourceFileForInclude(sPath, pObj, configFile, infObj) + sPath = sPath[len(pObj.GetWorkspace()) + 1:] + section.AddDescription('<li>\link %s \endlink </li>' % sPath) + section.AddDescription('</ul>\n') + modPage.AddSection(section) + + #sects = infObj.GetSectionByString('depex') + data = [] + #for sect in sects: + for obj in infObj.GetSectionObjectsByName('depex'): + data.append(str(obj)) + if len(data) != 0: + s = doxygen.Section('DependentSection', 'Module Dependencies') + s.AddDescription('<br>'.join(data)) + modPage.AddSection(s) + + return modPage + + def TranslateUniFile(self, path): + newpath = path + '.dox' + #import core.textfile as textfile + #file = textfile.TextFile(path) + + try: + file = open(path, 'r') + except (IOError, OSError) as msg: + return None + + t = file.read() + file.close() + + output = '/** @file \n' + #output = '<html><body>' + arr = t.split('\r\n') + for line in arr: + if line.find('@file') != -1: + continue + if line.find('*/') != -1: + continue + line = line.strip() + if line.strip().startswith('/'): + arr = line.split(' ') + if len(arr) > 1: + line = ' '.join(arr[1:]) + else: + continue + output += '%s<br>\n' % line + output += '**/' + + if os.path.exists(newpath): + os.remove(newpath) + + file = open(newpath, "w") + file.write(output) + file.close() + return newpath + + def SearchPcdPackage(self, pcdname, workspace, decObjs): + for decObj in decObjs: + for pcd in decObj.GetSectionObjectsByName('pcd'): + if pcdname == pcd.GetPcdName(): + return decObj.GetBaseName() + return None + + def SearchProtocolPackage(self, protname, workspace, decObjs): + for decObj in decObjs: + for proto in decObj.GetSectionObjectsByName('protocol'): + if protname == proto.GetName(): + return decObj.GetBaseName() + return None + + def SearchPpiPackage(self, ppiname, workspace, decObjs): + for decObj in decObjs: + for ppi in decObj.GetSectionObjectsByName('ppi'): + if ppiname == ppi.GetName(): + return decObj.GetBaseName() + return None + + def SearchGuidPackage(self, guidname, workspace, decObjs): + for decObj in decObjs: + for guid in decObj.GetSectionObjectsByName('guid'): + if guidname == guid.GetName(): + return decObj.GetBaseName() + return None + + def SearchLibraryClassHeaderFile(self, className, workspace, decObjs): + for decObj in decObjs: + for cls in decObj.GetSectionObjectsByName('libraryclasses'): + if cls.GetClassName().strip() == className: + path = cls.GetHeaderFile().strip() + path = os.path.join(decObj.GetPackageRootPath(), path) + path = path[len(workspace) + 1:] + return decObj.GetBaseName(), path.replace('\\', '/') + + return None + + def _ConvertPathToDoxygen(self, path, pObj): + pRootPath = pObj.GetWorkspace() + path = path[len(pRootPath) + 1:] + return path.replace('\\', '/') + +def IsCHeaderFile(path): + return CheckPathPostfix(path, 'h') + +def CheckPathPostfix(path, str): + index = path.rfind('.') + if index == -1: + return False + if path[index + 1:].lower() == str.lower(): + return True + return False diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/doxygengen_spec.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/doxygengen_spec.py index e37938c466..448e3682c1 100644 --- a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/doxygengen_spec.py +++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/doxygengen_spec.py @@ -1,1086 +1,1086 @@ -## @file
-#
-# This file produce action class to generate doxygen document for edk2 codebase.
-# The action classes are shared by GUI and command line tools.
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-
-from plugins.EdkPlugins.basemodel import doxygen
-import os
-try:
- import wx
- gInGui = True
-except:
- gInGui = False
-import re
-from plugins.EdkPlugins.edk2.model import inf
-from plugins.EdkPlugins.edk2.model import dec
-from plugins.EdkPlugins.basemodel.message import *
-
-_ignore_dir = ['.svn', '_svn', 'cvs']
-_inf_key_description_mapping_table = {
- 'INF_VERSION':'Version of INF file specification',
- #'BASE_NAME':'Module Name',
- 'FILE_GUID':'Module Guid',
- 'MODULE_TYPE': 'Module Type',
- 'VERSION_STRING': 'Module Version',
- 'LIBRARY_CLASS': 'Produced Library Class',
- 'EFI_SPECIFICATION_VERSION': 'UEFI Specification Version',
- 'PI_SPECIFICATION_VERSION': 'PI Specification Version',
- 'ENTRY_POINT': 'Module Entry Point Function',
- 'CONSTRUCTOR': 'Library Constructor Function'
-}
-
-_dec_key_description_mapping_table = {
- 'DEC_SPECIFICATION': 'Version of DEC file specification',
- 'PACKAGE_GUID': 'Package Guid'
-}
-class DoxygenAction:
- """This is base class for all doxygen action.
- """
-
- def __init__(self, doxPath, chmPath, outputPath, projname, mode='html', log=None, verbose=False):
- """Constructor function.
- @param doxPath the obosolution path of doxygen execute file.
- @param outputPath the obosolution output path.
- @param log log function for output message
- """
- self._doxPath = doxPath
- self._chmPath = chmPath
- self._outputPath = outputPath
- self._projname = projname
- self._configFile = None # doxygen config file is used by doxygen exe file
- self._indexPageFile = None # doxygen page file for index page.
- self._log = log
- self._mode = mode
- self._verbose = verbose
- self._doxygenCallback = None
- self._chmCallback = None
-
- def Log(self, message, level='info'):
- if self._log is not None:
- self._log(message, level)
-
- def IsVerbose(self):
- return self._verbose
-
- def Generate(self):
- """Generate interface called by outer directly"""
- self.Log(">>>>>> Start generate doxygen document for %s... Zzz....\n" % self._projname)
-
- # create doxygen config file at first
- self._configFile = doxygen.DoxygenConfigFile()
- self._configFile.SetOutputDir(self._outputPath)
-
- self._configFile.SetWarningFilePath(os.path.join(self._outputPath, 'warning.txt'))
- if self._mode.lower() == 'html':
- self._configFile.SetHtmlMode()
- else:
- self._configFile.SetChmMode()
-
- self.Log(" >>>>>> Initialize doxygen config file...Zzz...\n")
- self.InitializeConfigFile()
-
- self.Log(" >>>>>> Generate doxygen index page file...Zzz...\n")
- indexPagePath = self.GenerateIndexPage()
- if indexPagePath is None:
- self.Log("Fail to generate index page!\n", 'error')
- return False
- else:
- self.Log("Success to create doxygen index page file %s \n" % indexPagePath)
-
- # Add index page doxygen file to file list.
- self._configFile.AddFile(indexPagePath)
-
- # save config file to output path
- configFilePath = os.path.join(self._outputPath, self._projname + '.doxygen_config')
- self._configFile.Generate(configFilePath)
- self.Log(" <<<<<< Success Save doxygen config file to %s...\n" % configFilePath)
-
- # launch doxygen tool to generate document
- if self._doxygenCallback is not None:
- self.Log(" >>>>>> Start doxygen process...Zzz...\n")
- if not self._doxygenCallback(self._doxPath, configFilePath):
- return False
- else:
- self.Log("Fail to create doxygen process!", 'error')
- return False
-
- return True
-
- def InitializeConfigFile(self):
- """Initialize config setting for doxygen project. It will be invoked after config file
- object is created. Inherited class should implement it.
- """
-
- def GenerateIndexPage(self):
- """Generate doxygen index page. Inherited class should implement it."""
- return None
-
- def RegisterCallbackDoxygenProcess(self, callback):
- self._doxygenCallback = callback
-
- def RegisterCallbackCHMProcess(self, callback):
- self._chmCallback = callback
-
-class PlatformDocumentAction(DoxygenAction):
- """Generate platform doxygen document, will be implement at future."""
-
-class PackageDocumentAction(DoxygenAction):
- """Generate package reference document"""
-
- def __init__(self, doxPath, chmPath, outputPath, pObj, mode='html', log=None, arch=None, tooltag=None,
- macros=[], onlyInclude=False, verbose=False):
- DoxygenAction.__init__(self, doxPath, chmPath, outputPath, pObj.GetName(), mode, log, verbose)
- self._pObj = pObj
- self._arch = arch
- self._tooltag = tooltag
- self._macros = macros
- self._onlyIncludeDocument = onlyInclude
-
- def InitializeConfigFile(self):
- if self._arch == 'IA32':
- self._configFile.AddPreDefined('MDE_CPU_IA32')
- elif self._arch == 'X64':
- self._configFile.AddPreDefined('MDE_CPU_X64')
- elif self._arch == 'IPF':
- self._configFile.AddPreDefined('MDE_CPU_IPF')
- elif self._arch == 'EBC':
- self._configFile.AddPreDefined('MDE_CPU_EBC')
- else:
- self._arch = None
- self._configFile.AddPreDefined('MDE_CPU_IA32')
- self._configFile.AddPreDefined('MDE_CPU_X64')
- self._configFile.AddPreDefined('MDE_CPU_IPF')
- self._configFile.AddPreDefined('MDE_CPU_EBC')
- self._configFile.AddPreDefined('MDE_CPU_ARM')
-
- for macro in self._macros:
- self._configFile.AddPreDefined(macro)
-
- namestr = self._pObj.GetName()
- if self._arch is not None:
- namestr += '[%s]' % self._arch
- if self._tooltag is not None:
- namestr += '[%s]' % self._tooltag
- self._configFile.SetProjectName(namestr)
- self._configFile.SetStripPath(self._pObj.GetWorkspace())
- self._configFile.SetProjectVersion(self._pObj.GetFileObj().GetVersion())
- self._configFile.AddPattern('*.decdoxygen')
-
- if self._tooltag.lower() == 'msft':
- self._configFile.AddPreDefined('_MSC_EXTENSIONS')
- elif self._tooltag.lower() == 'gnu':
- self._configFile.AddPreDefined('__GNUC__')
- elif self._tooltag.lower() == 'intel':
- self._configFile.AddPreDefined('__INTEL_COMPILER')
- else:
- self._tooltag = None
- self._configFile.AddPreDefined('_MSC_EXTENSIONS')
- self._configFile.AddPreDefined('__GNUC__')
- self._configFile.AddPreDefined('__INTEL_COMPILER')
-
- self._configFile.AddPreDefined('ASM_PFX= ')
- self._configFile.AddPreDefined('OPTIONAL= ')
-
- def GenerateIndexPage(self):
- """Generate doxygen index page. Inherited class should implement it."""
- fObj = self._pObj.GetFileObj()
- pdObj = doxygen.DoxygenFile('%s Package Document' % self._pObj.GetName(),
- '%s.decdoxygen' % self._pObj.GetFilename())
- self._configFile.AddFile(pdObj.GetFilename())
- pdObj.AddDescription(fObj.GetFileHeader())
-
- defSection = fObj.GetSectionByName('defines')[0]
- baseSection = doxygen.Section('PackageBasicInformation', 'Package Basic Information')
- descr = '<TABLE>'
- for obj in defSection.GetObjects():
- if obj.GetKey() in _dec_key_description_mapping_table.keys():
- descr += '<TR>'
- descr += '<TD><B>%s</B></TD>' % _dec_key_description_mapping_table[obj.GetKey()]
- descr += '<TD>%s</TD>' % obj.GetValue()
- descr += '</TR>'
- descr += '</TABLE><br>'
- baseSection.AddDescription(descr)
- pdObj.AddSection(baseSection)
-
- knownIssueSection = doxygen.Section('Known_Issue_section', 'Known Issue')
- knownIssueSection.AddDescription('<ul>')
- knownIssueSection.AddDescription('<li> OPTIONAL macro for function parameter can not be dealed with doxygen, so it disapear in this document! </li>')
- knownIssueSection.AddDescription('</ul>')
- pdObj.AddSection(knownIssueSection)
-
- self.AddAllIncludeFiles(self._pObj, self._configFile)
- pages = self.GenerateIncludesSubPage(self._pObj, self._configFile)
- if len(pages) != 0:
- pdObj.AddPages(pages)
- pages = self.GenerateLibraryClassesSubPage(self._pObj, self._configFile)
- if len(pages) != 0:
- pdObj.AddPages(pages)
- pages = self.GeneratePcdSubPages(self._pObj, self._configFile)
- if len(pages) != 0:
- pdObj.AddPages(pages)
- pages = self.GenerateGuidSubPages(self._pObj, self._configFile)
- if len(pages) != 0:
- pdObj.AddPages(pages)
- pages = self.GeneratePpiSubPages(self._pObj, self._configFile)
- if len(pages) != 0:
- pdObj.AddPages(pages)
- pages = self.GenerateProtocolSubPages(self._pObj, self._configFile)
- if len(pages) != 0:
- pdObj.AddPages(pages)
- if not self._onlyIncludeDocument:
- pdObj.AddPages(self.GenerateModulePages(self._pObj, self._configFile))
-
- pdObj.Save()
- return pdObj.GetFilename()
-
- def GenerateIncludesSubPage(self, pObj, configFile):
- # by default add following path as include path to config file
- pkpath = pObj.GetFileObj().GetPackageRootPath()
- configFile.AddIncludePath(os.path.join(pkpath, 'Include'))
- configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Library'))
- configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Protocol'))
- configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Ppi'))
- configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Guid'))
- configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'IndustryStandard'))
-
- rootArray = []
- pageRoot = doxygen.Page("Public Includes", "%s_public_includes" % pObj.GetName())
- objs = pObj.GetFileObj().GetSectionObjectsByName('includes')
- if len(objs) == 0: return []
-
- for obj in objs:
- # Add path to include path
- path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetPath())
- configFile.AddIncludePath(path)
-
- # only list common folder's include file
- if obj.GetArch().lower() != 'common':
- continue
-
- bNeedAddIncludePage = False
- topPage = doxygen.Page(self._ConvertPathToDoxygen(path, pObj), 'public_include_top')
-
- topPage.AddDescription('<ul>\n')
- for file in os.listdir(path):
- if file.lower() in _ignore_dir: continue
- fullpath = os.path.join(path, file)
- if os.path.isfile(fullpath):
- self.ProcessSourceFileForInclude(fullpath, pObj, configFile)
- topPage.AddDescription('<li> \link %s\endlink </li>\n' % self._ConvertPathToDoxygen(fullpath, pObj))
- else:
- if file.lower() in ['library', 'protocol', 'guid', 'ppi', 'ia32', 'x64', 'ipf', 'ebc', 'arm', 'pi', 'uefi', 'aarch64']:
- continue
- bNeedAddSubPage = False
- subpage = doxygen.Page(self._ConvertPathToDoxygen(fullpath, pObj), 'public_include_%s' % file)
- subpage.AddDescription('<ul>\n')
- for subfile in os.listdir(fullpath):
- if subfile.lower() in _ignore_dir: continue
- bNeedAddSubPage = True
- subfullpath = os.path.join(fullpath, subfile)
- self.ProcessSourceFileForInclude(subfullpath, pObj, configFile)
- subpage.AddDescription('<li> \link %s \endlink </li>\n' % self._ConvertPathToDoxygen(subfullpath, pObj))
- subpage.AddDescription('</ul>\n')
- if bNeedAddSubPage:
- bNeedAddIncludePage = True
- pageRoot.AddPage(subpage)
- topPage.AddDescription('</ul>\n')
- if bNeedAddIncludePage:
- pageRoot.AddPage(topPage)
-
- if pageRoot.GetSubpageCount() != 0:
- return [pageRoot]
- else:
- return []
-
- def GenerateLibraryClassesSubPage(self, pObj, configFile):
- """
- Generate sub page for library class for package.
- One DEC file maybe contains many library class sections
- for different architecture.
-
- @param fObj DEC file object.
- """
- rootArray = []
- pageRoot = doxygen.Page("Library Class", "%s_libraryclass" % pObj.GetName())
- objs = pObj.GetFileObj().GetSectionObjectsByName('libraryclass', self._arch)
- if len(objs) == 0: return []
-
- if self._arch is not None:
- for obj in objs:
- classPage = doxygen.Page(obj.GetClassName(),
- "lc_%s" % obj.GetClassName())
- comments = obj.GetComment()
- if len(comments) != 0:
- classPage.AddDescription('<br>\n'.join(comments) + '<br>\n')
- pageRoot.AddPage(classPage)
- path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile())
- path = path[len(pObj.GetWorkspace()) + 1:]
- if len(comments) == 0:
- classPage.AddDescription('\copydoc %s<p>' % obj.GetHeaderFile())
- section = doxygen.Section('ref', 'Refer to Header File')
- section.AddDescription('\link %s\n' % obj.GetHeaderFile())
- section.AddDescription(' \endlink<p>\n')
- classPage.AddSection(section)
- fullPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile())
- self.ProcessSourceFileForInclude(fullPath, pObj, configFile)
- else:
- archPageDict = {}
- for obj in objs:
- if obj.GetArch() not in archPageDict.keys():
- archPageDict[obj.GetArch()] = doxygen.Page(obj.GetArch(),
- 'lc_%s' % obj.GetArch())
- pageRoot.AddPage(archPageDict[obj.GetArch()])
- subArchRoot = archPageDict[obj.GetArch()]
- classPage = doxygen.Page(obj.GetClassName(),
- "lc_%s" % obj.GetClassName())
- comments = obj.GetComment()
- if len(comments) != 0:
- classPage.AddDescription('<br>\n'.join(comments) + '<br>\n')
- subArchRoot.AddPage(classPage)
- path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile())
- path = path[len(pObj.GetWorkspace()) + 1:]
- if len(comments) == 0:
- classPage.AddDescription('\copydoc %s<p>' % obj.GetHeaderFile())
- section = doxygen.Section('ref', 'Refer to Header File')
- section.AddDescription('\link %s\n' % obj.GetHeaderFile())
- section.AddDescription(' \endlink<p>\n')
- classPage.AddSection(section)
- fullPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile())
-
- self.ProcessSourceFileForInclude(fullPath, pObj, configFile)
- rootArray.append(pageRoot)
- return rootArray
-
- def ProcessSourceFileForInclude(self, path, pObj, configFile, infObj=None):
- """
- @param path the analysising file full path
- @param pObj package object
- @param configFile doxygen config file.
- """
-
- if gInGui:
- wx.Yield()
- if not os.path.exists(path):
- ErrorMsg('Source file path %s does not exist!' % path)
- return
-
- if configFile.FileExists(path):
- return
-
- try:
- f = open(path, 'r')
- lines = f.readlines()
- f.close()
- except IOError:
- ErrorMsg('Fail to open file %s' % path)
- return
-
- configFile.AddFile(path)
- return
- no = 0
- for no in range(len(lines)):
- if len(lines[no].strip()) == 0:
- continue
- if lines[no].strip()[:2] in ['##', '//', '/*', '*/']:
- continue
- index = lines[no].lower().find('include')
- #mo = IncludePattern.finditer(lines[no].lower())
- mo = re.match(r"^#\s*include\s+[<\"]([\\/\w.]+)[>\"]$", lines[no].strip().lower())
- if not mo:
- continue
- mo = re.match(r"^[#\w\s]+[<\"]([\\/\w.]+)[>\"]$", lines[no].strip())
- filePath = mo.groups()[0]
-
- if filePath is None or len(filePath) == 0:
- continue
-
- # find header file in module's path firstly.
- fullPath = None
-
- if os.path.exists(os.path.join(os.path.dirname(path), filePath)):
- # Find the file in current directory
- fullPath = os.path.join(os.path.dirname(path), filePath).replace('\\', '/')
- else:
- # find in depedent package's include path
- incObjs = pObj.GetFileObj().GetSectionObjectsByName('includes')
- for incObj in incObjs:
- incPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), incObj.GetPath()).strip()
- incPath = os.path.realpath(os.path.join(incPath, filePath))
- if os.path.exists(incPath):
- fullPath = incPath
- break
- if infObj is not None:
- pkgInfObjs = infObj.GetSectionObjectsByName('packages')
- for obj in pkgInfObjs:
- decObj = dec.DECFile(os.path.join(pObj.GetWorkspace(), obj.GetPath()))
- if not decObj:
- ErrorMsg ('Fail to create pacakge object for %s' % obj.GetPackageName())
- continue
- if not decObj.Parse():
- ErrorMsg ('Fail to load package object for %s' % obj.GetPackageName())
- continue
- incObjs = decObj.GetSectionObjectsByName('includes')
- for incObj in incObjs:
- incPath = os.path.join(decObj.GetPackageRootPath(), incObj.GetPath()).replace('\\', '/')
- if os.path.exists(os.path.join(incPath, filePath)):
- fullPath = os.path.join(os.path.join(incPath, filePath))
- break
- if fullPath is not None:
- break
-
- if fullPath is None and self.IsVerbose():
- self.Log('Can not resolve header file %s for file %s in package %s\n' % (filePath, path, pObj.GetFileObj().GetFilename()), 'error')
- return
- else:
- fullPath = fullPath.replace('\\', '/')
- if self.IsVerbose():
- self.Log('Preprocessing: Add include file %s for file %s\n' % (fullPath, path))
- #LogMsg ('Preprocessing: Add include file %s for file %s' % (fullPath, path))
- self.ProcessSourceFileForInclude(fullPath, pObj, configFile, infObj)
-
- def AddAllIncludeFiles(self, pObj, configFile):
- objs = pObj.GetFileObj().GetSectionObjectsByName('includes')
- for obj in objs:
- incPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetPath())
- for root, dirs, files in os.walk(incPath):
- for dir in dirs:
- if dir.lower() in _ignore_dir:
- dirs.remove(dir)
- for file in files:
- path = os.path.normpath(os.path.join(root, file))
- configFile.AddFile(path.replace('/', '\\'))
-
- def GeneratePcdSubPages(self, pObj, configFile):
- """
- Generate sub pages for package's PCD definition.
- @param pObj package object
- @param configFile config file object
- """
- rootArray = []
- objs = pObj.GetFileObj().GetSectionObjectsByName('pcd')
- if len(objs) == 0:
- return []
-
- pcdRootPage = doxygen.Page('PCD', 'pcd_root_page')
- typeRootPageDict = {}
- typeArchRootPageDict = {}
- for obj in objs:
- if obj.GetPcdType() not in typeRootPageDict.keys():
- typeRootPageDict[obj.GetPcdType()] = doxygen.Page(obj.GetPcdType(), 'pcd_%s_root_page' % obj.GetPcdType())
- pcdRootPage.AddPage(typeRootPageDict[obj.GetPcdType()])
- typeRoot = typeRootPageDict[obj.GetPcdType()]
- if self._arch is not None:
- pcdPage = doxygen.Page('%s' % obj.GetPcdName(),
- 'pcd_%s_%s_%s' % (obj.GetPcdType(), obj.GetArch(), obj.GetPcdName().split('.')[1]))
- pcdPage.AddDescription('<br>\n'.join(obj.GetComment()) + '<br>\n')
- section = doxygen.Section('PCDinformation', 'PCD Information')
- desc = '<TABLE>'
- desc += '<TR>'
- desc += '<TD><CAPTION>Name</CAPTION></TD>'
- desc += '<TD><CAPTION>Token Space</CAPTION></TD>'
- desc += '<TD><CAPTION>Token number</CAPTION></TD>'
- desc += '<TD><CAPTION>Data Type</CAPTION></TD>'
- desc += '<TD><CAPTION>Default Value</CAPTION></TD>'
- desc += '</TR>'
- desc += '<TR>'
- desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[1]
- desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[0]
- desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdToken()
- desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdDataType()
- desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdValue()
- desc += '</TR>'
- desc += '</TABLE>'
- section.AddDescription(desc)
- pcdPage.AddSection(section)
- typeRoot.AddPage(pcdPage)
- else:
- keystr = obj.GetPcdType() + obj.GetArch()
- if keystr not in typeArchRootPageDict.keys():
- typeArchRootPage = doxygen.Page(obj.GetArch(), 'pcd_%s_%s_root_page' % (obj.GetPcdType(), obj.GetArch()))
- typeArchRootPageDict[keystr] = typeArchRootPage
- typeRoot.AddPage(typeArchRootPage)
- typeArchRoot = typeArchRootPageDict[keystr]
- pcdPage = doxygen.Page('%s' % obj.GetPcdName(),
- 'pcd_%s_%s_%s' % (obj.GetPcdType(), obj.GetArch(), obj.GetPcdName().split('.')[1]))
- pcdPage.AddDescription('<br>\n'.join(obj.GetComment()) + '<br>\n')
- section = doxygen.Section('PCDinformation', 'PCD Information')
- desc = '<TABLE>'
- desc += '<TR>'
- desc += '<TD><CAPTION>Name</CAPTION></TD>'
- desc += '<TD><CAPTION>Token Space</CAPTION></TD>'
- desc += '<TD><CAPTION>Token number</CAPTION></TD>'
- desc += '<TD><CAPTION>Data Type</CAPTION></TD>'
- desc += '<TD><CAPTION>Default Value</CAPTION></TD>'
- desc += '</TR>'
- desc += '<TR>'
- desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[1]
- desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[0]
- desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdToken()
- desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdDataType()
- desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdValue()
- desc += '</TR>'
- desc += '</TABLE>'
- section.AddDescription(desc)
- pcdPage.AddSection(section)
- typeArchRoot.AddPage(pcdPage)
- return [pcdRootPage]
-
- def _GenerateGuidSubPage(self, pObj, obj, configFile):
- guidPage = doxygen.Page('%s' % obj.GetName(),
- 'guid_%s_%s' % (obj.GetArch(), obj.GetName()))
- comments = obj.GetComment()
- if len(comments) != 0:
- guidPage.AddDescription('<br>'.join(obj.GetComment()) + '<br>')
- section = doxygen.Section('BasicGuidInfo', 'GUID Information')
- desc = '<TABLE>'
- desc += '<TR>'
- desc += '<TD><CAPTION>GUID\'s Guid Name</CAPTION></TD><TD><CAPTION>GUID\'s Guid</CAPTION></TD>'
- desc += '</TR>'
- desc += '<TR>'
- desc += '<TD>%s</TD>' % obj.GetName()
- desc += '<TD>%s</TD>' % obj.GetGuid()
- desc += '</TR>'
- desc += '</TABLE>'
- section.AddDescription(desc)
- guidPage.AddSection(section)
- refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile)
- if refFile:
- relPath = refFile[len(pObj.GetWorkspace()) + 1:]
- if len(comments) == 0:
- guidPage.AddDescription(' \\copydoc %s <br>' % relPath)
-
- section = doxygen.Section('ref', 'Refer to Header File')
- section.AddDescription('\link %s\n' % relPath)
- section.AddDescription('\endlink\n')
- self.ProcessSourceFileForInclude(refFile, pObj, configFile)
- guidPage.AddSection(section)
- return guidPage
-
- def GenerateGuidSubPages(self, pObj, configFile):
- """
- Generate sub pages for package's GUID definition.
- @param pObj package object
- @param configFilf doxygen config file object
- """
- pageRoot = doxygen.Page('GUID', 'guid_root_page')
- objs = pObj.GetFileObj().GetSectionObjectsByName('guids', self._arch)
- if len(objs) == 0: return []
- if self._arch is not None:
- for obj in objs:
- pageRoot.AddPage(self._GenerateGuidSubPage(pObj, obj, configFile))
- else:
- guidArchRootPageDict = {}
- for obj in objs:
- if obj.GetArch() not in guidArchRootPageDict.keys():
- guidArchRoot = doxygen.Page(obj.GetArch(), 'guid_arch_root_%s' % obj.GetArch())
- pageRoot.AddPage(guidArchRoot)
- guidArchRootPageDict[obj.GetArch()] = guidArchRoot
- guidArchRoot = guidArchRootPageDict[obj.GetArch()]
- guidArchRoot.AddPage(self._GenerateGuidSubPage(pObj, obj, configFile))
- return [pageRoot]
-
- def _GeneratePpiSubPage(self, pObj, obj, configFile):
- guidPage = doxygen.Page(obj.GetName(), 'ppi_page_%s' % obj.GetName())
- comments = obj.GetComment()
- if len(comments) != 0:
- guidPage.AddDescription('<br>'.join(obj.GetComment()) + '<br>')
- section = doxygen.Section('BasicPpiInfo', 'PPI Information')
- desc = '<TABLE>'
- desc += '<TR>'
- desc += '<TD><CAPTION>PPI\'s Guid Name</CAPTION></TD><TD><CAPTION>PPI\'s Guid</CAPTION></TD>'
- desc += '</TR>'
- desc += '<TR>'
- desc += '<TD>%s</TD>' % obj.GetName()
- desc += '<TD>%s</TD>' % obj.GetGuid()
- desc += '</TR>'
- desc += '</TABLE>'
- section.AddDescription(desc)
- guidPage.AddSection(section)
- refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile)
- if refFile:
- relPath = refFile[len(pObj.GetWorkspace()) + 1:]
- if len(comments) == 0:
- guidPage.AddDescription(' \\copydoc %s <br>' % relPath)
- section = doxygen.Section('ref', 'Refer to Header File')
- section.AddDescription('\link %s\n' % relPath)
- section.AddDescription('\endlink\n')
- self.ProcessSourceFileForInclude(refFile, pObj, configFile)
- guidPage.AddSection(section)
-
- return guidPage
-
- def GeneratePpiSubPages(self, pObj, configFile):
- """
- Generate sub pages for package's GUID definition.
- @param pObj package object
- @param configFilf doxygen config file object
- """
- pageRoot = doxygen.Page('PPI', 'ppi_root_page')
- objs = pObj.GetFileObj().GetSectionObjectsByName('ppis', self._arch)
- if len(objs) == 0: return []
- if self._arch is not None:
- for obj in objs:
- pageRoot.AddPage(self._GeneratePpiSubPage(pObj, obj, configFile))
- else:
- guidArchRootPageDict = {}
- for obj in objs:
- if obj.GetArch() not in guidArchRootPageDict.keys():
- guidArchRoot = doxygen.Page(obj.GetArch(), 'ppi_arch_root_%s' % obj.GetArch())
- pageRoot.AddPage(guidArchRoot)
- guidArchRootPageDict[obj.GetArch()] = guidArchRoot
- guidArchRoot = guidArchRootPageDict[obj.GetArch()]
- guidArchRoot.AddPage(self._GeneratePpiSubPage(pObj, obj, configFile))
- return [pageRoot]
-
- def _GenerateProtocolSubPage(self, pObj, obj, configFile):
- guidPage = doxygen.Page(obj.GetName(), 'protocol_page_%s' % obj.GetName())
- comments = obj.GetComment()
- if len(comments) != 0:
- guidPage.AddDescription('<br>'.join(obj.GetComment()) + '<br>')
- section = doxygen.Section('BasicProtocolInfo', 'PROTOCOL Information')
- desc = '<TABLE>'
- desc += '<TR>'
- desc += '<TD><CAPTION>PROTOCOL\'s Guid Name</CAPTION></TD><TD><CAPTION>PROTOCOL\'s Guid</CAPTION></TD>'
- desc += '</TR>'
- desc += '<TR>'
- desc += '<TD>%s</TD>' % obj.GetName()
- desc += '<TD>%s</TD>' % obj.GetGuid()
- desc += '</TR>'
- desc += '</TABLE>'
- section.AddDescription(desc)
- guidPage.AddSection(section)
-
- refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile)
- if refFile:
- relPath = refFile[len(pObj.GetWorkspace()) + 1:]
- if len(comments) == 0:
- guidPage.AddDescription(' \\copydoc %s <br>' % relPath)
- section = doxygen.Section('ref', 'Refer to Header File')
- section.AddDescription('\link %s\n' % relPath)
- section.AddDescription('\endlink\n')
- self.ProcessSourceFileForInclude(refFile, pObj, configFile)
- guidPage.AddSection(section)
-
- return guidPage
-
- def GenerateProtocolSubPages(self, pObj, configFile):
- """
- Generate sub pages for package's GUID definition.
- @param pObj package object
- @param configFilf doxygen config file object
- """
- pageRoot = doxygen.Page('PROTOCOL', 'protocol_root_page')
- objs = pObj.GetFileObj().GetSectionObjectsByName('protocols', self._arch)
- if len(objs) == 0: return []
- if self._arch is not None:
- for obj in objs:
- pageRoot.AddPage(self._GenerateProtocolSubPage(pObj, obj, configFile))
- else:
- guidArchRootPageDict = {}
- for obj in objs:
- if obj.GetArch() not in guidArchRootPageDict.keys():
- guidArchRoot = doxygen.Page(obj.GetArch(), 'protocol_arch_root_%s' % obj.GetArch())
- pageRoot.AddPage(guidArchRoot)
- guidArchRootPageDict[obj.GetArch()] = guidArchRoot
- guidArchRoot = guidArchRootPageDict[obj.GetArch()]
- guidArchRoot.AddPage(self._GenerateProtocolSubPage(pObj, obj, configFile))
- return [pageRoot]
-
- def FindHeaderFileForGuid(self, pObj, name, configFile):
- """
- For declaration header file for GUID/PPI/Protocol.
-
- @param pObj package object
- @param name guid/ppi/protocol's name
- @param configFile config file object
-
- @return full path of header file and None if not found.
- """
- startPath = pObj.GetFileObj().GetPackageRootPath()
- incPath = os.path.join(startPath, 'Include').replace('\\', '/')
- # if <PackagePath>/include exist, then search header under it.
- if os.path.exists(incPath):
- startPath = incPath
-
- for root, dirs, files in os.walk(startPath):
- for dir in dirs:
- if dir.lower() in _ignore_dir:
- dirs.remove(dir)
- for file in files:
- fPath = os.path.join(root, file)
- if not IsCHeaderFile(fPath):
- continue
- try:
- f = open(fPath, 'r')
- lines = f.readlines()
- f.close()
- except IOError:
- self.Log('Fail to open file %s\n' % fPath)
- continue
- for line in lines:
- if line.find(name) != -1 and \
- line.find('extern') != -1:
- return fPath.replace('\\', '/')
- return None
-
- def GetPackageModuleList(self, pObj):
- """
- Get all module's INF path under package's root path
- @param pObj package object
- @return arrary of INF full path
- """
- mArray = []
- packPath = pObj.GetFileObj().GetPackageRootPath()
- if not os.path.exists:
- return None
- for root, dirs, files in os.walk(packPath):
- for dir in dirs:
- if dir.lower() in _ignore_dir:
- dirs.remove(dir)
- for file in files:
- if CheckPathPostfix(file, 'inf'):
- fPath = os.path.join(root, file).replace('\\', '/')
- mArray.append(fPath)
- return mArray
-
- def GenerateModulePages(self, pObj, configFile):
- """
- Generate sub pages for package's module which is under the package
- root directory.
-
- @param pObj package object
- @param configFilf doxygen config file object
- """
- infList = self.GetPackageModuleList(pObj)
- rootPages = []
- libObjs = []
- modObjs = []
- for infpath in infList:
- infObj = inf.INFFile(infpath)
- #infObj = INFFileObject.INFFile (pObj.GetWorkspacePath(),
- # inf)
- if not infObj:
- self.Log('Fail create INF object for %s' % inf)
- continue
- if not infObj.Parse():
- self.Log('Fail to load INF file %s' % inf)
- continue
- if infObj.GetProduceLibraryClass() is not None:
- libObjs.append(infObj)
- else:
- modObjs.append(infObj)
-
- if len(libObjs) != 0:
- libRootPage = doxygen.Page('Libraries', 'lib_root_page')
- rootPages.append(libRootPage)
- for libInf in libObjs:
- libRootPage.AddPage(self.GenerateModulePage(pObj, libInf, configFile, True))
-
- if len(modObjs) != 0:
- modRootPage = doxygen.Page('Modules', 'module_root_page')
- rootPages.append(modRootPage)
- for modInf in modObjs:
- modRootPage.AddPage(self.GenerateModulePage(pObj, modInf, configFile, False))
-
- return rootPages
-
- def GenerateModulePage(self, pObj, infObj, configFile, isLib):
- """
- Generate page for a module/library.
- @param infObj INF file object for module/library
- @param configFile doxygen config file object
- @param isLib Whether this module is library
-
- @param module doxygen page object
- """
- workspace = pObj.GetWorkspace()
- refDecObjs = []
- for obj in infObj.GetSectionObjectsByName('packages'):
- decObj = dec.DECFile(os.path.join(workspace, obj.GetPath()))
- if not decObj:
- ErrorMsg ('Fail to create pacakge object for %s' % obj.GetPackageName())
- continue
- if not decObj.Parse():
- ErrorMsg ('Fail to load package object for %s' % obj.GetPackageName())
- continue
- refDecObjs.append(decObj)
-
- modPage = doxygen.Page('%s' % infObj.GetBaseName(),
- 'module_%s' % infObj.GetBaseName())
- modPage.AddDescription(infObj.GetFileHeader())
-
- basicInfSection = doxygen.Section('BasicModuleInformation', 'Basic Module Information')
- desc = "<TABLE>"
- for obj in infObj.GetSectionObjectsByName('defines'):
- key = obj.GetKey()
- value = obj.GetValue()
- if key not in _inf_key_description_mapping_table.keys(): continue
- if key == 'LIBRARY_CLASS' and value.find('|') != -1:
- clsname, types = value.split('|')
- desc += '<TR>'
- desc += '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table[key]
- desc += '<TD>%s</TD>' % clsname
- desc += '</TR>'
-
- desc += '<TR>'
- desc += '<TD><B>Supported Module Types</B></TD>'
- desc += '<TD>%s</TD>' % types
- desc += '</TR>'
- else:
- desc += '<TR>'
- desc += '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table[key]
- if key == 'EFI_SPECIFICATION_VERSION' and value == '0x00020000':
- value = '2.0'
- desc += '<TD>%s</TD>' % value
- desc += '</TR>'
- desc += '</TABLE>'
- basicInfSection.AddDescription(desc)
- modPage.AddSection(basicInfSection)
-
- # Add protocol section
- data = []
- for obj in infObj.GetSectionObjectsByName('pcd', self._arch):
- data.append(obj.GetPcdName().strip())
- if len(data) != 0:
- s = doxygen.Section('Pcds', 'Pcds')
- desc = "<TABLE>"
- desc += '<TR><TD><B>PCD Name</B></TD><TD><B>TokenSpace</B></TD><TD><B>Package</B></TD></TR>'
- for item in data:
- desc += '<TR>'
- desc += '<TD>%s</TD>' % item.split('.')[1]
- desc += '<TD>%s</TD>' % item.split('.')[0]
- pkgbasename = self.SearchPcdPackage(item, workspace, refDecObjs)
- desc += '<TD>%s</TD>' % pkgbasename
- desc += '</TR>'
- desc += "</TABLE>"
- s.AddDescription(desc)
- modPage.AddSection(s)
-
- # Add protocol section
- #sects = infObj.GetSectionByString('protocol')
- data = []
- #for sect in sects:
- for obj in infObj.GetSectionObjectsByName('protocol', self._arch):
- data.append(obj.GetName().strip())
- if len(data) != 0:
- s = doxygen.Section('Protocols', 'Protocols')
- desc = "<TABLE>"
- desc += '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
- for item in data:
- desc += '<TR>'
- desc += '<TD>%s</TD>' % item
- pkgbasename = self.SearchProtocolPackage(item, workspace, refDecObjs)
- desc += '<TD>%s</TD>' % pkgbasename
- desc += '</TR>'
- desc += "</TABLE>"
- s.AddDescription(desc)
- modPage.AddSection(s)
-
- # Add ppi section
- #sects = infObj.GetSectionByString('ppi')
- data = []
- #for sect in sects:
- for obj in infObj.GetSectionObjectsByName('ppi', self._arch):
- data.append(obj.GetName().strip())
- if len(data) != 0:
- s = doxygen.Section('Ppis', 'Ppis')
- desc = "<TABLE>"
- desc += '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
- for item in data:
- desc += '<TR>'
- desc += '<TD>%s</TD>' % item
- pkgbasename = self.SearchPpiPackage(item, workspace, refDecObjs)
- desc += '<TD>%s</TD>' % pkgbasename
- desc += '</TR>'
- desc += "</TABLE>"
- s.AddDescription(desc)
- modPage.AddSection(s)
-
- # Add guid section
- #sects = infObj.GetSectionByString('guid')
- data = []
- #for sect in sects:
- for obj in infObj.GetSectionObjectsByName('guid', self._arch):
- data.append(obj.GetName().strip())
- if len(data) != 0:
- s = doxygen.Section('Guids', 'Guids')
- desc = "<TABLE>"
- desc += '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>'
- for item in data:
- desc += '<TR>'
- desc += '<TD>%s</TD>' % item
- pkgbasename = self.SearchGuidPackage(item, workspace, refDecObjs)
- desc += '<TD>%s</TD>' % pkgbasename
- desc += '</TR>'
- desc += "</TABLE>"
- s.AddDescription(desc)
- modPage.AddSection(s)
-
- section = doxygen.Section('LibraryClasses', 'Library Classes')
- desc = "<TABLE>"
- desc += '<TR><TD><B>Name</B></TD><TD><B>Type</B></TD><TD><B>Package</B></TD><TD><B>Header File</B></TD></TR>'
- if isLib:
- desc += '<TR>'
- desc += '<TD>%s</TD>' % infObj.GetProduceLibraryClass()
- desc += '<TD>Produce</TD>'
- try:
- pkgname, hPath = self.SearchLibraryClassHeaderFile(infObj.GetProduceLibraryClass(),
- workspace,
- refDecObjs)
- except:
- self.Log ('fail to get package header file for lib class %s' % infObj.GetProduceLibraryClass())
- pkgname = 'NULL'
- hPath = 'NULL'
- desc += '<TD>%s</TD>' % pkgname
- if hPath != "NULL":
- #desc += '<TD>\link %s \endlink</TD>' % hPath
- desc += '<TD>%s</TD>' % hPath
- else:
- desc += '<TD>%s</TD>' % hPath
- desc += '</TR>'
- for lcObj in infObj.GetSectionObjectsByName('libraryclasses', self._arch):
- desc += '<TR>'
- desc += '<TD>%s</TD>' % lcObj.GetClass()
- retarr = self.SearchLibraryClassHeaderFile(lcObj.GetClass(),
- workspace,
- refDecObjs)
- if retarr is not None:
- pkgname, hPath = retarr
- else:
- self.Log('Fail find the library class %s definition from module %s dependent package!' % (lcObj.GetClass(), infObj.GetFilename()), 'error')
- pkgname = 'NULL'
- hPath = 'NULL'
- desc += '<TD>Consume</TD>'
- desc += '<TD>%s</TD>' % pkgname
- desc += '<TD>%s</TD>' % hPath
- desc += '</TR>'
- desc += "</TABLE>"
- section.AddDescription(desc)
- modPage.AddSection(section)
-
- section = doxygen.Section('SourceFiles', 'Source Files')
- section.AddDescription('<ul>\n')
- for obj in infObj.GetSourceObjects(self._arch, self._tooltag):
- sPath = infObj.GetModuleRootPath()
- sPath = os.path.join(sPath, obj.GetSourcePath()).replace('\\', '/').strip()
- if sPath.lower().endswith('.uni') or sPath.lower().endswith('.s') or sPath.lower().endswith('.asm') or sPath.lower().endswith('.nasm'):
- newPath = self.TranslateUniFile(sPath)
- configFile.AddFile(newPath)
- newPath = newPath[len(pObj.GetWorkspace()) + 1:]
- section.AddDescription('<li> \link %s \endlink </li>' % newPath)
- else:
- self.ProcessSourceFileForInclude(sPath, pObj, configFile, infObj)
- sPath = sPath[len(pObj.GetWorkspace()) + 1:]
- section.AddDescription('<li>\link %s \endlink </li>' % sPath)
- section.AddDescription('</ul>\n')
- modPage.AddSection(section)
-
- #sects = infObj.GetSectionByString('depex')
- data = []
- #for sect in sects:
- for obj in infObj.GetSectionObjectsByName('depex'):
- data.append(str(obj))
- if len(data) != 0:
- s = doxygen.Section('DependentSection', 'Module Dependencies')
- s.AddDescription('<br>'.join(data))
- modPage.AddSection(s)
-
- return modPage
-
- def TranslateUniFile(self, path):
- newpath = path + '.dox'
- #import core.textfile as textfile
- #file = textfile.TextFile(path)
-
- try:
- file = open(path, 'r')
- except (IOError, OSError) as msg:
- return None
-
- t = file.read()
- file.close()
-
- output = '/** @file \n'
- #output = '<html><body>'
- arr = t.split('\r\n')
- for line in arr:
- if line.find('@file') != -1:
- continue
- if line.find('*/') != -1:
- continue
- line = line.strip()
- if line.strip().startswith('/'):
- arr = line.split(' ')
- if len(arr) > 1:
- line = ' '.join(arr[1:])
- else:
- continue
- output += '%s<br>\n' % line
- output += '**/'
-
- if os.path.exists(newpath):
- os.remove(newpath)
-
- file = open(newpath, "w")
- file.write(output)
- file.close()
- return newpath
-
- def SearchPcdPackage(self, pcdname, workspace, decObjs):
- for decObj in decObjs:
- for pcd in decObj.GetSectionObjectsByName('pcd'):
- if pcdname == pcd.GetPcdName():
- return decObj.GetBaseName()
- return None
-
- def SearchProtocolPackage(self, protname, workspace, decObjs):
- for decObj in decObjs:
- for proto in decObj.GetSectionObjectsByName('protocol'):
- if protname == proto.GetName():
- return decObj.GetBaseName()
- return None
-
- def SearchPpiPackage(self, ppiname, workspace, decObjs):
- for decObj in decObjs:
- for ppi in decObj.GetSectionObjectsByName('ppi'):
- if ppiname == ppi.GetName():
- return decObj.GetBaseName()
- return None
-
- def SearchGuidPackage(self, guidname, workspace, decObjs):
- for decObj in decObjs:
- for guid in decObj.GetSectionObjectsByName('guid'):
- if guidname == guid.GetName():
- return decObj.GetBaseName()
- return None
-
- def SearchLibraryClassHeaderFile(self, className, workspace, decObjs):
- for decObj in decObjs:
- for cls in decObj.GetSectionObjectsByName('libraryclasses'):
- if cls.GetClassName().strip() == className:
- path = cls.GetHeaderFile().strip()
- path = os.path.join(decObj.GetPackageRootPath(), path)
- path = path[len(workspace) + 1:]
- return decObj.GetBaseName(), path.replace('\\', '/')
-
- return None
-
- def _ConvertPathToDoxygen(self, path, pObj):
- pRootPath = pObj.GetWorkspace()
- path = path[len(pRootPath) + 1:]
- return path.replace('\\', '/')
-
-def IsCHeaderFile(path):
- return CheckPathPostfix(path, 'h')
-
-def CheckPathPostfix(path, str):
- index = path.rfind('.')
- if index == -1:
- return False
- if path[index + 1:].lower() == str.lower():
- return True
- return False
+## @file +# +# This file produce action class to generate doxygen document for edk2 codebase. +# The action classes are shared by GUI and command line tools. +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent + +from plugins.EdkPlugins.basemodel import doxygen +import os +try: + import wx + gInGui = True +except: + gInGui = False +import re +from plugins.EdkPlugins.edk2.model import inf +from plugins.EdkPlugins.edk2.model import dec +from plugins.EdkPlugins.basemodel.message import * + +_ignore_dir = ['.svn', '_svn', 'cvs'] +_inf_key_description_mapping_table = { + 'INF_VERSION':'Version of INF file specification', + #'BASE_NAME':'Module Name', + 'FILE_GUID':'Module Guid', + 'MODULE_TYPE': 'Module Type', + 'VERSION_STRING': 'Module Version', + 'LIBRARY_CLASS': 'Produced Library Class', + 'EFI_SPECIFICATION_VERSION': 'UEFI Specification Version', + 'PI_SPECIFICATION_VERSION': 'PI Specification Version', + 'ENTRY_POINT': 'Module Entry Point Function', + 'CONSTRUCTOR': 'Library Constructor Function' +} + +_dec_key_description_mapping_table = { + 'DEC_SPECIFICATION': 'Version of DEC file specification', + 'PACKAGE_GUID': 'Package Guid' +} +class DoxygenAction: + """This is base class for all doxygen action. + """ + + def __init__(self, doxPath, chmPath, outputPath, projname, mode='html', log=None, verbose=False): + """Constructor function. + @param doxPath the obosolution path of doxygen execute file. + @param outputPath the obosolution output path. + @param log log function for output message + """ + self._doxPath = doxPath + self._chmPath = chmPath + self._outputPath = outputPath + self._projname = projname + self._configFile = None # doxygen config file is used by doxygen exe file + self._indexPageFile = None # doxygen page file for index page. + self._log = log + self._mode = mode + self._verbose = verbose + self._doxygenCallback = None + self._chmCallback = None + + def Log(self, message, level='info'): + if self._log is not None: + self._log(message, level) + + def IsVerbose(self): + return self._verbose + + def Generate(self): + """Generate interface called by outer directly""" + self.Log(">>>>>> Start generate doxygen document for %s... Zzz....\n" % self._projname) + + # create doxygen config file at first + self._configFile = doxygen.DoxygenConfigFile() + self._configFile.SetOutputDir(self._outputPath) + + self._configFile.SetWarningFilePath(os.path.join(self._outputPath, 'warning.txt')) + if self._mode.lower() == 'html': + self._configFile.SetHtmlMode() + else: + self._configFile.SetChmMode() + + self.Log(" >>>>>> Initialize doxygen config file...Zzz...\n") + self.InitializeConfigFile() + + self.Log(" >>>>>> Generate doxygen index page file...Zzz...\n") + indexPagePath = self.GenerateIndexPage() + if indexPagePath is None: + self.Log("Fail to generate index page!\n", 'error') + return False + else: + self.Log("Success to create doxygen index page file %s \n" % indexPagePath) + + # Add index page doxygen file to file list. + self._configFile.AddFile(indexPagePath) + + # save config file to output path + configFilePath = os.path.join(self._outputPath, self._projname + '.doxygen_config') + self._configFile.Generate(configFilePath) + self.Log(" <<<<<< Success Save doxygen config file to %s...\n" % configFilePath) + + # launch doxygen tool to generate document + if self._doxygenCallback is not None: + self.Log(" >>>>>> Start doxygen process...Zzz...\n") + if not self._doxygenCallback(self._doxPath, configFilePath): + return False + else: + self.Log("Fail to create doxygen process!", 'error') + return False + + return True + + def InitializeConfigFile(self): + """Initialize config setting for doxygen project. It will be invoked after config file + object is created. Inherited class should implement it. + """ + + def GenerateIndexPage(self): + """Generate doxygen index page. Inherited class should implement it.""" + return None + + def RegisterCallbackDoxygenProcess(self, callback): + self._doxygenCallback = callback + + def RegisterCallbackCHMProcess(self, callback): + self._chmCallback = callback + +class PlatformDocumentAction(DoxygenAction): + """Generate platform doxygen document, will be implement at future.""" + +class PackageDocumentAction(DoxygenAction): + """Generate package reference document""" + + def __init__(self, doxPath, chmPath, outputPath, pObj, mode='html', log=None, arch=None, tooltag=None, + macros=[], onlyInclude=False, verbose=False): + DoxygenAction.__init__(self, doxPath, chmPath, outputPath, pObj.GetName(), mode, log, verbose) + self._pObj = pObj + self._arch = arch + self._tooltag = tooltag + self._macros = macros + self._onlyIncludeDocument = onlyInclude + + def InitializeConfigFile(self): + if self._arch == 'IA32': + self._configFile.AddPreDefined('MDE_CPU_IA32') + elif self._arch == 'X64': + self._configFile.AddPreDefined('MDE_CPU_X64') + elif self._arch == 'IPF': + self._configFile.AddPreDefined('MDE_CPU_IPF') + elif self._arch == 'EBC': + self._configFile.AddPreDefined('MDE_CPU_EBC') + else: + self._arch = None + self._configFile.AddPreDefined('MDE_CPU_IA32') + self._configFile.AddPreDefined('MDE_CPU_X64') + self._configFile.AddPreDefined('MDE_CPU_IPF') + self._configFile.AddPreDefined('MDE_CPU_EBC') + self._configFile.AddPreDefined('MDE_CPU_ARM') + + for macro in self._macros: + self._configFile.AddPreDefined(macro) + + namestr = self._pObj.GetName() + if self._arch is not None: + namestr += '[%s]' % self._arch + if self._tooltag is not None: + namestr += '[%s]' % self._tooltag + self._configFile.SetProjectName(namestr) + self._configFile.SetStripPath(self._pObj.GetWorkspace()) + self._configFile.SetProjectVersion(self._pObj.GetFileObj().GetVersion()) + self._configFile.AddPattern('*.decdoxygen') + + if self._tooltag.lower() == 'msft': + self._configFile.AddPreDefined('_MSC_EXTENSIONS') + elif self._tooltag.lower() == 'gnu': + self._configFile.AddPreDefined('__GNUC__') + elif self._tooltag.lower() == 'intel': + self._configFile.AddPreDefined('__INTEL_COMPILER') + else: + self._tooltag = None + self._configFile.AddPreDefined('_MSC_EXTENSIONS') + self._configFile.AddPreDefined('__GNUC__') + self._configFile.AddPreDefined('__INTEL_COMPILER') + + self._configFile.AddPreDefined('ASM_PFX= ') + self._configFile.AddPreDefined('OPTIONAL= ') + + def GenerateIndexPage(self): + """Generate doxygen index page. Inherited class should implement it.""" + fObj = self._pObj.GetFileObj() + pdObj = doxygen.DoxygenFile('%s Package Document' % self._pObj.GetName(), + '%s.decdoxygen' % self._pObj.GetFilename()) + self._configFile.AddFile(pdObj.GetFilename()) + pdObj.AddDescription(fObj.GetFileHeader()) + + defSection = fObj.GetSectionByName('defines')[0] + baseSection = doxygen.Section('PackageBasicInformation', 'Package Basic Information') + descr = '<TABLE>' + for obj in defSection.GetObjects(): + if obj.GetKey() in _dec_key_description_mapping_table.keys(): + descr += '<TR>' + descr += '<TD><B>%s</B></TD>' % _dec_key_description_mapping_table[obj.GetKey()] + descr += '<TD>%s</TD>' % obj.GetValue() + descr += '</TR>' + descr += '</TABLE><br>' + baseSection.AddDescription(descr) + pdObj.AddSection(baseSection) + + knownIssueSection = doxygen.Section('Known_Issue_section', 'Known Issue') + knownIssueSection.AddDescription('<ul>') + knownIssueSection.AddDescription('<li> OPTIONAL macro for function parameter can not be dealed with doxygen, so it disapear in this document! </li>') + knownIssueSection.AddDescription('</ul>') + pdObj.AddSection(knownIssueSection) + + self.AddAllIncludeFiles(self._pObj, self._configFile) + pages = self.GenerateIncludesSubPage(self._pObj, self._configFile) + if len(pages) != 0: + pdObj.AddPages(pages) + pages = self.GenerateLibraryClassesSubPage(self._pObj, self._configFile) + if len(pages) != 0: + pdObj.AddPages(pages) + pages = self.GeneratePcdSubPages(self._pObj, self._configFile) + if len(pages) != 0: + pdObj.AddPages(pages) + pages = self.GenerateGuidSubPages(self._pObj, self._configFile) + if len(pages) != 0: + pdObj.AddPages(pages) + pages = self.GeneratePpiSubPages(self._pObj, self._configFile) + if len(pages) != 0: + pdObj.AddPages(pages) + pages = self.GenerateProtocolSubPages(self._pObj, self._configFile) + if len(pages) != 0: + pdObj.AddPages(pages) + if not self._onlyIncludeDocument: + pdObj.AddPages(self.GenerateModulePages(self._pObj, self._configFile)) + + pdObj.Save() + return pdObj.GetFilename() + + def GenerateIncludesSubPage(self, pObj, configFile): + # by default add following path as include path to config file + pkpath = pObj.GetFileObj().GetPackageRootPath() + configFile.AddIncludePath(os.path.join(pkpath, 'Include')) + configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Library')) + configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Protocol')) + configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Ppi')) + configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'Guid')) + configFile.AddIncludePath(os.path.join(pkpath, 'Include', 'IndustryStandard')) + + rootArray = [] + pageRoot = doxygen.Page("Public Includes", "%s_public_includes" % pObj.GetName()) + objs = pObj.GetFileObj().GetSectionObjectsByName('includes') + if len(objs) == 0: return [] + + for obj in objs: + # Add path to include path + path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetPath()) + configFile.AddIncludePath(path) + + # only list common folder's include file + if obj.GetArch().lower() != 'common': + continue + + bNeedAddIncludePage = False + topPage = doxygen.Page(self._ConvertPathToDoxygen(path, pObj), 'public_include_top') + + topPage.AddDescription('<ul>\n') + for file in os.listdir(path): + if file.lower() in _ignore_dir: continue + fullpath = os.path.join(path, file) + if os.path.isfile(fullpath): + self.ProcessSourceFileForInclude(fullpath, pObj, configFile) + topPage.AddDescription('<li> \link %s\endlink </li>\n' % self._ConvertPathToDoxygen(fullpath, pObj)) + else: + if file.lower() in ['library', 'protocol', 'guid', 'ppi', 'ia32', 'x64', 'ipf', 'ebc', 'arm', 'pi', 'uefi', 'aarch64']: + continue + bNeedAddSubPage = False + subpage = doxygen.Page(self._ConvertPathToDoxygen(fullpath, pObj), 'public_include_%s' % file) + subpage.AddDescription('<ul>\n') + for subfile in os.listdir(fullpath): + if subfile.lower() in _ignore_dir: continue + bNeedAddSubPage = True + subfullpath = os.path.join(fullpath, subfile) + self.ProcessSourceFileForInclude(subfullpath, pObj, configFile) + subpage.AddDescription('<li> \link %s \endlink </li>\n' % self._ConvertPathToDoxygen(subfullpath, pObj)) + subpage.AddDescription('</ul>\n') + if bNeedAddSubPage: + bNeedAddIncludePage = True + pageRoot.AddPage(subpage) + topPage.AddDescription('</ul>\n') + if bNeedAddIncludePage: + pageRoot.AddPage(topPage) + + if pageRoot.GetSubpageCount() != 0: + return [pageRoot] + else: + return [] + + def GenerateLibraryClassesSubPage(self, pObj, configFile): + """ + Generate sub page for library class for package. + One DEC file maybe contains many library class sections + for different architecture. + + @param fObj DEC file object. + """ + rootArray = [] + pageRoot = doxygen.Page("Library Class", "%s_libraryclass" % pObj.GetName()) + objs = pObj.GetFileObj().GetSectionObjectsByName('libraryclass', self._arch) + if len(objs) == 0: return [] + + if self._arch is not None: + for obj in objs: + classPage = doxygen.Page(obj.GetClassName(), + "lc_%s" % obj.GetClassName()) + comments = obj.GetComment() + if len(comments) != 0: + classPage.AddDescription('<br>\n'.join(comments) + '<br>\n') + pageRoot.AddPage(classPage) + path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile()) + path = path[len(pObj.GetWorkspace()) + 1:] + if len(comments) == 0: + classPage.AddDescription('\copydoc %s<p>' % obj.GetHeaderFile()) + section = doxygen.Section('ref', 'Refer to Header File') + section.AddDescription('\link %s\n' % obj.GetHeaderFile()) + section.AddDescription(' \endlink<p>\n') + classPage.AddSection(section) + fullPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile()) + self.ProcessSourceFileForInclude(fullPath, pObj, configFile) + else: + archPageDict = {} + for obj in objs: + if obj.GetArch() not in archPageDict.keys(): + archPageDict[obj.GetArch()] = doxygen.Page(obj.GetArch(), + 'lc_%s' % obj.GetArch()) + pageRoot.AddPage(archPageDict[obj.GetArch()]) + subArchRoot = archPageDict[obj.GetArch()] + classPage = doxygen.Page(obj.GetClassName(), + "lc_%s" % obj.GetClassName()) + comments = obj.GetComment() + if len(comments) != 0: + classPage.AddDescription('<br>\n'.join(comments) + '<br>\n') + subArchRoot.AddPage(classPage) + path = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile()) + path = path[len(pObj.GetWorkspace()) + 1:] + if len(comments) == 0: + classPage.AddDescription('\copydoc %s<p>' % obj.GetHeaderFile()) + section = doxygen.Section('ref', 'Refer to Header File') + section.AddDescription('\link %s\n' % obj.GetHeaderFile()) + section.AddDescription(' \endlink<p>\n') + classPage.AddSection(section) + fullPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetHeaderFile()) + + self.ProcessSourceFileForInclude(fullPath, pObj, configFile) + rootArray.append(pageRoot) + return rootArray + + def ProcessSourceFileForInclude(self, path, pObj, configFile, infObj=None): + """ + @param path the analysising file full path + @param pObj package object + @param configFile doxygen config file. + """ + + if gInGui: + wx.Yield() + if not os.path.exists(path): + ErrorMsg('Source file path %s does not exist!' % path) + return + + if configFile.FileExists(path): + return + + try: + f = open(path, 'r') + lines = f.readlines() + f.close() + except IOError: + ErrorMsg('Fail to open file %s' % path) + return + + configFile.AddFile(path) + return + no = 0 + for no in range(len(lines)): + if len(lines[no].strip()) == 0: + continue + if lines[no].strip()[:2] in ['##', '//', '/*', '*/']: + continue + index = lines[no].lower().find('include') + #mo = IncludePattern.finditer(lines[no].lower()) + mo = re.match(r"^#\s*include\s+[<\"]([\\/\w.]+)[>\"]$", lines[no].strip().lower()) + if not mo: + continue + mo = re.match(r"^[#\w\s]+[<\"]([\\/\w.]+)[>\"]$", lines[no].strip()) + filePath = mo.groups()[0] + + if filePath is None or len(filePath) == 0: + continue + + # find header file in module's path firstly. + fullPath = None + + if os.path.exists(os.path.join(os.path.dirname(path), filePath)): + # Find the file in current directory + fullPath = os.path.join(os.path.dirname(path), filePath).replace('\\', '/') + else: + # find in depedent package's include path + incObjs = pObj.GetFileObj().GetSectionObjectsByName('includes') + for incObj in incObjs: + incPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), incObj.GetPath()).strip() + incPath = os.path.realpath(os.path.join(incPath, filePath)) + if os.path.exists(incPath): + fullPath = incPath + break + if infObj is not None: + pkgInfObjs = infObj.GetSectionObjectsByName('packages') + for obj in pkgInfObjs: + decObj = dec.DECFile(os.path.join(pObj.GetWorkspace(), obj.GetPath())) + if not decObj: + ErrorMsg ('Fail to create pacakge object for %s' % obj.GetPackageName()) + continue + if not decObj.Parse(): + ErrorMsg ('Fail to load package object for %s' % obj.GetPackageName()) + continue + incObjs = decObj.GetSectionObjectsByName('includes') + for incObj in incObjs: + incPath = os.path.join(decObj.GetPackageRootPath(), incObj.GetPath()).replace('\\', '/') + if os.path.exists(os.path.join(incPath, filePath)): + fullPath = os.path.join(os.path.join(incPath, filePath)) + break + if fullPath is not None: + break + + if fullPath is None and self.IsVerbose(): + self.Log('Can not resolve header file %s for file %s in package %s\n' % (filePath, path, pObj.GetFileObj().GetFilename()), 'error') + return + else: + fullPath = fullPath.replace('\\', '/') + if self.IsVerbose(): + self.Log('Preprocessing: Add include file %s for file %s\n' % (fullPath, path)) + #LogMsg ('Preprocessing: Add include file %s for file %s' % (fullPath, path)) + self.ProcessSourceFileForInclude(fullPath, pObj, configFile, infObj) + + def AddAllIncludeFiles(self, pObj, configFile): + objs = pObj.GetFileObj().GetSectionObjectsByName('includes') + for obj in objs: + incPath = os.path.join(pObj.GetFileObj().GetPackageRootPath(), obj.GetPath()) + for root, dirs, files in os.walk(incPath): + for dir in dirs: + if dir.lower() in _ignore_dir: + dirs.remove(dir) + for file in files: + path = os.path.normpath(os.path.join(root, file)) + configFile.AddFile(path.replace('/', '\\')) + + def GeneratePcdSubPages(self, pObj, configFile): + """ + Generate sub pages for package's PCD definition. + @param pObj package object + @param configFile config file object + """ + rootArray = [] + objs = pObj.GetFileObj().GetSectionObjectsByName('pcd') + if len(objs) == 0: + return [] + + pcdRootPage = doxygen.Page('PCD', 'pcd_root_page') + typeRootPageDict = {} + typeArchRootPageDict = {} + for obj in objs: + if obj.GetPcdType() not in typeRootPageDict.keys(): + typeRootPageDict[obj.GetPcdType()] = doxygen.Page(obj.GetPcdType(), 'pcd_%s_root_page' % obj.GetPcdType()) + pcdRootPage.AddPage(typeRootPageDict[obj.GetPcdType()]) + typeRoot = typeRootPageDict[obj.GetPcdType()] + if self._arch is not None: + pcdPage = doxygen.Page('%s' % obj.GetPcdName(), + 'pcd_%s_%s_%s' % (obj.GetPcdType(), obj.GetArch(), obj.GetPcdName().split('.')[1])) + pcdPage.AddDescription('<br>\n'.join(obj.GetComment()) + '<br>\n') + section = doxygen.Section('PCDinformation', 'PCD Information') + desc = '<TABLE>' + desc += '<TR>' + desc += '<TD><CAPTION>Name</CAPTION></TD>' + desc += '<TD><CAPTION>Token Space</CAPTION></TD>' + desc += '<TD><CAPTION>Token number</CAPTION></TD>' + desc += '<TD><CAPTION>Data Type</CAPTION></TD>' + desc += '<TD><CAPTION>Default Value</CAPTION></TD>' + desc += '</TR>' + desc += '<TR>' + desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[1] + desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[0] + desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdToken() + desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdDataType() + desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdValue() + desc += '</TR>' + desc += '</TABLE>' + section.AddDescription(desc) + pcdPage.AddSection(section) + typeRoot.AddPage(pcdPage) + else: + keystr = obj.GetPcdType() + obj.GetArch() + if keystr not in typeArchRootPageDict.keys(): + typeArchRootPage = doxygen.Page(obj.GetArch(), 'pcd_%s_%s_root_page' % (obj.GetPcdType(), obj.GetArch())) + typeArchRootPageDict[keystr] = typeArchRootPage + typeRoot.AddPage(typeArchRootPage) + typeArchRoot = typeArchRootPageDict[keystr] + pcdPage = doxygen.Page('%s' % obj.GetPcdName(), + 'pcd_%s_%s_%s' % (obj.GetPcdType(), obj.GetArch(), obj.GetPcdName().split('.')[1])) + pcdPage.AddDescription('<br>\n'.join(obj.GetComment()) + '<br>\n') + section = doxygen.Section('PCDinformation', 'PCD Information') + desc = '<TABLE>' + desc += '<TR>' + desc += '<TD><CAPTION>Name</CAPTION></TD>' + desc += '<TD><CAPTION>Token Space</CAPTION></TD>' + desc += '<TD><CAPTION>Token number</CAPTION></TD>' + desc += '<TD><CAPTION>Data Type</CAPTION></TD>' + desc += '<TD><CAPTION>Default Value</CAPTION></TD>' + desc += '</TR>' + desc += '<TR>' + desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[1] + desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdName().split('.')[0] + desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdToken() + desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdDataType() + desc += '<TD><CAPTION>%s</CAPTION></TD>' % obj.GetPcdValue() + desc += '</TR>' + desc += '</TABLE>' + section.AddDescription(desc) + pcdPage.AddSection(section) + typeArchRoot.AddPage(pcdPage) + return [pcdRootPage] + + def _GenerateGuidSubPage(self, pObj, obj, configFile): + guidPage = doxygen.Page('%s' % obj.GetName(), + 'guid_%s_%s' % (obj.GetArch(), obj.GetName())) + comments = obj.GetComment() + if len(comments) != 0: + guidPage.AddDescription('<br>'.join(obj.GetComment()) + '<br>') + section = doxygen.Section('BasicGuidInfo', 'GUID Information') + desc = '<TABLE>' + desc += '<TR>' + desc += '<TD><CAPTION>GUID\'s Guid Name</CAPTION></TD><TD><CAPTION>GUID\'s Guid</CAPTION></TD>' + desc += '</TR>' + desc += '<TR>' + desc += '<TD>%s</TD>' % obj.GetName() + desc += '<TD>%s</TD>' % obj.GetGuid() + desc += '</TR>' + desc += '</TABLE>' + section.AddDescription(desc) + guidPage.AddSection(section) + refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile) + if refFile: + relPath = refFile[len(pObj.GetWorkspace()) + 1:] + if len(comments) == 0: + guidPage.AddDescription(' \\copydoc %s <br>' % relPath) + + section = doxygen.Section('ref', 'Refer to Header File') + section.AddDescription('\link %s\n' % relPath) + section.AddDescription('\endlink\n') + self.ProcessSourceFileForInclude(refFile, pObj, configFile) + guidPage.AddSection(section) + return guidPage + + def GenerateGuidSubPages(self, pObj, configFile): + """ + Generate sub pages for package's GUID definition. + @param pObj package object + @param configFilf doxygen config file object + """ + pageRoot = doxygen.Page('GUID', 'guid_root_page') + objs = pObj.GetFileObj().GetSectionObjectsByName('guids', self._arch) + if len(objs) == 0: return [] + if self._arch is not None: + for obj in objs: + pageRoot.AddPage(self._GenerateGuidSubPage(pObj, obj, configFile)) + else: + guidArchRootPageDict = {} + for obj in objs: + if obj.GetArch() not in guidArchRootPageDict.keys(): + guidArchRoot = doxygen.Page(obj.GetArch(), 'guid_arch_root_%s' % obj.GetArch()) + pageRoot.AddPage(guidArchRoot) + guidArchRootPageDict[obj.GetArch()] = guidArchRoot + guidArchRoot = guidArchRootPageDict[obj.GetArch()] + guidArchRoot.AddPage(self._GenerateGuidSubPage(pObj, obj, configFile)) + return [pageRoot] + + def _GeneratePpiSubPage(self, pObj, obj, configFile): + guidPage = doxygen.Page(obj.GetName(), 'ppi_page_%s' % obj.GetName()) + comments = obj.GetComment() + if len(comments) != 0: + guidPage.AddDescription('<br>'.join(obj.GetComment()) + '<br>') + section = doxygen.Section('BasicPpiInfo', 'PPI Information') + desc = '<TABLE>' + desc += '<TR>' + desc += '<TD><CAPTION>PPI\'s Guid Name</CAPTION></TD><TD><CAPTION>PPI\'s Guid</CAPTION></TD>' + desc += '</TR>' + desc += '<TR>' + desc += '<TD>%s</TD>' % obj.GetName() + desc += '<TD>%s</TD>' % obj.GetGuid() + desc += '</TR>' + desc += '</TABLE>' + section.AddDescription(desc) + guidPage.AddSection(section) + refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile) + if refFile: + relPath = refFile[len(pObj.GetWorkspace()) + 1:] + if len(comments) == 0: + guidPage.AddDescription(' \\copydoc %s <br>' % relPath) + section = doxygen.Section('ref', 'Refer to Header File') + section.AddDescription('\link %s\n' % relPath) + section.AddDescription('\endlink\n') + self.ProcessSourceFileForInclude(refFile, pObj, configFile) + guidPage.AddSection(section) + + return guidPage + + def GeneratePpiSubPages(self, pObj, configFile): + """ + Generate sub pages for package's GUID definition. + @param pObj package object + @param configFilf doxygen config file object + """ + pageRoot = doxygen.Page('PPI', 'ppi_root_page') + objs = pObj.GetFileObj().GetSectionObjectsByName('ppis', self._arch) + if len(objs) == 0: return [] + if self._arch is not None: + for obj in objs: + pageRoot.AddPage(self._GeneratePpiSubPage(pObj, obj, configFile)) + else: + guidArchRootPageDict = {} + for obj in objs: + if obj.GetArch() not in guidArchRootPageDict.keys(): + guidArchRoot = doxygen.Page(obj.GetArch(), 'ppi_arch_root_%s' % obj.GetArch()) + pageRoot.AddPage(guidArchRoot) + guidArchRootPageDict[obj.GetArch()] = guidArchRoot + guidArchRoot = guidArchRootPageDict[obj.GetArch()] + guidArchRoot.AddPage(self._GeneratePpiSubPage(pObj, obj, configFile)) + return [pageRoot] + + def _GenerateProtocolSubPage(self, pObj, obj, configFile): + guidPage = doxygen.Page(obj.GetName(), 'protocol_page_%s' % obj.GetName()) + comments = obj.GetComment() + if len(comments) != 0: + guidPage.AddDescription('<br>'.join(obj.GetComment()) + '<br>') + section = doxygen.Section('BasicProtocolInfo', 'PROTOCOL Information') + desc = '<TABLE>' + desc += '<TR>' + desc += '<TD><CAPTION>PROTOCOL\'s Guid Name</CAPTION></TD><TD><CAPTION>PROTOCOL\'s Guid</CAPTION></TD>' + desc += '</TR>' + desc += '<TR>' + desc += '<TD>%s</TD>' % obj.GetName() + desc += '<TD>%s</TD>' % obj.GetGuid() + desc += '</TR>' + desc += '</TABLE>' + section.AddDescription(desc) + guidPage.AddSection(section) + + refFile = self.FindHeaderFileForGuid(pObj, obj.GetName(), configFile) + if refFile: + relPath = refFile[len(pObj.GetWorkspace()) + 1:] + if len(comments) == 0: + guidPage.AddDescription(' \\copydoc %s <br>' % relPath) + section = doxygen.Section('ref', 'Refer to Header File') + section.AddDescription('\link %s\n' % relPath) + section.AddDescription('\endlink\n') + self.ProcessSourceFileForInclude(refFile, pObj, configFile) + guidPage.AddSection(section) + + return guidPage + + def GenerateProtocolSubPages(self, pObj, configFile): + """ + Generate sub pages for package's GUID definition. + @param pObj package object + @param configFilf doxygen config file object + """ + pageRoot = doxygen.Page('PROTOCOL', 'protocol_root_page') + objs = pObj.GetFileObj().GetSectionObjectsByName('protocols', self._arch) + if len(objs) == 0: return [] + if self._arch is not None: + for obj in objs: + pageRoot.AddPage(self._GenerateProtocolSubPage(pObj, obj, configFile)) + else: + guidArchRootPageDict = {} + for obj in objs: + if obj.GetArch() not in guidArchRootPageDict.keys(): + guidArchRoot = doxygen.Page(obj.GetArch(), 'protocol_arch_root_%s' % obj.GetArch()) + pageRoot.AddPage(guidArchRoot) + guidArchRootPageDict[obj.GetArch()] = guidArchRoot + guidArchRoot = guidArchRootPageDict[obj.GetArch()] + guidArchRoot.AddPage(self._GenerateProtocolSubPage(pObj, obj, configFile)) + return [pageRoot] + + def FindHeaderFileForGuid(self, pObj, name, configFile): + """ + For declaration header file for GUID/PPI/Protocol. + + @param pObj package object + @param name guid/ppi/protocol's name + @param configFile config file object + + @return full path of header file and None if not found. + """ + startPath = pObj.GetFileObj().GetPackageRootPath() + incPath = os.path.join(startPath, 'Include').replace('\\', '/') + # if <PackagePath>/include exist, then search header under it. + if os.path.exists(incPath): + startPath = incPath + + for root, dirs, files in os.walk(startPath): + for dir in dirs: + if dir.lower() in _ignore_dir: + dirs.remove(dir) + for file in files: + fPath = os.path.join(root, file) + if not IsCHeaderFile(fPath): + continue + try: + f = open(fPath, 'r') + lines = f.readlines() + f.close() + except IOError: + self.Log('Fail to open file %s\n' % fPath) + continue + for line in lines: + if line.find(name) != -1 and \ + line.find('extern') != -1: + return fPath.replace('\\', '/') + return None + + def GetPackageModuleList(self, pObj): + """ + Get all module's INF path under package's root path + @param pObj package object + @return arrary of INF full path + """ + mArray = [] + packPath = pObj.GetFileObj().GetPackageRootPath() + if not os.path.exists: + return None + for root, dirs, files in os.walk(packPath): + for dir in dirs: + if dir.lower() in _ignore_dir: + dirs.remove(dir) + for file in files: + if CheckPathPostfix(file, 'inf'): + fPath = os.path.join(root, file).replace('\\', '/') + mArray.append(fPath) + return mArray + + def GenerateModulePages(self, pObj, configFile): + """ + Generate sub pages for package's module which is under the package + root directory. + + @param pObj package object + @param configFilf doxygen config file object + """ + infList = self.GetPackageModuleList(pObj) + rootPages = [] + libObjs = [] + modObjs = [] + for infpath in infList: + infObj = inf.INFFile(infpath) + #infObj = INFFileObject.INFFile (pObj.GetWorkspacePath(), + # inf) + if not infObj: + self.Log('Fail create INF object for %s' % inf) + continue + if not infObj.Parse(): + self.Log('Fail to load INF file %s' % inf) + continue + if infObj.GetProduceLibraryClass() is not None: + libObjs.append(infObj) + else: + modObjs.append(infObj) + + if len(libObjs) != 0: + libRootPage = doxygen.Page('Libraries', 'lib_root_page') + rootPages.append(libRootPage) + for libInf in libObjs: + libRootPage.AddPage(self.GenerateModulePage(pObj, libInf, configFile, True)) + + if len(modObjs) != 0: + modRootPage = doxygen.Page('Modules', 'module_root_page') + rootPages.append(modRootPage) + for modInf in modObjs: + modRootPage.AddPage(self.GenerateModulePage(pObj, modInf, configFile, False)) + + return rootPages + + def GenerateModulePage(self, pObj, infObj, configFile, isLib): + """ + Generate page for a module/library. + @param infObj INF file object for module/library + @param configFile doxygen config file object + @param isLib Whether this module is library + + @param module doxygen page object + """ + workspace = pObj.GetWorkspace() + refDecObjs = [] + for obj in infObj.GetSectionObjectsByName('packages'): + decObj = dec.DECFile(os.path.join(workspace, obj.GetPath())) + if not decObj: + ErrorMsg ('Fail to create pacakge object for %s' % obj.GetPackageName()) + continue + if not decObj.Parse(): + ErrorMsg ('Fail to load package object for %s' % obj.GetPackageName()) + continue + refDecObjs.append(decObj) + + modPage = doxygen.Page('%s' % infObj.GetBaseName(), + 'module_%s' % infObj.GetBaseName()) + modPage.AddDescription(infObj.GetFileHeader()) + + basicInfSection = doxygen.Section('BasicModuleInformation', 'Basic Module Information') + desc = "<TABLE>" + for obj in infObj.GetSectionObjectsByName('defines'): + key = obj.GetKey() + value = obj.GetValue() + if key not in _inf_key_description_mapping_table.keys(): continue + if key == 'LIBRARY_CLASS' and value.find('|') != -1: + clsname, types = value.split('|') + desc += '<TR>' + desc += '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table[key] + desc += '<TD>%s</TD>' % clsname + desc += '</TR>' + + desc += '<TR>' + desc += '<TD><B>Supported Module Types</B></TD>' + desc += '<TD>%s</TD>' % types + desc += '</TR>' + else: + desc += '<TR>' + desc += '<TD><B>%s</B></TD>' % _inf_key_description_mapping_table[key] + if key == 'EFI_SPECIFICATION_VERSION' and value == '0x00020000': + value = '2.0' + desc += '<TD>%s</TD>' % value + desc += '</TR>' + desc += '</TABLE>' + basicInfSection.AddDescription(desc) + modPage.AddSection(basicInfSection) + + # Add protocol section + data = [] + for obj in infObj.GetSectionObjectsByName('pcd', self._arch): + data.append(obj.GetPcdName().strip()) + if len(data) != 0: + s = doxygen.Section('Pcds', 'Pcds') + desc = "<TABLE>" + desc += '<TR><TD><B>PCD Name</B></TD><TD><B>TokenSpace</B></TD><TD><B>Package</B></TD></TR>' + for item in data: + desc += '<TR>' + desc += '<TD>%s</TD>' % item.split('.')[1] + desc += '<TD>%s</TD>' % item.split('.')[0] + pkgbasename = self.SearchPcdPackage(item, workspace, refDecObjs) + desc += '<TD>%s</TD>' % pkgbasename + desc += '</TR>' + desc += "</TABLE>" + s.AddDescription(desc) + modPage.AddSection(s) + + # Add protocol section + #sects = infObj.GetSectionByString('protocol') + data = [] + #for sect in sects: + for obj in infObj.GetSectionObjectsByName('protocol', self._arch): + data.append(obj.GetName().strip()) + if len(data) != 0: + s = doxygen.Section('Protocols', 'Protocols') + desc = "<TABLE>" + desc += '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>' + for item in data: + desc += '<TR>' + desc += '<TD>%s</TD>' % item + pkgbasename = self.SearchProtocolPackage(item, workspace, refDecObjs) + desc += '<TD>%s</TD>' % pkgbasename + desc += '</TR>' + desc += "</TABLE>" + s.AddDescription(desc) + modPage.AddSection(s) + + # Add ppi section + #sects = infObj.GetSectionByString('ppi') + data = [] + #for sect in sects: + for obj in infObj.GetSectionObjectsByName('ppi', self._arch): + data.append(obj.GetName().strip()) + if len(data) != 0: + s = doxygen.Section('Ppis', 'Ppis') + desc = "<TABLE>" + desc += '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>' + for item in data: + desc += '<TR>' + desc += '<TD>%s</TD>' % item + pkgbasename = self.SearchPpiPackage(item, workspace, refDecObjs) + desc += '<TD>%s</TD>' % pkgbasename + desc += '</TR>' + desc += "</TABLE>" + s.AddDescription(desc) + modPage.AddSection(s) + + # Add guid section + #sects = infObj.GetSectionByString('guid') + data = [] + #for sect in sects: + for obj in infObj.GetSectionObjectsByName('guid', self._arch): + data.append(obj.GetName().strip()) + if len(data) != 0: + s = doxygen.Section('Guids', 'Guids') + desc = "<TABLE>" + desc += '<TR><TD><B>Name</B></TD><TD><B>Package</B></TD></TR>' + for item in data: + desc += '<TR>' + desc += '<TD>%s</TD>' % item + pkgbasename = self.SearchGuidPackage(item, workspace, refDecObjs) + desc += '<TD>%s</TD>' % pkgbasename + desc += '</TR>' + desc += "</TABLE>" + s.AddDescription(desc) + modPage.AddSection(s) + + section = doxygen.Section('LibraryClasses', 'Library Classes') + desc = "<TABLE>" + desc += '<TR><TD><B>Name</B></TD><TD><B>Type</B></TD><TD><B>Package</B></TD><TD><B>Header File</B></TD></TR>' + if isLib: + desc += '<TR>' + desc += '<TD>%s</TD>' % infObj.GetProduceLibraryClass() + desc += '<TD>Produce</TD>' + try: + pkgname, hPath = self.SearchLibraryClassHeaderFile(infObj.GetProduceLibraryClass(), + workspace, + refDecObjs) + except: + self.Log ('fail to get package header file for lib class %s' % infObj.GetProduceLibraryClass()) + pkgname = 'NULL' + hPath = 'NULL' + desc += '<TD>%s</TD>' % pkgname + if hPath != "NULL": + #desc += '<TD>\link %s \endlink</TD>' % hPath + desc += '<TD>%s</TD>' % hPath + else: + desc += '<TD>%s</TD>' % hPath + desc += '</TR>' + for lcObj in infObj.GetSectionObjectsByName('libraryclasses', self._arch): + desc += '<TR>' + desc += '<TD>%s</TD>' % lcObj.GetClass() + retarr = self.SearchLibraryClassHeaderFile(lcObj.GetClass(), + workspace, + refDecObjs) + if retarr is not None: + pkgname, hPath = retarr + else: + self.Log('Fail find the library class %s definition from module %s dependent package!' % (lcObj.GetClass(), infObj.GetFilename()), 'error') + pkgname = 'NULL' + hPath = 'NULL' + desc += '<TD>Consume</TD>' + desc += '<TD>%s</TD>' % pkgname + desc += '<TD>%s</TD>' % hPath + desc += '</TR>' + desc += "</TABLE>" + section.AddDescription(desc) + modPage.AddSection(section) + + section = doxygen.Section('SourceFiles', 'Source Files') + section.AddDescription('<ul>\n') + for obj in infObj.GetSourceObjects(self._arch, self._tooltag): + sPath = infObj.GetModuleRootPath() + sPath = os.path.join(sPath, obj.GetSourcePath()).replace('\\', '/').strip() + if sPath.lower().endswith('.uni') or sPath.lower().endswith('.s') or sPath.lower().endswith('.asm') or sPath.lower().endswith('.nasm'): + newPath = self.TranslateUniFile(sPath) + configFile.AddFile(newPath) + newPath = newPath[len(pObj.GetWorkspace()) + 1:] + section.AddDescription('<li> \link %s \endlink </li>' % newPath) + else: + self.ProcessSourceFileForInclude(sPath, pObj, configFile, infObj) + sPath = sPath[len(pObj.GetWorkspace()) + 1:] + section.AddDescription('<li>\link %s \endlink </li>' % sPath) + section.AddDescription('</ul>\n') + modPage.AddSection(section) + + #sects = infObj.GetSectionByString('depex') + data = [] + #for sect in sects: + for obj in infObj.GetSectionObjectsByName('depex'): + data.append(str(obj)) + if len(data) != 0: + s = doxygen.Section('DependentSection', 'Module Dependencies') + s.AddDescription('<br>'.join(data)) + modPage.AddSection(s) + + return modPage + + def TranslateUniFile(self, path): + newpath = path + '.dox' + #import core.textfile as textfile + #file = textfile.TextFile(path) + + try: + file = open(path, 'r') + except (IOError, OSError) as msg: + return None + + t = file.read() + file.close() + + output = '/** @file \n' + #output = '<html><body>' + arr = t.split('\r\n') + for line in arr: + if line.find('@file') != -1: + continue + if line.find('*/') != -1: + continue + line = line.strip() + if line.strip().startswith('/'): + arr = line.split(' ') + if len(arr) > 1: + line = ' '.join(arr[1:]) + else: + continue + output += '%s<br>\n' % line + output += '**/' + + if os.path.exists(newpath): + os.remove(newpath) + + file = open(newpath, "w") + file.write(output) + file.close() + return newpath + + def SearchPcdPackage(self, pcdname, workspace, decObjs): + for decObj in decObjs: + for pcd in decObj.GetSectionObjectsByName('pcd'): + if pcdname == pcd.GetPcdName(): + return decObj.GetBaseName() + return None + + def SearchProtocolPackage(self, protname, workspace, decObjs): + for decObj in decObjs: + for proto in decObj.GetSectionObjectsByName('protocol'): + if protname == proto.GetName(): + return decObj.GetBaseName() + return None + + def SearchPpiPackage(self, ppiname, workspace, decObjs): + for decObj in decObjs: + for ppi in decObj.GetSectionObjectsByName('ppi'): + if ppiname == ppi.GetName(): + return decObj.GetBaseName() + return None + + def SearchGuidPackage(self, guidname, workspace, decObjs): + for decObj in decObjs: + for guid in decObj.GetSectionObjectsByName('guid'): + if guidname == guid.GetName(): + return decObj.GetBaseName() + return None + + def SearchLibraryClassHeaderFile(self, className, workspace, decObjs): + for decObj in decObjs: + for cls in decObj.GetSectionObjectsByName('libraryclasses'): + if cls.GetClassName().strip() == className: + path = cls.GetHeaderFile().strip() + path = os.path.join(decObj.GetPackageRootPath(), path) + path = path[len(workspace) + 1:] + return decObj.GetBaseName(), path.replace('\\', '/') + + return None + + def _ConvertPathToDoxygen(self, path, pObj): + pRootPath = pObj.GetWorkspace() + path = path[len(pRootPath) + 1:] + return path.replace('\\', '/') + +def IsCHeaderFile(path): + return CheckPathPostfix(path, 'h') + +def CheckPathPostfix(path, str): + index = path.rfind('.') + if index == -1: + return False + if path[index + 1:].lower() == str.lower(): + return True + return False diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/dsc.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/dsc.py index a2d23a7732..40535cea27 100644 --- a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/dsc.py +++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/dsc.py @@ -1,195 +1,195 @@ -## @file
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-
-from plugins.EdkPlugins.basemodel import ini
-import re, os
-from plugins.EdkPlugins.basemodel.message import *
-
-class DSCFile(ini.BaseINIFile):
- def GetSectionInstance(self, parent, name, isCombined=False):
- return DSCSection(parent, name, isCombined)
-
- def GetComponents(self):
- return self.GetSectionObjectsByName('Components')
-
-class DSCSection(ini.BaseINISection):
- def GetSectionINIObject(self, parent):
- type = self.GetType()
-
- if type.lower() == 'components':
- return DSCComponentObject(self)
- if type.lower() == 'libraryclasses':
- return DSCLibraryClassObject(self)
- if type.lower() == 'defines':
- return ini.BaseINISectionObject(self)
- if type.lower() == 'pcdsfeatureflag' or \
- type.lower() == 'pcdsfixedatbuild' or \
- type.lower() == 'pcdspatchableinmodule' or\
- type.lower() == 'pcdsdynamicdefault' or \
- type.lower() == 'pcdsdynamicex' or \
- type.lower() == 'pcdsdynamichii' or \
- type.lower() == 'pcdsdynamicvpd':
- return DSCPcdObject(self)
-
- return DSCSectionObject(self)
-
- def GetType(self):
- arr = self._name.split('.')
- return arr[0].strip()
-
- def GetArch(self):
- arr = self._name.split('.')
- if len(arr) == 1:
- return 'common'
- return arr[1]
-
- def GetModuleType(self):
- arr = self._name.split('.')
- if len(arr) < 3:
- return 'common'
- return arr[2]
-
-class DSCSectionObject(ini.BaseINISectionObject):
- def GetArch(self):
- return self.GetParent().GetArch()
-
-class DSCPcdObject(DSCSectionObject):
-
- def __init__(self, parent):
- ini.BaseINISectionObject.__init__(self, parent)
- self._name = None
-
- def Parse(self):
- line = self.GetLineByOffset(self._start).strip().split('#')[0]
- self._name = line.split('|')[0]
- self._value = line.split('|')[1]
- return True
-
- def GetPcdName(self):
- return self._name
-
- def GetPcdType(self):
- return self.GetParent().GetType()
-
- def GetPcdValue(self):
- return self._value
-
-class DSCLibraryClassObject(DSCSectionObject):
- def __init__(self, parent):
- ini.BaseINISectionObject.__init__(self, parent)
-
- def GetClass(self):
- line = self.GetLineByOffset(self._start)
- return line.split('#')[0].split('|')[0].strip()
-
- def GetInstance(self):
- line = self.GetLineByOffset(self._start)
- return line.split('#')[0].split('|')[1].strip()
-
- def GetArch(self):
- return self.GetParent().GetArch()
-
- def GetModuleType(self):
- return self.GetParent().GetModuleType()
-
-class DSCComponentObject(DSCSectionObject):
-
- def __init__(self, parent):
- ini.BaseINISectionObject.__init__(self, parent)
- self._OveridePcds = {}
- self._OverideLibraries = {}
- self._Filename = ''
-
- def __del__(self):
- self._OverideLibraries.clear()
- self._OverideLibraries.clear()
- ini.BaseINISectionObject.__del__(self)
-
- def AddOverideLib(self, libclass, libinstPath):
- if libclass not in self._OverideLibraries.keys():
- self._OverideLibraries[libclass] = libinstPath
-
- def AddOveridePcd(self, name, type, value=None):
- if type not in self._OveridePcds.keys():
- self._OveridePcds[type] = []
- self._OveridePcds[type].append((name, value))
-
- def GetOverideLibs(self):
- return self._OverideLibraries
-
- def GetArch(self):
- return self.GetParent().GetArch()
-
- def GetOveridePcds(self):
- return self._OveridePcds
-
- def GetFilename(self):
- return self.GetLineByOffset(self._start).split('#')[0].split('{')[0].strip()
-
- def SetFilename(self, fName):
- self._Filename = fName
-
- def Parse(self):
- if (self._start < self._end):
- #
- # The first line is inf path and could be ignored
- # The end line is '}' and could be ignored
- #
- curr = self._start + 1
- end = self._end - 1
- OverideName = ''
- while (curr <= end):
- line = self.GetLineByOffset(curr).strip()
- if len(line) > 0 and line[0] != '#':
- line = line.split('#')[0].strip()
- if line[0] == '<':
- OverideName = line[1:len(line)-1]
- elif OverideName.lower() == 'libraryclasses':
- arr = line.split('|')
- self._OverideLibraries[arr[0].strip()] = arr[1].strip()
- elif OverideName.lower() == 'pcds':
- ErrorMsg('EDES does not support PCD overide',
- self.GetFileName(),
- self.GetParent().GetLinenumberByOffset(curr))
- curr = curr + 1
- return True
-
- def GenerateLines(self):
- lines = []
- hasLib = False
- hasPcd = False
- if len(self._OverideLibraries) != 0:
- hasLib = True
- if len(self._OveridePcds) != 0:
- hasPcd = True
-
- if hasLib or hasPcd:
- lines.append((' %s {\n' % self._Filename))
- else:
- lines.append((' %s \n' % self._Filename))
- return lines
-
- if hasLib:
- lines.append(' <LibraryClasses>\n')
- for libKey in self._OverideLibraries.keys():
- lines.append(' %s|%s\n' % (libKey, self._OverideLibraries[libKey]))
-
- if hasPcd:
- for key in self._OveridePcds.keys():
- lines.append(' <%s>\n' % key)
-
- for name, value in self._OveridePcds[key]:
- if value is not None:
- lines.append(' %s|%s\n' % (name, value))
- else:
- lines.append(' %s\n' % name)
-
- if hasLib or hasPcd:
- lines.append(' }\n')
-
- return lines
-
+## @file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +from plugins.EdkPlugins.basemodel import ini +import re, os +from plugins.EdkPlugins.basemodel.message import * + +class DSCFile(ini.BaseINIFile): + def GetSectionInstance(self, parent, name, isCombined=False): + return DSCSection(parent, name, isCombined) + + def GetComponents(self): + return self.GetSectionObjectsByName('Components') + +class DSCSection(ini.BaseINISection): + def GetSectionINIObject(self, parent): + type = self.GetType() + + if type.lower() == 'components': + return DSCComponentObject(self) + if type.lower() == 'libraryclasses': + return DSCLibraryClassObject(self) + if type.lower() == 'defines': + return ini.BaseINISectionObject(self) + if type.lower() == 'pcdsfeatureflag' or \ + type.lower() == 'pcdsfixedatbuild' or \ + type.lower() == 'pcdspatchableinmodule' or\ + type.lower() == 'pcdsdynamicdefault' or \ + type.lower() == 'pcdsdynamicex' or \ + type.lower() == 'pcdsdynamichii' or \ + type.lower() == 'pcdsdynamicvpd': + return DSCPcdObject(self) + + return DSCSectionObject(self) + + def GetType(self): + arr = self._name.split('.') + return arr[0].strip() + + def GetArch(self): + arr = self._name.split('.') + if len(arr) == 1: + return 'common' + return arr[1] + + def GetModuleType(self): + arr = self._name.split('.') + if len(arr) < 3: + return 'common' + return arr[2] + +class DSCSectionObject(ini.BaseINISectionObject): + def GetArch(self): + return self.GetParent().GetArch() + +class DSCPcdObject(DSCSectionObject): + + def __init__(self, parent): + ini.BaseINISectionObject.__init__(self, parent) + self._name = None + + def Parse(self): + line = self.GetLineByOffset(self._start).strip().split('#')[0] + self._name = line.split('|')[0] + self._value = line.split('|')[1] + return True + + def GetPcdName(self): + return self._name + + def GetPcdType(self): + return self.GetParent().GetType() + + def GetPcdValue(self): + return self._value + +class DSCLibraryClassObject(DSCSectionObject): + def __init__(self, parent): + ini.BaseINISectionObject.__init__(self, parent) + + def GetClass(self): + line = self.GetLineByOffset(self._start) + return line.split('#')[0].split('|')[0].strip() + + def GetInstance(self): + line = self.GetLineByOffset(self._start) + return line.split('#')[0].split('|')[1].strip() + + def GetArch(self): + return self.GetParent().GetArch() + + def GetModuleType(self): + return self.GetParent().GetModuleType() + +class DSCComponentObject(DSCSectionObject): + + def __init__(self, parent): + ini.BaseINISectionObject.__init__(self, parent) + self._OveridePcds = {} + self._OverideLibraries = {} + self._Filename = '' + + def __del__(self): + self._OverideLibraries.clear() + self._OverideLibraries.clear() + ini.BaseINISectionObject.__del__(self) + + def AddOverideLib(self, libclass, libinstPath): + if libclass not in self._OverideLibraries.keys(): + self._OverideLibraries[libclass] = libinstPath + + def AddOveridePcd(self, name, type, value=None): + if type not in self._OveridePcds.keys(): + self._OveridePcds[type] = [] + self._OveridePcds[type].append((name, value)) + + def GetOverideLibs(self): + return self._OverideLibraries + + def GetArch(self): + return self.GetParent().GetArch() + + def GetOveridePcds(self): + return self._OveridePcds + + def GetFilename(self): + return self.GetLineByOffset(self._start).split('#')[0].split('{')[0].strip() + + def SetFilename(self, fName): + self._Filename = fName + + def Parse(self): + if (self._start < self._end): + # + # The first line is inf path and could be ignored + # The end line is '}' and could be ignored + # + curr = self._start + 1 + end = self._end - 1 + OverideName = '' + while (curr <= end): + line = self.GetLineByOffset(curr).strip() + if len(line) > 0 and line[0] != '#': + line = line.split('#')[0].strip() + if line[0] == '<': + OverideName = line[1:len(line)-1] + elif OverideName.lower() == 'libraryclasses': + arr = line.split('|') + self._OverideLibraries[arr[0].strip()] = arr[1].strip() + elif OverideName.lower() == 'pcds': + ErrorMsg('EDES does not support PCD overide', + self.GetFileName(), + self.GetParent().GetLinenumberByOffset(curr)) + curr = curr + 1 + return True + + def GenerateLines(self): + lines = [] + hasLib = False + hasPcd = False + if len(self._OverideLibraries) != 0: + hasLib = True + if len(self._OveridePcds) != 0: + hasPcd = True + + if hasLib or hasPcd: + lines.append((' %s {\n' % self._Filename)) + else: + lines.append((' %s \n' % self._Filename)) + return lines + + if hasLib: + lines.append(' <LibraryClasses>\n') + for libKey in self._OverideLibraries.keys(): + lines.append(' %s|%s\n' % (libKey, self._OverideLibraries[libKey])) + + if hasPcd: + for key in self._OveridePcds.keys(): + lines.append(' <%s>\n' % key) + + for name, value in self._OveridePcds[key]: + if value is not None: + lines.append(' %s|%s\n' % (name, value)) + else: + lines.append(' %s\n' % name) + + if hasLib or hasPcd: + lines.append(' }\n') + + return lines + diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/inf.py b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/inf.py index 430e71af2d..fc8056b1ab 100644 --- a/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/inf.py +++ b/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/edk2/model/inf.py @@ -1,335 +1,335 @@ -## @file
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-
-from plugins.EdkPlugins.basemodel import ini
-import re, os
-from plugins.EdkPlugins.basemodel.message import *
-
-class INFFile(ini.BaseINIFile):
- _libobjs = {}
-
- def GetSectionInstance(self, parent, name, isCombined=False):
- return INFSection(parent, name, isCombined)
-
- def GetProduceLibraryClass(self):
- obj = self.GetDefine("LIBRARY_CLASS")
- if obj is None: return None
-
- return obj.split('|')[0].strip()
-
- def GetSectionObjectsByName(self, name, arch=None):
- arr = []
- sects = self.GetSectionByName(name)
- for sect in sects:
- # skip unmatched archtecture content
- if not sect.IsArchMatch(arch):
- continue
-
- for obj in sect.GetObjects():
- arr.append(obj)
-
- return arr
-
- def GetSourceObjects(self, arch=None, tool=None):
- arr = []
- sects = self.GetSectionByName('sources')
- for sect in sects:
- # skip unmatched archtecture content
- if not sect.IsArchMatch(arch):
- continue
-
- for obj in sect.GetObjects():
- if not obj.IsMatchFamily(tool):
- continue
- arr.append(obj)
-
- return arr
-
- def Parse(self):
- if not ini.BaseINIFile.Parse(self):
- return False
- classname = self.GetProduceLibraryClass()
- if classname is not None:
- libobjdict = INFFile._libobjs
- if classname in libobjdict:
- if self not in libobjdict[classname]:
- libobjdict[classname].append(self)
- else:
- libobjdict[classname] = [self]
-
- return True
-
- def GetBaseName(self):
- return self.GetDefine("BASE_NAME").strip()
-
- def GetModuleRootPath(self):
- return os.path.dirname(self.GetFilename())
-
- def Clear(self):
- classname = self.GetProduceLibraryClass()
- if classname is not None:
- libobjdict = INFFile._libobjs
- libobjdict[classname].remove(self)
- if len(libobjdict[classname]) == 0:
- del libobjdict[classname]
- ini.BaseINIFile.Clear(self)
-
-
-class INFSection(ini.BaseINISection):
- def GetSectionINIObject(self, parent):
- type = self.GetType()
-
- if type.lower() == 'libraryclasses':
- return INFLibraryClassObject(self)
- if type.lower() == 'sources':
- return INFSourceObject(self)
- if type.lower().find('pcd') != -1:
- return INFPcdObject(self)
- if type.lower() == 'packages':
- return INFDependentPackageObject(self)
- if type.lower() in ['guids', 'protocols', 'ppis']:
- return INFGuidObject(self)
- if type.lower() == 'defines':
- return INFDefineSectionObject(self)
- return INFSectionObject(self)
-
- def GetType(self):
- arr = self._name.split('.')
- return arr[0].strip()
-
- def GetArch(self):
- arr = self._name.split('.')
- if len(arr) == 1:
- return 'common'
- return arr[1]
-
- def IsArchMatch(self, arch):
- if arch is None or self.GetArch() == 'common':
- return True
-
- if self.GetArch().lower() != arch.lower():
- return False
-
- return True
-
-class INFSectionObject(ini.BaseINISectionObject):
- def GetArch(self):
- return self.GetParent().GetArch()
-
-class INFDefineSectionObject(INFSectionObject):
- def __init__(self, parent):
- INFSectionObject.__init__(self, parent)
- self._key = None
- self._value = None
-
- def Parse(self):
- assert (self._start == self._end), 'The object in define section must be in single line'
-
- line = self.GetLineByOffset(self._start).strip()
-
- line = line.split('#')[0]
- arr = line.split('=')
- if len(arr) != 2:
- ErrorMsg('Invalid define section object',
- self.GetFilename(),
- self._start
- )
- return False
-
- self._key = arr[0].strip()
- self._value = arr[1].strip()
-
- return True
-
- def GetKey(self):
- return self._key
-
- def GetValue(self):
- return self._value
-
-class INFLibraryClassObject(INFSectionObject):
- _objs = {}
- def __init__(self, parent):
- INFSectionObject.__init__(self, parent)
- self._classname = None
-
- def GetClass(self):
- return self._classname
-
- def Parse(self):
- self._classname = self.GetLineByOffset(self._start).split('#')[0].strip()
- objdict = INFLibraryClassObject._objs
- if self._classname in objdict:
- objdict[self._classname].append(self)
- else:
- objdict[self._classname] = [self]
- return True
-
- def Destroy(self):
- objdict = INFLibraryClassObject._objs
- objdict[self._classname].remove(self)
- if len(objdict[self._classname]) == 0:
- del objdict[self._classname]
-
- def GetName(self):
- return self._classname
-
- @staticmethod
- def GetObjectDict():
- return INFLibraryClassObject._objs
-
-class INFDependentPackageObject(INFSectionObject):
- def GetPath(self):
- return self.GetLineByOffset(self._start).split('#')[0].strip()
-
-class INFSourceObject(INFSectionObject):
- _objs = {}
- def __init__(self, parent):
- INFSectionObject.__init__(self, parent)
-
- self.mSourcename = None
- self.mToolCode = None
- self.mFamily = None
- self.mTagName = None
- self.mFeaturePcd = None
- self.mFilename = None
-
- def GetSourcePath(self):
- return self.mSourcename
-
- def GetSourceFullPath(self):
- path = os.path.dirname(self.GetFilename())
- path = os.path.join(path, self.GetSourcePath())
- return os.path.normpath(path)
-
- def GetToolCode(self):
- return self.mToolCode
-
- def GetFamily(self):
- return self.mFamily
-
- def GetTagName(self):
- return self.mTagName
-
- def GetFeaturePcd(self):
- return self.mFeaturePcd
-
- def Parse(self):
- line = self.GetLineByOffset(self._start).strip().split('#')[0]
-
- arr = line.split('|')
-
- self.mSourcename = arr[0].strip()
- if len(arr) >= 2:
- self.mFamily = arr[1].strip()
- if len(arr) >= 3:
- self.mTagName = arr[2].strip()
- if len(arr) >= 4:
- self.mToolCode = arr[3].strip()
- if len(arr) >= 5:
- self.mFeaturePcd = arr[4].strip()
-
- self.mFilename = os.path.basename(self.GetSourceFullPath())
- objdict = INFSourceObject._objs
- if self.mFilename not in objdict:
- objdict[self.mFilename] = [self]
- else:
- objdict[self.mFilename].append(self)
-
- return True
-
- def GetName(self):
- return self.mFilename
-
- def Destroy(self):
- objdict = INFSourceObject._objs
- objdict[self.mFilename].remove(self)
- if len(objdict[self.mFilename]) == 0:
- del objdict[self.mFilename]
-
- def IsMatchFamily(self, family):
- if family is None:
- return True
- if self.mFamily is not None:
- if family.strip().lower() == self.mFamily.lower():
- return True
- else:
- return False
- else:
- fname = self.GetSourcePath()
- if fname.endswith('.S') and family.lower() != 'gcc':
- return False
- if fname.endswith('.s') and (self.GetArch().lower() != 'ipf' and self.GetArch().lower() != 'common'):
- return False
- if fname.lower().endswith('.asm') and (family.lower() != 'msft' and family.lower() != 'intel'):
- return False
- return True
-
- @staticmethod
- def GetObjectDict():
- return INFSourceObject._objs
-
-class INFPcdObject(INFSectionObject):
- _objs = {}
-
- def __init__(self, parent):
- INFSectionObject.__init__(self, parent)
-
- self.mPcdType = None
- self.mDefaultValue = None
- self.mPcdName = None
-
- @staticmethod
- def GetObjectDict():
- return INFPcdObject._objs
-
- def Parse(self):
- line = self.GetLineByOffset(self._start).strip().split('#')[0]
-
- arr = line.split('|')
- self.mPcdName = arr[0].strip()
-
- if len(arr) >= 2:
- self.mDefaultValue = arr[1].strip()
-
- objdict = INFPcdObject._objs
- if self.GetName() in objdict:
- if self not in objdict[self.GetName()]:
- objdict[self.GetName()].append(self)
- else:
- objdict[self.GetName()] = [self]
- return True
-
- def GetPcdName(self):
- return self.mPcdName
-
- def GetPcdType(self):
- return self.GetParent().GetType()
-
- def GetName(self):
- return self.mPcdName.split('.')[1]
-
- def Destroy(self):
- objdict = INFPcdObject._objs
- objdict[self.GetName()].remove(self)
- if len(objdict[self.GetName()]) == 0:
- del objdict[self.GetName()]
-
-class INFGuidObject(INFSectionObject):
- def __init__(self, parent):
- INFSectionObject.__init__(self, parent)
- self._name = None
-
- def Parse(self):
- line = self.GetLineByOffset(self._start).strip().split('#')[0].split("|")[0]
- self._name = line.strip()
- return True
-
- def GetName(self):
- return self._name
-
-
+## @file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +from plugins.EdkPlugins.basemodel import ini +import re, os +from plugins.EdkPlugins.basemodel.message import * + +class INFFile(ini.BaseINIFile): + _libobjs = {} + + def GetSectionInstance(self, parent, name, isCombined=False): + return INFSection(parent, name, isCombined) + + def GetProduceLibraryClass(self): + obj = self.GetDefine("LIBRARY_CLASS") + if obj is None: return None + + return obj.split('|')[0].strip() + + def GetSectionObjectsByName(self, name, arch=None): + arr = [] + sects = self.GetSectionByName(name) + for sect in sects: + # skip unmatched archtecture content + if not sect.IsArchMatch(arch): + continue + + for obj in sect.GetObjects(): + arr.append(obj) + + return arr + + def GetSourceObjects(self, arch=None, tool=None): + arr = [] + sects = self.GetSectionByName('sources') + for sect in sects: + # skip unmatched archtecture content + if not sect.IsArchMatch(arch): + continue + + for obj in sect.GetObjects(): + if not obj.IsMatchFamily(tool): + continue + arr.append(obj) + + return arr + + def Parse(self): + if not ini.BaseINIFile.Parse(self): + return False + classname = self.GetProduceLibraryClass() + if classname is not None: + libobjdict = INFFile._libobjs + if classname in libobjdict: + if self not in libobjdict[classname]: + libobjdict[classname].append(self) + else: + libobjdict[classname] = [self] + + return True + + def GetBaseName(self): + return self.GetDefine("BASE_NAME").strip() + + def GetModuleRootPath(self): + return os.path.dirname(self.GetFilename()) + + def Clear(self): + classname = self.GetProduceLibraryClass() + if classname is not None: + libobjdict = INFFile._libobjs + libobjdict[classname].remove(self) + if len(libobjdict[classname]) == 0: + del libobjdict[classname] + ini.BaseINIFile.Clear(self) + + +class INFSection(ini.BaseINISection): + def GetSectionINIObject(self, parent): + type = self.GetType() + + if type.lower() == 'libraryclasses': + return INFLibraryClassObject(self) + if type.lower() == 'sources': + return INFSourceObject(self) + if type.lower().find('pcd') != -1: + return INFPcdObject(self) + if type.lower() == 'packages': + return INFDependentPackageObject(self) + if type.lower() in ['guids', 'protocols', 'ppis']: + return INFGuidObject(self) + if type.lower() == 'defines': + return INFDefineSectionObject(self) + return INFSectionObject(self) + + def GetType(self): + arr = self._name.split('.') + return arr[0].strip() + + def GetArch(self): + arr = self._name.split('.') + if len(arr) == 1: + return 'common' + return arr[1] + + def IsArchMatch(self, arch): + if arch is None or self.GetArch() == 'common': + return True + + if self.GetArch().lower() != arch.lower(): + return False + + return True + +class INFSectionObject(ini.BaseINISectionObject): + def GetArch(self): + return self.GetParent().GetArch() + +class INFDefineSectionObject(INFSectionObject): + def __init__(self, parent): + INFSectionObject.__init__(self, parent) + self._key = None + self._value = None + + def Parse(self): + assert (self._start == self._end), 'The object in define section must be in single line' + + line = self.GetLineByOffset(self._start).strip() + + line = line.split('#')[0] + arr = line.split('=') + if len(arr) != 2: + ErrorMsg('Invalid define section object', + self.GetFilename(), + self._start + ) + return False + + self._key = arr[0].strip() + self._value = arr[1].strip() + + return True + + def GetKey(self): + return self._key + + def GetValue(self): + return self._value + +class INFLibraryClassObject(INFSectionObject): + _objs = {} + def __init__(self, parent): + INFSectionObject.__init__(self, parent) + self._classname = None + + def GetClass(self): + return self._classname + + def Parse(self): + self._classname = self.GetLineByOffset(self._start).split('#')[0].strip() + objdict = INFLibraryClassObject._objs + if self._classname in objdict: + objdict[self._classname].append(self) + else: + objdict[self._classname] = [self] + return True + + def Destroy(self): + objdict = INFLibraryClassObject._objs + objdict[self._classname].remove(self) + if len(objdict[self._classname]) == 0: + del objdict[self._classname] + + def GetName(self): + return self._classname + + @staticmethod + def GetObjectDict(): + return INFLibraryClassObject._objs + +class INFDependentPackageObject(INFSectionObject): + def GetPath(self): + return self.GetLineByOffset(self._start).split('#')[0].strip() + +class INFSourceObject(INFSectionObject): + _objs = {} + def __init__(self, parent): + INFSectionObject.__init__(self, parent) + + self.mSourcename = None + self.mToolCode = None + self.mFamily = None + self.mTagName = None + self.mFeaturePcd = None + self.mFilename = None + + def GetSourcePath(self): + return self.mSourcename + + def GetSourceFullPath(self): + path = os.path.dirname(self.GetFilename()) + path = os.path.join(path, self.GetSourcePath()) + return os.path.normpath(path) + + def GetToolCode(self): + return self.mToolCode + + def GetFamily(self): + return self.mFamily + + def GetTagName(self): + return self.mTagName + + def GetFeaturePcd(self): + return self.mFeaturePcd + + def Parse(self): + line = self.GetLineByOffset(self._start).strip().split('#')[0] + + arr = line.split('|') + + self.mSourcename = arr[0].strip() + if len(arr) >= 2: + self.mFamily = arr[1].strip() + if len(arr) >= 3: + self.mTagName = arr[2].strip() + if len(arr) >= 4: + self.mToolCode = arr[3].strip() + if len(arr) >= 5: + self.mFeaturePcd = arr[4].strip() + + self.mFilename = os.path.basename(self.GetSourceFullPath()) + objdict = INFSourceObject._objs + if self.mFilename not in objdict: + objdict[self.mFilename] = [self] + else: + objdict[self.mFilename].append(self) + + return True + + def GetName(self): + return self.mFilename + + def Destroy(self): + objdict = INFSourceObject._objs + objdict[self.mFilename].remove(self) + if len(objdict[self.mFilename]) == 0: + del objdict[self.mFilename] + + def IsMatchFamily(self, family): + if family is None: + return True + if self.mFamily is not None: + if family.strip().lower() == self.mFamily.lower(): + return True + else: + return False + else: + fname = self.GetSourcePath() + if fname.endswith('.S') and family.lower() != 'gcc': + return False + if fname.endswith('.s') and (self.GetArch().lower() != 'ipf' and self.GetArch().lower() != 'common'): + return False + if fname.lower().endswith('.asm') and (family.lower() != 'msft' and family.lower() != 'intel'): + return False + return True + + @staticmethod + def GetObjectDict(): + return INFSourceObject._objs + +class INFPcdObject(INFSectionObject): + _objs = {} + + def __init__(self, parent): + INFSectionObject.__init__(self, parent) + + self.mPcdType = None + self.mDefaultValue = None + self.mPcdName = None + + @staticmethod + def GetObjectDict(): + return INFPcdObject._objs + + def Parse(self): + line = self.GetLineByOffset(self._start).strip().split('#')[0] + + arr = line.split('|') + self.mPcdName = arr[0].strip() + + if len(arr) >= 2: + self.mDefaultValue = arr[1].strip() + + objdict = INFPcdObject._objs + if self.GetName() in objdict: + if self not in objdict[self.GetName()]: + objdict[self.GetName()].append(self) + else: + objdict[self.GetName()] = [self] + return True + + def GetPcdName(self): + return self.mPcdName + + def GetPcdType(self): + return self.GetParent().GetType() + + def GetName(self): + return self.mPcdName.split('.')[1] + + def Destroy(self): + objdict = INFPcdObject._objs + objdict[self.GetName()].remove(self) + if len(objdict[self.GetName()]) == 0: + del objdict[self.GetName()] + +class INFGuidObject(INFSectionObject): + def __init__(self, parent): + INFSectionObject.__init__(self, parent) + self._name = None + + def Parse(self): + line = self.GetLineByOffset(self._start).strip().split('#')[0].split("|")[0] + self._name = line.strip() + return True + + def GetName(self): + return self._name + + diff --git a/BaseTools/Scripts/PackageDocumentTools/plugins/__init__.py b/BaseTools/Scripts/PackageDocumentTools/plugins/__init__.py index 57dfebde59..a7909346f3 100644 --- a/BaseTools/Scripts/PackageDocumentTools/plugins/__init__.py +++ b/BaseTools/Scripts/PackageDocumentTools/plugins/__init__.py @@ -1,6 +1,6 @@ -## @file
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
+## @file +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# |
