]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/Python/Workspace/MetaFileParser.py
Sync BaseTools Trunk (version r2518) to EDKII main trunk.
[mirror_edk2.git] / BaseTools / Source / Python / Workspace / MetaFileParser.py
index d907b11ba11ac07053fe9c1688deee8eeb1ddf64..a6668774b570371fd3b8af039abeea1edeabaa61 100644 (file)
@@ -59,17 +59,29 @@ def ParseMacro(Parser):
             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)
 
-        self._ItemType = self.DataType[Type]
+        Value = ReplaceMacro(Value, self._Macros)
+        if Type in self.DataType:
+            self._ItemType = self.DataType[Type]
+        else:
+            self._ItemType = MODEL_META_DATA_DEFINE
         # DEFINE defined macros
-        if self._ItemType == MODEL_META_DATA_DEFINE:
-            if self._SectionType == MODEL_META_DATA_HEADER:
-                self._FileLocalMacros[Name] = Value
+        if Type == TAB_DSC_DEFINES_DEFINE:
+            #
+            # First judge whether this DEFINE is in conditional directive statements or not.
+            #
+            if type(self) == DscParser and self._InDirective > -1:
+                pass
             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
+                if type(self) == DecParser:
+                    if MODEL_META_DATA_HEADER in self._SectionType:
+                        self._FileLocalMacros[Name] = Value
+                    else:
+                        self._ConstructSectionMacroDict(Name, Value)
+                elif self._SectionType == MODEL_META_DATA_HEADER:
+                    self._FileLocalMacros[Name] = Value
+                else:
+                    self._ConstructSectionMacroDict(Name, Value)
+
         # EDK_GLOBAL defined macros
         elif type(self) != DscParser:
             EdkLogger.error('Parser', FORMAT_INVALID, "EDK_GLOBAL can only be used in .dsc file",
@@ -310,6 +322,7 @@ class MetaFileParser(object):
             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':
@@ -319,7 +332,6 @@ class MetaFileParser(object):
                 EdkLogger.error('Parser', FORMAT_INVALID, "Invalid version number",
                                 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
 
-        Value = ReplaceMacro(Value, self._Macros)
         if type(self) == InfParser and self._Version < 0x00010005:
             # EDK module allows using defines as macros
             self._FileLocalMacros[Name] = Value
@@ -328,6 +340,7 @@ class MetaFileParser(object):
     ## [BuildOptions] section parser
     @ParseMacro
     def _BuildOptionParser(self):
+        self._CurrentLine = CleanString(self._CurrentLine, BuildOption=True)
         TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
         TokenList2 = GetSplitValueList(TokenList[0], ':', 1)
         if len(TokenList2) == 2:
@@ -354,15 +367,59 @@ class MetaFileParser(object):
         Macros.update(self._GetApplicableSectionMacro())
         return Macros
 
+    ## Construct section Macro dict 
+    def _ConstructSectionMacroDict(self, Name, Value):
+        ScopeKey = [(Scope[0], Scope[1]) for Scope in self._Scope]
+        ScopeKey = tuple(ScopeKey)
+        SectionDictKey = self._SectionType, ScopeKey
+        #
+        # DecParser SectionType is a list, will contain more than one item only in Pcd Section
+        # As Pcd section macro usage is not alllowed, so here it is safe
+        #
+        if type(self) == DecParser:
+            SectionDictKey = self._SectionType[0], ScopeKey
+        if SectionDictKey not in self._SectionsMacroDict:
+            self._SectionsMacroDict[SectionDictKey] = {}
+        SectionLocalMacros = self._SectionsMacroDict[SectionDictKey]
+        SectionLocalMacros[Name] = Value
 
     ## 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 SectionType, Scope1, Scope2 in self._SectionsMacroDict:
-            if (SectionType == self._SectionType) and (Scope1 == self._Scope[0][0] or Scope1 == "COMMON") and (Scope2 == self._Scope[0][1] or Scope2 == "COMMON"):
-                Macros.update(self._SectionsMacroDict[(SectionType, Scope1, Scope2)])
+        ComComMacroDict = {}
+        ComSpeMacroDict = {}
+        SpeSpeMacroDict = {}
+        
+        ActiveSectionType = self._SectionType
+        if type(self) == DecParser:
+            ActiveSectionType = self._SectionType[0]
+            
+        for (SectionType, Scope) in self._SectionsMacroDict:
+            if SectionType != ActiveSectionType:
+                continue
+
+            for ActiveScope in self._Scope:
+                Scope0, Scope1 = ActiveScope[0], ActiveScope[1]
+                if(Scope0, Scope1) not in Scope:
+                    break
+            else:
+                SpeSpeMacroDict.update(self._SectionsMacroDict[(SectionType, Scope)])
+            
+            for ActiveScope in self._Scope:
+                Scope0, Scope1 = ActiveScope[0], ActiveScope[1]
+                if(Scope0, Scope1) not in Scope and (Scope0, "COMMON") not in Scope and ("COMMON", Scope1) not in Scope:
+                    break
+            else:
+                ComSpeMacroDict.update(self._SectionsMacroDict[(SectionType, Scope)])
+
+            if ("COMMON", "COMMON") in Scope:
+                ComComMacroDict.update(self._SectionsMacroDict[(SectionType, Scope)])
+
+        Macros.update(ComComMacroDict)
+        Macros.update(ComSpeMacroDict)
+        Macros.update(SpeSpeMacroDict)
 
         return Macros
 
@@ -499,7 +556,8 @@ class InfParser(MetaFileParser):
             self._ValueList = ['','','']
             # parse current line, result will be put in self._ValueList
             self._SectionParser[self._SectionType](self)
-            if self._ValueList == None:
+            if self._ValueList == None or self._ItemType == MODEL_META_DATA_DEFINE:
+                self._ItemType = -1
                 continue
             #
             # Model, Value1, Value2, Value3, Arch, Platform, BelongsToItem=-1,
@@ -733,7 +791,12 @@ class DscParser(MetaFileParser):
         self._DirectiveStack = []
         self._DirectiveEvalStack = []
         self._Enabled = 1
-
+        
+        #
+        # Specify whether current line is in uncertain condition
+        #
+        self._InDirective = -1
+        
         # Final valid replacable symbols
         self._Symbols = {}
         #
@@ -838,12 +901,22 @@ class DscParser(MetaFileParser):
         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', '!IFNDEF']:
+            self._InDirective += 1
+
+        if DirectiveName in ['!ENDIF']:
+            self._InDirective -= 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]
+        Scope = [['COMMON', 'COMMON']]
+        if ItemType == MODEL_META_DATA_INCLUDE:
+            Scope = self._Scope
         if ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF:
             # Remove all directives between !if and !endif, including themselves
             while self._DirectiveStack:
@@ -876,21 +949,22 @@ class DscParser(MetaFileParser):
         # 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._From,
-                                self._LineIndex+1,
-                                -1,
-                                self._LineIndex+1,
-                                -1,
-                                0
-                                )
+        for Arch, ModuleType in Scope:
+            self._LastItem = self._Store(
+                                    ItemType,
+                                    self._ValueList[0],
+                                    self._ValueList[1],
+                                    self._ValueList[2],
+                                    Arch,
+                                    ModuleType,
+                                    self._Owner[-1],
+                                    self._From,
+                                    self._LineIndex+1,
+                                    -1,
+                                    self._LineIndex+1,
+                                    -1,
+                                    0
+                                    )
 
     ## [defines] section parser
     @ParseMacro
