BaseTools: Improve build performance of structure PCD value generation
Add cache for building PcdValueInit.c. If PcdValueInit.c is not changed,
it will not be regenerated.
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
(cherry picked from commit 0a57a9782b)
			
			
This commit is contained in:
		@@ -326,6 +326,7 @@ def main():
 | 
				
			|||||||
                                    FvObj.FvRegionInFD = RegionObj.Size
 | 
					                                    FvObj.FvRegionInFD = RegionObj.Size
 | 
				
			||||||
                                    RegionObj.BlockInfoOfRegion(FdObj.BlockSizeList, FvObj)
 | 
					                                    RegionObj.BlockInfoOfRegion(FdObj.BlockSizeList, FvObj)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        GlobalData.BuildOptionPcd     = Options.OptionPcd if Options.OptionPcd else {}
 | 
				
			||||||
        """Call GenFds"""
 | 
					        """Call GenFds"""
 | 
				
			||||||
        GenFds.GenFd('', FdfParserObj, BuildWorkSpace, ArchList)
 | 
					        GenFds.GenFd('', FdfParserObj, BuildWorkSpace, ArchList)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -95,6 +95,7 @@ class DecBuildData(PackageBuildClassObject):
 | 
				
			|||||||
        self._Ppis              = None
 | 
					        self._Ppis              = None
 | 
				
			||||||
        self._Guids             = None
 | 
					        self._Guids             = None
 | 
				
			||||||
        self._Includes          = None
 | 
					        self._Includes          = None
 | 
				
			||||||
 | 
					        self._CommonIncludes    = None
 | 
				
			||||||
        self._LibraryClasses    = None
 | 
					        self._LibraryClasses    = None
 | 
				
			||||||
        self._Pcds              = None
 | 
					        self._Pcds              = None
 | 
				
			||||||
        self.__Macros           = None
 | 
					        self.__Macros           = None
 | 
				
			||||||
@@ -296,7 +297,8 @@ class DecBuildData(PackageBuildClassObject):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    ## Retrieve public include paths declared in this package
 | 
					    ## Retrieve public include paths declared in this package
 | 
				
			||||||
    def _GetInclude(self):
 | 
					    def _GetInclude(self):
 | 
				
			||||||
        if self._Includes == None:
 | 
					        if self._Includes == None or self._CommonIncludes is None:
 | 
				
			||||||
 | 
					            self._CommonIncludes = []
 | 
				
			||||||
            self._Includes = []
 | 
					            self._Includes = []
 | 
				
			||||||
            self._PrivateIncludes = []
 | 
					            self._PrivateIncludes = []
 | 
				
			||||||
            PublicInclues = []
 | 
					            PublicInclues = []
 | 
				
			||||||
@@ -324,7 +326,8 @@ class DecBuildData(PackageBuildClassObject):
 | 
				
			|||||||
                        PublicInclues.append(File)
 | 
					                        PublicInclues.append(File)
 | 
				
			||||||
                    if File in self._PrivateIncludes:
 | 
					                    if File in self._PrivateIncludes:
 | 
				
			||||||
                        EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % File, File=self.MetaFile, Line=LineNo)
 | 
					                        EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % File, File=self.MetaFile, Line=LineNo)
 | 
				
			||||||
 | 
					                if Record[3] == "COMMON":
 | 
				
			||||||
 | 
					                    self._CommonIncludes.append(File)
 | 
				
			||||||
        return self._Includes
 | 
					        return self._Includes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ## Retrieve library class declarations (not used in build at present)
 | 
					    ## Retrieve library class declarations (not used in build at present)
 | 
				
			||||||
@@ -452,6 +455,11 @@ class DecBuildData(PackageBuildClassObject):
 | 
				
			|||||||
            Pcds[pcd.TokenCName, pcd.TokenSpaceGuidCName, self._PCD_TYPE_STRING_[Type]] = pcd
 | 
					            Pcds[pcd.TokenCName, pcd.TokenSpaceGuidCName, self._PCD_TYPE_STRING_[Type]] = pcd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return Pcds
 | 
					        return Pcds
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def CommonIncludes(self):
 | 
				
			||||||
 | 
					        if self._CommonIncludes is None:
 | 
				
			||||||
 | 
					            self.Includes
 | 
				
			||||||
 | 
					        return self._CommonIncludes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _Macros = property(_GetMacros)
 | 
					    _Macros = property(_GetMacros)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,6 +37,7 @@ from Common.Parsing import IsValidWord
 | 
				
			|||||||
from Common.VariableAttributes import VariableAttributes
 | 
					from Common.VariableAttributes import VariableAttributes
 | 
				
			||||||
