Reviewed-by: Liming Gao <liming....@intel.com>

-----Original Message-----
From: Zhu, Yonghong 
Sent: Tuesday, May 10, 2016 6:17 PM
To: edk2-devel@lists.01.org
Cc: Gao, Liming <liming....@intel.com>
Subject: [Patch] BaseTools: support private package definition

EDKII build spec and DEC spec updated to support private package
definition.
If GUID, Protocol or PPI is listed in a DEC file, where the  Private
modifier is used in the section tag ([Guids.common.Private] for example),
only modules within the package are permitted to use the GUID, Protocol
or PPI. If a module or library instance outside of the package attempts
to use the item, the build must fail with an appropriate error message.

Cc: Liming Gao <liming....@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Yonghong Zhu <yonghong....@intel.com>
---
 BaseTools/Source/Python/AutoGen/AutoGen.py         | 10 ++--
 BaseTools/Source/Python/Common/Misc.py             | 29 ++++++++---
 .../Source/Python/Workspace/MetaFileParser.py      | 12 +++++
 BaseTools/Source/Python/Workspace/MetaFileTable.py |  4 +-
 .../Source/Python/Workspace/WorkspaceDatabase.py   | 59 +++++++++++++++++-----
 5 files changed, 90 insertions(+), 24 deletions(-)

diff --git a/BaseTools/Source/Python/AutoGen/AutoGen.py 
b/BaseTools/Source/Python/AutoGen/AutoGen.py
index ae0f8a6..2f2bed0 100644
--- a/BaseTools/Source/Python/AutoGen/AutoGen.py
+++ b/BaseTools/Source/Python/AutoGen/AutoGen.py
@@ -2172,11 +2172,11 @@ class PlatformAutoGen(AutoGen):
             self._OverridePcd(PcdInModule, PcdInPlatform, Module)
             # resolve the VariableGuid value
             for SkuId in PcdInModule.SkuInfoList:
                 Sku = PcdInModule.SkuInfoList[SkuId]
                 if Sku.VariableGuid == '': continue
