## @file
# This module provide command line entry for generating package document!
#
# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
#
# This program and the accompanying materials are licensed and made available
# under the terms and conditions of the BSD License which accompanies this
# distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
import os, sys, logging, traceback, subprocess
from optparse import OptionParser
import plugins.EdkPlugins.edk2.model.baseobject as baseobject
import plugins.EdkPlugins.edk2.model.doxygengen as 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=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() == '
References '): ModuleEntryDlCount = ModuleEntryDlCount + 1 if ModuleEntryDlCount == 1: ModuleEntryDelStart = index + 1 if bInEfiMain: if line.startswith(''): 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 EFIAPI _ModuleEntryPoint ') != -1: bInModuleEntry = True if line.find('EFI_STATUS EFIAPI EfiMain ') != -1: bInEfiMain = True if line.startswith('