import Common.GlobalData as GlobalData
 | 
					import Common.GlobalData as GlobalData
 | 
				
			||||||
import subprocess
 | 
					import subprocess
 | 
				
			||||||
 | 
					from Common.Misc import SaveFileOnChange
 | 
				
			||||||
from Workspace.BuildClassObject import PlatformBuildClassObject, StructurePcd, PcdClassObject, ModuleBuildClassObject
 | 
					from Workspace.BuildClassObject import PlatformBuildClassObject, StructurePcd, PcdClassObject, ModuleBuildClassObject
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
@@ -89,7 +90,6 @@ LIBS = $(LIB_PATH)\Common.lib
 | 
				
			|||||||
'''
 | 
					'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PcdGccMakefile = '''
 | 
					PcdGccMakefile = '''
 | 
				
			||||||
ARCH ?= IA32
 | 
					 | 
				
			||||||
MAKEROOT ?= $(EDK_TOOLS_PATH)/Source/C
 | 
					MAKEROOT ?= $(EDK_TOOLS_PATH)/Source/C
 | 
				
			||||||
LIBS = -lCommon
 | 
					LIBS = -lCommon
 | 
				
			||||||
'''
 | 
					'''
 | 
				
			||||||
@@ -156,12 +156,15 @@ class DscBuildData(PlatformBuildClassObject):
 | 
				
			|||||||
        self._ToolChainFamily = None
 | 
					        self._ToolChainFamily = None
 | 
				
			||||||
        self._Clear()
 | 
					        self._Clear()
 | 
				
			||||||
        self._HandleOverridePath()
 | 
					        self._HandleOverridePath()
 | 
				
			||||||
        if os.getenv("WORKSPACE"):
 | 
					        self.WorkspaceDir = os.getenv("WORKSPACE") if os.getenv("WORKSPACE") else ""
 | 
				
			||||||
            self.OutputPath = os.path.join(os.getenv("WORKSPACE"), 'Build', PcdValueInitName)
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            self.OutputPath = os.path.dirname(self.DscFile)
 | 
					 | 
				
			||||||
        self.DefaultStores = None
 | 
					        self.DefaultStores = None
 | 
				
			||||||
        self.SkuIdMgr = SkuClass(self.SkuName, self.SkuIds)
 | 
					        self.SkuIdMgr = SkuClass(self.SkuName, self.SkuIds)
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def OutputPath(self):
 | 
				
			||||||
 | 
					        if os.getenv("WORKSPACE"):
 | 
				
			||||||
 | 
					            return os.path.join(os.getenv("WORKSPACE"), self.OutputDirectory, self._Target + "_" + self._Toolchain,PcdValueInitName)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return os.path.dirname(self.DscFile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ## XXX[key] = value
 | 
					    ## XXX[key] = value
 | 
				
			||||||
    def __setitem__(self, key, value):
 | 
					    def __setitem__(self, key, value):
 | 
				
			||||||
@@ -1300,7 +1303,7 @@ class DscBuildData(PlatformBuildClassObject):
 | 
				
			|||||||
                    str_pcd_obj_str.DefaultFromDSC = {skuname:{defaultstore: str_pcd_obj.SkuInfoList[skuname].DefaultStoreDict.get(defaultstore, str_pcd_obj.SkuInfoList[skuname].DefaultValue) for defaultstore in DefaultStores} for skuname in str_pcd_obj.SkuInfoList}
 | 
					                    str_pcd_obj_str.DefaultFromDSC = {skuname:{defaultstore: str_pcd_obj.SkuInfoList[skuname].DefaultStoreDict.get(defaultstore, str_pcd_obj.SkuInfoList[skuname].DefaultValue) for defaultstore in DefaultStores} for skuname in str_pcd_obj.SkuInfoList}
 | 
				
			||||||
                for str_pcd_data in StrPcdSet[str_pcd]:
 | 
					                for str_pcd_data in StrPcdSet[str_pcd]:
 | 
				
			||||||
                    if str_pcd_data[3] in SkuIds:
 | 
					                    if str_pcd_data[3] in SkuIds:
 | 
				
			||||||
                        str_pcd_obj_str.AddOverrideValue(str_pcd_data[2], str(str_pcd_data[6]), 'DEFAULT' if str_pcd_data[3] == 'COMMON' else str_pcd_data[3],'STANDARD' if str_pcd_data[4] == 'COMMON' else str_pcd_data[4], self.MetaFile.File,LineNo=str_pcd_data[5])
 | 
					                        str_pcd_obj_str.AddOverrideValue(str_pcd_data[2], str(str_pcd_data[6]), 'DEFAULT' if str_pcd_data[3] == 'COMMON' else str_pcd_data[3],'STANDARD' if str_pcd_data[4] == 'COMMON' else str_pcd_data[4], self.MetaFile.File if self.WorkspaceDir not in self.MetaFile.File else self.MetaFile.File[len(self.WorkspaceDir) if self.WorkspaceDir.endswith(os.path.sep) else len(self.WorkspaceDir)+1:],LineNo=str_pcd_data[5])
 | 
				
			||||||
                S_pcd_set[str_pcd[1], str_pcd[0]] = str_pcd_obj_str
 | 
					                S_pcd_set[str_pcd[1], str_pcd[0]] = str_pcd_obj_str
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                EdkLogger.error('build', PARSER_ERROR,
 | 
					                EdkLogger.error('build', PARSER_ERROR,
 | 
				
			||||||
@@ -1809,10 +1812,10 @@ class DscBuildData(PlatformBuildClassObject):
 | 
				
			|||||||
                    Includes[IncludeFile] = True
 | 
					                    Includes[IncludeFile] = True
 | 
				
			||||||
                    CApp = CApp + '#include <%s>\n' % (IncludeFile)
 | 
					                    CApp = CApp + '#include <%s>\n' % (IncludeFile)
 | 
				
			||||||
        CApp = CApp + '\n'
 | 
					        CApp = CApp + '\n'
 | 
				
			||||||
 | 
					 | 
				
			||||||
        for PcdName in StructuredPcds:
 | 
					        for PcdName in StructuredPcds:
 | 
				
			||||||
            Pcd = StructuredPcds[PcdName]
 | 
					            Pcd = StructuredPcds[PcdName]
 | 
				
			||||||
            if not Pcd.SkuOverrideValues:
 | 
					            if not Pcd.SkuOverrideValues or Pcd.Type in [self._PCD_TYPE_STRING_[MODEL_PCD_FIXED_AT_BUILD],
 | 
				
			||||||
 | 
					                        self._PCD_TYPE_STRING_[MODEL_PCD_PATCHABLE_IN_MODULE]]:
 | 
				
			||||||
                InitByteValue, CApp = self.GenerateInitializeFunc(self.SkuIdMgr.SystemSkuId, 'STANDARD', Pcd, InitByteValue, CApp)
 | 
					                InitByteValue, CApp = self.GenerateInitializeFunc(self.SkuIdMgr.SystemSkuId, 'STANDARD', Pcd, InitByteValue, CApp)
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                for SkuName in self.SkuIdMgr.SkuOverrideOrder():
 | 
					                for SkuName in self.SkuIdMgr.SkuOverrideOrder():
 | 
				
			||||||
@@ -1828,7 +1831,7 @@ class DscBuildData(PlatformBuildClassObject):
 | 
				
			|||||||
        CApp = CApp + '  )\n'
 | 
					        CApp = CApp + '  )\n'
 | 
				
			||||||
        CApp = CApp + '{\n'
 | 
					        CApp = CApp + '{\n'
 | 
				
			||||||
        for Pcd in StructuredPcds.values():
 | 
					        for Pcd in StructuredPcds.values():
 | 
				
			||||||
            if not Pcd.SkuOverrideValues:
 | 
					            if not Pcd.SkuOverrideValues or Pcd.Type in [self._PCD_TYPE_STRING_[MODEL_PCD_FIXED_AT_BUILD],self._PCD_TYPE_STRING_[MODEL_PCD_PATCHABLE_IN_MODULE]]:
 | 
				
			||||||
                CApp = CApp + '  Initialize_%s_%s_%s_%s();\n' % (self.SkuIdMgr.SystemSkuId, 'STANDARD', Pcd.TokenSpaceGuidCName, Pcd.TokenCName)
 | 
					                CApp = CApp + '  Initialize_%s_%s_%s_%s();\n' % (self.SkuIdMgr.SystemSkuId, 'STANDARD', Pcd.TokenSpaceGuidCName, Pcd.TokenCName)
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                for SkuName in self.SkuIdMgr.SkuOverrideOrder():
 | 
					                for SkuName in self.SkuIdMgr.SkuOverrideOrder():
 | 
				
			||||||
@@ -1843,13 +1846,11 @@ class DscBuildData(PlatformBuildClassObject):
 | 
				
			|||||||
        if not os.path.exists(self.OutputPath):
 | 
					        if not os.path.exists(self.OutputPath):
 | 
				
			||||||
            os.makedirs(self.OutputPath)
 | 
					            os.makedirs(self.OutputPath)
 | 
				
			||||||
        CAppBaseFileName = os.path.join(self.OutputPath, PcdValueInitName)
 | 
					        CAppBaseFileName = os.path.join(self.OutputPath, PcdValueInitName)
 | 
				
			||||||
        File = open (CAppBaseFileName + '.c', 'w')
 | 
					        SaveFileOnChange(CAppBaseFileName + '.c', CApp, False)
 | 
				
			||||||
        File.write(CApp)
 | 
					 | 
				
			||||||
        File.close()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        MakeApp = PcdMakefileHeader
 | 
					        MakeApp = PcdMakefileHeader
 | 
				
			||||||
        if sys.platform == "win32":
 | 
					        if sys.platform == "win32":
 | 
				
			||||||
            MakeApp = MakeApp + 'ARCH = IA32\nAPPNAME = %s\n' % (PcdValueInitName) + 'OBJECTS = %s\%s.obj\n' % (self.OutputPath, PcdValueInitName) + 'INC = '
 | 
					            MakeApp = MakeApp + 'APPNAME = %s\n' % (PcdValueInitName) + 'OBJECTS = %s\%s.obj\n' % (self.OutputPath, PcdValueInitName) + 'INC = '
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            MakeApp = MakeApp + PcdGccMakefile
 | 
					            MakeApp = MakeApp + PcdGccMakefile
 | 
				
			||||||
            MakeApp = MakeApp + 'APPNAME = %s\n' % (PcdValueInitName) + 'OBJECTS = %s/%s.o\n' % (self.OutputPath, PcdValueInitName) + \
 | 
					            MakeApp = MakeApp + 'APPNAME = %s\n' % (PcdValueInitName) + 'OBJECTS = %s/%s.o\n' % (self.OutputPath, PcdValueInitName) + \
 | 
				
			||||||
@@ -1861,7 +1862,7 @@ class DscBuildData(PlatformBuildClassObject):
 | 
				
			|||||||
                continue
 | 
					                continue
 | 
				
			||||||
            if Cache.Includes:
 | 
					            if Cache.Includes:
 | 
				
			||||||
                if str(Cache.MetaFile.Path) not in PlatformInc:
 | 
					                if str(Cache.MetaFile.Path) not in PlatformInc:
 | 
				
			||||||
                    PlatformInc[str(Cache.MetaFile.Path)] = Cache.Includes
 | 
					                    PlatformInc[str(Cache.MetaFile.Path)] = Cache.CommonIncludes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        PcdDependDEC = []
 | 
					        PcdDependDEC = []
 | 
				
			||||||
        for Pcd in StructuredPcds.values():
 | 
					        for Pcd in StructuredPcds.values():
 | 
				
			||||||
@@ -1925,16 +1926,18 @@ class DscBuildData(PlatformBuildClassObject):
 | 
				
			|||||||
        if sys.platform == "win32":
 | 
					        if sys.platform == "win32":
 | 
				
			||||||
            MakeApp = MakeApp + PcdMakefileEnd
 | 
					            MakeApp = MakeApp + PcdMakefileEnd
 | 
				
			||||||
        MakeFileName = os.path.join(self.OutputPath, 'Makefile')
 | 
					        MakeFileName = os.path.join(self.OutputPath, 'Makefile')
 | 
				
			||||||
        File = open (MakeFileName, 'w')
 | 
					        SaveFileOnChange(MakeFileName, MakeApp, False)
 | 
				
			||||||
        File.write(MakeApp)
 | 
					 | 
				
			||||||
        File.close()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        InputValueFile = os.path.join(self.OutputPath, 'Input.txt')
 | 
					        InputValueFile = os.path.join(self.OutputPath, 'Input.txt')
 | 
				
			||||||
        OutputValueFile = os.path.join(self.OutputPath, 'Output.txt')
 | 
					        OutputValueFile = os.path.join(self.OutputPath, 'Output.txt')
 | 
				
			||||||
        File = open (InputValueFile, 'w')
 | 
					        SaveFileOnChange(InputValueFile, InitByteValue, False)
 | 
				
			||||||
        File.write(InitByteValue)
 | 
					 | 
				
			||||||
        File.close()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        PcdValueInitExe = PcdValueInitName
 | 
				
			||||||
 | 
					        if not sys.platform == "win32":
 | 
				
			||||||
 | 
					            PcdValueInitExe = os.path.join(os.getenv("EDK_TOOLS_PATH"), 'Source', 'C', 'bin', PcdValueInitName)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            PcdValueInitExe = os.path.join(os.getenv("EDK_TOOLS_PATH"), 'Bin', 'Win32', PcdValueInitName) +".exe"
 | 
				
			||||||
 | 
					        if not os.path.exists(PcdValueInitExe) or self.NeedUpdateOutput(OutputValueFile, CAppBaseFileName + '.c',MakeFileName,InputValueFile):
 | 
				
			||||||
            Messages = ''
 | 
					            Messages = ''
 | 
				
			||||||
            if sys.platform == "win32":
 | 
					            if sys.platform == "win32":
 | 
				
			||||||
                MakeCommand = 'nmake clean & nmake -f %s' % (MakeFileName)
 | 
					                MakeCommand = 'nmake clean & nmake -f %s' % (MakeFileName)
 | 
				
			||||||
@@ -1987,17 +1990,11 @@ class DscBuildData(PlatformBuildClassObject):
 | 
				
			|||||||
                    EdkLogger.error("build", PCD_STRUCTURE_PCD_ERROR, "\n".join(MessageGroup) )
 | 
					                    EdkLogger.error("build", PCD_STRUCTURE_PCD_ERROR, "\n".join(MessageGroup) )
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    EdkLogger.error('Build', COMMAND_FAILURE, 'Can not execute command: %s' % MakeCommand)
 | 
					                    EdkLogger.error('Build', COMMAND_FAILURE, 'Can not execute command: %s' % MakeCommand)
 | 
				
			||||||
 | 
					 | 
				
			||||||
        PcdValueInitExe = PcdValueInitName
 | 
					 | 
				
			||||||
        if not sys.platform == "win32":
 | 
					 | 
				
			||||||
            PcdValueInitExe = os.path.join(os.getenv("EDK_TOOLS_PATH"), 'Source', 'C', 'bin', PcdValueInitName)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Command = PcdValueInitExe + ' -i %s -o %s' % (InputValueFile, OutputValueFile)
 | 
					            Command = PcdValueInitExe + ' -i %s -o %s' % (InputValueFile, OutputValueFile)
 | 
				
			||||||
            returncode, StdOut, StdErr = self.ExecuteCommand (Command)
 | 
					            returncode, StdOut, StdErr = self.ExecuteCommand (Command)
 | 
				
			||||||
            if returncode <> 0:
 | 
					            if returncode <> 0:
 | 
				
			||||||
                EdkLogger.warn('Build', COMMAND_FAILURE, 'Can not collect output from command: %s' % Command)
 | 
					                EdkLogger.warn('Build', COMMAND_FAILURE, 'Can not collect output from command: %s' % Command)
 | 
				
			||||||
            FileBuffer = []
 | 
					
 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
        File = open (OutputValueFile, 'r')
 | 
					        File = open (OutputValueFile, 'r')
 | 
				
			||||||
        FileBuffer = File.readlines()
 | 
					        FileBuffer = File.readlines()
 | 
				
			||||||
        File.close()
 | 
					        File.close()
 | 
				
			||||||
@@ -2009,6 +2006,17 @@ class DscBuildData(PlatformBuildClassObject):
 | 
				
			|||||||
            StructurePcdSet.append((PcdInfo[0],PcdInfo[1], PcdInfo[2], PcdInfo[3], PcdValue[2].strip()))
 | 
					            StructurePcdSet.append((PcdInfo[0],PcdInfo[1], PcdInfo[2], PcdInfo[3], PcdValue[2].strip()))
 | 
				
			||||||
        return StructurePcdSet
 | 
					        return StructurePcdSet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def NeedUpdateOutput(self,OutputFile, ValueCFile, MakeFile, StructureInput):
 | 
				
			||||||
 | 
					        if not os.path.exists(OutputFile):
 | 
				
			||||||
 | 
					            return True
 | 
				
			||||||
 | 
					        if os.stat(OutputFile).st_mtime <= os.stat(ValueCFile).st_mtime:
 | 
				
			||||||
 | 
					            return True
 | 
				
			||||||
 | 
					        if os.stat(OutputFile).st_mtime <= os.stat(MakeFile).st_mtime:
 | 
				
			||||||
 | 
					            return True
 | 
				
			||||||
 | 
					        if os.stat(OutputFile).st_mtime <= os.stat(StructureInput).st_mtime:
 | 
				
			||||||
 | 
					            return True
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ## Retrieve dynamic PCD settings
 | 
					    ## Retrieve dynamic PCD settings
 | 
				
			||||||
    #
 | 
					    #
 | 
				
			||||||
    #   @param  Type    PCD type
 | 
					    #   @param  Type    PCD type
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user