1. Add a recovery mode for UPT failure 2. Add UNI file support 3. Add binary file header support 4. Add support for PCD error message 5. Add support for replace 6. Format generated INF/DEC files 7. Update dependency check 8. Other minor fixes Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hess Chen <hesheng.chen@intel.com> Reviewed-by: Gao, Liming <liming.gao@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15896 6f19259b-4bc3-4df7-8a09-765794883524
500 lines
20 KiB
Python
500 lines
20 KiB
Python
## @file
|
|
# This file contained the parser for sections in INF file
|
|
#
|
|
# Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
|
|
#
|
|
# 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.
|
|
#
|
|
|
|
'''
|
|
InfSectionParser
|
|
'''
|
|
##
|
|
# Import Modules
|
|
#
|
|
from copy import deepcopy
|
|
import re
|
|
|
|
from Library.String import GetSplitValueList
|
|
from Library.CommentParsing import ParseHeaderCommentSection
|
|
from Library.CommentParsing import ParseComment
|
|
|
|
from Library import DataType as DT
|
|
|
|
import Logger.Log as Logger
|
|
from Logger import StringTable as ST
|
|
from Logger.ToolError import FORMAT_INVALID
|
|
|
|
from Object.Parser.InfDefineObject import InfDefObject
|
|
from Object.Parser.InfBuildOptionObject import InfBuildOptionsObject
|
|
from Object.Parser.InfLibraryClassesObject import InfLibraryClassObject
|
|
from Object.Parser.InfPackagesObject import InfPackageObject
|
|
from Object.Parser.InfPcdObject import InfPcdObject
|
|
from Object.Parser.InfSoucesObject import InfSourcesObject
|
|
from Object.Parser.InfUserExtensionObject import InfUserExtensionObject
|
|
from Object.Parser.InfProtocolObject import InfProtocolObject
|
|
from Object.Parser.InfPpiObject import InfPpiObject
|
|
from Object.Parser.InfGuidObject import InfGuidObject
|
|
from Object.Parser.InfDepexObject import InfDepexObject
|
|
from Object.Parser.InfBinaryObject import InfBinariesObject
|
|
from Object.Parser.InfHeaderObject import InfHeaderObject
|
|
from Object.Parser.InfMisc import InfSpecialCommentObject
|
|
from Object.Parser.InfMisc import InfHobObject
|
|
from Object.Parser.InfMisc import InfBootModeObject
|
|
from Object.Parser.InfMisc import InfEventObject
|
|
from Parser.InfParserMisc import gINF_SECTION_DEF
|
|
from Parser.InfDefineSectionParser import InfDefinSectionParser
|
|
from Parser.InfBuildOptionSectionParser import InfBuildOptionSectionParser
|
|
from Parser.InfSourceSectionParser import InfSourceSectionParser
|
|
from Parser.InfLibrarySectionParser import InfLibrarySectionParser
|
|
from Parser.InfPackageSectionParser import InfPackageSectionParser
|
|
from Parser.InfGuidPpiProtocolSectionParser import InfGuidPpiProtocolSectionParser
|
|
from Parser.InfBinarySectionParser import InfBinarySectionParser
|
|
from Parser.InfPcdSectionParser import InfPcdSectionParser
|
|
from Parser.InfDepexSectionParser import InfDepexSectionParser
|
|
|
|
## GetSpecialStr2
|
|
#
|
|
# GetSpecialStr2
|
|
#
|
|
def GetSpecialStr2(ItemList, FileName, LineNo, SectionString):
|
|
Str2 = ''
|
|
#
|
|
# S2 may be Platform or ModuleType
|
|
#
|
|
if len(ItemList) == 3:
|
|
#
|
|
# Except [LibraryClass], [Depex]
|
|
# section can has more than 2 items in section header string,
|
|
# others should report error.
|
|
#
|
|
if not (ItemList[0].upper() == DT.TAB_LIBRARY_CLASSES.upper() or \
|
|
ItemList[0].upper() == DT.TAB_DEPEX.upper() or \
|
|
ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper()):
|
|
if ItemList[2] != '':
|
|
Logger.Error('Parser',
|
|
FORMAT_INVALID,
|
|
ST.ERR_INF_PARSER_SOURCE_SECTION_SECTIONNAME_INVALID % (SectionString),
|
|
File=FileName,
|
|
Line=LineNo,
|
|
ExtraData=SectionString)
|
|
Str2 = ItemList[2]
|
|
elif len(ItemList) == 4:
|
|
#
|
|
# Except [UserExtension]
|
|
# section can has 4 items in section header string,
|
|
# others should report error.
|
|
#
|
|
if not ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper() or ItemList[0].upper() == DT.TAB_DEPEX.upper():
|
|
if ItemList[3] != '':
|
|
Logger.Error('Parser', FORMAT_INVALID, ST.ERR_INF_PARSER_SOURCE_SECTION_SECTIONNAME_INVALID \
|
|
% (SectionString), File=FileName, Line=LineNo, ExtraData=SectionString)
|
|
|
|
if not ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper():
|
|
Str2 = ItemList[2] + ' | ' + ItemList[3]
|
|
else:
|
|
Str2 = ItemList[2]
|
|
|
|
elif len(ItemList) > 4:
|
|
Logger.Error('Parser', FORMAT_INVALID, ST.ERR_INF_PARSER_SOURCE_SECTION_SECTIONNAME_INVALID \
|
|
% (SectionString), File=FileName, Line=LineNo, ExtraData=SectionString)
|
|
|
|
return Str2
|
|
|
|
## ProcessUseExtHeader
|
|
#
|
|
#
|
|
def ProcessUseExtHeader(ItemList):
|
|
NewItemList = []
|
|
AppendContent = ''
|
|
CompleteFlag = False
|
|
for Item in ItemList:
|
|
if Item.startswith('\"') and not Item.endswith('\"'):
|
|
AppendContent = Item
|
|
CompleteFlag = True
|
|
elif Item.endswith('\"') and not Item.startswith('\"'):
|
|
#
|
|
# Should not have an userId or IdString not starts with " before but ends with ".
|
|
#
|
|
if not CompleteFlag:
|
|
return False, []
|
|
AppendContent = AppendContent + "." + Item
|
|
NewItemList.append(AppendContent)
|
|
CompleteFlag = False
|
|
AppendContent = ''
|
|
elif Item.endswith('\"') and Item.startswith('\"'):
|
|
#
|
|
# Common item, not need to combine the information
|
|
#
|
|
NewItemList.append(Item)
|
|
else:
|
|
if not CompleteFlag:
|
|
NewItemList.append(Item)
|
|
else:
|
|
AppendContent = AppendContent + "." + Item
|
|
|
|
if len(NewItemList) > 4:
|
|
return False, []
|
|
|
|
return True, NewItemList
|
|
|
|
## GetArch
|
|
#
|
|
# GetArch
|
|
#
|
|
def GetArch(ItemList, ArchList, FileName, LineNo, SectionString):
|
|
#
|
|
# S1 is always Arch
|
|
#
|
|
if len(ItemList) > 1:
|
|
Arch = ItemList[1]
|
|
else:
|
|
Arch = 'COMMON'
|
|
ArchList.add(Arch)
|
|
|
|
#
|
|
# 'COMMON' must not be used with specific ARCHs at the same section
|
|
#
|
|
if 'COMMON' in ArchList and len(ArchList) > 1:
|
|
Logger.Error('Parser',
|
|
FORMAT_INVALID,
|
|
ST.ERR_INF_PARSER_SECTION_ARCH_CONFLICT,
|
|
File=FileName,
|
|
Line=LineNo,
|
|
ExtraData=SectionString)
|
|
|
|
return Arch, ArchList
|
|
|
|
## InfSectionParser
|
|
#
|
|
# Inherit from object
|
|
#
|
|
class InfSectionParser(InfDefinSectionParser,
|
|
InfBuildOptionSectionParser,
|
|
InfSourceSectionParser,
|
|
InfLibrarySectionParser,
|
|
InfPackageSectionParser,
|
|
InfGuidPpiProtocolSectionParser,
|
|
InfBinarySectionParser,
|
|
InfPcdSectionParser,
|
|
InfDepexSectionParser):
|
|
#
|
|
# Parser objects used to implement singleton
|
|
#
|
|
MetaFiles = {}
|
|
|
|
## Factory method
|
|
#
|
|
# One file, one parser object. This factory method makes sure that there's
|
|
# only one object constructed for one meta file.
|
|
#
|
|
# @param Class class object of real AutoGen class
|
|
# (InfParser, DecParser or DscParser)
|
|
# @param FilePath The path of meta file
|
|
#
|
|
def __new__(cls, FilePath, *args, **kwargs):
|
|
if args:
|
|
pass
|
|
if kwargs:
|
|
pass
|
|
if FilePath in cls.MetaFiles:
|
|
return cls.MetaFiles[FilePath]
|
|
else:
|
|
ParserObject = super(InfSectionParser, cls).__new__(cls)
|
|
cls.MetaFiles[FilePath] = ParserObject
|
|
return ParserObject
|
|
|
|
def __init__(self):
|
|
InfDefinSectionParser.__init__(self)
|
|
InfBuildOptionSectionParser.__init__(self)
|
|
InfSourceSectionParser.__init__(self)
|
|
InfLibrarySectionParser.__init__(self)
|
|
InfPackageSectionParser.__init__(self)
|
|
InfGuidPpiProtocolSectionParser.__init__(self)
|
|
InfBinarySectionParser.__init__(self)
|
|
InfPcdSectionParser.__init__(self)
|
|
InfDepexSectionParser.__init__(self)
|
|
#
|
|
# Initialize all objects that an INF file will generated.
|
|
#
|
|
self.InfDefSection = InfDefObject()
|
|
self.InfBuildOptionSection = InfBuildOptionsObject()
|
|
self.InfLibraryClassSection = InfLibraryClassObject()
|
|
self.InfPackageSection = InfPackageObject()
|
|
self.InfPcdSection = InfPcdObject(self.MetaFiles.keys()[0])
|
|
self.InfSourcesSection = InfSourcesObject()
|
|
self.InfUserExtensionSection = InfUserExtensionObject()
|
|
self.InfProtocolSection = InfProtocolObject()
|
|
self.InfPpiSection = InfPpiObject()
|
|
self.InfGuidSection = InfGuidObject()
|
|
self.InfDepexSection = InfDepexObject()
|
|
self.InfPeiDepexSection = InfDepexObject()
|
|
self.InfDxeDepexSection = InfDepexObject()
|
|
self.InfSmmDepexSection = InfDepexObject()
|
|
self.InfBinariesSection = InfBinariesObject()
|
|
self.InfHeader = InfHeaderObject()
|
|
self.InfBinaryHeader = InfHeaderObject()
|
|
self.InfSpecialCommentSection = InfSpecialCommentObject()
|
|
|
|
#
|
|
# A List for store define section content.
|
|
#
|
|
self._PcdNameList = []
|
|
self._SectionName = ''
|
|
self._SectionType = 0
|
|
self.RelaPath = ''
|
|
self.FileName = ''
|
|
|
|
#
|
|
# File Header content parser
|
|
#
|
|
def InfHeaderParser(self, Content, InfHeaderObject2, FileName, IsBinaryHeader = False):
|
|
if IsBinaryHeader:
|
|
(Abstract, Description, Copyright, License) = ParseHeaderCommentSection(Content, FileName, True)
|
|
if not Abstract or not Description or not Copyright or not License:
|
|
Logger.Error('Parser',
|
|
FORMAT_INVALID,
|
|
ST.ERR_INVALID_BINARYHEADER_FORMAT,
|
|
File=FileName)
|
|
else:
|
|
(Abstract, Description, Copyright, License) = ParseHeaderCommentSection(Content, FileName)
|
|
#
|
|
# Not process file name now, for later usage.
|
|
#
|
|
if self.FileName:
|
|
pass
|
|
|
|
#
|
|
# Insert Abstract, Description, CopyRight, License into header object
|
|
#
|
|
InfHeaderObject2.SetAbstract(Abstract)
|
|
InfHeaderObject2.SetDescription(Description)
|
|
InfHeaderObject2.SetCopyright(Copyright)
|
|
InfHeaderObject2.SetLicense(License)
|
|
|
|
|
|
|
|
|
|
## Section header parser
|
|
#
|
|
# The section header is always in following format:
|
|
#
|
|
# [section_name.arch<.platform|module_type>]
|
|
#
|
|
# @param String A string contained the content need to be parsed.
|
|
#
|
|
def SectionHeaderParser(self, SectionString, FileName, LineNo):
|
|
_Scope = []
|
|
_SectionName = ''
|
|
ArchList = set()
|
|
_ValueList = []
|
|
_PcdNameList = [DT.TAB_INF_FIXED_PCD.upper(),
|
|
DT.TAB_INF_FEATURE_PCD.upper(),
|
|
DT.TAB_INF_PATCH_PCD.upper(),
|
|
DT.TAB_INF_PCD.upper(),
|
|
DT.TAB_INF_PCD_EX.upper()
|
|
]
|
|
SectionString = SectionString.strip()
|
|
for Item in GetSplitValueList(SectionString[1:-1], DT.TAB_COMMA_SPLIT):
|
|
if Item == '':
|
|
Logger.Error('Parser',
|
|
FORMAT_INVALID,
|
|
ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % (""),
|
|
File=FileName,
|
|
Line=LineNo,
|
|
ExtraData=SectionString)
|
|
ItemList = GetSplitValueList(Item, DT.TAB_SPLIT)
|
|
#
|
|
# different section should not mix in one section
|
|
# Allow different PCD type sections mixed together
|
|
#
|
|
if _SectionName.upper() not in _PcdNameList:
|
|
if _SectionName != '' and _SectionName.upper() != ItemList[0].upper():
|
|
Logger.Error('Parser',
|
|
FORMAT_INVALID,
|
|
ST.ERR_INF_PARSER_SECTION_NAME_DUPLICATE,
|
|
File=FileName,
|
|
Line=LineNo,
|
|
ExtraData=SectionString)
|
|
elif _PcdNameList[1] in [_SectionName.upper(), ItemList[0].upper()] and \
|
|
(_SectionName.upper()!= ItemList[0].upper()):
|
|
Logger.Error('Parser',
|
|
FORMAT_INVALID,
|
|
ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % (""),
|
|
File=FileName,
|
|
Line=LineNo,
|
|
ExtraData=SectionString)
|
|
|
|
_SectionName = ItemList[0]
|
|
if _SectionName.upper() in gINF_SECTION_DEF:
|
|
self._SectionType = gINF_SECTION_DEF[_SectionName.upper()]
|
|
else:
|
|
self._SectionType = DT.MODEL_UNKNOWN
|
|
Logger.Error("Parser",
|
|
FORMAT_INVALID,
|
|
ST.ERR_INF_PARSER_UNKNOWN_SECTION,
|
|
File=FileName,
|
|
Line=LineNo,
|
|
ExtraData=SectionString)
|
|
|
|
#
|
|
# Get Arch
|
|
#
|
|
Str1, ArchList = GetArch(ItemList, ArchList, FileName, LineNo, SectionString)
|
|
|
|
#
|
|
# For [Defines] section, do special check.
|
|
#
|
|
if ItemList[0].upper() == DT.TAB_COMMON_DEFINES.upper():
|
|
if len(ItemList) != 1:
|
|
Logger.Error('Parser',
|
|
FORMAT_INVALID,
|
|
ST.ERR_INF_PARSER_DEFINE_FROMAT_INVALID % (SectionString),
|
|
File=FileName, Line=LineNo, ExtraData=SectionString)
|
|
|
|
#
|
|
# For [UserExtension] section, do special check.
|
|
#
|
|
if ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper():
|
|
|
|
RetValue = ProcessUseExtHeader(ItemList)
|
|
|
|
if not RetValue[0]:
|
|
Logger.Error('Parser',
|
|
FORMAT_INVALID,
|
|
ST.ERR_INF_PARSER_DEFINE_FROMAT_INVALID % (SectionString),
|
|
File=FileName, Line=LineNo, ExtraData=SectionString)
|
|
else:
|
|
ItemList = RetValue[1]
|
|
|
|
if len(ItemList) == 3:
|
|
ItemList.append('COMMON')
|
|
|
|
Str1 = ItemList[1]
|
|
|
|
#
|
|
# For Library classes, need to check module type.
|
|
#
|
|
if ItemList[0].upper() == DT.TAB_LIBRARY_CLASSES.upper() and len(ItemList) == 3:
|
|
if ItemList[2] != '':
|
|
ModuleTypeList = GetSplitValueList(ItemList[2], DT.TAB_VALUE_SPLIT)
|
|
for Item in ModuleTypeList:
|
|
if Item.strip() not in DT.MODULE_LIST:
|
|
Logger.Error('Parser',
|
|
FORMAT_INVALID,
|
|
ST.ERR_INF_PARSER_DEFINE_MODULETYPE_INVALID % (Item),
|
|
File=FileName,
|
|
Line=LineNo,
|
|
ExtraData=SectionString)
|
|
#
|
|
# GetSpecialStr2
|
|
#
|
|
Str2 = GetSpecialStr2(ItemList, FileName, LineNo, SectionString)
|
|
|
|
_Scope.append([Str1, Str2])
|
|
|
|
_NewValueList = []
|
|
_AppendFlag = True
|
|
if _SectionName.upper() in _PcdNameList:
|
|
for ValueItem in _ValueList:
|
|
if _SectionName.upper() == ValueItem[0].upper() and Str1.upper() not in ValueItem[1].split():
|
|
ValueItem[1] = ValueItem[1] + " " + Str1
|
|
_AppendFlag = False
|
|
elif _SectionName.upper() == ValueItem[0].upper() and Str1.upper() in ValueItem[1].split():
|
|
_AppendFlag = False
|
|
|
|
_NewValueList.append(ValueItem)
|
|
|
|
_ValueList = _NewValueList
|
|
|
|
if _AppendFlag:
|
|
if not ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper():
|
|
_ValueList.append([_SectionName, Str1, Str2, LineNo])
|
|
else:
|
|
if len(ItemList) == 4:
|
|
_ValueList.append([_SectionName, Str1, Str2, ItemList[3], LineNo])
|
|
|
|
self.SectionHeaderContent = deepcopy(_ValueList)
|
|
|
|
## GenSpecialSectionList
|
|
#
|
|
# @param SpecialSectionList: a list of list, of which item's format
|
|
# (Comment, LineNum)
|
|
# @param ContainerFile: Input value for filename of Inf file
|
|
#
|
|
def InfSpecialCommentParser (self, SpecialSectionList, InfSectionObject, ContainerFile, SectionType):
|
|
ReFindSpecialCommentRe = re.compile(r"""#(?:\s*)\[(.*?)\](?:.*)""", re.DOTALL)
|
|
ReFindHobArchRe = re.compile(r"""[Hh][Oo][Bb]\.([^,]*)""", re.DOTALL)
|
|
if self.FileName:
|
|
pass
|
|
SpecialObjectList = []
|
|
ArchList = []
|
|
if SectionType == DT.TYPE_EVENT_SECTION:
|
|
TokenDict = DT.EVENT_TOKENS
|
|
elif SectionType == DT.TYPE_HOB_SECTION:
|
|
TokenDict = DT.HOB_TOKENS
|
|
else:
|
|
TokenDict = DT.BOOTMODE_TOKENS
|
|
|
|
for List in SpecialSectionList:
|
|
#
|
|
# Hob has Arch attribute, need to be handled specially here
|
|
#
|
|
if SectionType == DT.TYPE_HOB_SECTION:
|
|
|
|
MatchObject = ReFindSpecialCommentRe.search(List[0][0])
|
|
HobSectionStr = MatchObject.group(1)
|
|
ArchList = []
|
|
for Match in ReFindHobArchRe.finditer(HobSectionStr):
|
|
Arch = Match.groups(1)[0].upper()
|
|
ArchList.append(Arch)
|
|
CommentSoFar = ''
|
|
for Index in xrange(1, len(List)):
|
|
Result = ParseComment(List[Index], DT.ALL_USAGE_TOKENS, TokenDict, [], False)
|
|
Usage = Result[0]
|
|
Type = Result[1]
|
|
HelpText = Result[3]
|
|
|
|
if Usage == DT.ITEM_UNDEFINED and Type == DT.ITEM_UNDEFINED:
|
|
if HelpText is None:
|
|
HelpText = ''
|
|
if not HelpText.endswith('\n'):
|
|
HelpText += '\n'
|
|
CommentSoFar += HelpText
|
|
else:
|
|
if HelpText:
|
|
CommentSoFar += HelpText
|
|
if SectionType == DT.TYPE_EVENT_SECTION:
|
|
SpecialObject = InfEventObject()
|
|
SpecialObject.SetEventType(Type)
|
|
SpecialObject.SetUsage(Usage)
|
|
SpecialObject.SetHelpString(CommentSoFar)
|
|
elif SectionType == DT.TYPE_HOB_SECTION:
|
|
SpecialObject = InfHobObject()
|
|
SpecialObject.SetHobType(Type)
|
|
SpecialObject.SetUsage(Usage)
|
|
SpecialObject.SetHelpString(CommentSoFar)
|
|
if len(ArchList) >= 1:
|
|
SpecialObject.SetSupArchList(ArchList)
|
|
else:
|
|
SpecialObject = InfBootModeObject()
|
|
SpecialObject.SetSupportedBootModes(Type)
|
|
SpecialObject.SetUsage(Usage)
|
|
SpecialObject.SetHelpString(CommentSoFar)
|
|
|
|
SpecialObjectList.append(SpecialObject)
|
|
CommentSoFar = ''
|
|
if not InfSectionObject.SetSpecialComments(SpecialObjectList,
|
|
SectionType):
|
|
Logger.Error('InfParser',
|
|
FORMAT_INVALID,
|
|
ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % (SectionType),
|
|
ContainerFile
|
|
)
|