@@ -923,6 +997,7 @@ class DscParser(MetaFileParser):
         self._ValueList[0:len(TokenList)] = TokenList
 
     ## Parse Edk style of library modules
+    @ParseMacro
     def _LibraryInstanceParser(self):
         self._ValueList[0] = self._CurrentLine
 
@@ -995,6 +1070,7 @@ class DscParser(MetaFileParser):
     ## [BuildOptions] section parser
     @ParseMacro
     def _BuildOptionParser(self):
+        self._CurrentLine = CleanString(self._CurrentLine, BuildOption=True)
         TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
         TokenList2 = GetSplitValueList(TokenList[0], ':', 1)
         if len(TokenList2) == 2:
@@ -1084,6 +1160,21 @@ class DscParser(MetaFileParser):
             self._ContentIndex += 1
 
             self._Scope = [[S1, S2]]
+            #
+            # For !include directive, handle it specially,
+            # merge arch and module type in case of duplicate items
+            #
+            while self._ItemType == MODEL_META_DATA_INCLUDE:
+                if self._ContentIndex >= len(self._Content):
+                    break
+                Record = self._Content[self._ContentIndex]
+                if LineStart == Record[9] and LineEnd == Record[11]:
+                    if [Record[5], Record[6]] not in self._Scope:
+                        self._Scope.append([Record[5], Record[6]])
+                    self._ContentIndex += 1
+                else:
+                    break
+
             self._LineIndex = LineStart - 1
             self._ValueList = [V1, V2, V3]
 
