mirror of https://github.com/acidanthera/audk.git
491 lines
20 KiB
Python
491 lines
20 KiB
Python
|
## @file
|
||
|
# This file contained the parser for sections in INF file
|
||
|
#
|
||
|
# Copyright (c) 2011, 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.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):
|
||
|
(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
|
||
|
)
|