-                Sku.VariableGuidValue = GuidValue(Sku.VariableGuid, 
self.PackageList)
+                Sku.VariableGuidValue = GuidValue(Sku.VariableGuid, 
self.PackageList, self.MetaFile.Path)
                 if Sku.VariableGuidValue == None:
                     PackageList = "\n\t".join([str(P) for P in 
self.PackageList])
                     EdkLogger.error(
                                 'build',
                                 RESOURCE_NOT_AVAILABLE,
@@ -3392,11 +3392,15 @@ class ModuleAutoGen(AutoGen):
 
             for Package in self.Module.Packages:
                 PackageDir = mws.join(self.WorkspaceDir, Package.MetaFile.Dir)
                 if PackageDir not in self._IncludePathList:
                     self._IncludePathList.append(PackageDir)
-                for Inc in Package.Includes:
+                IncludesList = Package.Includes
+                if Package._PrivateIncludes:
+                    if not self.MetaFile.Path.startswith(PackageDir):
+                        IncludesList = 
list(set(Package.Includes).difference(set(Package._PrivateIncludes)))
+                for Inc in IncludesList:
                     if Inc not in self._IncludePathList:
                         self._IncludePathList.append(str(Inc))
         return self._IncludePathList
 
     def _GetIncludePathLength(self):
@@ -3459,11 +3463,11 @@ class ModuleAutoGen(AutoGen):
             if Pcd.Type != TAB_PCDS_DYNAMIC_EX_HII:
                 continue
             for SkuName in Pcd.SkuInfoList:
                 SkuInfo = Pcd.SkuInfoList[SkuName]
                 Name = ConvertStringToByteArray(SkuInfo.VariableName)
-                Value = GuidValue(SkuInfo.VariableGuid, 
self.PlatformInfo.PackageList)
+                Value = GuidValue(SkuInfo.VariableGuid, 
self.PlatformInfo.PackageList, self.MetaFile.Path)
                 if not Value:
                     continue
                 Guid = GuidStructureStringToGuidString(Value)
                 if (Name, Guid) in NameGuids and Pcd not in HiiExPcds:
                     HiiExPcds.append(Pcd)
diff --git a/BaseTools/Source/Python/Common/Misc.py 
b/BaseTools/Source/Python/Common/Misc.py
index 777450d..c99716d 100644
--- a/BaseTools/Source/Python/Common/Misc.py
+++ b/BaseTools/Source/Python/Common/Misc.py
@@ -1,9 +1,9 @@
 ## @file
 # Common routines used by all tools
 #
-# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
 # This program and the accompanying materials
 # are licensed and made available under the terms and conditions of the BSD 
License
 # which accompanies this distribution.  The full text of the license may be 
found at
 # http://opensource.org/licenses/bsd-license.php
 #
@@ -792,45 +792,60 @@ def GetRelPath(Path1, Path2):
 
 ## Get GUID value from given packages
 #
 #   @param      CName           The CName of the GUID
 #   @param      PackageList     List of packages looking-up in
+#   @param      Inffile         The driver file
 #
 #   @retval     GuidValue   if the CName is found in any given package
 #   @retval     None        if the CName is not found in all given packages
 #
-def GuidValue(CName, PackageList):
+def GuidValue(CName, PackageList, Inffile = None):
     for P in PackageList:
-        if CName in P.Guids:
+        GuidKeys = P.Guids.keys()
+        if Inffile and P._PrivateGuids:
+            if not Inffile.startswith(P.MetaFile.Dir):
+                GuidKeys = (dict.fromkeys(x for x in P.Guids if x not in 
P._PrivateGuids)).keys()
+        if CName in GuidKeys:
             return P.Guids[CName]
     return None
 
 ## Get Protocol value from given packages
 #
 #   @param      CName           The CName of the GUID
 #   @param      PackageList     List of packages looking-up in
+#   @param      Inffile         The driver file
 #
 #   @retval     GuidValue   if the CName is found in any given package
 #   @retval     None        if the CName is not found in all given packages
 #
-def ProtocolValue(CName, PackageList):
+def ProtocolValue(CName, PackageList, Inffile = None):
     for P in PackageList:
-        if CName in P.Protocols:
+        ProtocolKeys = P.Protocols.keys()
+        if Inffile and P._PrivateProtocols:
+            if not Inffile.startswith(P.MetaFile.Dir):
+                ProtocolKeys = (dict.fromkeys(x for x in P.Protocols if x not 
in P._PrivateProtocols)).keys()
+        if CName in ProtocolKeys:
             return P.Protocols[CName]
     return None
 
 ## Get PPI value from given packages
 #
 #   @param      CName           The CName of the GUID
 #   @param      PackageList     List of packages looking-up in
+#   @param      Inffile         The driver file
 #
 #   @retval     GuidValue   if the CName is found in any given package
 #   @retval     None        if the CName is not found in all given packages
 #
-def PpiValue(CName, PackageList):
+def PpiValue(CName, PackageList, Inffile = None):
     for P in PackageList:
-        if CName in P.Ppis:
+        PpiKeys = P.Ppis.keys()
+        if Inffile and P._PrivatePpis:
+            if not Inffile.startswith(P.MetaFile.Dir):
+                PpiKeys = (dict.fromkeys(x for x in P.Ppis if x not in 
P._PrivatePpis)).keys()
+        if CName in PpiKeys:
             return P.Ppis[CName]
     return None
 
 ## A string template class
 #
diff --git a/BaseTools/Source/Python/Workspace/MetaFileParser.py 
b/BaseTools/Source/Python/Workspace/MetaFileParser.py
index 209f47c..82d874f 100644
--- a/BaseTools/Source/Python/Workspace/MetaFileParser.py
+++ b/BaseTools/Source/Python/Workspace/MetaFileParser.py
@@ -1720,10 +1720,11 @@ class DecParser(MetaFileParser):
     def _SectionHeaderParser(self):
         self._Scope = []
         self._SectionName = ''
         self._SectionType = []
         ArchList = set()
+        PrivateList = set()
         Line = self._CurrentLine.replace("%s%s" % (TAB_COMMA_SPLIT, 
TAB_SPACE_SPLIT), TAB_COMMA_SPLIT)
         for Item in Line[1:-1].split(TAB_COMMA_SPLIT):
             if Item == '':
                 EdkLogger.error("Parser", FORMAT_UNKNOWN_ERROR,
                                 "section name can NOT be empty or incorrectly 
use separator comma",
@@ -1755,20 +1756,31 @@ class DecParser(MetaFileParser):
                 S1 = 'COMMON'
             ArchList.add(S1)
             # S2 may be Platform or ModuleType
             if len(ItemList) > 2:
                 S2 = ItemList[2].upper()
+                # only Includes, GUIDs, PPIs, Protocols section have Private 
tag
+                if self._SectionName in [TAB_INCLUDES.upper(), 
TAB_GUIDS.upper(), TAB_PROTOCOLS.upper(), TAB_PPIS.upper()]:
+                    if S2 != 'PRIVATE':
+                        EdkLogger.error("Parser", FORMAT_INVALID, 'Please use 
keyword "Private" as section tag modifier.',
+                                        File=self.MetaFile, 
Line=self._LineIndex + 1, ExtraData=self._CurrentLine)
             else:
                 S2 = 'COMMON'
+            PrivateList.add(S2)
             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)
 
+        # It is not permissible to mix section tags without the Private 
attribute with section tags with the Private attribute
+        if 'COMMON' in PrivateList and len(PrivateList) > 1:
+            EdkLogger.error('Parser', FORMAT_INVALID, "Can't mix section tags 
without the Private attribute with section tags with the Private attribute",
+                            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:
diff --git a/BaseTools/Source/Python/Workspace/MetaFileTable.py 
b/BaseTools/Source/Python/Workspace/MetaFileTable.py
index 449e56e..ab18070 100644
--- a/BaseTools/Source/Python/Workspace/MetaFileTable.py
+++ b/BaseTools/Source/Python/Workspace/MetaFileTable.py
@@ -1,9 +1,9 @@
 ## @file
 # This file is used to create/update/query/erase a meta file table
 #
-# Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2008 - 2016, Intel Corporation. All rights reserved.<BR>
 # This program and the accompanying materials
 # are licensed and made available under the terms and conditions of the BSD 
License
 # which accompanies this distribution.  The full text of the license may be 
found at
 # http://opensource.org/licenses/bsd-license.php
 #
@@ -216,11 +216,11 @@ class PackageTable(MetaFileTable):
     #
     # @retval:       A recordSet of all found records 
     #
     def Query(self, Model, Arch=None):
         ConditionString = "Model=%s AND Enabled>=0" % Model
-        ValueString = "Value1,Value2,Value3,Scope1,ID,StartLine"
+        ValueString = "Value1,Value2,Value3,Scope1,Scope2,ID,StartLine"
 
         if Arch != None and Arch != 'COMMON':
             ConditionString += " AND (Scope1='%s' OR Scope1='COMMON')" % Arch
 
         SqlCommand = "SELECT %s FROM %s WHERE %s" % (ValueString, self.Table, 
ConditionString)
diff --git a/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py 
b/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py
index 7cd0004..5168e83 100644
--- a/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py
+++ b/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py
@@ -1326,10 +1326,14 @@ class DecBuildData(PackageBuildClassObject):
         self._Guids             = None
         self._Includes          = None
         self._LibraryClasses    = None
         self._Pcds              = None
         self.__Macros           = None
+        self._PrivateProtocols  = None
+        self._PrivatePpis       = None
+        self._PrivateGuids      = None
+        self._PrivateIncludes   = None
 
     ## Get current effective macros
     def _GetMacros(self):
         if self.__Macros == None:
             self.__Macros = {}
@@ -1400,81 +1404,109 @@ class DecBuildData(PackageBuildClassObject):
             #
             # tdict is a special kind of dict, used for selecting correct
             # protocol defition for given ARCH
             #
             ProtocolDict = tdict(True)
+            PrivateProtocolDict = tdict(True)
             NameList = []
+            PrivateNameList = []
             # find out all protocol definitions for specific and 'common' arch
             RecordList = self._RawData[MODEL_EFI_PROTOCOL, self._Arch]
-            for Name, Guid, Dummy, Arch, ID, LineNo in RecordList:
+            for Name, Guid, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList:
+                if PrivateFlag == 'PRIVATE':
+                    if Name not in PrivateNameList:
+                        PrivateNameList.append(Name)
+                        PrivateProtocolDict[Arch, Name] = Guid
                 if Name not in NameList:
                     NameList.append(Name)
                 ProtocolDict[Arch, Name] = Guid
             # use sdict to keep the order
             self._Protocols = sdict()
+            self._PrivateProtocols = sdict()
             for Name in NameList:
                 #
                 # limit the ARCH to self._Arch, if no self._Arch found, tdict
                 # will automatically turn to 'common' ARCH for trying
                 #
                 self._Protocols[Name] = ProtocolDict[self._Arch, Name]
+            for Name in PrivateNameList:
+                self._PrivateProtocols[Name] = PrivateProtocolDict[self._Arch, 
Name]
         return self._Protocols
 
     ## Retrieve PPI definitions (name/value pairs)
     def _GetPpi(self):
         if self._Ppis == None:
             #
             # tdict is a special kind of dict, used for selecting correct
             # PPI defition for given ARCH
             #
             PpiDict = tdict(True)
+            PrivatePpiDict = tdict(True)
             NameList = []
+            PrivateNameList = []
             # find out all PPI definitions for specific arch and 'common' arch
             RecordList = self._RawData[MODEL_EFI_PPI, self._Arch]
-            for Name, Guid, Dummy, Arch, ID, LineNo in RecordList:
+            for Name, Guid, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList:
+                if PrivateFlag == 'PRIVATE':
+                    if Name not in PrivateNameList:
+                        PrivateNameList.append(Name)
+                        PrivatePpiDict[Arch, Name] = Guid
                 if Name not in NameList:
                     NameList.append(Name)
                 PpiDict[Arch, Name] = Guid
             # use sdict to keep the order
             self._Ppis = sdict()
+            self._PrivatePpis = sdict()
             for Name in NameList:
                 #
                 # limit the ARCH to self._Arch, if no self._Arch found, tdict
                 # will automatically turn to 'common' ARCH for trying
                 #
                 self._Ppis[Name] = PpiDict[self._Arch, Name]
+            for Name in PrivateNameList:
+                self._PrivatePpis[Name] = PrivatePpiDict[self._Arch, Name]
         return self._Ppis
 
     ## Retrieve GUID definitions (name/value pairs)
     def _GetGuid(self):
         if self._Guids == None:
             #
             # tdict is a special kind of dict, used for selecting correct
             # GUID defition for given ARCH
             #
             GuidDict = tdict(True)
+            PrivateGuidDict = tdict(True)
             NameList = []
+            PrivateNameList = []
             # find out all protocol definitions for specific and 'common' arch
             RecordList = self._RawData[MODEL_EFI_GUID, self._Arch]
-            for Name, Guid, Dummy, Arch, ID, LineNo in RecordList:
+            for Name, Guid, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList:
+                if PrivateFlag == 'PRIVATE':
+                    if Name not in PrivateNameList:
+                        PrivateNameList.append(Name)
+                        PrivateGuidDict[Arch, Name] = Guid
                 if Name not in NameList:
                     NameList.append(Name)
                 GuidDict[Arch, Name] = Guid
             # use sdict to keep the order
             self._Guids = sdict()
+            self._PrivateGuids = sdict()
             for Name in NameList:
                 #
                 # limit the ARCH to self._Arch, if no self._Arch found, tdict
                 # will automatically turn to 'common' ARCH for trying
                 #
                 self._Guids[Name] = GuidDict[self._Arch, Name]
+            for Name in PrivateNameList:
+                self._PrivateGuids[Name] = PrivateGuidDict[self._Arch, Name]
         return self._Guids
 
     ## Retrieve public include paths declared in this package
     def _GetInclude(self):
         if self._Includes == None:
             self._Includes = []
+            self._PrivateIncludes = []
             RecordList = self._RawData[MODEL_EFI_INCLUDE, self._Arch]
             Macros = self._Macros
             Macros["EDK_SOURCE"] = GlobalData.gEcpSource
             for Record in RecordList:
                 File = PathClass(NormPath(Record[0], Macros), 
self._PackageDir, Arch=self._Arch)
@@ -1485,10 +1517,13 @@ class DecBuildData(PackageBuildClassObject):
                     EdkLogger.error('build', ErrorCode, ExtraData=ErrorInfo, 
File=self.MetaFile, Line=LineNo)
 
                 # avoid duplicate include path
                 if File not in self._Includes:
                     self._Includes.append(File)
+                if Record[4] == 'PRIVATE':
+                    if File not in self._PrivateIncludes:
+                        self._PrivateIncludes.append(File)
         return self._Includes
 
     ## Retrieve library class declarations (not used in build at present)
     def _GetLibraryClass(self):
         if self._LibraryClasses == None:
@@ -1498,11 +1533,11 @@ class DecBuildData(PackageBuildClassObject):
             #
             LibraryClassDict = tdict(True)
             LibraryClassSet = set()
             RecordList = self._RawData[MODEL_EFI_LIBRARY_CLASS, self._Arch]
             Macros = self._Macros
-            for LibraryClass, File, Dummy, Arch, ID, LineNo in RecordList:
+            for LibraryClass, File, Dummy, Arch, PrivateFlag, ID, LineNo in 
RecordList:
                 File = PathClass(NormPath(File, Macros), self._PackageDir, 
Arch=self._Arch)
                 # check the file validation
                 ErrorCode, ErrorInfo = File.Validate()
                 if ErrorCode != 0:
                     EdkLogger.error('build', ErrorCode, ExtraData=ErrorInfo, 
File=self.MetaFile, Line=LineNo)
@@ -1534,11 +1569,11 @@ class DecBuildData(PackageBuildClassObject):
         PcdDict = tdict(True, 3)
         # for summarizing PCD
         PcdSet = set()
         # find out all PCDs of the 'type'
         RecordList = self._RawData[Type, self._Arch]
-        for TokenSpaceGuid, PcdCName, Setting, Arch, Dummy1, Dummy2 in 
RecordList:
+        for TokenSpaceGuid, PcdCName, Setting, Arch, PrivateFlag, Dummy1, 
Dummy2 in RecordList:
             PcdDict[Arch, PcdCName, TokenSpaceGuid] = Setting
             PcdSet.add((PcdCName, TokenSpaceGuid))
 
         for PcdCName, TokenSpaceGuid in PcdSet:
             #
@@ -2273,11 +2308,11 @@ class InfBuildData(ModuleBuildClassObject):
             self._Protocols = sdict()
             self._ProtocolComments = sdict()
             RecordList = self._RawData[MODEL_EFI_PROTOCOL, self._Arch, 
self._Platform]
             for Record in RecordList:
                 CName = Record[0]
-                Value = ProtocolValue(CName, self.Packages)
+                Value = ProtocolValue(CName, self.Packages, self.MetaFile.Path)
                 if Value == None:
                     PackageList = "\n\t".join([str(P) for P in self.Packages])
                     EdkLogger.error('build', RESOURCE_NOT_AVAILABLE,
                                     "Value of Protocol [%s] is not found under 
[Protocols] section in" % CName,
                                     ExtraData=PackageList, File=self.MetaFile, 
Line=Record[-1])
@@ -2298,11 +2333,11 @@ class InfBuildData(ModuleBuildClassObject):
             self._Ppis = sdict()
             self._PpiComments = sdict()
             RecordList = self._RawData[MODEL_EFI_PPI, self._Arch, 
self._Platform]
             for Record in RecordList:
                 CName = Record[0]
-                Value = PpiValue(CName, self.Packages)
+                Value = PpiValue(CName, self.Packages, self.MetaFile.Path)
                 if Value == None:
                     PackageList = "\n\t".join([str(P) for P in self.Packages])
                     EdkLogger.error('build', RESOURCE_NOT_AVAILABLE,
                                     "Value of PPI [%s] is not found under 
[Ppis] section in " % CName,
                                     ExtraData=PackageList, File=self.MetaFile, 
Line=Record[-1])
@@ -2323,11 +2358,11 @@ class InfBuildData(ModuleBuildClassObject):
             self._Guids = sdict()
             self._GuidComments = sdict()
             RecordList = self._RawData[MODEL_EFI_GUID, self._Arch, 
self._Platform]
             for Record in RecordList:
                 CName = Record[0]
-                Value = GuidValue(CName, self.Packages)
+                Value = GuidValue(CName, self.Packages, self.MetaFile.Path)
                 if Value == None:
                     PackageList = "\n\t".join([str(P) for P in self.Packages])
                     EdkLogger.error('build', RESOURCE_NOT_AVAILABLE,
                                     "Value of Guid [%s] is not found under 
[Guids] section in" % CName,
                                     ExtraData=PackageList, File=self.MetaFile, 
Line=Record[-1])
@@ -2492,15 +2527,15 @@ class InfBuildData(ModuleBuildClassObject):
                             EdkLogger.error('build', RESOURCE_NOT_AVAILABLE, 
"Module is not found in active platform",
                                             ExtraData=Token, 
File=self.MetaFile, Line=Record[-1])
                         DepexList.append(Module.Guid)
                     else:
                         # get the GUID value now
-                        Value = ProtocolValue(Token, self.Packages)
+                        Value = ProtocolValue(Token, self.Packages, 
self.MetaFile.Path)
                         if Value == None:
-                            Value = PpiValue(Token, self.Packages)
+                            Value = PpiValue(Token, self.Packages, 
self.MetaFile.Path)
                             if Value == None:
-                                Value = GuidValue(Token, self.Packages)
+                                Value = GuidValue(Token, self.Packages, 
self.MetaFile.Path)
                         if Value == None:
                             PackageList = "\n\t".join([str(P) for P in 
self.Packages])
                             EdkLogger.error('build', RESOURCE_NOT_AVAILABLE,
                                             "Value of [%s] is not found in" % 
Token,
                                             ExtraData=PackageList, 
File=self.MetaFile, Line=Record[-1])
@@ -2539,11 +2574,11 @@ class InfBuildData(ModuleBuildClassObject):
         for TokenSpaceGuid, PcdCName, Setting, Arch, Platform, Id, LineNo in 
RecordList:
             PcdDict[Arch, Platform, PcdCName, TokenSpaceGuid] = (Setting, 
LineNo)
             PcdList.append((PcdCName, TokenSpaceGuid))
             # get the guid value
             if TokenSpaceGuid not in self.Guids:
-                Value = GuidValue(TokenSpaceGuid, self.Packages)
+                Value = GuidValue(TokenSpaceGuid, self.Packages, 
self.MetaFile.Path)
                 if Value == None:
                     PackageList = "\n\t".join([str(P) for P in self.Packages])
                     EdkLogger.error('build', RESOURCE_NOT_AVAILABLE,
                                     "Value of Guid [%s] is not found under 
[Guids] section in" % TokenSpaceGuid,
                                     ExtraData=PackageList, File=self.MetaFile, 
Line=LineNo)
-- 
2.6.1.windows.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to