@@ -1094,9 +1185,23 @@ class DscParser(MetaFileParser):
                 # Only catch expression evaluation error here. We need to report
                 # the precise number of line on which the error occurred
                 #
-                EdkLogger.error('Parser', FORMAT_INVALID, "Invalid expression: %s" % str(Excpt),
-                                File=self._FileWithError, ExtraData=' '.join(self._ValueList), 
-                                Line=self._LineIndex+1)
+                if hasattr(Excpt, 'Pcd'):
+                    if Excpt.Pcd in GlobalData.gPlatformOtherPcds:
+                        Info = GlobalData.gPlatformOtherPcds[Excpt.Pcd]
+                        EdkLogger.error('Parser', FORMAT_INVALID, "Cannot use this PCD (%s) in an expression as"
+                                        " it must be defined in a [PcdsFixedAtBuild] or [PcdsFeatureFlag] section"
+                                        " of the DSC file, and it is currently defined in this section:"
+                                        " %s, line #: %d." % (Excpt.Pcd, Info[0], Info[1]),
+                                    File=self._FileWithError, ExtraData=' '.join(self._ValueList), 
+                                    Line=self._LineIndex+1)
+                    else:
+                        EdkLogger.error('Parser', FORMAT_INVALID, "PCD (%s) is not defined in DSC file" % Excpt.Pcd,
+                                    File=self._FileWithError, ExtraData=' '.join(self._ValueList), 
+                                    Line=self._LineIndex+1)
+                else:
+                    EdkLogger.error('Parser', FORMAT_INVALID, "Invalid expression: %s" % str(Excpt),
+                                    File=self._FileWithError, ExtraData=' '.join(self._ValueList), 
+                                    Line=self._LineIndex+1)
             except MacroException, Excpt:
                 EdkLogger.error('Parser', FORMAT_INVALID, str(Excpt),
                                 File=self._FileWithError, ExtraData=' '.join(self._ValueList), 
@@ -1146,29 +1251,29 @@ class DscParser(MetaFileParser):
         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 
+            Name = TokenSpaceGuid + '.' + PcdName
             self._Symbols[Name] = Value
 
+        Content = open(str(self.MetaFile), 'r').readlines()
+        GlobalData.gPlatformOtherPcds['DSCFILE'] = str(self.MetaFile)
+        for PcdType in (MODEL_PCD_PATCHABLE_IN_MODULE, MODEL_PCD_DYNAMIC_DEFAULT, MODEL_PCD_DYNAMIC_HII,
+                        MODEL_PCD_DYNAMIC_VPD, MODEL_PCD_DYNAMIC_EX_DEFAULT, MODEL_PCD_DYNAMIC_EX_HII,
+                        MODEL_PCD_DYNAMIC_EX_VPD):
+            Records = self._RawTable.Query(PcdType, BelongsToItem=-1.0)
+            for TokenSpaceGuid,PcdName,Value,Dummy2,Dummy3,ID,Line in Records:
+                Name = TokenSpaceGuid + '.' + PcdName
+                if Name not in GlobalData.gPlatformOtherPcds:
+                    PcdLine = Line
+                    while not Content[Line - 1].lstrip().startswith(TAB_SECTION_START):
+                        Line -= 1
+                    GlobalData.gPlatformOtherPcds[Name] = (CleanString(Content[Line - 1]), PcdLine, PcdType)
+
     def __ProcessDefine(self):
         if not self._Enabled:
             return
@@ -1179,11 +1284,7 @@ class DscParser(MetaFileParser):
             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
+                self._ConstructSectionMacroDict(Name, Value)
         elif self._ItemType == MODEL_META_DATA_GLOBAL_DEFINE:
             GlobalData.gEdkGlobal[Name] = Value
         
@@ -1234,8 +1335,9 @@ class DscParser(MetaFileParser):
             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._DirectiveStack.append(self._ItemType)
             self._DirectiveEvalStack[-1] = not self._DirectiveEvalStack[-1]
+            self._DirectiveEvalStack.append(True)
         elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF:
             # Back to the nearest !if/!ifdef/!ifndef
             while self._DirectiveStack:
@@ -1243,7 +1345,6 @@ class DscParser(MetaFileParser):
                 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:
@@ -1324,14 +1425,47 @@ class DscParser(MetaFileParser):
         self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros, RaiseError=True)
 
     def __ProcessPcd(self):
