mirror of
https://github.com/acidanthera/audk.git
synced 2025-04-08 17:05:09 +02:00
REF:https://bugzilla.tianocore.org/show_bug.cgi?id=3872 When doing ecc inf version check, the decimal type version number like 1.27 is treated as invalid version. So the code should be updated to support decimal type version number. Cc: Bob Feng <bob.c.feng@intel.com> Cc: Liming Gao <gaoliming@byosoft.com.cn> Cc: Yuwei Chen <yuwei.chen@intel.com> Signed-off-by: Wenyi Xie <xiewenyi2@huawei.com> Reviewed-by: Bob Feng <bob.c.feng@intel.com>
2102 lines
99 KiB
Python
2102 lines
99 KiB
Python
## @file
|
|
# This file is used to parse meta files
|
|
#
|
|
# Copyright (c) 2008 - 2020, Intel Corporation. All rights reserved.<BR>
|
|
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
#
|
|
|
|
##
|
|
# Import Modules
|
|
#
|
|
from __future__ import absolute_import
|
|
import Common.LongFilePathOs as os
|
|
import re
|
|
import time
|
|
import copy
|
|
from hashlib import md5
|
|
import Common.EdkLogger as EdkLogger
|
|
import Common.GlobalData as GlobalData
|
|
import Ecc.EccGlobalData as EccGlobalData
|
|
import Ecc.EccToolError as EccToolError
|
|
|
|
from CommonDataClass.DataClass import *
|
|
from Common.DataType import *
|
|
from Common.StringUtils import *
|
|
from Common.Misc import GuidStructureStringToGuidString, CheckPcdDatum, PathClass, AnalyzePcdData
|
|
from Common.Expression import *
|
|
from CommonDataClass.Exceptions import *
|
|
|
|
from Ecc.MetaFileWorkspace.MetaFileTable import MetaFileStorage
|
|
from GenFds.FdfParser import FdfParser
|
|
from Common.LongFilePathSupport import OpenLongFilePath as open
|
|
from Common.LongFilePathSupport import CodecOpenLongFilePath
|
|
|
|
## RegEx for finding file versions
|
|
hexVersionPattern = re.compile(r'0[xX][\da-f-A-F]{5,8}')
|
|
decVersionPattern = re.compile(r'\d+\.\d+')
|
|
|
|
## A decorator used to parse macro definition
|
|
def ParseMacro(Parser):
|
|
def MacroParser(self):
|
|
Match = GlobalData.gMacroDefPattern.match(self._CurrentLine)
|
|
if not Match:
|
|
# Not 'DEFINE/EDK_GLOBAL' statement, call decorated method
|
|
Parser(self)
|
|
return
|
|
|
|
TokenList = GetSplitValueList(self._CurrentLine[Match.end(1):], TAB_EQUAL_SPLIT, 1)
|
|
# Syntax check
|
|
if not TokenList[0]:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "No macro name given",
|
|
ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
|
|
if len(TokenList) < 2:
|
|
TokenList.append('')
|
|
|
|
Type = Match.group(1)
|
|
Name, Value = TokenList
|
|
# Global macros can be only defined via environment variable
|
|
if Name in GlobalData.gGlobalDefines:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "%s can only be defined via environment variable" % Name,
|
|
ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
|
|
# Only upper case letters, digit and '_' are allowed
|
|
if not GlobalData.gMacroNamePattern.match(Name):
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
|
|
ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
|
|
|
|
Value = ReplaceMacro(Value, self._Macros)
|
|
self._ItemType = MODEL_META_DATA_DEFINE
|
|
# DEFINE defined macros
|
|
if Type == TAB_DSC_DEFINES_DEFINE:
|
|
if isinstance(self, DecParser):
|
|
if MODEL_META_DATA_HEADER in self._SectionType:
|
|
self._FileLocalMacros[Name] = Value
|
|
else:
|
|
for Scope in self._Scope:
|
|
self._SectionsMacroDict.setdefault((Scope[2], Scope[0], Scope[1]), {})[Name] = Value
|
|
elif self._SectionType == MODEL_META_DATA_HEADER:
|
|
self._FileLocalMacros[Name] = Value
|
|
else:
|
|
SectionDictKey = self._SectionType, self._Scope[0][0], self._Scope[0][1]
|
|
if SectionDictKey not in self._SectionsMacroDict:
|
|
self._SectionsMacroDict[SectionDictKey] = {}
|
|
SectionLocalMacros = self._SectionsMacroDict[SectionDictKey]
|
|
SectionLocalMacros[Name] = Value
|
|
# EDK_GLOBAL defined macros
|
|
elif not isinstance(self, DscParser):
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "EDK_GLOBAL can only be used in .dsc file",
|
|
ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
|
|
elif self._SectionType != MODEL_META_DATA_HEADER:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "EDK_GLOBAL can only be used under [Defines] section",
|
|
ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
|
|
elif (Name in self._FileLocalMacros) and (self._FileLocalMacros[Name] != Value):
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "EDK_GLOBAL defined a macro with the same name and different value as one defined by 'DEFINE'",
|
|
ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
|
|
|
|
self._ValueList = [Type, Name, Value]
|
|
|
|
return MacroParser
|
|
|
|
## Base class of parser
|
|
#
|
|
# This class is used for derivation purpose. The specific parser for one kind
|
|
# type file must derive this class and implement some public interfaces.
|
|
#
|
|
# @param FilePath The path of platform description file
|
|
# @param FileType The raw data of DSC file
|
|
# @param Table Database used to retrieve module/package information
|
|
# @param Macros Macros used for replacement in file
|
|
# @param Owner Owner ID (for sub-section parsing)
|
|
# @param From ID from which the data comes (for !INCLUDE directive)
|
|
#
|
|
class MetaFileParser(object):
|
|
# data type (file content) for specific file type
|
|
DataType = {}
|
|
|
|
# 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
|
|
# @param *args The specific class related parameters
|
|
# @param **kwargs The specific class related dict parameters
|
|
#
|
|
def __new__(Class, FilePath, *args, **kwargs):
|
|
if FilePath in Class.MetaFiles:
|
|
return Class.MetaFiles[FilePath]
|
|
else:
|
|
ParserObject = super(MetaFileParser, Class).__new__(Class)
|
|
Class.MetaFiles[FilePath] = ParserObject
|
|
return ParserObject
|
|
|
|
## Constructor of MetaFileParser
|
|
#
|
|
# Initialize object of MetaFileParser
|
|
#
|
|
# @param FilePath The path of platform description file
|
|
# @param FileType The raw data of DSC file
|
|
# @param Table Database used to retrieve module/package information
|
|
# @param Macros Macros used for replacement in file
|
|
# @param Owner Owner ID (for sub-section parsing)
|
|
# @param From ID from which the data comes (for !INCLUDE directive)
|
|
#
|
|
def __init__(self, FilePath, FileType, Table, Owner=-1, From=-1):
|
|
self._Table = Table
|
|
self._RawTable = Table
|
|
self._FileType = FileType
|
|
self.MetaFile = FilePath
|
|
self._Defines = {}
|
|
self._FileLocalMacros = {}
|
|
self._SectionsMacroDict = {}
|
|
|
|
# for recursive parsing
|
|
self._Owner = [Owner]
|
|
self._From = From
|
|
|
|
# parsr status for parsing
|
|
self._ValueList = ['', '', '', '', '']
|
|
self._Scope = []
|
|
self._LineIndex = 0
|
|
self._CurrentLine = ''
|
|
self._SectionType = MODEL_UNKNOWN
|
|
self._SectionName = ''
|
|
self._InSubsection = False
|
|
self._SubsectionType = MODEL_UNKNOWN
|
|
self._SubsectionName = ''
|
|
self._ItemType = MODEL_UNKNOWN
|
|
self._LastItem = -1
|
|
self._Enabled = 0
|
|
self._Finished = False
|
|
self._PostProcessed = False
|
|
# Different version of meta-file has different way to parse.
|
|
self._Version = 0
|
|
# UNI object and extra UNI object
|
|
self._UniObj = None
|
|
self._UniExtraObj = None
|
|
|
|
## Store the parsed data in table
|
|
def _Store(self, *Args):
|
|
return self._Table.Insert(*Args)
|
|
|
|
## Virtual method for starting parse
|
|
def Start(self):
|
|
raise NotImplementedError
|
|
|
|
## Notify a post-process is needed
|
|
def DoPostProcess(self):
|
|
self._PostProcessed = False
|
|
|
|
## Set parsing complete flag in both class and table
|
|
def _Done(self):
|
|
self._Finished = True
|
|
## Do not set end flag when processing included files
|
|
if self._From == -1:
|
|
self._Table.SetEndFlag()
|
|
|
|
def _PostProcess(self):
|
|
self._PostProcessed = True
|
|
|
|
## Get the parse complete flag
|
|
def _GetFinished(self):
|
|
return self._Finished
|
|
|
|
## Set the complete flag
|
|
def _SetFinished(self, Value):
|
|
self._Finished = Value
|
|
|
|
## Use [] style to query data in table, just for readability
|
|
#
|
|
# DataInfo = [data_type, scope1(arch), scope2(platform/moduletype)]
|
|
#
|
|
def __getitem__(self, DataInfo):
|
|
if not isinstance(DataInfo, type(())):
|
|
DataInfo = (DataInfo,)
|
|
|
|
# Parse the file first, if necessary
|
|
if not self._Finished:
|
|
if self._RawTable.IsIntegrity():
|
|
self._Finished = True
|
|
else:
|
|
self._Table = self._RawTable
|
|
self._PostProcessed = False
|
|
self.Start()
|
|
|
|
# No specific ARCH or Platform given, use raw data
|
|
if self._RawTable and (len(DataInfo) == 1 or DataInfo[1] is None):
|
|
return self._RawTable.Query(*DataInfo)
|
|
|
|
# Do post-process if necessary
|
|
if not self._PostProcessed:
|
|
self._PostProcess()
|
|
|
|
return self._Table.Query(*DataInfo)
|
|
|
|
## Data parser for the common format in different type of file
|
|
#
|
|
# The common format in the meatfile is like
|
|
#
|
|
# xxx1 | xxx2 | xxx3
|
|
#
|
|
@ParseMacro
|
|
def _CommonParser(self):
|
|
TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
|
|
self._ValueList[0:len(TokenList)] = TokenList
|
|
|
|
## Data parser for the format in which there's path
|
|
#
|
|
# Only path can have macro used. So we need to replace them before use.
|
|
#
|
|
@ParseMacro
|
|
def _PathParser(self):
|
|
TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
|
|
self._ValueList[0:len(TokenList)] = TokenList
|
|
# Don't do macro replacement for dsc file at this point
|
|
if not isinstance(self, DscParser):
|
|
Macros = self._Macros
|
|
self._ValueList = [ReplaceMacro(Value, Macros) for Value in self._ValueList]
|
|
|
|
## Skip unsupported data
|
|
def _Skip(self):
|
|
if self._SectionName == TAB_USER_EXTENSIONS.upper() and self._CurrentLine.upper().endswith('.UNI'):
|
|
if EccGlobalData.gConfig.UniCheckHelpInfo == '1' or EccGlobalData.gConfig.UniCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
|
|
ExtraUni = self._CurrentLine.strip()
|
|
ExtraUniFile = os.path.join(os.path.dirname(self.MetaFile), ExtraUni)
|
|
IsModuleUni = self.MetaFile.upper().endswith('.INF')
|
|
self._UniExtraObj = UniParser(ExtraUniFile, IsExtraUni=True, IsModuleUni=IsModuleUni)
|
|
self._UniExtraObj.Start()
|
|
else:
|
|
EdkLogger.warn("Parser", "Unrecognized content", File=self.MetaFile,
|
|
Line=self._LineIndex + 1, ExtraData=self._CurrentLine);
|
|
self._ValueList[0:1] = [self._CurrentLine]
|
|
|
|
## Section header parser
|
|
#
|
|
# The section header is always in following format:
|
|
#
|
|
# [section_name.arch<.platform|module_type>]
|
|
#
|
|
def _SectionHeaderParser(self):
|
|
self._Scope = []
|
|
self._SectionName = ''
|
|
ArchList = set()
|
|
for Item in GetSplitValueList(self._CurrentLine[1:-1], TAB_COMMA_SPLIT):
|
|
if Item == '':
|
|
continue
|
|
ItemList = GetSplitValueList(Item, TAB_SPLIT)
|
|
# different section should not mix in one section
|
|
if self._SectionName != '' and self._SectionName != ItemList[0].upper():
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "Different section names in the same section",
|
|
File=self.MetaFile, Line=self._LineIndex+1, ExtraData=self._CurrentLine)
|
|
self._SectionName = ItemList[0].upper()
|
|
if self._SectionName in self.DataType:
|
|
self._SectionType = self.DataType[self._SectionName]
|
|
else:
|
|
self._SectionType = MODEL_UNKNOWN
|
|
EdkLogger.warn("Parser", "Unrecognized section", File=self.MetaFile,
|
|
Line=self._LineIndex+1, ExtraData=self._CurrentLine)
|
|
# S1 is always Arch
|
|
if len(ItemList) > 1:
|
|
S1 = ItemList[1].upper()
|
|
else:
|
|
S1 = 'COMMON'
|
|
ArchList.add(S1)
|
|
# S2 may be Platform or ModuleType
|
|
if len(ItemList) > 2:
|
|
S2 = ItemList[2].upper()
|
|
else:
|
|
S2 = 'COMMON'
|
|
self._Scope.append([S1, S2])
|
|
|
|
# 'COMMON' must not be used with specific ARCHs at the same section
|
|
if 'COMMON' in ArchList and len(ArchList) > 1:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "'common' ARCH must not be used with specific ARCHs",
|
|
File=self.MetaFile, Line=self._LineIndex+1, ExtraData=self._CurrentLine)
|
|
# If the section information is needed later, it should be stored in database
|
|
self._ValueList[0] = self._SectionName
|
|
|
|
## [defines] section parser
|
|
@ParseMacro
|
|
def _DefineParser(self):
|
|
TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
|
|
self._ValueList[1:len(TokenList)] = TokenList
|
|
if not self._ValueList[1]:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "No name specified",
|
|
ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
|
|
if not self._ValueList[2]:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "No value specified",
|
|
ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
|
|
|
|
self._ValueList = [ReplaceMacro(Value, self._Macros) for Value in self._ValueList]
|
|
Name, Value = self._ValueList[1], self._ValueList[2]
|
|
# Sometimes, we need to make differences between EDK and EDK2 modules
|
|
if Name == 'INF_VERSION':
|
|
if hexVersionPattern.match(Value):
|
|
self._Version = int(Value, 0)
|
|
elif decVersionPattern.match(Value):
|
|
ValueList = Value.split('.')
|
|
Major = int(ValueList[0], 0)
|
|
Minor = int(ValueList[1], 0)
|
|
if Major > 0xffff or Minor > 0xffff:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "Invalid version number",
|
|
ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex + 1)
|
|
self._Version = int('0x{0:04x}{1:04x}'.format(Major, Minor), 0)
|
|
else:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "Invalid version number",
|
|
ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex + 1)
|
|
elif Name == 'MODULE_UNI_FILE':
|
|
UniFile = os.path.join(os.path.dirname(self.MetaFile), Value)
|
|
if os.path.exists(UniFile):
|
|
self._UniObj = UniParser(UniFile, IsExtraUni=False, IsModuleUni=True)
|
|
self._UniObj.Start()
|
|
else:
|
|
EdkLogger.error('Parser', FILE_NOT_FOUND, "Module UNI file %s is missing." % Value,
|
|
ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1,
|
|
RaiseError=False)
|
|
elif Name == 'PACKAGE_UNI_FILE':
|
|
UniFile = os.path.join(os.path.dirname(self.MetaFile), Value)
|
|
if os.path.exists(UniFile):
|
|
self._UniObj = UniParser(UniFile, IsExtraUni=False, IsModuleUni=False)
|
|
|
|
if isinstance(self, InfParser) and self._Version < 0x00010005:
|
|
# EDK module allows using defines as macros
|
|
self._FileLocalMacros[Name] = Value
|
|
self._Defines[Name] = Value
|
|
|
|
## [BuildOptions] section parser
|
|
@ParseMacro
|
|
def _BuildOptionParser(self):
|
|
TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
|
|
TokenList2 = GetSplitValueList(TokenList[0], ':', 1)
|
|
if len(TokenList2) == 2:
|
|
self._ValueList[0] = TokenList2[0] # toolchain family
|
|
self._ValueList[1] = TokenList2[1] # keys
|
|
else:
|
|
self._ValueList[1] = TokenList[0]
|
|
if len(TokenList) == 2 and not isinstance(self, DscParser): # value
|
|
self._ValueList[2] = ReplaceMacro(TokenList[1], self._Macros)
|
|
|
|
if self._ValueList[1].count('_') != 4:
|
|
EdkLogger.error(
|
|
'Parser',
|
|
FORMAT_INVALID,
|
|
"'%s' must be in format of <TARGET>_<TOOLCHAIN>_<ARCH>_<TOOL>_FLAGS" % self._ValueList[1],
|
|
ExtraData=self._CurrentLine,
|
|
File=self.MetaFile,
|
|
Line=self._LineIndex+1
|
|
)
|
|
|
|
def _GetMacros(self):
|
|
Macros = {}
|
|
Macros.update(self._FileLocalMacros)
|
|
Macros.update(self._GetApplicableSectionMacro())
|
|
return Macros
|
|
|
|
|
|
## Get section Macros that are applicable to current line, which may come from other sections
|
|
## that share the same name while scope is wider
|
|
def _GetApplicableSectionMacro(self):
|
|
Macros = {}
|
|
for Scope1, Scope2 in [("COMMON", "COMMON"), ("COMMON", self._Scope[0][1]),
|
|
(self._Scope[0][0], "COMMON"), (self._Scope[0][0], self._Scope[0][1])]:
|
|
if (self._SectionType, Scope1, Scope2) in self._SectionsMacroDict:
|
|
Macros.update(self._SectionsMacroDict[(self._SectionType, Scope1, Scope2)])
|
|
return Macros
|
|
|
|
_SectionParser = {}
|
|
Finished = property(_GetFinished, _SetFinished)
|
|
_Macros = property(_GetMacros)
|
|
|
|
|
|
## INF file parser class
|
|
#
|
|
# @param FilePath The path of platform description file
|
|
# @param FileType The raw data of DSC file
|
|
# @param Table Database used to retrieve module/package information
|
|
# @param Macros Macros used for replacement in file
|
|
#
|
|
class InfParser(MetaFileParser):
|
|
# INF file supported data types (one type per section)
|
|
DataType = {
|
|
TAB_UNKNOWN.upper() : MODEL_UNKNOWN,
|
|
TAB_INF_DEFINES.upper() : MODEL_META_DATA_HEADER,
|
|
TAB_DSC_DEFINES_DEFINE : MODEL_META_DATA_DEFINE,
|
|
TAB_BUILD_OPTIONS.upper() : MODEL_META_DATA_BUILD_OPTION,
|
|
TAB_INCLUDES.upper() : MODEL_EFI_INCLUDE,
|
|
TAB_LIBRARIES.upper() : MODEL_EFI_LIBRARY_INSTANCE,
|
|
TAB_LIBRARY_CLASSES.upper() : MODEL_EFI_LIBRARY_CLASS,
|
|
TAB_PACKAGES.upper() : MODEL_META_DATA_PACKAGE,
|
|
TAB_NMAKE.upper() : MODEL_META_DATA_NMAKE,
|
|
TAB_INF_FIXED_PCD.upper() : MODEL_PCD_FIXED_AT_BUILD,
|
|
TAB_INF_PATCH_PCD.upper() : MODEL_PCD_PATCHABLE_IN_MODULE,
|
|
TAB_INF_FEATURE_PCD.upper() : MODEL_PCD_FEATURE_FLAG,
|
|
TAB_INF_PCD_EX.upper() : MODEL_PCD_DYNAMIC_EX,
|
|
TAB_INF_PCD.upper() : MODEL_PCD_DYNAMIC,
|
|
TAB_SOURCES.upper() : MODEL_EFI_SOURCE_FILE,
|
|
TAB_GUIDS.upper() : MODEL_EFI_GUID,
|
|
TAB_PROTOCOLS.upper() : MODEL_EFI_PROTOCOL,
|
|
TAB_PPIS.upper() : MODEL_EFI_PPI,
|
|
TAB_DEPEX.upper() : MODEL_EFI_DEPEX,
|
|
TAB_BINARIES.upper() : MODEL_EFI_BINARY_FILE,
|
|
TAB_USER_EXTENSIONS.upper() : MODEL_META_DATA_USER_EXTENSION
|
|
}
|
|
|
|
## Constructor of InfParser
|
|
#
|
|
# Initialize object of InfParser
|
|
#
|
|
# @param FilePath The path of module description file
|
|
# @param FileType The raw data of DSC file
|
|
# @param Table Database used to retrieve module/package information
|
|
# @param Macros Macros used for replacement in file
|
|
#
|
|
def __init__(self, FilePath, FileType, Table):
|
|
# prevent re-initialization
|
|
if hasattr(self, "_Table"):
|
|
return
|
|
MetaFileParser.__init__(self, FilePath, FileType, Table)
|
|
self.TblFile = EccGlobalData.gDb.TblFile
|
|
self.FileID = -1
|
|
|
|
## Parser starter
|
|
def Start(self):
|
|
NmakeLine = ''
|
|
Content = ''
|
|
Usage = ''
|
|
try:
|
|
Content = open(str(self.MetaFile), 'r').readlines()
|
|
except:
|
|
EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
|
|
#
|
|
# Insert a record for file
|
|
#
|
|
Filename = NormPath(self.MetaFile)
|
|
FileID = self.TblFile.GetFileId(Filename)
|
|
if FileID:
|
|
self.FileID = FileID
|
|
else:
|
|
self.FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_INF)
|
|
|
|
# parse the file line by line
|
|
IsFindBlockComment = False
|
|
|
|
for Index in range(0, len(Content)):
|
|
if self._SectionType in [MODEL_EFI_GUID,
|
|
MODEL_EFI_PROTOCOL,
|
|
MODEL_EFI_PPI,
|
|
MODEL_PCD_FIXED_AT_BUILD,
|
|
MODEL_PCD_PATCHABLE_IN_MODULE,
|
|
MODEL_PCD_FEATURE_FLAG,
|
|
MODEL_PCD_DYNAMIC_EX,
|
|
MODEL_PCD_DYNAMIC]:
|
|
Line = Content[Index].strip()
|
|
if Line.startswith(TAB_SPECIAL_COMMENT):
|
|
Usage += ' ' + Line[Line.find(TAB_SPECIAL_COMMENT):]
|
|
continue
|
|
elif Line.startswith(TAB_COMMENT_SPLIT):
|
|
continue
|
|
elif Line.find(TAB_COMMENT_SPLIT) > 0:
|
|
Usage += ' ' + Line[Line.find(TAB_COMMENT_SPLIT):]
|
|
Line = Line[:Line.find(TAB_COMMENT_SPLIT)]
|
|
else:
|
|
# skip empty, commented, block commented lines
|
|
Line = CleanString(Content[Index], AllowCppStyleComment=True)
|
|
Usage = ''
|
|
NextLine = ''
|
|
if Index + 1 < len(Content):
|
|
NextLine = CleanString(Content[Index + 1])
|
|
if Line == '':
|
|
continue
|
|
if Line.find(DataType.TAB_COMMENT_EDK_START) > -1:
|
|
IsFindBlockComment = True
|
|
continue
|
|
if Line.find(DataType.TAB_COMMENT_EDK_END) > -1:
|
|
IsFindBlockComment = False
|
|
continue
|
|
if IsFindBlockComment:
|
|
continue
|
|
|
|
self._LineIndex = Index
|
|
self._CurrentLine = Line
|
|
|
|
# section header
|
|
if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
|
|
self._SectionHeaderParser()
|
|
# Check invalid sections
|
|
if self._Version < 0x00010005:
|
|
if self._SectionType in [MODEL_META_DATA_BUILD_OPTION,
|
|
MODEL_EFI_LIBRARY_CLASS,
|
|
MODEL_META_DATA_PACKAGE,
|
|
MODEL_PCD_FIXED_AT_BUILD,
|
|
MODEL_PCD_PATCHABLE_IN_MODULE,
|
|
MODEL_PCD_FEATURE_FLAG,
|
|
MODEL_PCD_DYNAMIC_EX,
|
|
MODEL_PCD_DYNAMIC,
|
|
MODEL_EFI_GUID,
|
|
MODEL_EFI_PROTOCOL,
|
|
MODEL_EFI_PPI,
|
|
MODEL_META_DATA_USER_EXTENSION]:
|
|
EdkLogger.error('Parser', FORMAT_INVALID,
|
|
"Section [%s] is not allowed in inf file without version" % (self._SectionName),
|
|
ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
|
|
elif self._SectionType in [MODEL_EFI_INCLUDE,
|
|
MODEL_EFI_LIBRARY_INSTANCE,
|
|
MODEL_META_DATA_NMAKE]:
|
|
EdkLogger.error('Parser', FORMAT_INVALID,
|
|
"Section [%s] is not allowed in inf file with version 0x%08x" % (self._SectionName, self._Version),
|
|
ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
|
|
continue
|
|
# merge two lines specified by '\' in section NMAKE
|
|
elif self._SectionType == MODEL_META_DATA_NMAKE:
|
|
if Line[-1] == '\\':
|
|
if NextLine == '':
|
|
self._CurrentLine = NmakeLine + Line[0:-1]
|
|
NmakeLine = ''
|
|
else:
|
|
if NextLine[0] == TAB_SECTION_START and NextLine[-1] == TAB_SECTION_END:
|
|
self._CurrentLine = NmakeLine + Line[0:-1]
|
|
NmakeLine = ''
|
|
else:
|
|
NmakeLine = NmakeLine + ' ' + Line[0:-1]
|
|
continue
|
|
else:
|
|
self._CurrentLine = NmakeLine + Line
|
|
NmakeLine = ''
|
|
|
|
# section content
|
|
self._ValueList = ['', '', '']
|
|
# parse current line, result will be put in self._ValueList
|
|
self._SectionParser[self._SectionType](self)
|
|
if self._ValueList is None or self._ItemType == MODEL_META_DATA_DEFINE:
|
|
self._ItemType = -1
|
|
continue
|
|
#
|
|
# Model, Value1, Value2, Value3, Arch, Platform, BelongsToItem=-1,
|
|
# LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1
|
|
#
|
|
self._ValueList[0] = self._ValueList[0].replace('/', '\\')
|
|
Usage = Usage.strip()
|
|
for Arch, Platform in self._Scope:
|
|
self._Store(self._SectionType,
|
|
self._ValueList[0],
|
|
self._ValueList[1],
|
|
self._ValueList[2],
|
|
Arch,
|
|
Platform,
|
|
self._Owner[-1],
|
|
self.FileID,
|
|
self._LineIndex+1,
|
|
-1,
|
|
self._LineIndex+1,
|
|
-1,
|
|
0,
|
|
Usage
|
|
)
|
|
Usage = ''
|
|
if IsFindBlockComment:
|
|
EdkLogger.error("Parser", FORMAT_INVALID, "Open block comments (starting with /*) are expected to end with */",
|
|
File=self.MetaFile)
|
|
self._Done()
|
|
|
|
## Data parser for the format in which there's path
|
|
#
|
|
# Only path can have macro used. So we need to replace them before use.
|
|
#
|
|
def _IncludeParser(self):
|
|
TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
|
|
self._ValueList[0:len(TokenList)] = TokenList
|
|
Macros = self._Macros
|
|
if Macros:
|
|
for Index in range(0, len(self._ValueList)):
|
|
Value = self._ValueList[Index]
|
|
if not Value:
|
|
continue
|
|
|
|
self._ValueList[Index] = ReplaceMacro(Value, Macros)
|
|
|
|
## Parse [Sources] section
|
|
#
|
|
# Only path can have macro used. So we need to replace them before use.
|
|
#
|
|
@ParseMacro
|
|
def _SourceFileParser(self):
|
|
TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
|
|
self._ValueList[0:len(TokenList)] = TokenList
|
|
Macros = self._Macros
|
|
# For Acpi tables, remove macro like ' TABLE_NAME=Sata1'
|
|
if 'COMPONENT_TYPE' in Macros:
|
|
if self._Defines['COMPONENT_TYPE'].upper() == 'ACPITABLE':
|
|
self._ValueList[0] = GetSplitValueList(self._ValueList[0], ' ', 1)[0]
|
|
if self._Defines['BASE_NAME'] == 'Microcode':
|
|
pass
|
|
self._ValueList = [ReplaceMacro(Value, Macros) for Value in self._ValueList]
|
|
|
|
## Parse [Binaries] section
|
|
#
|
|
# Only path can have macro used. So we need to replace them before use.
|
|
#
|
|
@ParseMacro
|
|
def _BinaryFileParser(self):
|
|
TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 2)
|
|
if len(TokenList) < 2:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "No file type or path specified",
|
|
ExtraData=self._CurrentLine + " (<FileType> | <FilePath> [| <Target>])",
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
if not TokenList[0]:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "No file type specified",
|
|
ExtraData=self._CurrentLine + " (<FileType> | <FilePath> [| <Target>])",
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
if not TokenList[1]:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "No file path specified",
|
|
ExtraData=self._CurrentLine + " (<FileType> | <FilePath> [| <Target>])",
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
self._ValueList[0:len(TokenList)] = TokenList
|
|
self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros)
|
|
|
|
## [nmake] section parser (Edk.x style only)
|
|
def _NmakeParser(self):
|
|
TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
|
|
self._ValueList[0:len(TokenList)] = TokenList
|
|
# remove macros
|
|
self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros)
|
|
# remove self-reference in macro setting
|
|
#self._ValueList[1] = ReplaceMacro(self._ValueList[1], {self._ValueList[0]:''})
|
|
|
|
## [FixedPcd], [FeaturePcd], [PatchPcd], [Pcd] and [PcdEx] sections parser
|
|
@ParseMacro
|
|
def _PcdParser(self):
|
|
TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
|
|
ValueList = GetSplitValueList(TokenList[0], TAB_SPLIT)
|
|
if len(ValueList) != 2:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "Illegal token space GUID and PCD name format",
|
|
ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<PcdCName>)",
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
self._ValueList[0:1] = ValueList
|
|
if len(TokenList) > 1:
|
|
self._ValueList[2] = TokenList[1]
|
|
if self._ValueList[0] == '' or self._ValueList[1] == '':
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
|
|
ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<PcdCName>)",
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
|
|
# if value are 'True', 'true', 'TRUE' or 'False', 'false', 'FALSE', replace with integer 1 or 0.
|
|
if self._ValueList[2] != '':
|
|
InfPcdValueList = GetSplitValueList(TokenList[1], TAB_VALUE_SPLIT, 1)
|
|
if InfPcdValueList[0] in ['True', 'true', 'TRUE']:
|
|
self._ValueList[2] = TokenList[1].replace(InfPcdValueList[0], '1', 1);
|
|
elif InfPcdValueList[0] in ['False', 'false', 'FALSE']:
|
|
self._ValueList[2] = TokenList[1].replace(InfPcdValueList[0], '0', 1);
|
|
|
|
## [depex] section parser
|
|
@ParseMacro
|
|
def _DepexParser(self):
|
|
self._ValueList[0:1] = [self._CurrentLine]
|
|
|
|
_SectionParser = {
|
|
MODEL_UNKNOWN : MetaFileParser._Skip,
|
|
MODEL_META_DATA_HEADER : MetaFileParser._DefineParser,
|
|
MODEL_META_DATA_BUILD_OPTION : MetaFileParser._BuildOptionParser,
|
|
MODEL_EFI_INCLUDE : _IncludeParser, # for Edk.x modules
|
|
MODEL_EFI_LIBRARY_INSTANCE : MetaFileParser._CommonParser, # for Edk.x modules
|
|
MODEL_EFI_LIBRARY_CLASS : MetaFileParser._PathParser,
|
|
MODEL_META_DATA_PACKAGE : MetaFileParser._PathParser,
|
|
MODEL_META_DATA_NMAKE : _NmakeParser, # for Edk.x modules
|
|
MODEL_PCD_FIXED_AT_BUILD : _PcdParser,
|
|
MODEL_PCD_PATCHABLE_IN_MODULE : _PcdParser,
|
|
MODEL_PCD_FEATURE_FLAG : _PcdParser,
|
|
MODEL_PCD_DYNAMIC_EX : _PcdParser,
|
|
MODEL_PCD_DYNAMIC : _PcdParser,
|
|
MODEL_EFI_SOURCE_FILE : _SourceFileParser,
|
|
MODEL_EFI_GUID : MetaFileParser._CommonParser,
|
|
MODEL_EFI_PROTOCOL : MetaFileParser._CommonParser,
|
|
MODEL_EFI_PPI : MetaFileParser._CommonParser,
|
|
MODEL_EFI_DEPEX : _DepexParser,
|
|
MODEL_EFI_BINARY_FILE : _BinaryFileParser,
|
|
MODEL_META_DATA_USER_EXTENSION : MetaFileParser._Skip,
|
|
}
|
|
|
|
## DSC file parser class
|
|
#
|
|
# @param FilePath The path of platform description file
|
|
# @param FileType The raw data of DSC file
|
|
# @param Table Database used to retrieve module/package information
|
|
# @param Macros Macros used for replacement in file
|
|
# @param Owner Owner ID (for sub-section parsing)
|
|
# @param From ID from which the data comes (for !INCLUDE directive)
|
|
#
|
|
class DscParser(MetaFileParser):
|
|
# DSC file supported data types (one type per section)
|
|
DataType = {
|
|
TAB_SKUIDS.upper() : MODEL_EFI_SKU_ID,
|
|
TAB_LIBRARIES.upper() : MODEL_EFI_LIBRARY_INSTANCE,
|
|
TAB_LIBRARY_CLASSES.upper() : MODEL_EFI_LIBRARY_CLASS,
|
|
TAB_BUILD_OPTIONS.upper() : MODEL_META_DATA_BUILD_OPTION,
|
|
TAB_PCDS_FIXED_AT_BUILD_NULL.upper() : MODEL_PCD_FIXED_AT_BUILD,
|
|
TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper() : MODEL_PCD_PATCHABLE_IN_MODULE,
|
|
TAB_PCDS_FEATURE_FLAG_NULL.upper() : MODEL_PCD_FEATURE_FLAG,
|
|
TAB_PCDS_DYNAMIC_DEFAULT_NULL.upper() : MODEL_PCD_DYNAMIC_DEFAULT,
|
|
TAB_PCDS_DYNAMIC_HII_NULL.upper() : MODEL_PCD_DYNAMIC_HII,
|
|
TAB_PCDS_DYNAMIC_VPD_NULL.upper() : MODEL_PCD_DYNAMIC_VPD,
|
|
TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL.upper() : MODEL_PCD_DYNAMIC_EX_DEFAULT,
|
|
TAB_PCDS_DYNAMIC_EX_HII_NULL.upper() : MODEL_PCD_DYNAMIC_EX_HII,
|
|
TAB_PCDS_DYNAMIC_EX_VPD_NULL.upper() : MODEL_PCD_DYNAMIC_EX_VPD,
|
|
TAB_COMPONENTS.upper() : MODEL_META_DATA_COMPONENT,
|
|
TAB_DSC_DEFINES.upper() : MODEL_META_DATA_HEADER,
|
|
TAB_DSC_DEFINES_DEFINE : MODEL_META_DATA_DEFINE,
|
|
TAB_DSC_DEFINES_EDKGLOBAL : MODEL_META_DATA_GLOBAL_DEFINE,
|
|
TAB_INCLUDE.upper() : MODEL_META_DATA_INCLUDE,
|
|
TAB_IF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
|
|
TAB_IF_DEF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
|
|
TAB_IF_N_DEF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF,
|
|
TAB_ELSE_IF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF,
|
|
TAB_ELSE.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE,
|
|
TAB_END_IF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF,
|
|
TAB_ERROR.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_ERROR,
|
|
}
|
|
|
|
# Valid names in define section
|
|
DefineKeywords = [
|
|
"DSC_SPECIFICATION",
|
|
"PLATFORM_NAME",
|
|
"PLATFORM_GUID",
|
|
"PLATFORM_VERSION",
|
|
"SKUID_IDENTIFIER",
|
|
"PCD_INFO_GENERATION",
|
|
"SUPPORTED_ARCHITECTURES",
|
|
"BUILD_TARGETS",
|
|
"OUTPUT_DIRECTORY",
|
|
"FLASH_DEFINITION",
|
|
"BUILD_NUMBER",
|
|
"RFC_LANGUAGES",
|
|
"ISO_LANGUAGES",
|
|
"TIME_STAMP_FILE",
|
|
"VPD_TOOL_GUID",
|
|
"FIX_LOAD_TOP_MEMORY_ADDRESS"
|
|
]
|
|
|
|
SubSectionDefineKeywords = [
|
|
"FILE_GUID"
|
|
]
|
|
|
|
SymbolPattern = ValueExpression.SymbolPattern
|
|
|
|
## Constructor of DscParser
|
|
#
|
|
# Initialize object of DscParser
|
|
#
|
|
# @param FilePath The path of platform description file
|
|
# @param FileType The raw data of DSC file
|
|
# @param Table Database used to retrieve module/package information
|
|
# @param Macros Macros used for replacement in file
|
|
# @param Owner Owner ID (for sub-section parsing)
|
|
# @param From ID from which the data comes (for !INCLUDE directive)
|
|
#
|
|
def __init__(self, FilePath, FileType, Table, Owner=-1, From=-1):
|
|
# prevent re-initialization
|
|
if hasattr(self, "_Table"):
|
|
return
|
|
MetaFileParser.__init__(self, FilePath, FileType, Table, Owner, From)
|
|
self._Version = 0x00010005 # Only EDK2 dsc file is supported
|
|
# to store conditional directive evaluation result
|
|
self._DirectiveStack = []
|
|
self._DirectiveEvalStack = []
|
|
self._Enabled = 1
|
|
|
|
# Final valid replacable symbols
|
|
self._Symbols = {}
|
|
#
|
|
# Map the ID between the original table and new table to track
|
|
# the owner item
|
|
#
|
|
self._IdMapping = {-1:-1}
|
|
|
|
self.TblFile = EccGlobalData.gDb.TblFile
|
|
self.FileID = -1
|
|
|
|
## Parser starter
|
|
def Start(self):
|
|
Content = ''
|
|
try:
|
|
Content = open(str(self.MetaFile.Path), 'r').readlines()
|
|
except:
|
|
EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
|
|
#
|
|
# Insert a record for file
|
|
#
|
|
Filename = NormPath(self.MetaFile.Path)
|
|
FileID = self.TblFile.GetFileId(Filename)
|
|
if FileID:
|
|
self.FileID = FileID
|
|
else:
|
|
self.FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_DSC)
|
|
|
|
|
|
for Index in range(0, len(Content)):
|
|
Line = CleanString(Content[Index])
|
|
# skip empty line
|
|
if Line == '':
|
|
continue
|
|
|
|
self._CurrentLine = Line
|
|
self._LineIndex = Index
|
|
if self._InSubsection and self._Owner[-1] == -1:
|
|
self._Owner.append(self._LastItem)
|
|
|
|
# section header
|
|
if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
|
|
self._SectionType = MODEL_META_DATA_SECTION_HEADER
|
|
# subsection ending
|
|
elif Line[0] == '}' and self._InSubsection:
|
|
self._InSubsection = False
|
|
self._SubsectionType = MODEL_UNKNOWN
|
|
self._SubsectionName = ''
|
|
self._Owner[-1] = -1
|
|
continue
|
|
# subsection header
|
|
elif Line[0] == TAB_OPTION_START and Line[-1] == TAB_OPTION_END:
|
|
self._SubsectionType = MODEL_META_DATA_SUBSECTION_HEADER
|
|
# directive line
|
|
elif Line[0] == '!':
|
|
self._DirectiveParser()
|
|
continue
|
|
|
|
if self._InSubsection:
|
|
SectionType = self._SubsectionType
|
|
else:
|
|
SectionType = self._SectionType
|
|
self._ItemType = SectionType
|
|
|
|
self._ValueList = ['', '', '']
|
|
self._SectionParser[SectionType](self)
|
|
if self._ValueList is None:
|
|
continue
|
|
#
|
|
# Model, Value1, Value2, Value3, Arch, ModuleType, BelongsToItem=-1, BelongsToFile=-1,
|
|
# LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1
|
|
#
|
|
for Arch, ModuleType in self._Scope:
|
|
self._LastItem = self._Store(
|
|
self._ItemType,
|
|
self._ValueList[0],
|
|
self._ValueList[1],
|
|
self._ValueList[2],
|
|
Arch,
|
|
ModuleType,
|
|
self._Owner[-1],
|
|
self.FileID,
|
|
self._From,
|
|
self._LineIndex+1,
|
|
-1,
|
|
self._LineIndex+1,
|
|
-1,
|
|
self._Enabled
|
|
)
|
|
|
|
if self._DirectiveStack:
|
|
Type, Line, Text = self._DirectiveStack[-1]
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "No matching '!endif' found",
|
|
ExtraData=Text, File=self.MetaFile, Line=Line)
|
|
self._Done()
|
|
|
|
## <subsection_header> parser
|
|
def _SubsectionHeaderParser(self):
|
|
self._SubsectionName = self._CurrentLine[1:-1].upper()
|
|
if self._SubsectionName in self.DataType:
|
|
self._SubsectionType = self.DataType[self._SubsectionName]
|
|
else:
|
|
self._SubsectionType = MODEL_UNKNOWN
|
|
EdkLogger.warn("Parser", "Unrecognized sub-section", File=self.MetaFile,
|
|
Line=self._LineIndex+1, ExtraData=self._CurrentLine)
|
|
self._ValueList[0] = self._SubsectionName
|
|
|
|
## Directive statement parser
|
|
def _DirectiveParser(self):
|
|
self._ValueList = ['', '', '']
|
|
TokenList = GetSplitValueList(self._CurrentLine, ' ', 1)
|
|
self._ValueList[0:len(TokenList)] = TokenList
|
|
|
|
# Syntax check
|
|
DirectiveName = self._ValueList[0].upper()
|
|
if DirectiveName not in self.DataType:
|
|
EdkLogger.error("Parser", FORMAT_INVALID, "Unknown directive [%s]" % DirectiveName,
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
if DirectiveName in ['!IF', '!IFDEF', '!INCLUDE', '!IFNDEF', '!ELSEIF'] and self._ValueList[1] == '':
|
|
EdkLogger.error("Parser", FORMAT_INVALID, "Missing expression",
|
|
File=self.MetaFile, Line=self._LineIndex+1,
|
|
ExtraData=self._CurrentLine)
|
|
|
|
ItemType = self.DataType[DirectiveName]
|
|
if ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF:
|
|
# Remove all directives between !if and !endif, including themselves
|
|
while self._DirectiveStack:
|
|
# Remove any !else or !elseif
|
|
DirectiveInfo = self._DirectiveStack.pop()
|
|
if DirectiveInfo[0] in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
|
|
MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
|
|
MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF]:
|
|
break
|
|
else:
|
|
EdkLogger.error("Parser", FORMAT_INVALID, "Redundant '!endif'",
|
|
File=self.MetaFile, Line=self._LineIndex+1,
|
|
ExtraData=self._CurrentLine)
|
|
elif ItemType != MODEL_META_DATA_INCLUDE:
|
|
# Break if there's a !else is followed by a !elseif
|
|
if ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF and \
|
|
self._DirectiveStack and \
|
|
self._DirectiveStack[-1][0] == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE:
|
|
EdkLogger.error("Parser", FORMAT_INVALID, "'!elseif' after '!else'",
|
|
File=self.MetaFile, Line=self._LineIndex+1,
|
|
ExtraData=self._CurrentLine)
|
|
self._DirectiveStack.append((ItemType, self._LineIndex+1, self._CurrentLine))
|
|
elif self._From > 0:
|
|
EdkLogger.error('Parser', FORMAT_INVALID,
|
|
"No '!include' allowed in included file",
|
|
ExtraData=self._CurrentLine, File=self.MetaFile,
|
|
Line=self._LineIndex+1)
|
|
|
|
#
|
|
# Model, Value1, Value2, Value3, Arch, ModuleType, BelongsToItem=-1, BelongsToFile=-1,
|
|
# LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1
|
|
#
|
|
self._LastItem = self._Store(
|
|
ItemType,
|
|
self._ValueList[0],
|
|
self._ValueList[1],
|
|
self._ValueList[2],
|
|
'COMMON',
|
|
'COMMON',
|
|
self._Owner[-1],
|
|
self.FileID,
|
|
self._From,
|
|
self._LineIndex+1,
|
|
-1,
|
|
self._LineIndex+1,
|
|
-1,
|
|
0
|
|
)
|
|
|
|
## [defines] section parser
|
|
@ParseMacro
|
|
def _DefineParser(self):
|
|
TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
|
|
self._ValueList[1:len(TokenList)] = TokenList
|
|
|
|
# Syntax check
|
|
if not self._ValueList[1]:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "No name specified",
|
|
ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
|
|
if not self._ValueList[2]:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "No value specified",
|
|
ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
|
|
if (not self._ValueList[1] in self.DefineKeywords and
|
|
(self._InSubsection and self._ValueList[1] not in self.SubSectionDefineKeywords)):
|
|
EdkLogger.error('Parser', FORMAT_INVALID,
|
|
"Unknown keyword found: %s. "
|
|
"If this is a macro you must "
|
|
"add it as a DEFINE in the DSC" % self._ValueList[1],
|
|
ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
|
|
self._Defines[self._ValueList[1]] = self._ValueList[2]
|
|
self._ItemType = self.DataType[TAB_DSC_DEFINES.upper()]
|
|
|
|
@ParseMacro
|
|
def _SkuIdParser(self):
|
|
TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
|
|
if len(TokenList) != 2:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "Correct format is '<Integer>|<UiName>'",
|
|
ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
|
|
self._ValueList[0:len(TokenList)] = TokenList
|
|
|
|
## Parse Edk style of library modules
|
|
def _LibraryInstanceParser(self):
|
|
self._ValueList[0] = self._CurrentLine
|
|
|
|
## PCD sections parser
|
|
#
|
|
# [PcdsFixedAtBuild]
|
|
# [PcdsPatchableInModule]
|
|
# [PcdsFeatureFlag]
|
|
# [PcdsDynamicEx
|
|
# [PcdsDynamicExDefault]
|
|
# [PcdsDynamicExVpd]
|
|
# [PcdsDynamicExHii]
|
|
# [PcdsDynamic]
|
|
# [PcdsDynamicDefault]
|
|
# [PcdsDynamicVpd]
|
|
# [PcdsDynamicHii]
|
|
#
|
|
@ParseMacro
|
|
def _PcdParser(self):
|
|
TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
|
|
self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
|
|
if len(TokenList) == 2:
|
|
self._ValueList[2] = TokenList[1]
|
|
if self._ValueList[0] == '' or self._ValueList[1] == '':
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
|
|
ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<TokenCName>|<PcdValue>)",
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
if self._ValueList[2] == '':
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "No PCD value given",
|
|
ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<TokenCName>|<PcdValue>)",
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
# if value are 'True', 'true', 'TRUE' or 'False', 'false', 'FALSE', replace with integer 1 or 0.
|
|
DscPcdValueList = GetSplitValueList(TokenList[1], TAB_VALUE_SPLIT, 1)
|
|
if DscPcdValueList[0] in ['True', 'true', 'TRUE']:
|
|
self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '1', 1);
|
|
elif DscPcdValueList[0] in ['False', 'false', 'FALSE']:
|
|
self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '0', 1);
|
|
|
|
## [components] section parser
|
|
@ParseMacro
|
|
def _ComponentParser(self):
|
|
if self._CurrentLine[-1] == '{':
|
|
self._ValueList[0] = self._CurrentLine[0:-1].strip()
|
|
self._InSubsection = True
|
|
else:
|
|
self._ValueList[0] = self._CurrentLine
|
|
|
|
## [LibraryClasses] section
|
|
@ParseMacro
|
|
def _LibraryClassParser(self):
|
|
TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
|
|
if len(TokenList) < 2:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "No library class or instance specified",
|
|
ExtraData=self._CurrentLine + " (<LibraryClassName>|<LibraryInstancePath>)",
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
if TokenList[0] == '':
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "No library class specified",
|
|
ExtraData=self._CurrentLine + " (<LibraryClassName>|<LibraryInstancePath>)",
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
if TokenList[1] == '':
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "No library instance specified",
|
|
ExtraData=self._CurrentLine + " (<LibraryClassName>|<LibraryInstancePath>)",
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
|
|
self._ValueList[0:len(TokenList)] = TokenList
|
|
|
|
|
|
## [BuildOptions] section parser
|
|
@ParseMacro
|
|
def _BuildOptionParser(self):
|
|
TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
|
|
TokenList2 = GetSplitValueList(TokenList[0], ':', 1)
|
|
if len(TokenList2) == 2:
|
|
self._ValueList[0] = TokenList2[0] # toolchain family
|
|
self._ValueList[1] = TokenList2[1] # keys
|
|
else:
|
|
self._ValueList[1] = TokenList[0]
|
|
if len(TokenList) == 2: # value
|
|
self._ValueList[2] = TokenList[1]
|
|
|
|
if self._ValueList[1].count('_') != 4:
|
|
EdkLogger.error(
|
|
'Parser',
|
|
FORMAT_INVALID,
|
|
"'%s' must be in format of <TARGET>_<TOOLCHAIN>_<ARCH>_<TOOL>_FLAGS" % self._ValueList[1],
|
|
ExtraData=self._CurrentLine,
|
|
File=self.MetaFile,
|
|
Line=self._LineIndex+1
|
|
)
|
|
|
|
## Override parent's method since we'll do all macro replacements in parser
|
|
def _GetMacros(self):
|
|
Macros = dict( [('ARCH', 'IA32'), ('FAMILY', TAB_COMPILER_MSFT), ('TOOL_CHAIN_TAG', 'VS2008x86'), ('TARGET', 'DEBUG')])
|
|
Macros.update(self._FileLocalMacros)
|
|
Macros.update(self._GetApplicableSectionMacro())
|
|
Macros.update(GlobalData.gEdkGlobal)
|
|
Macros.update(GlobalData.gPlatformDefines)
|
|
Macros.update(GlobalData.gCommandLineDefines)
|
|
# PCD cannot be referenced in macro definition
|
|
if self._ItemType not in [MODEL_META_DATA_DEFINE, MODEL_META_DATA_GLOBAL_DEFINE]:
|
|
Macros.update(self._Symbols)
|
|
return Macros
|
|
|
|
def _PostProcess(self):
|
|
Processer = {
|
|
MODEL_META_DATA_SECTION_HEADER : self.__ProcessSectionHeader,
|
|
MODEL_META_DATA_SUBSECTION_HEADER : self.__ProcessSubsectionHeader,
|
|
MODEL_META_DATA_HEADER : self.__ProcessDefine,
|
|
MODEL_META_DATA_DEFINE : self.__ProcessDefine,
|
|
MODEL_META_DATA_GLOBAL_DEFINE : self.__ProcessDefine,
|
|
MODEL_META_DATA_INCLUDE : self.__ProcessDirective,
|
|
MODEL_META_DATA_CONDITIONAL_STATEMENT_IF : self.__ProcessDirective,
|
|
MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE : self.__ProcessDirective,
|
|
MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF : self.__ProcessDirective,
|
|
MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF : self.__ProcessDirective,
|
|
MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF : self.__ProcessDirective,
|
|
MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF : self.__ProcessDirective,
|
|
MODEL_EFI_SKU_ID : self.__ProcessSkuId,
|
|
MODEL_EFI_LIBRARY_INSTANCE : self.__ProcessLibraryInstance,
|
|
MODEL_EFI_LIBRARY_CLASS : self.__ProcessLibraryClass,
|
|
MODEL_PCD_FIXED_AT_BUILD : self.__ProcessPcd,
|
|
MODEL_PCD_PATCHABLE_IN_MODULE : self.__ProcessPcd,
|
|
MODEL_PCD_FEATURE_FLAG : self.__ProcessPcd,
|
|
MODEL_PCD_DYNAMIC_DEFAULT : self.__ProcessPcd,
|
|
MODEL_PCD_DYNAMIC_HII : self.__ProcessPcd,
|
|
MODEL_PCD_DYNAMIC_VPD : self.__ProcessPcd,
|
|
MODEL_PCD_DYNAMIC_EX_DEFAULT : self.__ProcessPcd,
|
|
MODEL_PCD_DYNAMIC_EX_HII : self.__ProcessPcd,
|
|
MODEL_PCD_DYNAMIC_EX_VPD : self.__ProcessPcd,
|
|
MODEL_META_DATA_COMPONENT : self.__ProcessComponent,
|
|
MODEL_META_DATA_BUILD_OPTION : self.__ProcessBuildOption,
|
|
MODEL_UNKNOWN : self._Skip,
|
|
MODEL_META_DATA_USER_EXTENSION : self._Skip,
|
|
MODEL_META_DATA_CONDITIONAL_STATEMENT_ERROR : self._Skip,
|
|
}
|
|
|
|
self._RawTable = self._Table
|
|
self._Table = MetaFileStorage(self._RawTable.Cur, self.MetaFile, MODEL_FILE_DSC, True)
|
|
self._DirectiveStack = []
|
|
self._DirectiveEvalStack = []
|
|
self._FileWithError = self.MetaFile
|
|
self._FileLocalMacros = {}
|
|
self._SectionsMacroDict = {}
|
|
GlobalData.gPlatformDefines = {}
|
|
|
|
# Get all macro and PCD which has straitforward value
|
|
self.__RetrievePcdValue()
|
|
self._Content = self._RawTable.GetAll()
|
|
self._ContentIndex = 0
|
|
while self._ContentIndex < len(self._Content) :
|
|
Id, self._ItemType, V1, V2, V3, S1, S2, Owner, BelongsToFile, self._From, \
|
|
LineStart, ColStart, LineEnd, ColEnd, Enabled = self._Content[self._ContentIndex]
|
|
|
|
if self._From < 0:
|
|
self._FileWithError = self.MetaFile
|
|
|
|
self._ContentIndex += 1
|
|
|
|
self._Scope = [[S1, S2]]
|
|
self._LineIndex = LineStart - 1
|
|
self._ValueList = [V1, V2, V3]
|
|
|
|
try:
|
|
Processer[self._ItemType]()
|
|
except EvaluationException as Excpt:
|
|
#
|
|
# Only catch expression evaluation error here. We need to report
|
|
# the precise number of line on which the error occurred
|
|
#
|
|
pass
|
|
# EdkLogger.error('Parser', FORMAT_INVALID, "Invalid expression: %s" % str(Excpt),
|
|
# File=self._FileWithError, ExtraData=' '.join(self._ValueList),
|
|
# Line=self._LineIndex+1)
|
|
except MacroException as Excpt:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, str(Excpt),
|
|
File=self._FileWithError, ExtraData=' '.join(self._ValueList),
|
|
Line=self._LineIndex+1)
|
|
|
|
if self._ValueList is None:
|
|
continue
|
|
|
|
NewOwner = self._IdMapping.get(Owner, -1)
|
|
self._Enabled = int((not self._DirectiveEvalStack) or (False not in self._DirectiveEvalStack))
|
|
self._LastItem = self._Store(
|
|
self._ItemType,
|
|
self._ValueList[0],
|
|
self._ValueList[1],
|
|
self._ValueList[2],
|
|
S1,
|
|
S2,
|
|
NewOwner,
|
|
BelongsToFile,
|
|
self._From,
|
|
self._LineIndex+1,
|
|
-1,
|
|
self._LineIndex+1,
|
|
-1,
|
|
self._Enabled
|
|
)
|
|
self._IdMapping[Id] = self._LastItem
|
|
|
|
RecordList = self._Table.GetAll()
|
|
|
|
self._RawTable.Drop()
|
|
self._Table.Drop()
|
|
for Record in RecordList:
|
|
EccGlobalData.gDb.TblDsc.Insert(Record[1], Record[2], Record[3], Record[4], Record[5], Record[6], Record[7], Record[8], Record[9], Record[10], Record[11], Record[12], Record[13], Record[14])
|
|
GlobalData.gPlatformDefines.update(self._FileLocalMacros)
|
|
self._PostProcessed = True
|
|
self._Content = None
|
|
|
|
def __ProcessSectionHeader(self):
|
|
self._SectionName = self._ValueList[0]
|
|
if self._SectionName in self.DataType:
|
|
self._SectionType = self.DataType[self._SectionName]
|
|
else:
|
|
self._SectionType = MODEL_UNKNOWN
|
|
|
|
def __ProcessSubsectionHeader(self):
|
|
self._SubsectionName = self._ValueList[0]
|
|
if self._SubsectionName in self.DataType:
|
|
self._SubsectionType = self.DataType[self._SubsectionName]
|
|
else:
|
|
self._SubsectionType = MODEL_UNKNOWN
|
|
|
|
def __RetrievePcdValue(self):
|
|
Records = self._RawTable.Query(MODEL_PCD_FEATURE_FLAG, BelongsToItem=-1.0)
|
|
for TokenSpaceGuid, PcdName, Value, Dummy2, Dummy3, ID, Line in Records:
|
|
Value, DatumType, MaxDatumSize = AnalyzePcdData(Value)
|
|
# Only use PCD whose value is straitforward (no macro and PCD)
|
|
if self.SymbolPattern.findall(Value):
|
|
continue
|
|
Name = TokenSpaceGuid + '.' + PcdName
|
|
# Don't use PCD with different values.
|
|
if Name in self._Symbols and self._Symbols[Name] != Value:
|
|
self._Symbols.pop(Name)
|
|
continue
|
|
self._Symbols[Name] = Value
|
|
|
|
Records = self._RawTable.Query(MODEL_PCD_FIXED_AT_BUILD, BelongsToItem=-1.0)
|
|
for TokenSpaceGuid, PcdName, Value, Dummy2, Dummy3, ID, Line in Records:
|
|
Value, DatumType, MaxDatumSize = AnalyzePcdData(Value)
|
|
# Only use PCD whose value is straitforward (no macro and PCD)
|
|
if self.SymbolPattern.findall(Value):
|
|
continue
|
|
Name = TokenSpaceGuid+'.'+PcdName
|
|
# Don't use PCD with different values.
|
|
if Name in self._Symbols and self._Symbols[Name] != Value:
|
|
self._Symbols.pop(Name)
|
|
continue
|
|
self._Symbols[Name] = Value
|
|
|
|
def __ProcessDefine(self):
|
|
if not self._Enabled:
|
|
return
|
|
|
|
Type, Name, Value = self._ValueList
|
|
Value = ReplaceMacro(Value, self._Macros, False)
|
|
if self._ItemType == MODEL_META_DATA_DEFINE:
|
|
if self._SectionType == MODEL_META_DATA_HEADER:
|
|
self._FileLocalMacros[Name] = Value
|
|
else:
|
|
SectionDictKey = self._SectionType, self._Scope[0][0], self._Scope[0][1]
|
|
if SectionDictKey not in self._SectionsMacroDict:
|
|
self._SectionsMacroDict[SectionDictKey] = {}
|
|
SectionLocalMacros = self._SectionsMacroDict[SectionDictKey]
|
|
SectionLocalMacros[Name] = Value
|
|
elif self._ItemType == MODEL_META_DATA_GLOBAL_DEFINE:
|
|
GlobalData.gEdkGlobal[Name] = Value
|
|
|
|
#
|
|
# Keyword in [Defines] section can be used as Macros
|
|
#
|
|
if (self._ItemType == MODEL_META_DATA_HEADER) and (self._SectionType == MODEL_META_DATA_HEADER):
|
|
self._FileLocalMacros[Name] = Value
|
|
|
|
self._ValueList = [Type, Name, Value]
|
|
|
|
def __ProcessDirective(self):
|
|
Result = None
|
|
if self._ItemType in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
|
|
MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF]:
|
|
Macros = self._Macros
|
|
Macros.update(GlobalData.gGlobalDefines)
|
|
try:
|
|
Result = ValueExpression(self._ValueList[1], Macros)()
|
|
except SymbolNotFound as Exc:
|
|
EdkLogger.debug(EdkLogger.DEBUG_5, str(Exc), self._ValueList[1])
|
|
Result = False
|
|
except WrnExpression as Excpt:
|
|
#
|
|
# Catch expression evaluation warning here. We need to report
|
|
# the precise number of line and return the evaluation result
|
|
#
|
|
EdkLogger.warn('Parser', "Suspicious expression: %s" % str(Excpt),
|
|
File=self._FileWithError, ExtraData=' '.join(self._ValueList),
|
|
Line=self._LineIndex+1)
|
|
Result = Excpt.result
|
|
except BadExpression as Exc:
|
|
EdkLogger.debug(EdkLogger.DEBUG_5, str(Exc), self._ValueList[1])
|
|
Result = False
|
|
|
|
if self._ItemType in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
|
|
MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
|
|
MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF]:
|
|
self._DirectiveStack.append(self._ItemType)
|
|
if self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_IF:
|
|
Result = bool(Result)
|
|
else:
|
|
Macro = self._ValueList[1]
|
|
Macro = Macro[2:-1] if (Macro.startswith("$(") and Macro.endswith(")")) else Macro
|
|
Result = Macro in self._Macros
|
|
if self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF:
|
|
Result = not Result
|
|
self._DirectiveEvalStack.append(Result)
|
|
elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF:
|
|
self._DirectiveStack.append(self._ItemType)
|
|
self._DirectiveEvalStack[-1] = not self._DirectiveEvalStack[-1]
|
|
self._DirectiveEvalStack.append(bool(Result))
|
|
elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE:
|
|
self._DirectiveStack[-1] = self._ItemType
|
|
self._DirectiveEvalStack[-1] = not self._DirectiveEvalStack[-1]
|
|
elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF:
|
|
# Back to the nearest !if/!ifdef/!ifndef
|
|
while self._DirectiveStack:
|
|
self._DirectiveEvalStack.pop()
|
|
Directive = self._DirectiveStack.pop()
|
|
if Directive in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
|
|
MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
|
|
MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE,
|
|
MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF]:
|
|
break
|
|
elif self._ItemType == MODEL_META_DATA_INCLUDE:
|
|
# The included file must be relative to workspace or same directory as DSC file
|
|
__IncludeMacros = {}
|
|
#
|
|
# Allow using system environment variables in path after !include
|
|
#
|
|
__IncludeMacros['WORKSPACE'] = GlobalData.gGlobalDefines['WORKSPACE']
|
|
|
|
#
|
|
# Allow using MACROs comes from [Defines] section to keep compatible.
|
|
#
|
|
__IncludeMacros.update(self._Macros)
|
|
|
|
IncludedFile = NormPath(ReplaceMacro(self._ValueList[1], __IncludeMacros, RaiseError=True))
|
|
#
|
|
# First search the include file under the same directory as DSC file
|
|
#
|
|
IncludedFile1 = PathClass(IncludedFile, self.MetaFile.Dir)
|
|
ErrorCode, ErrorInfo1 = IncludedFile1.Validate()
|
|
if ErrorCode != 0:
|
|
#
|
|
# Also search file under the WORKSPACE directory
|
|
#
|
|
IncludedFile1 = PathClass(IncludedFile, GlobalData.gWorkspace)
|
|
ErrorCode, ErrorInfo2 = IncludedFile1.Validate()
|
|
if ErrorCode != 0:
|
|
EdkLogger.error('parser', ErrorCode, File=self._FileWithError,
|
|
Line=self._LineIndex+1, ExtraData=ErrorInfo1 + "\n"+ ErrorInfo2)
|
|
|
|
self._FileWithError = IncludedFile1
|
|
|
|
IncludedFileTable = MetaFileStorage(self._Table.Cur, IncludedFile1, MODEL_FILE_DSC, True)
|
|
Owner = self._Content[self._ContentIndex-1][0]
|
|
Parser = DscParser(IncludedFile1, self._FileType, IncludedFileTable,
|
|
Owner=Owner, From=Owner)
|
|
|
|
# set the parser status with current status
|
|
Parser._SectionName = self._SectionName
|
|
Parser._SectionType = self._SectionType
|
|
Parser._Scope = self._Scope
|
|
Parser._Enabled = self._Enabled
|
|
# Parse the included file
|
|
Parser.Start()
|
|
|
|
# update current status with sub-parser's status
|
|
self._SectionName = Parser._SectionName
|
|
self._SectionType = Parser._SectionType
|
|
self._Scope = Parser._Scope
|
|
self._Enabled = Parser._Enabled
|
|
|
|
# Insert all records in the table for the included file into dsc file table
|
|
Records = IncludedFileTable.GetAll()
|
|
if Records:
|
|
self._Content[self._ContentIndex:self._ContentIndex] = Records
|
|
self._Content.pop(self._ContentIndex-1)
|
|
self._ValueList = None
|
|
self._ContentIndex -= 1
|
|
|
|
def __ProcessSkuId(self):
|
|
self._ValueList = [ReplaceMacro(Value, self._Macros, RaiseError=True)
|
|
for Value in self._ValueList]
|
|
|
|
def __ProcessLibraryInstance(self):
|
|
self._ValueList = [ReplaceMacro(Value, self._Macros) for Value in self._ValueList]
|
|
|
|
def __ProcessLibraryClass(self):
|
|
self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros, RaiseError=True)
|
|
|
|
def __ProcessPcd(self):
|
|
ValueList = GetSplitValueList(self._ValueList[2])
|
|
#
|
|
# PCD value can be an expression
|
|
#
|
|
if len(ValueList) > 1 and ValueList[1] == TAB_VOID:
|
|
PcdValue = ValueList[0]
|
|
try:
|
|
ValueList[0] = ValueExpression(PcdValue, self._Macros)(True)
|
|
except WrnExpression as Value:
|
|
ValueList[0] = Value.result
|
|
else:
|
|
PcdValue = ValueList[-1]
|
|
try:
|
|
ValueList[-1] = ValueExpression(PcdValue, self._Macros)(True)
|
|
except WrnExpression as Value:
|
|
ValueList[-1] = Value.result
|
|
|
|
if ValueList[-1] == 'True':
|
|
ValueList[-1] = '1'
|
|
if ValueList[-1] == 'False':
|
|
ValueList[-1] = '0'
|
|
|
|
self._ValueList[2] = '|'.join(ValueList)
|
|
|
|
def __ProcessComponent(self):
|
|
self._ValueList[0] = ReplaceMacro(self._ValueList[0], self._Macros)
|
|
|
|
def __ProcessBuildOption(self):
|
|
self._ValueList = [ReplaceMacro(Value, self._Macros, RaiseError=False)
|
|
for Value in self._ValueList]
|
|
|
|
_SectionParser = {
|
|
MODEL_META_DATA_HEADER : _DefineParser,
|
|
MODEL_EFI_SKU_ID : _SkuIdParser,
|
|
MODEL_EFI_LIBRARY_INSTANCE : _LibraryInstanceParser,
|
|
MODEL_EFI_LIBRARY_CLASS : _LibraryClassParser,
|
|
MODEL_PCD_FIXED_AT_BUILD : _PcdParser,
|
|
MODEL_PCD_PATCHABLE_IN_MODULE : _PcdParser,
|
|
MODEL_PCD_FEATURE_FLAG : _PcdParser,
|
|
MODEL_PCD_DYNAMIC_DEFAULT : _PcdParser,
|
|
MODEL_PCD_DYNAMIC_HII : _PcdParser,
|
|
MODEL_PCD_DYNAMIC_VPD : _PcdParser,
|
|
MODEL_PCD_DYNAMIC_EX_DEFAULT : _PcdParser,
|
|
MODEL_PCD_DYNAMIC_EX_HII : _PcdParser,
|
|
MODEL_PCD_DYNAMIC_EX_VPD : _PcdParser,
|
|
MODEL_META_DATA_COMPONENT : _ComponentParser,
|
|
MODEL_META_DATA_BUILD_OPTION : _BuildOptionParser,
|
|
MODEL_UNKNOWN : MetaFileParser._Skip,
|
|
MODEL_META_DATA_USER_EXTENSION : MetaFileParser._Skip,
|
|
MODEL_META_DATA_SECTION_HEADER : MetaFileParser._SectionHeaderParser,
|
|
MODEL_META_DATA_SUBSECTION_HEADER : _SubsectionHeaderParser,
|
|
}
|
|
|
|
_Macros = property(_GetMacros)
|
|
|
|
## DEC file parser class
|
|
#
|
|
# @param FilePath The path of platform description file
|
|
# @param FileType The raw data of DSC file
|
|
# @param Table Database used to retrieve module/package information
|
|
# @param Macros Macros used for replacement in file
|
|
#
|
|
class DecParser(MetaFileParser):
|
|
# DEC file supported data types (one type per section)
|
|
DataType = {
|
|
TAB_DEC_DEFINES.upper() : MODEL_META_DATA_HEADER,
|
|
TAB_DSC_DEFINES_DEFINE : MODEL_META_DATA_DEFINE,
|
|
TAB_INCLUDES.upper() : MODEL_EFI_INCLUDE,
|
|
TAB_LIBRARY_CLASSES.upper() : MODEL_EFI_LIBRARY_CLASS,
|
|
TAB_GUIDS.upper() : MODEL_EFI_GUID,
|
|
TAB_PPIS.upper() : MODEL_EFI_PPI,
|
|
TAB_PROTOCOLS.upper() : MODEL_EFI_PROTOCOL,
|
|
TAB_PCDS_FIXED_AT_BUILD_NULL.upper() : MODEL_PCD_FIXED_AT_BUILD,
|
|
TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper() : MODEL_PCD_PATCHABLE_IN_MODULE,
|
|
TAB_PCDS_FEATURE_FLAG_NULL.upper() : MODEL_PCD_FEATURE_FLAG,
|
|
TAB_PCDS_DYNAMIC_NULL.upper() : MODEL_PCD_DYNAMIC,
|
|
TAB_PCDS_DYNAMIC_EX_NULL.upper() : MODEL_PCD_DYNAMIC_EX,
|
|
}
|
|
|
|
## Constructor of DecParser
|
|
#
|
|
# Initialize object of DecParser
|
|
#
|
|
# @param FilePath The path of platform description file
|
|
# @param FileType The raw data of DSC file
|
|
# @param Table Database used to retrieve module/package information
|
|
# @param Macros Macros used for replacement in file
|
|
#
|
|
def __init__(self, FilePath, FileType, Table):
|
|
# prevent re-initialization
|
|
if hasattr(self, "_Table"):
|
|
return
|
|
MetaFileParser.__init__(self, FilePath, FileType, Table)
|
|
self._Comments = []
|
|
self._Version = 0x00010005 # Only EDK2 dec file is supported
|
|
self.TblFile = EccGlobalData.gDb.TblFile
|
|
self.FileID = -1
|
|
|
|
self._CurrentStructurePcdName = ""
|
|
self._include_flag = False
|
|
self._package_flag = False
|
|
|
|
## Parser starter
|
|
def Start(self):
|
|
Content = ''
|
|
try:
|
|
Content = open(str(self.MetaFile), 'r').readlines()
|
|
except:
|
|
EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
|
|
|
|
#
|
|
# Insert a record for file
|
|
#
|
|
Filename = NormPath(self.MetaFile)
|
|
FileID = self.TblFile.GetFileId(Filename)
|
|
if FileID:
|
|
self.FileID = FileID
|
|
else:
|
|
self.FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_DEC)
|
|
|
|
for Index in range(0, len(Content)):
|
|
Line, Comment = CleanString2(Content[Index])
|
|
self._CurrentLine = Line
|
|
self._LineIndex = Index
|
|
|
|
# save comment for later use
|
|
if Comment:
|
|
self._Comments.append((Comment, self._LineIndex+1))
|
|
# skip empty line
|
|
if Line == '':
|
|
continue
|
|
|
|
# section header
|
|
if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
|
|
self._SectionHeaderParser()
|
|
self._Comments = []
|
|
continue
|
|
elif len(self._SectionType) == 0:
|
|
self._Comments = []
|
|
continue
|
|
|
|
# section content
|
|
self._ValueList = ['', '', '']
|
|
self._SectionParser[self._SectionType[0]](self)
|
|
if self._ValueList is None or self._ItemType == MODEL_META_DATA_DEFINE:
|
|
self._ItemType = -1
|
|
self._Comments = []
|
|
continue
|
|
|
|
#
|
|
# Model, Value1, Value2, Value3, Arch, BelongsToItem=-1, LineBegin=-1,
|
|
# ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, FeatureFlag='', Enabled=-1
|
|
#
|
|
for Arch, ModuleType, Type in self._Scope:
|
|
self._LastItem = self._Store(
|
|
Type,
|
|
self._ValueList[0],
|
|
self._ValueList[1],
|
|
self._ValueList[2],
|
|
Arch,
|
|
ModuleType,
|
|
self._Owner[-1],
|
|
self.FileID,
|
|
self._LineIndex+1,
|
|
-1,
|
|
self._LineIndex+1,
|
|
-1,
|
|
0
|
|
)
|
|
for Comment, LineNo in self._Comments:
|
|
self._Store(
|
|
MODEL_META_DATA_COMMENT,
|
|
Comment,
|
|
self._ValueList[0],
|
|
self._ValueList[1],
|
|
Arch,
|
|
ModuleType,
|
|
self._LastItem,
|
|
self.FileID,
|
|
LineNo,
|
|
-1,
|
|
LineNo,
|
|
-1,
|
|
0
|
|
)
|
|
self._Comments = []
|
|
self._Done()
|
|
|
|
def _GetApplicableSectionMacro(self):
|
|
Macros = {}
|
|
for S1, S2, SectionType in self._Scope:
|
|
for Scope1, Scope2 in [("COMMON", "COMMON"), ("COMMON", S2), (S1, "COMMON"), (S1, S2)]:
|
|
if (SectionType, Scope1, Scope2) in self._SectionsMacroDict:
|
|
Macros.update(self._SectionsMacroDict[(SectionType, Scope1, Scope2)])
|
|
return Macros
|
|
|
|
## Section header parser
|
|
#
|
|
# The section header is always in following format:
|
|
#
|
|
# [section_name.arch<.platform|module_type>]
|
|
#
|
|
def _SectionHeaderParser(self):
|
|
self._Scope = []
|
|
self._SectionName = ''
|
|
self._SectionType = []
|
|
ArchList = set()
|
|
for Item in GetSplitValueList(self._CurrentLine[1:-1], TAB_COMMA_SPLIT):
|
|
if Item == '':
|
|
continue
|
|
ItemList = GetSplitValueList(Item, TAB_SPLIT)
|
|
|
|
# different types of PCD are permissible in one section
|
|
self._SectionName = ItemList[0].upper()
|
|
if self._SectionName in self.DataType:
|
|
if self.DataType[self._SectionName] not in self._SectionType:
|
|
self._SectionType.append(self.DataType[self._SectionName])
|
|
else:
|
|
EdkLogger.warn("Parser", "Unrecognized section", File=self.MetaFile,
|
|
Line=self._LineIndex+1, ExtraData=self._CurrentLine)
|
|
continue
|
|
|
|
if MODEL_PCD_FEATURE_FLAG in self._SectionType and len(self._SectionType) > 1:
|
|
EdkLogger.error(
|
|
'Parser',
|
|
FORMAT_INVALID,
|
|
"%s must not be in the same section of other types of PCD" % TAB_PCDS_FEATURE_FLAG_NULL,
|
|
File=self.MetaFile,
|
|
Line=self._LineIndex+1,
|
|
ExtraData=self._CurrentLine
|
|
)
|
|
# S1 is always Arch
|
|
if len(ItemList) > 1:
|
|
S1 = ItemList[1].upper()
|
|
else:
|
|
S1 = 'COMMON'
|
|
ArchList.add(S1)
|
|
# S2 may be Platform or ModuleType
|
|
if len(ItemList) > 2:
|
|
S2 = ItemList[2].upper()
|
|
else:
|
|
S2 = 'COMMON'
|
|
if [S1, S2, self.DataType[self._SectionName]] not in self._Scope:
|
|
self._Scope.append([S1, S2, self.DataType[self._SectionName]])
|
|
|
|
# 'COMMON' must not be used with specific ARCHs at the same section
|
|
if 'COMMON' in ArchList and len(ArchList) > 1:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "'common' ARCH must not be used with specific ARCHs",
|
|
File=self.MetaFile, Line=self._LineIndex+1, ExtraData=self._CurrentLine)
|
|
|
|
## [guids], [ppis] and [protocols] section parser
|
|
@ParseMacro
|
|
def _GuidParser(self):
|
|
TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
|
|
if len(TokenList) < 2:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "No GUID name or value specified",
|
|
ExtraData=self._CurrentLine + " (<CName> = <GuidValueInCFormat>)",
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
if TokenList[0] == '':
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "No GUID name specified",
|
|
ExtraData=self._CurrentLine + " (<CName> = <GuidValueInCFormat>)",
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
if TokenList[1] == '':
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "No GUID value specified",
|
|
ExtraData=self._CurrentLine + " (<CName> = <GuidValueInCFormat>)",
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
if TokenList[1][0] != '{' or TokenList[1][-1] != '}' or GuidStructureStringToGuidString(TokenList[1]) == '':
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "Invalid GUID value format",
|
|
ExtraData=self._CurrentLine + \
|
|
" (<CName> = <GuidValueInCFormat:{8,4,4,{2,2,2,2,2,2,2,2}}>)",
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
self._ValueList[0] = TokenList[0]
|
|
#Parse the Guid value format
|
|
GuidValueList = TokenList[1].strip(' {}').split(',')
|
|
Index = 0
|
|
HexList = []
|
|
if len(GuidValueList) == 11:
|
|
for GuidValue in GuidValueList:
|
|
GuidValue = GuidValue.strip()
|
|
if GuidValue.startswith('0x') or GuidValue.startswith('0X'):
|
|
HexList.append('0x' + str(GuidValue[2:]))
|
|
Index += 1
|
|
continue
|
|
else:
|
|
if GuidValue.startswith('{'):
|
|
GuidValue = GuidValue.lstrip(' {')
|
|
HexList.append('0x' + str(GuidValue[2:]))
|
|
Index += 1
|
|
self._ValueList[1] = "{ %s, %s, %s, { %s, %s, %s, %s, %s, %s, %s, %s }}" % (HexList[0], HexList[1], HexList[2], HexList[3], HexList[4], HexList[5], HexList[6], HexList[7], HexList[8], HexList[9], HexList[10])
|
|
else:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "Invalid GUID value format",
|
|
ExtraData=self._CurrentLine + \
|
|
" (<CName> = <GuidValueInCFormat:{8,4,4,{2,2,2,2,2,2,2,2}}>)",
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
self._ValueList[0] = ''
|
|
|
|
def ParsePcdName(self,namelist):
|
|
if "[" in namelist[1]:
|
|
pcdname = namelist[1][:namelist[1].index("[")]
|
|
arrayindex = namelist[1][namelist[1].index("["):]
|
|
namelist[1] = pcdname
|
|
if len(namelist) == 2:
|
|
namelist.append(arrayindex)
|
|
else:
|
|
namelist[2] = ".".join((arrayindex,namelist[2]))
|
|
return namelist
|
|
|
|
def StructPcdParser(self):
|
|
self._ValueList[0] = self._CurrentStructurePcdName
|
|
|
|
if "|" not in self._CurrentLine:
|
|
if "<HeaderFiles>" == self._CurrentLine:
|
|
self._include_flag = True
|
|
self._package_flag = False
|
|
self._ValueList = None
|
|
return
|
|
if "<Packages>" == self._CurrentLine:
|
|
self._package_flag = True
|
|
self._ValueList = None
|
|
self._include_flag = False
|
|
return
|
|
|
|
if self._include_flag:
|
|
self._ValueList[1] = "<HeaderFiles>_" + md5(self._CurrentLine.encode('utf-8')).hexdigest()
|
|
self._ValueList[2] = self._CurrentLine
|
|
if self._package_flag and "}" != self._CurrentLine:
|
|
self._ValueList[1] = "<Packages>_" + md5(self._CurrentLine.encode('utf-8')).hexdigest()
|
|
self._ValueList[2] = self._CurrentLine
|
|
if self._CurrentLine == "}":
|
|
self._package_flag = False
|
|
self._include_flag = False
|
|
self._ValueList = None
|
|
else:
|
|
PcdTockens = self._CurrentLine.split(TAB_VALUE_SPLIT)
|
|
PcdNames = self.ParsePcdName(PcdTockens[0].split(TAB_SPLIT))
|
|
if len(PcdNames) == 2:
|
|
if PcdNames[1].strip().endswith("]"):
|
|
PcdName = PcdNames[1][:PcdNames[1].index('[')]
|
|
Index = PcdNames[1][PcdNames[1].index('['):]
|
|
self._ValueList[0] = TAB_SPLIT.join((PcdNames[0], PcdName))
|
|
self._ValueList[1] = Index
|
|
self._ValueList[2] = PcdTockens[1]
|
|
else:
|
|
self._CurrentStructurePcdName = ""
|
|
else:
|
|
if self._CurrentStructurePcdName != TAB_SPLIT.join(PcdNames[:2]):
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "Pcd Name does not match: %s and %s " % (
|
|
self._CurrentStructurePcdName, TAB_SPLIT.join(PcdNames[:2])),
|
|
File=self.MetaFile, Line=self._LineIndex + 1)
|
|
self._ValueList[1] = TAB_SPLIT.join(PcdNames[2:])
|
|
self._ValueList[2] = PcdTockens[1]
|
|
|
|
## PCD sections parser
|
|
#
|
|
# [PcdsFixedAtBuild]
|
|
# [PcdsPatchableInModule]
|
|
# [PcdsFeatureFlag]
|
|
# [PcdsDynamicEx
|
|
# [PcdsDynamic]
|
|
#
|
|
@ParseMacro
|
|
def _PcdParser(self):
|
|
if self._CurrentStructurePcdName:
|
|
self.StructPcdParser()
|
|
return
|
|
TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
|
|
self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
|
|
# check PCD information
|
|
if self._ValueList[0] == '' or self._ValueList[1] == '':
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
|
|
ExtraData=self._CurrentLine + \
|
|
" (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
# check PCD datum information
|
|
if len(TokenList) < 2 or TokenList[1] == '':
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "No PCD Datum information given",
|
|
ExtraData=self._CurrentLine + \
|
|
" (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
|
|
|
|
ValueRe = re.compile(r'^\s*L?\".*\|.*\"')
|
|
PtrValue = ValueRe.findall(TokenList[1])
|
|
|
|
# Has VOID* type string, may contain "|" character in the string.
|
|
if len(PtrValue) != 0:
|
|
ptrValueList = re.sub(ValueRe, '', TokenList[1])
|
|
ValueList = GetSplitValueList(ptrValueList)
|
|
ValueList[0] = PtrValue[0]
|
|
else:
|
|
ValueList = GetSplitValueList(TokenList[1])
|
|
|
|
|
|
# check if there's enough datum information given
|
|
if len(ValueList) != 3:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "Invalid PCD Datum information given",
|
|
ExtraData=self._CurrentLine + \
|
|
" (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
# check default value
|
|
if ValueList[0] == '':
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "Missing DefaultValue in PCD Datum information",
|
|
ExtraData=self._CurrentLine + \
|
|
" (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
# check datum type
|
|
if ValueList[1] == '':
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "Missing DatumType in PCD Datum information",
|
|
ExtraData=self._CurrentLine + \
|
|
" (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
# check token of the PCD
|
|
if ValueList[2] == '':
|
|
EdkLogger.error('Parser', FORMAT_INVALID, "Missing Token in PCD Datum information",
|
|
ExtraData=self._CurrentLine + \
|
|
" (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
# check format of default value against the datum type
|
|
IsValid, Cause = CheckPcdDatum(ValueList[1], ValueList[0])
|
|
if not IsValid:
|
|
EdkLogger.error('Parser', FORMAT_INVALID, Cause, ExtraData=self._CurrentLine,
|
|
File=self.MetaFile, Line=self._LineIndex+1)
|
|
if Cause == "StructurePcd":
|
|
self._CurrentStructurePcdName = TAB_SPLIT.join(self._ValueList[0:2])
|
|
self._ValueList[0] = self._CurrentStructurePcdName
|
|
self._ValueList[1] = ValueList[1].strip()
|
|
|
|
if EccGlobalData.gConfig.UniCheckPCDInfo == '1' or EccGlobalData.gConfig.UniCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
|
|
# check Description, Prompt information
|
|
PatternDesc = re.compile('##\s*([\x21-\x7E\s]*)', re.S)
|
|
PatternPrompt = re.compile('#\s+@Prompt\s+([\x21-\x7E\s]*)', re.S)
|
|
Description = None
|
|
Prompt = None
|
|
# check @ValidRange, @ValidList and @Expression format valid
|
|
ErrorCodeValid = '0x0 <= %s <= 0xFFFFFFFF'
|
|
PatternValidRangeIn = '(NOT)?\s*(\d+\s*-\s*\d+|0[xX][a-fA-F0-9]+\s*-\s*0[xX][a-fA-F0-9]+|LT\s*\d+|LT\s*0[xX][a-fA-F0-9]+|GT\s*\d+|GT\s*0[xX][a-fA-F0-9]+|LE\s*\d+|LE\s*0[xX][a-fA-F0-9]+|GE\s*\d+|GE\s*0[xX][a-fA-F0-9]+|XOR\s*\d+|XOR\s*0[xX][a-fA-F0-9]+|EQ\s*\d+|EQ\s*0[xX][a-fA-F0-9]+)'
|
|
PatternValidRng = re.compile('^' + '(NOT)?\s*' + PatternValidRangeIn + '$')
|
|
for Comment in self._Comments:
|
|
Comm = Comment[0].strip()
|
|
if not Comm:
|
|
continue
|
|
if not Description:
|
|
Description = PatternDesc.findall(Comm)
|
|
if not Prompt:
|
|
Prompt = PatternPrompt.findall(Comm)
|
|
if Comm[0] == '#':
|
|
ValidFormt = Comm.lstrip('#')
|
|
ValidFormt = ValidFormt.lstrip()
|
|
if ValidFormt[0:11] == '@ValidRange':
|
|
ValidFormt = ValidFormt[11:]
|
|
ValidFormt = ValidFormt.lstrip()
|
|
try:
|
|
ErrorCode, Expression = ValidFormt.split('|', 1)
|
|
except ValueError:
|
|
ErrorCode = '0x0'
|
|
Expression = ValidFormt
|
|
ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
|
|
try:
|
|
if not eval(ErrorCodeValid % ErrorCode):
|
|
EdkLogger.warn('Parser', '@ValidRange ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
|
|
except:
|
|
EdkLogger.warn('Parser', '@ValidRange ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
|
|
if not PatternValidRng.search(Expression):
|
|
EdkLogger.warn('Parser', '@ValidRange Expression(%s) of PCD %s is incorrect format.' % (Expression, TokenList[0]))
|
|
if ValidFormt[0:10] == '@ValidList':
|
|
ValidFormt = ValidFormt[10:]
|
|
ValidFormt = ValidFormt.lstrip()
|
|
try:
|
|
ErrorCode, Expression = ValidFormt.split('|', 1)
|
|
except ValueError:
|
|
ErrorCode = '0x0'
|
|
Expression = ValidFormt
|
|
ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
|
|
try:
|
|
if not eval(ErrorCodeValid % ErrorCode):
|
|
EdkLogger.warn('Parser', '@ValidList ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
|
|
except:
|
|
EdkLogger.warn('Parser', '@ValidList ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
|
|
Values = Expression.split(',')
|
|
for Value in Values:
|
|
Value = Value.strip()
|
|
try:
|
|
eval(Value)
|
|
except:
|
|
EdkLogger.warn('Parser', '@ValidList Expression of PCD %s include a invalid value(%s).' % (TokenList[0], Value))
|
|
break
|
|
if ValidFormt[0:11] == '@Expression':
|
|
ValidFormt = ValidFormt[11:]
|
|
ValidFormt = ValidFormt.lstrip()
|
|
try:
|
|
ErrorCode, Expression = ValidFormt.split('|', 1)
|
|
except ValueError:
|
|
ErrorCode = '0x0'
|
|
Expression = ValidFormt
|
|
ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
|
|
try:
|
|
if not eval(ErrorCodeValid % ErrorCode):
|
|
EdkLogger.warn('Parser', '@Expression ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
|
|
except:
|
|
EdkLogger.warn('Parser', '@Expression ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
|
|
if not Expression:
|
|
EdkLogger.warn('Parser', '@Expression Expression of PCD %s is incorrect format.' % TokenList[0])
|
|
if not Description:
|
|
EdkLogger.warn('Parser', 'PCD %s Description information is not provided.' % TokenList[0])
|
|
if not Prompt:
|
|
EdkLogger.warn('Parser', 'PCD %s Prompt information is not provided.' % TokenList[0])
|
|
# check Description, Prompt localization information
|
|
if self._UniObj:
|
|
self._UniObj.CheckPcdInfo(TokenList[0])
|
|
|
|
if ValueList[0] in ['True', 'true', 'TRUE']:
|
|
ValueList[0] = '1'
|
|
elif ValueList[0] in ['False', 'false', 'FALSE']:
|
|
ValueList[0] = '0'
|
|
|
|
self._ValueList[2] = ValueList[0].strip() + '|' + ValueList[1].strip() + '|' + ValueList[2].strip()
|
|
|
|
_SectionParser = {
|
|
MODEL_META_DATA_HEADER : MetaFileParser._DefineParser,
|
|
MODEL_EFI_INCLUDE : MetaFileParser._PathParser,
|
|
MODEL_EFI_LIBRARY_CLASS : MetaFileParser._PathParser,
|
|
MODEL_EFI_GUID : _GuidParser,
|
|
MODEL_EFI_PPI : _GuidParser,
|
|
MODEL_EFI_PROTOCOL : _GuidParser,
|
|
MODEL_PCD_FIXED_AT_BUILD : _PcdParser,
|
|
MODEL_PCD_PATCHABLE_IN_MODULE : _PcdParser,
|
|
MODEL_PCD_FEATURE_FLAG : _PcdParser,
|
|
MODEL_PCD_DYNAMIC : _PcdParser,
|
|
MODEL_PCD_DYNAMIC_EX : _PcdParser,
|
|
MODEL_UNKNOWN : MetaFileParser._Skip,
|
|
MODEL_META_DATA_USER_EXTENSION : MetaFileParser._Skip,
|
|
}
|
|
|
|
|
|
## Fdf
|
|
#
|
|
# This class defined the structure used in Fdf object
|
|
#
|
|
# @param Filename: Input value for Ffilename of Fdf file, default is None
|
|
# @param WorkspaceDir: Input value for current workspace directory, default is None
|
|
#
|
|
class Fdf(object):
|
|
def __init__(self, Filename = None, IsToDatabase = False, WorkspaceDir = None, Database = None):
|
|
self.WorkspaceDir = WorkspaceDir
|
|
self.IsToDatabase = IsToDatabase
|
|
|
|
self.Cur = Database.Cur
|
|
self.TblFile = Database.TblFile
|
|
self.TblFdf = Database.TblFdf
|
|
self.FileID = -1
|
|
self.FileList = {}
|
|
|
|
#
|
|
# Load Fdf file if filename is not None
|
|
#
|
|
if Filename is not None:
|
|
try:
|
|
self.LoadFdfFile(Filename)
|
|
except Exception:
|
|
pass
|
|
|
|
#
|
|
# Insert a FDF file record into database
|
|
#
|
|
def InsertFile(self, Filename):
|
|
FileID = -1
|
|
Filename = NormPath(Filename)
|
|
if Filename not in self.FileList:
|
|
FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_FDF)
|
|
self.FileList[Filename] = FileID
|
|
|
|
return self.FileList[Filename]
|
|
|
|
|
|
## Load Fdf file
|
|
#
|
|
# Load the file if it exists
|
|
#
|
|
# @param Filename: Input value for filename of Fdf file
|
|
#
|
|
def LoadFdfFile(self, Filename):
|
|
FileList = []
|
|
#
|
|
# Parse Fdf file
|
|
#
|
|
Filename = NormPath(Filename)
|
|
Fdf = FdfParser(Filename)
|
|
Fdf.ParseFile()
|
|
|
|
#
|
|
# Insert inf file and pcd information
|
|
#
|
|
if self.IsToDatabase:
|
|
(Model, Value1, Value2, Value3, Scope1, Scope2, BelongsToItem, BelongsToFile, StartLine, StartColumn, EndLine, EndColumn, Enabled) = \
|
|
(0, '', '', '', 'COMMON', 'COMMON', -1, -1, -1, -1, -1, -1, 0)
|
|
for Index in range(0, len(Fdf.Profile.PcdDict)):
|
|
pass
|
|
for Key in Fdf.Profile.PcdDict.keys():
|
|
Model = MODEL_PCD
|
|
Value1 = Key[1]
|
|
Value2 = Key[0]
|
|
FileName = Fdf.Profile.PcdFileLineDict[Key][0]
|
|
StartLine = Fdf.Profile.PcdFileLineDict[Key][1]
|
|
BelongsToFile = self.InsertFile(FileName)
|
|
self.TblFdf.Insert(Model, Value1, Value2, Value3, Scope1, Scope2, BelongsToItem, BelongsToFile, StartLine, StartColumn, EndLine, EndColumn, Enabled)
|
|
for Index in range(0, len(Fdf.Profile.InfList)):
|
|
Model = MODEL_META_DATA_COMPONENT
|
|
Value1 = Fdf.Profile.InfList[Index]
|
|
Value2 = ''
|
|
FileName = Fdf.Profile.InfFileLineList[Index][0]
|
|
StartLine = Fdf.Profile.InfFileLineList[Index][1]
|
|
BelongsToFile = self.InsertFile(FileName)
|
|
self.TblFdf.Insert(Model, Value1, Value2, Value3, Scope1, Scope2, BelongsToItem, BelongsToFile, StartLine, StartColumn, EndLine, EndColumn, Enabled)
|
|
|
|
class UniParser(object):
|
|
# IsExtraUni defined the UNI file is Module UNI or extra Module UNI
|
|
# IsModuleUni defined the UNI file is Module UNI or Package UNI
|
|
def __init__(self, FilePath, IsExtraUni=False, IsModuleUni=True):
|
|
self.FilePath = FilePath
|
|
self.FileName = os.path.basename(FilePath)
|
|
self.IsExtraUni = IsExtraUni
|
|
self.IsModuleUni = IsModuleUni
|
|
self.FileIn = None
|
|
self.Missing = []
|
|
self.__read()
|
|
|
|
def __read(self):
|
|
try:
|
|
self.FileIn = CodecOpenLongFilePath(self.FilePath, Mode='rb', Encoding='utf_8').read()
|
|
except UnicodeError:
|
|
self.FileIn = CodecOpenLongFilePath(self.FilePath, Mode='rb', Encoding='utf_16').read()
|
|
except UnicodeError:
|
|
self.FileIn = CodecOpenLongFilePath(self.FilePath, Mode='rb', Encoding='utf_16_le').read()
|
|
except IOError:
|
|
self.FileIn = ""
|
|
|
|
def Start(self):
|
|
if self.IsModuleUni:
|
|
if self.IsExtraUni:
|
|
ModuleName = self.CheckKeyValid('STR_PROPERTIES_MODULE_NAME')
|
|
self.PrintLog('STR_PROPERTIES_MODULE_NAME', ModuleName)
|
|
else:
|
|
ModuleAbstract = self.CheckKeyValid('STR_MODULE_ABSTRACT')
|
|
self.PrintLog('STR_MODULE_ABSTRACT', ModuleAbstract)
|
|
ModuleDescription = self.CheckKeyValid('STR_MODULE_DESCRIPTION')
|
|
self.PrintLog('STR_MODULE_DESCRIPTION', ModuleDescription)
|
|
else:
|
|
if self.IsExtraUni:
|
|
PackageName = self.CheckKeyValid('STR_PROPERTIES_PACKAGE_NAME')
|
|
self.PrintLog('STR_PROPERTIES_PACKAGE_NAME', PackageName)
|
|
else:
|
|
PackageAbstract = self.CheckKeyValid('STR_PACKAGE_ABSTRACT')
|
|
self.PrintLog('STR_PACKAGE_ABSTRACT', PackageAbstract)
|
|
PackageDescription = self.CheckKeyValid('STR_PACKAGE_DESCRIPTION')
|
|
self.PrintLog('STR_PACKAGE_DESCRIPTION', PackageDescription)
|
|
|
|
def CheckKeyValid(self, Key, Contents=None):
|
|
if not Contents:
|
|
Contents = self.FileIn
|
|
KeyPattern = re.compile('#string\s+%s\s+.*?#language.*?".*?"' % Key, re.S)
|
|
if KeyPattern.search(Contents):
|
|
return True
|
|
return False
|
|
|
|
def CheckPcdInfo(self, PcdCName):
|
|
PromptKey = 'STR_%s_PROMPT' % PcdCName.replace('.', '_')
|
|
PcdPrompt = self.CheckKeyValid(PromptKey)
|
|
self.PrintLog(PromptKey, PcdPrompt)
|
|
HelpKey = 'STR_%s_HELP' % PcdCName.replace('.', '_')
|
|
PcdHelp = self.CheckKeyValid(HelpKey)
|
|
self.PrintLog(HelpKey, PcdHelp)
|
|
|
|
def PrintLog(self, Key, Value):
|
|
if not Value and Key not in self.Missing:
|
|
Msg = '%s is missing in the %s file.' % (Key, self.FileName)
|
|
EdkLogger.warn('Parser', Msg)
|
|
EccGlobalData.gDb.TblReport.Insert(EccToolError.ERROR_GENERAL_CHECK_UNI_HELP_INFO, OtherMsg=Msg, BelongsToTable='File', BelongsToItem=-2)
|
|
self.Missing.append(Key)
|
|
|
|
##
|
|
#
|
|
# This acts like the main() function for the script, unless it is 'import'ed into another
|
|
# script.
|
|
#
|
|
if __name__ == '__main__':
|
|
pass
|
|
|