+        PcdValue = None
         ValueList = GetSplitValueList(self._ValueList[2])
+        #
+        # PCD value can be an expression
+        #
         if len(ValueList) > 1 and ValueList[1] == 'VOID*':
+            PcdValue = ValueList[0]      
+            try:
+                ValueList[0] = ValueExpression(PcdValue, self._Macros)(True)
+            except WrnExpression, Value:
+                ValueList[0] = Value.result
             PcdValue = ValueList[0]
-            ValueList[0] = ReplaceMacro(PcdValue, self._Macros)
         else:
-            PcdValue = ValueList[-1]
-            ValueList[-1] = ReplaceMacro(PcdValue, self._Macros)
-
+            #
+            # Int*/Boolean VPD PCD
+            # TokenSpace | PcdCName | Offset | [Value]
+            # 
+            # VOID* VPD PCD
+            # TokenSpace | PcdCName | Offset | [Size] | [Value]
+            #
+            if self._ItemType == MODEL_PCD_DYNAMIC_VPD:
+                if len(ValueList) >= 4:
+                    PcdValue = ValueList[-1]
+            else:
+                PcdValue = ValueList[-1]
+            #
+            # For the VPD PCD, there may not have PcdValue data in DSC file
+            #
+            if PcdValue:
+                try:
+                    ValueList[-1] = ValueExpression(PcdValue, self._Macros)(True)
+                except WrnExpression, Value:
+                    ValueList[-1] = Value.result
+                
+                if ValueList[-1] == 'True':
+                    ValueList[-1] = '1'
+                if ValueList[-1] == 'False':
+                    ValueList[-1] = '0'
+                PcdValue = ValueList[-1]
+        if PcdValue and self._ItemType in [MODEL_PCD_FEATURE_FLAG, MODEL_PCD_FIXED_AT_BUILD]:
+            GlobalData.gPlatformPcds[TAB_SPLIT.join(self._ValueList[0:2])] = PcdValue
         self._ValueList[2] = '|'.join(ValueList)
 
     def __ProcessComponent(self):
@@ -1380,6 +1514,7 @@ 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,
@@ -1441,7 +1576,8 @@ class DecParser(MetaFileParser):
             # section content
             self._ValueList = ['','','']
             self._SectionParser[self._SectionType[0]](self)
-            if self._ValueList == None:
+            if self._ValueList == None or self._ItemType == MODEL_META_DATA_DEFINE:
+                self._ItemType = -1
                 self._Comments = []
                 continue
 
@@ -1482,6 +1618,7 @@ class DecParser(MetaFileParser):
             self._Comments = []
         self._Done()
 
+
     ## Section header parser
     #
     #   The section header is always in following format: