]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/AutoGen/PlatformAutoGen.py
BaseTools: Decouple AutoGen Objects
[mirror_edk2.git] / BaseTools / Source / Python / AutoGen / PlatformAutoGen.py
1 ## @file
2 # Create makefile for MS nmake and GNU make
3 #
4 # Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
5 # SPDX-License-Identifier: BSD-2-Clause-Patent
6 #
7
8 ## Import Modules
9 #
10 from __future__ import print_function
11 from __future__ import absolute_import
12 import os.path as path
13 import copy
14 from collections import defaultdict
15
16 from .BuildEngine import BuildRule,gDefaultBuildRuleFile,AutoGenReqBuildRuleVerNum
17 from .GenVar import VariableMgr, var_info
18 from . import GenMake
19 from AutoGen.DataPipe import MemoryDataPipe
20 from AutoGen.ModuleAutoGen import ModuleAutoGen
21 from AutoGen.AutoGen import AutoGen
22 from AutoGen.AutoGen import CalculatePriorityValue
23 from Workspace.WorkspaceCommon import GetModuleLibInstances
24 from CommonDataClass.CommonClass import SkuInfoClass
25 from Common.caching import cached_class_function
26 from Common.Expression import ValueExpressionEx
27 from Common.StringUtils import StringToArray,NormPath
28 from Common.BuildToolError import *
29 from Common.DataType import *
30 from Common.Misc import *
31 import Common.VpdInfoFile as VpdInfoFile
32
33 ## Split command line option string to list
34 #
35 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
36 # in non-windows platform to launch command
37 #
38 def _SplitOption(OptionString):
39 OptionList = []
40 LastChar = " "
41 OptionStart = 0
42 QuotationMark = ""
43 for Index in range(0, len(OptionString)):
44 CurrentChar = OptionString[Index]
45 if CurrentChar in ['"', "'"]:
46 if QuotationMark == CurrentChar:
47 QuotationMark = ""
48 elif QuotationMark == "":
49 QuotationMark = CurrentChar
50 continue
51 elif QuotationMark:
52 continue
53
54 if CurrentChar in ["/", "-"] and LastChar in [" ", "\t", "\r", "\n"]:
55 if Index > OptionStart:
56 OptionList.append(OptionString[OptionStart:Index - 1])
57 OptionStart = Index
58 LastChar = CurrentChar
59 OptionList.append(OptionString[OptionStart:])
60 return OptionList
61
62 ## AutoGen class for platform
63 #
64 # PlatformAutoGen class will process the original information in platform
65 # file in order to generate makefile for platform.
66 #
67 class PlatformAutoGen(AutoGen):
68 # call super().__init__ then call the worker function with different parameter count
69 def __init__(self, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs):
70 if not hasattr(self, "_Init"):
71 self._InitWorker(Workspace, MetaFile, Target, Toolchain, Arch)
72 self._Init = True
73 #
74 # Used to store all PCDs for both PEI and DXE phase, in order to generate
75 # correct PCD database
76 #
77 _DynaPcdList_ = []
78 _NonDynaPcdList_ = []
79 _PlatformPcds = {}
80
81
82
83 ## Initialize PlatformAutoGen
84 #
85 #
86 # @param Workspace WorkspaceAutoGen object
87 # @param PlatformFile Platform file (DSC file)
88 # @param Target Build target (DEBUG, RELEASE)
89 # @param Toolchain Name of tool chain
90 # @param Arch arch of the platform supports
91 #
92 def _InitWorker(self, Workspace, PlatformFile, Target, Toolchain, Arch):
93 EdkLogger.debug(EdkLogger.DEBUG_9, "AutoGen platform [%s] [%s]" % (PlatformFile, Arch))
94 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (PlatformFile, Arch, Toolchain, Target)
95
96 self.MetaFile = PlatformFile
97 self.Workspace = Workspace
98 self.WorkspaceDir = Workspace.WorkspaceDir
99 self.ToolChain = Toolchain
100 self.BuildTarget = Target
101 self.Arch = Arch
102 self.SourceDir = PlatformFile.SubDir
103 self.FdTargetList = self.Workspace.FdTargetList
104 self.FvTargetList = self.Workspace.FvTargetList
105 # get the original module/package/platform objects
106 self.BuildDatabase = Workspace.BuildDatabase
107 self.DscBuildDataObj = Workspace.Platform
108
109 # flag indicating if the makefile/C-code file has been created or not
110 self.IsMakeFileCreated = False
111
112 self._DynamicPcdList = None # [(TokenCName1, TokenSpaceGuidCName1), (TokenCName2, TokenSpaceGuidCName2), ...]
113 self._NonDynamicPcdList = None # [(TokenCName1, TokenSpaceGuidCName1), (TokenCName2, TokenSpaceGuidCName2), ...]
114
115 self._AsBuildInfList = []
116 self._AsBuildModuleList = []
117
118 self.VariableInfo = None
119
120 if GlobalData.gFdfParser is not None:
121 self._AsBuildInfList = GlobalData.gFdfParser.Profile.InfList
122 for Inf in self._AsBuildInfList:
123 InfClass = PathClass(NormPath(Inf), GlobalData.gWorkspace, self.Arch)
124 M = self.BuildDatabase[InfClass, self.Arch, self.BuildTarget, self.ToolChain]
125 if not M.IsBinaryModule:
126 continue
127 self._AsBuildModuleList.append(InfClass)
128 # get library/modules for build
129 self.LibraryBuildDirectoryList = []
130 self.ModuleBuildDirectoryList = []
131
132 self.DataPipe = MemoryDataPipe(self.BuildDir)
133 self.DataPipe.FillData(self)
134
135 return True
136 ## hash() operator of PlatformAutoGen
137 #
138 # The platform file path and arch string will be used to represent
139 # hash value of this object
140 #
141 # @retval int Hash value of the platform file path and arch
142 #
143 @cached_class_function
144 def __hash__(self):
145 return hash((self.MetaFile, self.Arch))
146 @cached_class_function
147 def __repr__(self):
148 return "%s [%s]" % (self.MetaFile, self.Arch)
149
150 ## Create autogen code for platform and modules
151 #
152 # Since there's no autogen code for platform, this method will do nothing
153 # if CreateModuleCodeFile is set to False.
154 #
155 # @param CreateModuleCodeFile Flag indicating if creating module's
156 # autogen code file or not
157 #
158 @cached_class_function
159 def CreateCodeFile(self, CreateModuleCodeFile=False):
160 # only module has code to be created, so do nothing if CreateModuleCodeFile is False
161 if not CreateModuleCodeFile:
162 return
163
164 for Ma in self.ModuleAutoGenList:
165 Ma.CreateCodeFile(True)
166
167 ## Generate Fds Command
168 @cached_property
169 def GenFdsCommand(self):
170 return self.Workspace.GenFdsCommand
171
172 ## Create makefile for the platform and modules in it
173 #
174 # @param CreateModuleMakeFile Flag indicating if the makefile for
175 # modules will be created as well
176 #
177 def CreateMakeFile(self, CreateModuleMakeFile=False, FfsCommand = {}):
178 if CreateModuleMakeFile:
179 for Ma in self._MaList:
180 key = (Ma.MetaFile.File, self.Arch)
181 if key in FfsCommand:
182 Ma.CreateMakeFile(True, FfsCommand[key])
183 else:
184 Ma.CreateMakeFile(True)
185
186 # no need to create makefile for the platform more than once
187 if self.IsMakeFileCreated:
188 return
189
190 # create library/module build dirs for platform
191 Makefile = GenMake.PlatformMakefile(self)
192 self.LibraryBuildDirectoryList = Makefile.GetLibraryBuildDirectoryList()
193 self.ModuleBuildDirectoryList = Makefile.GetModuleBuildDirectoryList()
194
195 self.IsMakeFileCreated = True
196
197 @property
198 def AllPcdList(self):
199 return self.DynamicPcdList + self.NonDynamicPcdList
200 ## Deal with Shared FixedAtBuild Pcds
201 #
202 def CollectFixedAtBuildPcds(self):
203 for LibAuto in self.LibraryAutoGenList:
204 FixedAtBuildPcds = {}
205 ShareFixedAtBuildPcdsSameValue = {}
206 for Module in LibAuto.ReferenceModules:
207 for Pcd in set(Module.FixedAtBuildPcds + LibAuto.FixedAtBuildPcds):
208 DefaultValue = Pcd.DefaultValue
209 # Cover the case: DSC component override the Pcd value and the Pcd only used in one Lib
210 if Pcd in Module.LibraryPcdList:
211 Index = Module.LibraryPcdList.index(Pcd)
212 DefaultValue = Module.LibraryPcdList[Index].DefaultValue
213 key = ".".join((Pcd.TokenSpaceGuidCName, Pcd.TokenCName))
214 if key not in FixedAtBuildPcds:
215 ShareFixedAtBuildPcdsSameValue[key] = True
216 FixedAtBuildPcds[key] = DefaultValue
217 else:
218 if FixedAtBuildPcds[key] != DefaultValue:
219 ShareFixedAtBuildPcdsSameValue[key] = False
220 for Pcd in LibAuto.FixedAtBuildPcds:
221 key = ".".join((Pcd.TokenSpaceGuidCName, Pcd.TokenCName))
222 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) not in self.NonDynamicPcdDict:
223 continue
224 else:
225 DscPcd = self.NonDynamicPcdDict[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName)]
226 if DscPcd.Type != TAB_PCDS_FIXED_AT_BUILD:
227 continue
228 if key in ShareFixedAtBuildPcdsSameValue and ShareFixedAtBuildPcdsSameValue[key]:
229 LibAuto.ConstPcd[key] = FixedAtBuildPcds[key]
230
231 def CollectVariables(self, DynamicPcdSet):
232 VpdRegionSize = 0
233 VpdRegionBase = 0
234 if self.Workspace.FdfFile:
235 FdDict = self.Workspace.FdfProfile.FdDict[GlobalData.gFdfParser.CurrentFdName]
236 for FdRegion in FdDict.RegionList:
237 for item in FdRegion.RegionDataList:
238 if self.Platform.VpdToolGuid.strip() and self.Platform.VpdToolGuid in item:
239 VpdRegionSize = FdRegion.Size
240 VpdRegionBase = FdRegion.Offset
241 break
242
243 VariableInfo = VariableMgr(self.DscBuildDataObj._GetDefaultStores(), self.DscBuildDataObj.SkuIds)
244 VariableInfo.SetVpdRegionMaxSize(VpdRegionSize)
245 VariableInfo.SetVpdRegionOffset(VpdRegionBase)
246 Index = 0
247 for Pcd in DynamicPcdSet:
248 pcdname = ".".join((Pcd.TokenSpaceGuidCName, Pcd.TokenCName))
249 for SkuName in Pcd.SkuInfoList:
250 Sku = Pcd.SkuInfoList[SkuName]
251 SkuId = Sku.SkuId
252 if SkuId is None or SkuId == '':
253 continue
254 if len(Sku.VariableName) > 0:
255 if Sku.VariableAttribute and 'NV' not in Sku.VariableAttribute:
256 continue
257 VariableGuidStructure = Sku.VariableGuidValue
258 VariableGuid = GuidStructureStringToGuidString(VariableGuidStructure)
259 for StorageName in Sku.DefaultStoreDict:
260 VariableInfo.append_variable(var_info(Index, pcdname, StorageName, SkuName, StringToArray(Sku.VariableName), VariableGuid, Sku.VariableOffset, Sku.VariableAttribute, Sku.HiiDefaultValue, Sku.DefaultStoreDict[StorageName] if Pcd.DatumType in TAB_PCD_NUMERIC_TYPES else StringToArray(Sku.DefaultStoreDict[StorageName]), Pcd.DatumType, Pcd.CustomAttribute['DscPosition'], Pcd.CustomAttribute.get('IsStru',False)))
261 Index += 1
262 return VariableInfo
263
264 def UpdateNVStoreMaxSize(self, OrgVpdFile):
265 if self.VariableInfo:
266 VpdMapFilePath = os.path.join(self.BuildDir, TAB_FV_DIRECTORY, "%s.map" % self.Platform.VpdToolGuid)
267 PcdNvStoreDfBuffer = [item for item in self._DynamicPcdList if item.TokenCName == "PcdNvStoreDefaultValueBuffer" and item.TokenSpaceGuidCName == "gEfiMdeModulePkgTokenSpaceGuid"]
268
269 if PcdNvStoreDfBuffer:
270 if os.path.exists(VpdMapFilePath):
271 OrgVpdFile.Read(VpdMapFilePath)
272 PcdItems = OrgVpdFile.GetOffset(PcdNvStoreDfBuffer[0])
273 NvStoreOffset = list(PcdItems.values())[0].strip() if PcdItems else '0'
274 else:
275 EdkLogger.error("build", FILE_READ_FAILURE, "Can not find VPD map file %s to fix up VPD offset." % VpdMapFilePath)
276
277 NvStoreOffset = int(NvStoreOffset, 16) if NvStoreOffset.upper().startswith("0X") else int(NvStoreOffset)
278 default_skuobj = PcdNvStoreDfBuffer[0].SkuInfoList.get(TAB_DEFAULT)
279 maxsize = self.VariableInfo.VpdRegionSize - NvStoreOffset if self.VariableInfo.VpdRegionSize else len(default_skuobj.DefaultValue.split(","))
280 var_data = self.VariableInfo.PatchNVStoreDefaultMaxSize(maxsize)
281
282 if var_data and default_skuobj:
283 default_skuobj.DefaultValue = var_data
284 PcdNvStoreDfBuffer[0].DefaultValue = var_data
285 PcdNvStoreDfBuffer[0].SkuInfoList.clear()
286 PcdNvStoreDfBuffer[0].SkuInfoList[TAB_DEFAULT] = default_skuobj
287 PcdNvStoreDfBuffer[0].MaxDatumSize = str(len(default_skuobj.DefaultValue.split(",")))
288
289 return OrgVpdFile
290
291 ## Collect dynamic PCDs
292 #
293 # Gather dynamic PCDs list from each module and their settings from platform
294 # This interface should be invoked explicitly when platform action is created.
295 #
296 def CollectPlatformDynamicPcds(self):
297 self.CategoryPcds()
298 self.SortDynamicPcd()
299
300 def CategoryPcds(self):
301 # Category Pcds into DynamicPcds and NonDynamicPcds
302 # for gathering error information
303 NoDatumTypePcdList = set()
304 FdfModuleList = []
305 for InfName in self._AsBuildInfList:
306 InfName = mws.join(self.WorkspaceDir, InfName)
307 FdfModuleList.append(os.path.normpath(InfName))
308 for M in self._MbList:
309 # F is the Module for which M is the module autogen
310 ModPcdList = self.ApplyPcdSetting(M, M.ModulePcdList)
311 LibPcdList = []
312 for lib in M.LibraryPcdList:
313 LibPcdList.extend(self.ApplyPcdSetting(M, M.LibraryPcdList[lib], lib))
314 for PcdFromModule in ModPcdList + LibPcdList:
315
316 # make sure that the "VOID*" kind of datum has MaxDatumSize set
317 if PcdFromModule.DatumType == TAB_VOID and not PcdFromModule.MaxDatumSize:
318 NoDatumTypePcdList.add("%s.%s [%s]" % (PcdFromModule.TokenSpaceGuidCName, PcdFromModule.TokenCName, M.MetaFile))
319
320 # Check the PCD from Binary INF or Source INF
321 if M.IsBinaryModule == True:
322 PcdFromModule.IsFromBinaryInf = True
323
324 # Check the PCD from DSC or not
325 PcdFromModule.IsFromDsc = (PcdFromModule.TokenCName, PcdFromModule.TokenSpaceGuidCName) in self.Platform.Pcds
326
327 if PcdFromModule.Type in PCD_DYNAMIC_TYPE_SET or PcdFromModule.Type in PCD_DYNAMIC_EX_TYPE_SET:
328 if M.MetaFile.Path not in FdfModuleList:
329 # If one of the Source built modules listed in the DSC is not listed
330 # in FDF modules, and the INF lists a PCD can only use the PcdsDynamic
331 # access method (it is only listed in the DEC file that declares the
332 # PCD as PcdsDynamic), then build tool will report warning message
333 # notify the PI that they are attempting to build a module that must
334 # be included in a flash image in order to be functional. These Dynamic
335 # PCD will not be added into the Database unless it is used by other
336 # modules that are included in the FDF file.
337 if PcdFromModule.Type in PCD_DYNAMIC_TYPE_SET and \
338 PcdFromModule.IsFromBinaryInf == False:
339 # Print warning message to let the developer make a determine.
340 continue
341 # If one of the Source built modules listed in the DSC is not listed in
342 # FDF modules, and the INF lists a PCD can only use the PcdsDynamicEx
343 # access method (it is only listed in the DEC file that declares the
344 # PCD as PcdsDynamicEx), then DO NOT break the build; DO NOT add the
345 # PCD to the Platform's PCD Database.
346 if PcdFromModule.Type in PCD_DYNAMIC_EX_TYPE_SET:
347 continue
348 #
349 # If a dynamic PCD used by a PEM module/PEI module & DXE module,
350 # it should be stored in Pcd PEI database, If a dynamic only
351 # used by DXE module, it should be stored in DXE PCD database.
352 # The default Phase is DXE
353 #
354 if M.ModuleType in SUP_MODULE_SET_PEI:
355 PcdFromModule.Phase = "PEI"
356 if PcdFromModule not in self._DynaPcdList_:
357 self._DynaPcdList_.append(PcdFromModule)
358 elif PcdFromModule.Phase == 'PEI':
359 # overwrite any the same PCD existing, if Phase is PEI
360 Index = self._DynaPcdList_.index(PcdFromModule)
361 self._DynaPcdList_[Index] = PcdFromModule
362 elif PcdFromModule not in self._NonDynaPcdList_:
363 self._NonDynaPcdList_.append(PcdFromModule)
364 elif PcdFromModule in self._NonDynaPcdList_ and PcdFromModule.IsFromBinaryInf == True:
365 Index = self._NonDynaPcdList_.index(PcdFromModule)
366 if self._NonDynaPcdList_[Index].IsFromBinaryInf == False:
367 #The PCD from Binary INF will override the same one from source INF
368 self._NonDynaPcdList_.remove (self._NonDynaPcdList_[Index])
369 PcdFromModule.Pending = False
370 self._NonDynaPcdList_.append (PcdFromModule)
371 DscModuleSet = {os.path.normpath(ModuleInf.Path) for ModuleInf in self.Platform.Modules}
372 # add the PCD from modules that listed in FDF but not in DSC to Database
373 for InfName in FdfModuleList:
374 if InfName not in DscModuleSet:
375 InfClass = PathClass(InfName)
376 M = self.BuildDatabase[InfClass, self.Arch, self.BuildTarget, self.ToolChain]
377 # If a module INF in FDF but not in current arch's DSC module list, it must be module (either binary or source)
378 # for different Arch. PCDs in source module for different Arch is already added before, so skip the source module here.
379 # For binary module, if in current arch, we need to list the PCDs into database.
380 if not M.IsBinaryModule:
381 continue
382 # Override the module PCD setting by platform setting
383 ModulePcdList = self.ApplyPcdSetting(M, M.Pcds)
384 for PcdFromModule in ModulePcdList:
385 PcdFromModule.IsFromBinaryInf = True
386 PcdFromModule.IsFromDsc = False
387 # Only allow the DynamicEx and Patchable PCD in AsBuild INF
388 if PcdFromModule.Type not in PCD_DYNAMIC_EX_TYPE_SET and PcdFromModule.Type not in TAB_PCDS_PATCHABLE_IN_MODULE:
389 EdkLogger.error("build", AUTOGEN_ERROR, "PCD setting error",
390 File=self.MetaFile,
391 ExtraData="\n\tExisted %s PCD %s in:\n\t\t%s\n"
392 % (PcdFromModule.Type, PcdFromModule.TokenCName, InfName))
393 # make sure that the "VOID*" kind of datum has MaxDatumSize set
394 if PcdFromModule.DatumType == TAB_VOID and not PcdFromModule.MaxDatumSize:
395 NoDatumTypePcdList.add("%s.%s [%s]" % (PcdFromModule.TokenSpaceGuidCName, PcdFromModule.TokenCName, InfName))
396 if M.ModuleType in SUP_MODULE_SET_PEI:
397 PcdFromModule.Phase = "PEI"
398 if PcdFromModule not in self._DynaPcdList_ and PcdFromModule.Type in PCD_DYNAMIC_EX_TYPE_SET:
399 self._DynaPcdList_.append(PcdFromModule)
400 elif PcdFromModule not in self._NonDynaPcdList_ and PcdFromModule.Type in TAB_PCDS_PATCHABLE_IN_MODULE:
401 self._NonDynaPcdList_.append(PcdFromModule)
402 if PcdFromModule in self._DynaPcdList_ and PcdFromModule.Phase == 'PEI' and PcdFromModule.Type in PCD_DYNAMIC_EX_TYPE_SET:
403 # Overwrite the phase of any the same PCD existing, if Phase is PEI.
404 # It is to solve the case that a dynamic PCD used by a PEM module/PEI
405 # module & DXE module at a same time.
406 # Overwrite the type of the PCDs in source INF by the type of AsBuild
407 # INF file as DynamicEx.
408 Index = self._DynaPcdList_.index(PcdFromModule)
409 self._DynaPcdList_[Index].Phase = PcdFromModule.Phase
410 self._DynaPcdList_[Index].Type = PcdFromModule.Type
411 for PcdFromModule in self._NonDynaPcdList_:
412 # If a PCD is not listed in the DSC file, but binary INF files used by
413 # this platform all (that use this PCD) list the PCD in a [PatchPcds]
414 # section, AND all source INF files used by this platform the build
415 # that use the PCD list the PCD in either a [Pcds] or [PatchPcds]
416 # section, then the tools must NOT add the PCD to the Platform's PCD
417 # Database; the build must assign the access method for this PCD as
418 # PcdsPatchableInModule.
419 if PcdFromModule not in self._DynaPcdList_:
420 continue
421 Index = self._DynaPcdList_.index(PcdFromModule)
422 if PcdFromModule.IsFromDsc == False and \
423 PcdFromModule.Type in TAB_PCDS_PATCHABLE_IN_MODULE and \
424 PcdFromModule.IsFromBinaryInf == True and \
425 self._DynaPcdList_[Index].IsFromBinaryInf == False:
426 Index = self._DynaPcdList_.index(PcdFromModule)
427 self._DynaPcdList_.remove (self._DynaPcdList_[Index])
428
429 # print out error information and break the build, if error found
430 if len(NoDatumTypePcdList) > 0:
431 NoDatumTypePcdListString = "\n\t\t".join(NoDatumTypePcdList)
432 EdkLogger.error("build", AUTOGEN_ERROR, "PCD setting error",
433 File=self.MetaFile,
434 ExtraData="\n\tPCD(s) without MaxDatumSize:\n\t\t%s\n"
435 % NoDatumTypePcdListString)
436 self._NonDynamicPcdList = self._NonDynaPcdList_
437 self._DynamicPcdList = self._DynaPcdList_
438
439 def SortDynamicPcd(self):
440 #
441 # Sort dynamic PCD list to:
442 # 1) If PCD's datum type is VOID* and value is unicode string which starts with L, the PCD item should
443 # try to be put header of dynamicd List
444 # 2) If PCD is HII type, the PCD item should be put after unicode type PCD
445 #
446 # The reason of sorting is make sure the unicode string is in double-byte alignment in string table.
447 #
448 UnicodePcdArray = set()
449 HiiPcdArray = set()
450 OtherPcdArray = set()
451 VpdPcdDict = {}
452 VpdFile = VpdInfoFile.VpdInfoFile()
453 NeedProcessVpdMapFile = False
454
455 for pcd in self.Platform.Pcds:
456 if pcd not in self._PlatformPcds:
457 self._PlatformPcds[pcd] = self.Platform.Pcds[pcd]
458
459 for item in self._PlatformPcds:
460 if self._PlatformPcds[item].DatumType and self._PlatformPcds[item].DatumType not in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64, TAB_VOID, "BOOLEAN"]:
461 self._PlatformPcds[item].DatumType = TAB_VOID
462
463 if (self.Workspace.ArchList[-1] == self.Arch):
464 for Pcd in self._DynamicPcdList:
465 # just pick the a value to determine whether is unicode string type
466 Sku = Pcd.SkuInfoList.get(TAB_DEFAULT)
467 Sku.VpdOffset = Sku.VpdOffset.strip()
468
469 if Pcd.DatumType not in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64, TAB_VOID, "BOOLEAN"]:
470 Pcd.DatumType = TAB_VOID
471
472 # if found PCD which datum value is unicode string the insert to left size of UnicodeIndex
473 # if found HII type PCD then insert to right of UnicodeIndex
474 if Pcd.Type in [TAB_PCDS_DYNAMIC_VPD, TAB_PCDS_DYNAMIC_EX_VPD]:
475 VpdPcdDict[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName)] = Pcd
476
477 #Collect DynamicHii PCD values and assign it to DynamicExVpd PCD gEfiMdeModulePkgTokenSpaceGuid.PcdNvStoreDefaultValueBuffer
478 PcdNvStoreDfBuffer = VpdPcdDict.get(("PcdNvStoreDefaultValueBuffer", "gEfiMdeModulePkgTokenSpaceGuid"))
479 if PcdNvStoreDfBuffer:
480 self.VariableInfo = self.CollectVariables(self._DynamicPcdList)
481 vardump = self.VariableInfo.dump()
482 if vardump:
483 #
484 #According to PCD_DATABASE_INIT in edk2\MdeModulePkg\Include\Guid\PcdDataBaseSignatureGuid.h,
485 #the max size for string PCD should not exceed USHRT_MAX 65535(0xffff).
486 #typedef UINT16 SIZE_INFO;
487 #//SIZE_INFO SizeTable[];
488 if len(vardump.split(",")) > 0xffff:
489 EdkLogger.error("build", RESOURCE_OVERFLOW, 'The current length of PCD %s value is %d, it exceeds to the max size of String PCD.' %(".".join([PcdNvStoreDfBuffer.TokenSpaceGuidCName,PcdNvStoreDfBuffer.TokenCName]) ,len(vardump.split(","))))
490 PcdNvStoreDfBuffer.DefaultValue = vardump
491 for skuname in PcdNvStoreDfBuffer.SkuInfoList:
492 PcdNvStoreDfBuffer.SkuInfoList[skuname].DefaultValue = vardump
493 PcdNvStoreDfBuffer.MaxDatumSize = str(len(vardump.split(",")))
494 else:
495 #If the end user define [DefaultStores] and [XXX.Menufacturing] in DSC, but forget to configure PcdNvStoreDefaultValueBuffer to PcdsDynamicVpd
496 if [Pcd for Pcd in self._DynamicPcdList if Pcd.UserDefinedDefaultStoresFlag]:
497 EdkLogger.warn("build", "PcdNvStoreDefaultValueBuffer should be defined as PcdsDynamicExVpd in dsc file since the DefaultStores is enabled for this platform.\n%s" %self.Platform.MetaFile.Path)
498 PlatformPcds = sorted(self._PlatformPcds.keys())
499 #
500 # Add VPD type PCD into VpdFile and determine whether the VPD PCD need to be fixed up.
501 #
502 VpdSkuMap = {}
503 for PcdKey in PlatformPcds:
504 Pcd = self._PlatformPcds[PcdKey]
505 if Pcd.Type in [TAB_PCDS_DYNAMIC_VPD, TAB_PCDS_DYNAMIC_EX_VPD] and \
506 PcdKey in VpdPcdDict:
507 Pcd = VpdPcdDict[PcdKey]
508 SkuValueMap = {}
509 DefaultSku = Pcd.SkuInfoList.get(TAB_DEFAULT)
510 if DefaultSku:
511 PcdValue = DefaultSku.DefaultValue
512 if PcdValue not in SkuValueMap:
513 SkuValueMap[PcdValue] = []
514 VpdFile.Add(Pcd, TAB_DEFAULT, DefaultSku.VpdOffset)
515 SkuValueMap[PcdValue].append(DefaultSku)
516
517 for (SkuName, Sku) in Pcd.SkuInfoList.items():
518 Sku.VpdOffset = Sku.VpdOffset.strip()
519 PcdValue = Sku.DefaultValue
520 if PcdValue == "":
521 PcdValue = Pcd.DefaultValue
522 if Sku.VpdOffset != TAB_STAR:
523 if PcdValue.startswith("{"):
524 Alignment = 8
525 elif PcdValue.startswith("L"):
526 Alignment = 2
527 else:
528 Alignment = 1
529 try:
530 VpdOffset = int(Sku.VpdOffset)
531 except:
532 try:
533 VpdOffset = int(Sku.VpdOffset, 16)
534 except:
535 EdkLogger.error("build", FORMAT_INVALID, "Invalid offset value %s for PCD %s.%s." % (Sku.VpdOffset, Pcd.TokenSpaceGuidCName, Pcd.TokenCName))
536 if VpdOffset % Alignment != 0:
537 if PcdValue.startswith("{"):
538 EdkLogger.warn("build", "The offset value of PCD %s.%s is not 8-byte aligned!" %(Pcd.TokenSpaceGuidCName, Pcd.TokenCName), File=self.MetaFile)
539 else:
540 EdkLogger.error("build", FORMAT_INVALID, 'The offset value of PCD %s.%s should be %s-byte aligned.' % (Pcd.TokenSpaceGuidCName, Pcd.TokenCName, Alignment))
541 if PcdValue not in SkuValueMap:
542 SkuValueMap[PcdValue] = []
543 VpdFile.Add(Pcd, SkuName, Sku.VpdOffset)
544 SkuValueMap[PcdValue].append(Sku)
545 # if the offset of a VPD is *, then it need to be fixed up by third party tool.
546 if not NeedProcessVpdMapFile and Sku.VpdOffset == TAB_STAR:
547 NeedProcessVpdMapFile = True
548 if self.Platform.VpdToolGuid is None or self.Platform.VpdToolGuid == '':
549 EdkLogger.error("Build", FILE_NOT_FOUND, \
550 "Fail to find third-party BPDG tool to process VPD PCDs. BPDG Guid tool need to be defined in tools_def.txt and VPD_TOOL_GUID need to be provided in DSC file.")
551
552 VpdSkuMap[PcdKey] = SkuValueMap
553 #
554 # Fix the PCDs define in VPD PCD section that never referenced by module.
555 # An example is PCD for signature usage.
556 #
557 for DscPcd in PlatformPcds:
558 DscPcdEntry = self._PlatformPcds[DscPcd]
559 if DscPcdEntry.Type in [TAB_PCDS_DYNAMIC_VPD, TAB_PCDS_DYNAMIC_EX_VPD]:
560 if not (self.Platform.VpdToolGuid is None or self.Platform.VpdToolGuid == ''):
561 FoundFlag = False
562 for VpdPcd in VpdFile._VpdArray:
563 # This PCD has been referenced by module
564 if (VpdPcd.TokenSpaceGuidCName == DscPcdEntry.TokenSpaceGuidCName) and \
565 (VpdPcd.TokenCName == DscPcdEntry.TokenCName):
566 FoundFlag = True
567
568 # Not found, it should be signature
569 if not FoundFlag :
570 # just pick the a value to determine whether is unicode string type
571 SkuValueMap = {}
572 SkuObjList = list(DscPcdEntry.SkuInfoList.items())
573 DefaultSku = DscPcdEntry.SkuInfoList.get(TAB_DEFAULT)
574 if DefaultSku:
575 defaultindex = SkuObjList.index((TAB_DEFAULT, DefaultSku))
576 SkuObjList[0], SkuObjList[defaultindex] = SkuObjList[defaultindex], SkuObjList[0]
577 for (SkuName, Sku) in SkuObjList:
578 Sku.VpdOffset = Sku.VpdOffset.strip()
579
580 # Need to iterate DEC pcd information to get the value & datumtype
581 for eachDec in self.PackageList:
582 for DecPcd in eachDec.Pcds:
583 DecPcdEntry = eachDec.Pcds[DecPcd]
584 if (DecPcdEntry.TokenSpaceGuidCName == DscPcdEntry.TokenSpaceGuidCName) and \
585 (DecPcdEntry.TokenCName == DscPcdEntry.TokenCName):
586 # Print warning message to let the developer make a determine.
587 EdkLogger.warn("build", "Unreferenced vpd pcd used!",
588 File=self.MetaFile, \
589 ExtraData = "PCD: %s.%s used in the DSC file %s is unreferenced." \
590 %(DscPcdEntry.TokenSpaceGuidCName, DscPcdEntry.TokenCName, self.Platform.MetaFile.Path))
591
592 DscPcdEntry.DatumType = DecPcdEntry.DatumType
593 DscPcdEntry.DefaultValue = DecPcdEntry.DefaultValue
594 DscPcdEntry.TokenValue = DecPcdEntry.TokenValue
595 DscPcdEntry.TokenSpaceGuidValue = eachDec.Guids[DecPcdEntry.TokenSpaceGuidCName]
596 # Only fix the value while no value provided in DSC file.
597 if not Sku.DefaultValue:
598 DscPcdEntry.SkuInfoList[list(DscPcdEntry.SkuInfoList.keys())[0]].DefaultValue = DecPcdEntry.DefaultValue
599
600 if DscPcdEntry not in self._DynamicPcdList:
601 self._DynamicPcdList.append(DscPcdEntry)
602 Sku.VpdOffset = Sku.VpdOffset.strip()
603 PcdValue = Sku.DefaultValue
604 if PcdValue == "":
605 PcdValue = DscPcdEntry.DefaultValue
606 if Sku.VpdOffset != TAB_STAR:
607 if PcdValue.startswith("{"):
608 Alignment = 8
609 elif PcdValue.startswith("L"):
610 Alignment = 2
611 else:
612 Alignment = 1
613 try:
614 VpdOffset = int(Sku.VpdOffset)
615 except:
616 try:
617 VpdOffset = int(Sku.VpdOffset, 16)
618 except:
619 EdkLogger.error("build", FORMAT_INVALID, "Invalid offset value %s for PCD %s.%s." % (Sku.VpdOffset, DscPcdEntry.TokenSpaceGuidCName, DscPcdEntry.TokenCName))
620 if VpdOffset % Alignment != 0:
621 if PcdValue.startswith("{"):
622 EdkLogger.warn("build", "The offset value of PCD %s.%s is not 8-byte aligned!" %(DscPcdEntry.TokenSpaceGuidCName, DscPcdEntry.TokenCName), File=self.MetaFile)
623 else:
624 EdkLogger.error("build", FORMAT_INVALID, 'The offset value of PCD %s.%s should be %s-byte aligned.' % (DscPcdEntry.TokenSpaceGuidCName, DscPcdEntry.TokenCName, Alignment))
625 if PcdValue not in SkuValueMap:
626 SkuValueMap[PcdValue] = []
627 VpdFile.Add(DscPcdEntry, SkuName, Sku.VpdOffset)
628 SkuValueMap[PcdValue].append(Sku)
629 if not NeedProcessVpdMapFile and Sku.VpdOffset == TAB_STAR:
630 NeedProcessVpdMapFile = True
631 if DscPcdEntry.DatumType == TAB_VOID and PcdValue.startswith("L"):
632 UnicodePcdArray.add(DscPcdEntry)
633 elif len(Sku.VariableName) > 0:
634 HiiPcdArray.add(DscPcdEntry)
635 else:
636 OtherPcdArray.add(DscPcdEntry)
637
638 # if the offset of a VPD is *, then it need to be fixed up by third party tool.
639 VpdSkuMap[DscPcd] = SkuValueMap
640 if (self.Platform.FlashDefinition is None or self.Platform.FlashDefinition == '') and \
641 VpdFile.GetCount() != 0:
642 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE,
643 "Fail to get FLASH_DEFINITION definition in DSC file %s which is required when DSC contains VPD PCD." % str(self.Platform.MetaFile))
644
645 if VpdFile.GetCount() != 0:
646
647 self.FixVpdOffset(VpdFile)
648
649 self.FixVpdOffset(self.UpdateNVStoreMaxSize(VpdFile))
650 PcdNvStoreDfBuffer = [item for item in self._DynamicPcdList if item.TokenCName == "PcdNvStoreDefaultValueBuffer" and item.TokenSpaceGuidCName == "gEfiMdeModulePkgTokenSpaceGuid"]
651 if PcdNvStoreDfBuffer:
652 PcdName,PcdGuid = PcdNvStoreDfBuffer[0].TokenCName, PcdNvStoreDfBuffer[0].TokenSpaceGuidCName
653 if (PcdName,PcdGuid) in VpdSkuMap:
654 DefaultSku = PcdNvStoreDfBuffer[0].SkuInfoList.get(TAB_DEFAULT)
655 VpdSkuMap[(PcdName,PcdGuid)] = {DefaultSku.DefaultValue:[SkuObj for SkuObj in PcdNvStoreDfBuffer[0].SkuInfoList.values() ]}
656
657 # Process VPD map file generated by third party BPDG tool
658 if NeedProcessVpdMapFile:
659 VpdMapFilePath = os.path.join(self.BuildDir, TAB_FV_DIRECTORY, "%s.map" % self.Platform.VpdToolGuid)
660 if os.path.exists(VpdMapFilePath):
661 VpdFile.Read(VpdMapFilePath)
662
663 # Fixup TAB_STAR offset
664 for pcd in VpdSkuMap:
665 vpdinfo = VpdFile.GetVpdInfo(pcd)
666 if vpdinfo is None:
667 # just pick the a value to determine whether is unicode string type
668 continue
669 for pcdvalue in VpdSkuMap[pcd]:
670 for sku in VpdSkuMap[pcd][pcdvalue]:
671 for item in vpdinfo:
672 if item[2] == pcdvalue:
673 sku.VpdOffset = item[1]
674 else:
675 EdkLogger.error("build", FILE_READ_FAILURE, "Can not find VPD map file %s to fix up VPD offset." % VpdMapFilePath)
676
677 # Delete the DynamicPcdList At the last time enter into this function
678 for Pcd in self._DynamicPcdList:
679 # just pick the a value to determine whether is unicode string type
680 Sku = Pcd.SkuInfoList.get(TAB_DEFAULT)
681 Sku.VpdOffset = Sku.VpdOffset.strip()
682
683 if Pcd.DatumType not in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64, TAB_VOID, "BOOLEAN"]:
684 Pcd.DatumType = TAB_VOID
685
686 PcdValue = Sku.DefaultValue
687 if Pcd.DatumType == TAB_VOID and PcdValue.startswith("L"):
688 # if found PCD which datum value is unicode string the insert to left size of UnicodeIndex
689 UnicodePcdArray.add(Pcd)
690 elif len(Sku.VariableName) > 0:
691 # if found HII type PCD then insert to right of UnicodeIndex
692 HiiPcdArray.add(Pcd)
693 else:
694 OtherPcdArray.add(Pcd)
695 del self._DynamicPcdList[:]
696 self._DynamicPcdList.extend(list(UnicodePcdArray))
697 self._DynamicPcdList.extend(list(HiiPcdArray))
698 self._DynamicPcdList.extend(list(OtherPcdArray))
699 allskuset = [(SkuName, Sku.SkuId) for pcd in self._DynamicPcdList for (SkuName, Sku) in pcd.SkuInfoList.items()]
700 for pcd in self._DynamicPcdList:
701 if len(pcd.SkuInfoList) == 1:
702 for (SkuName, SkuId) in allskuset:
703 if isinstance(SkuId, str) and eval(SkuId) == 0 or SkuId == 0:
704 continue
705 pcd.SkuInfoList[SkuName] = copy.deepcopy(pcd.SkuInfoList[TAB_DEFAULT])
706 pcd.SkuInfoList[SkuName].SkuId = SkuId
707 pcd.SkuInfoList[SkuName].SkuIdName = SkuName
708
709 def FixVpdOffset(self, VpdFile ):
710 FvPath = os.path.join(self.BuildDir, TAB_FV_DIRECTORY)
711 if not os.path.exists(FvPath):
712 try:
713 os.makedirs(FvPath)
714 except:
715 EdkLogger.error("build", FILE_WRITE_FAILURE, "Fail to create FV folder under %s" % self.BuildDir)
716
717 VpdFilePath = os.path.join(FvPath, "%s.txt" % self.Platform.VpdToolGuid)
718
719 if VpdFile.Write(VpdFilePath):
720 # retrieve BPDG tool's path from tool_def.txt according to VPD_TOOL_GUID defined in DSC file.
721 BPDGToolName = None
722 for ToolDef in self.ToolDefinition.values():
723 if TAB_GUID in ToolDef and ToolDef[TAB_GUID] == self.Platform.VpdToolGuid:
724 if "PATH" not in ToolDef:
725 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "PATH attribute was not provided for BPDG guid tool %s in tools_def.txt" % self.Platform.VpdToolGuid)
726 BPDGToolName = ToolDef["PATH"]
727 break
728 # Call third party GUID BPDG tool.
729 if BPDGToolName is not None:
730 VpdInfoFile.CallExtenalBPDGTool(BPDGToolName, VpdFilePath)
731 else:
732 EdkLogger.error("Build", FILE_NOT_FOUND, "Fail to find third-party BPDG tool to process VPD PCDs. BPDG Guid tool need to be defined in tools_def.txt and VPD_TOOL_GUID need to be provided in DSC file.")
733
734 ## Return the platform build data object
735 @cached_property
736 def Platform(self):
737 return self.BuildDatabase[self.MetaFile, self.Arch, self.BuildTarget, self.ToolChain]
738
739 ## Return platform name
740 @cached_property
741 def Name(self):
742 return self.Platform.PlatformName
743
744 ## Return the meta file GUID
745 @cached_property
746 def Guid(self):
747 return self.Platform.Guid
748
749 ## Return the platform version
750 @cached_property
751 def Version(self):
752 return self.Platform.Version
753
754 ## Return the FDF file name
755 @cached_property
756 def FdfFile(self):
757 if self.Workspace.FdfFile:
758 RetVal= mws.join(self.WorkspaceDir, self.Workspace.FdfFile)
759 else:
760 RetVal = ''
761 return RetVal
762
763 ## Return the build output directory platform specifies
764 @cached_property
765 def OutputDir(self):
766 return self.Platform.OutputDirectory
767
768 ## Return the directory to store all intermediate and final files built
769 @cached_property
770 def BuildDir(self):
771 if os.path.isabs(self.OutputDir):
772 GlobalData.gBuildDirectory = RetVal = path.join(
773 path.abspath(self.OutputDir),
774 self.BuildTarget + "_" + self.ToolChain,
775 )
776 else:
777 GlobalData.gBuildDirectory = RetVal = path.join(
778 self.WorkspaceDir,
779 self.OutputDir,
780 self.BuildTarget + "_" + self.ToolChain,
781 )
782 return RetVal
783
784 ## Return directory of platform makefile
785 #
786 # @retval string Makefile directory
787 #
788 @cached_property
789 def MakeFileDir(self):
790 return path.join(self.BuildDir, self.Arch)
791
792 ## Return build command string
793 #
794 # @retval string Build command string
795 #
796 @cached_property
797 def BuildCommand(self):
798 RetVal = []
799 if "MAKE" in self.ToolDefinition and "PATH" in self.ToolDefinition["MAKE"]:
800 RetVal += _SplitOption(self.ToolDefinition["MAKE"]["PATH"])
801 if "FLAGS" in self.ToolDefinition["MAKE"]:
802 NewOption = self.ToolDefinition["MAKE"]["FLAGS"].strip()
803 if NewOption != '':
804 RetVal += _SplitOption(NewOption)
805 if "MAKE" in self.EdkIIBuildOption:
806 if "FLAGS" in self.EdkIIBuildOption["MAKE"]:
807 Flags = self.EdkIIBuildOption["MAKE"]["FLAGS"]
808 if Flags.startswith('='):
809 RetVal = [RetVal[0]] + [Flags[1:]]
810 else:
811 RetVal.append(Flags)
812 return RetVal
813
814 ## Get tool chain definition
815 #
816 # Get each tool definition for given tool chain from tools_def.txt and platform
817 #
818 @cached_property
819 def ToolDefinition(self):
820 ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDictionary
821 if TAB_TOD_DEFINES_COMMAND_TYPE not in self.Workspace.ToolDef.ToolsDefTxtDatabase:
822 EdkLogger.error('build', RESOURCE_NOT_AVAILABLE, "No tools found in configuration",
823 ExtraData="[%s]" % self.MetaFile)
824 RetVal = OrderedDict()
825 DllPathList = set()
826 for Def in ToolDefinition:
827 Target, Tag, Arch, Tool, Attr = Def.split("_")
828 if Target != self.BuildTarget or Tag != self.ToolChain or Arch != self.Arch:
829 continue
830
831 Value = ToolDefinition[Def]
832 # don't record the DLL
833 if Attr == "DLL":
834 DllPathList.add(Value)
835 continue
836
837 if Tool not in RetVal:
838 RetVal[Tool] = OrderedDict()
839 RetVal[Tool][Attr] = Value
840
841 ToolsDef = ''
842 if GlobalData.gOptions.SilentMode and "MAKE" in RetVal:
843 if "FLAGS" not in RetVal["MAKE"]:
844 RetVal["MAKE"]["FLAGS"] = ""
845 RetVal["MAKE"]["FLAGS"] += " -s"
846 MakeFlags = ''
847 for Tool in RetVal:
848 for Attr in RetVal[Tool]:
849 Value = RetVal[Tool][Attr]
850 if Tool in self._BuildOptionWithToolDef(RetVal) and Attr in self._BuildOptionWithToolDef(RetVal)[Tool]:
851 # check if override is indicated
852 if self._BuildOptionWithToolDef(RetVal)[Tool][Attr].startswith('='):
853 Value = self._BuildOptionWithToolDef(RetVal)[Tool][Attr][1:]
854 else:
855 if Attr != 'PATH':
856 Value += " " + self._BuildOptionWithToolDef(RetVal)[Tool][Attr]
857 else:
858 Value = self._BuildOptionWithToolDef(RetVal)[Tool][Attr]
859
860 if Attr == "PATH":
861 # Don't put MAKE definition in the file
862 if Tool != "MAKE":
863 ToolsDef += "%s = %s\n" % (Tool, Value)
864 elif Attr != "DLL":
865 # Don't put MAKE definition in the file
866 if Tool == "MAKE":
867 if Attr == "FLAGS":
868 MakeFlags = Value
869 else:
870 ToolsDef += "%s_%s = %s\n" % (Tool, Attr, Value)
871 ToolsDef += "\n"
872
873 tool_def_file = os.path.join(self.MakeFileDir, "TOOLS_DEF." + self.Arch)
874 SaveFileOnChange(tool_def_file, ToolsDef, False)
875 for DllPath in DllPathList:
876 os.environ["PATH"] = DllPath + os.pathsep + os.environ["PATH"]
877 os.environ["MAKE_FLAGS"] = MakeFlags
878
879 return RetVal
880
881 ## Return the paths of tools
882 @cached_property
883 def ToolDefinitionFile(self):
884 tool_def_file = os.path.join(self.MakeFileDir, "TOOLS_DEF." + self.Arch)
885 if not os.path.exists(tool_def_file):
886 self.ToolDefinition
887 return tool_def_file
888
889 ## Retrieve the toolchain family of given toolchain tag. Default to 'MSFT'.
890 @cached_property
891 def ToolChainFamily(self):
892 ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDatabase
893 if TAB_TOD_DEFINES_FAMILY not in ToolDefinition \
894 or self.ToolChain not in ToolDefinition[TAB_TOD_DEFINES_FAMILY] \
895 or not ToolDefinition[TAB_TOD_DEFINES_FAMILY][self.ToolChain]:
896 EdkLogger.verbose("No tool chain family found in configuration for %s. Default to MSFT." \
897 % self.ToolChain)
898 RetVal = TAB_COMPILER_MSFT
899 else:
900 RetVal = ToolDefinition[TAB_TOD_DEFINES_FAMILY][self.ToolChain]
901 return RetVal
902
903 @cached_property
904 def BuildRuleFamily(self):
905 ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDatabase
906 if TAB_TOD_DEFINES_BUILDRULEFAMILY not in ToolDefinition \
907 or self.ToolChain not in ToolDefinition[TAB_TOD_DEFINES_BUILDRULEFAMILY] \
908 or not ToolDefinition[TAB_TOD_DEFINES_BUILDRULEFAMILY][self.ToolChain]:
909 EdkLogger.verbose("No tool chain family found in configuration for %s. Default to MSFT." \
910 % self.ToolChain)
911 return TAB_COMPILER_MSFT
912
913 return ToolDefinition[TAB_TOD_DEFINES_BUILDRULEFAMILY][self.ToolChain]
914
915 ## Return the build options specific for all modules in this platform
916 @cached_property
917 def BuildOption(self):
918 return self._ExpandBuildOption(self.Platform.BuildOptions)
919
920 def _BuildOptionWithToolDef(self, ToolDef):
921 return self._ExpandBuildOption(self.Platform.BuildOptions, ToolDef=ToolDef)
922
923 ## Return the build options specific for EDK modules in this platform
924 @cached_property
925 def EdkBuildOption(self):
926 return self._ExpandBuildOption(self.Platform.BuildOptions, EDK_NAME)
927
928 ## Return the build options specific for EDKII modules in this platform
929 @cached_property
930 def EdkIIBuildOption(self):
931 return self._ExpandBuildOption(self.Platform.BuildOptions, EDKII_NAME)
932
933 ## Parse build_rule.txt in Conf Directory.
934 #
935 # @retval BuildRule object
936 #
937 @cached_property
938 def BuildRule(self):
939 BuildRuleFile = None
940 if TAB_TAT_DEFINES_BUILD_RULE_CONF in self.Workspace.TargetTxt.TargetTxtDictionary:
941 BuildRuleFile = self.Workspace.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_BUILD_RULE_CONF]
942 if not BuildRuleFile:
943 BuildRuleFile = gDefaultBuildRuleFile
944 RetVal = BuildRule(BuildRuleFile)
945 if RetVal._FileVersion == "":
946 RetVal._FileVersion = AutoGenReqBuildRuleVerNum
947 else:
948 if RetVal._FileVersion < AutoGenReqBuildRuleVerNum :
949 # If Build Rule's version is less than the version number required by the tools, halting the build.
950 EdkLogger.error("build", AUTOGEN_ERROR,
951 ExtraData="The version number [%s] of build_rule.txt is less than the version number required by the AutoGen.(the minimum required version number is [%s])"\
952 % (RetVal._FileVersion, AutoGenReqBuildRuleVerNum))
953 return RetVal
954
955 ## Summarize the packages used by modules in this platform
956 @cached_property
957 def PackageList(self):
958 RetVal = set()
959 for Mb in self._MbList:
960 RetVal.update(Mb.Packages)
961 for lb in Mb.LibInstances:
962 RetVal.update(lb.Packages)
963 #Collect package set information from INF of FDF
964 for ModuleFile in self._AsBuildModuleList:
965 if ModuleFile in self.Platform.Modules:
966 continue
967 ModuleData = self.BuildDatabase[ModuleFile, self.Arch, self.BuildTarget, self.ToolChain]
968 RetVal.update(ModuleData.Packages)
969 return list(RetVal)
970
971 @cached_property
972 def NonDynamicPcdDict(self):
973 return {(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):Pcd for Pcd in self.NonDynamicPcdList}
974
975 ## Get list of non-dynamic PCDs
976 @property
977 def NonDynamicPcdList(self):
978 if not self._NonDynamicPcdList:
979 self.CollectPlatformDynamicPcds()
980 return self._NonDynamicPcdList
981
982 ## Get list of dynamic PCDs
983 @property
984 def DynamicPcdList(self):
985 if not self._DynamicPcdList:
986 self.CollectPlatformDynamicPcds()
987 return self._DynamicPcdList
988
989 ## Generate Token Number for all PCD
990 @cached_property
991 def PcdTokenNumber(self):
992 RetVal = OrderedDict()
993 TokenNumber = 1
994 #
995 # Make the Dynamic and DynamicEx PCD use within different TokenNumber area.
996 # Such as:
997 #
998 # Dynamic PCD:
999 # TokenNumber 0 ~ 10
1000 # DynamicEx PCD:
1001 # TokeNumber 11 ~ 20
1002 #
1003 for Pcd in self.DynamicPcdList:
1004 if Pcd.Phase == "PEI" and Pcd.Type in PCD_DYNAMIC_TYPE_SET:
1005 EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))
1006 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
1007 TokenNumber += 1
1008
1009 for Pcd in self.DynamicPcdList:
1010 if Pcd.Phase == "PEI" and Pcd.Type in PCD_DYNAMIC_EX_TYPE_SET:
1011 EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))
1012 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
1013 TokenNumber += 1
1014
1015 for Pcd in self.DynamicPcdList:
1016 if Pcd.Phase == "DXE" and Pcd.Type in PCD_DYNAMIC_TYPE_SET:
1017 EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))
1018 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
1019 TokenNumber += 1
1020
1021 for Pcd in self.DynamicPcdList:
1022 if Pcd.Phase == "DXE" and Pcd.Type in PCD_DYNAMIC_EX_TYPE_SET:
1023 EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))
1024 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
1025 TokenNumber += 1
1026
1027 for Pcd in self.NonDynamicPcdList:
1028 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
1029 TokenNumber += 1
1030 return RetVal
1031
1032 @cached_property
1033 def _MbList(self):
1034 return [self.BuildDatabase[m, self.Arch, self.BuildTarget, self.ToolChain] for m in self.Platform.Modules]
1035
1036 @cached_property
1037 def _MaList(self):
1038 for ModuleFile in self.Platform.Modules:
1039 Ma = ModuleAutoGen(
1040 self.Workspace,
1041 ModuleFile,
1042 self.BuildTarget,
1043 self.ToolChain,
1044 self.Arch,
1045 self.MetaFile,
1046 self.DataPipe
1047 )
1048 self.Platform.Modules[ModuleFile].M = Ma
1049 return [x.M for x in self.Platform.Modules.values()]
1050
1051 ## Summarize ModuleAutoGen objects of all modules to be built for this platform
1052 @cached_property
1053 def ModuleAutoGenList(self):
1054 RetVal = []
1055 for Ma in self._MaList:
1056 if Ma not in RetVal:
1057 RetVal.append(Ma)
1058 return RetVal
1059
1060 ## Summarize ModuleAutoGen objects of all libraries to be built for this platform
1061 @cached_property
1062 def LibraryAutoGenList(self):
1063 RetVal = []
1064 for Ma in self._MaList:
1065 for La in Ma.LibraryAutoGenList:
1066 if La not in RetVal:
1067 RetVal.append(La)
1068 if Ma not in La.ReferenceModules:
1069 La.ReferenceModules.append(Ma)
1070 return RetVal
1071
1072 ## Test if a module is supported by the platform
1073 #
1074 # An error will be raised directly if the module or its arch is not supported
1075 # by the platform or current configuration
1076 #
1077 def ValidModule(self, Module):
1078 return Module in self.Platform.Modules or Module in self.Platform.LibraryInstances \
1079 or Module in self._AsBuildModuleList
1080 @cached_property
1081 def GetAllModuleInfo(self,WithoutPcd=True):
1082 ModuleLibs = set()
1083 for m in self.Platform.Modules:
1084 module_obj = self.BuildDatabase[m,self.Arch,self.BuildTarget,self.ToolChain]
1085 if not bool(module_obj.LibraryClass):
1086 Libs = GetModuleLibInstances(module_obj, self.Platform, self.BuildDatabase, self.Arch,self.BuildTarget,self.ToolChain)
1087 else:
1088 Libs = []
1089 ModuleLibs.update( set([(l.MetaFile.File,l.MetaFile.Root,l.Arch,True) for l in Libs]))
1090 if WithoutPcd and module_obj.PcdIsDriver:
1091 continue
1092 ModuleLibs.add((m.File,m.Root,module_obj.Arch,False))
1093
1094 return ModuleLibs
1095
1096 ## Resolve the library classes in a module to library instances
1097 #
1098 # This method will not only resolve library classes but also sort the library
1099 # instances according to the dependency-ship.
1100 #
1101 # @param Module The module from which the library classes will be resolved
1102 #
1103 # @retval library_list List of library instances sorted
1104 #
1105 def ApplyLibraryInstance(self, Module):
1106 # Cover the case that the binary INF file is list in the FDF file but not DSC file, return empty list directly
1107 if str(Module) not in self.Platform.Modules:
1108 return []
1109
1110 return GetModuleLibInstances(Module,
1111 self.Platform,
1112 self.BuildDatabase,
1113 self.Arch,
1114 self.BuildTarget,
1115 self.ToolChain,
1116 self.MetaFile,
1117 EdkLogger)
1118
1119 ## Override PCD setting (type, value, ...)
1120 #
1121 # @param ToPcd The PCD to be overridden
1122 # @param FromPcd The PCD overriding from
1123 #
1124 def _OverridePcd(self, ToPcd, FromPcd, Module="", Msg="", Library=""):
1125 #
1126 # in case there's PCDs coming from FDF file, which have no type given.
1127 # at this point, ToPcd.Type has the type found from dependent
1128 # package
1129 #
1130 TokenCName = ToPcd.TokenCName
1131 for PcdItem in GlobalData.MixedPcd:
1132 if (ToPcd.TokenCName, ToPcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
1133 TokenCName = PcdItem[0]
1134 break
1135 if FromPcd is not None:
1136 if ToPcd.Pending and FromPcd.Type:
1137 ToPcd.Type = FromPcd.Type
1138 elif ToPcd.Type and FromPcd.Type\
1139 and ToPcd.Type != FromPcd.Type and ToPcd.Type in FromPcd.Type:
1140 if ToPcd.Type.strip() == TAB_PCDS_DYNAMIC_EX:
1141 ToPcd.Type = FromPcd.Type
1142 elif ToPcd.Type and FromPcd.Type \
1143 and ToPcd.Type != FromPcd.Type:
1144 if Library:
1145 Module = str(Module) + " 's library file (" + str(Library) + ")"
1146 EdkLogger.error("build", OPTION_CONFLICT, "Mismatched PCD type",
1147 ExtraData="%s.%s is used as [%s] in module %s, but as [%s] in %s."\
1148 % (ToPcd.TokenSpaceGuidCName, TokenCName,
1149 ToPcd.Type, Module, FromPcd.Type, Msg),
1150 File=self.MetaFile)
1151
1152 if FromPcd.MaxDatumSize:
1153 ToPcd.MaxDatumSize = FromPcd.MaxDatumSize
1154 ToPcd.MaxSizeUserSet = FromPcd.MaxDatumSize
1155 if FromPcd.DefaultValue:
1156 ToPcd.DefaultValue = FromPcd.DefaultValue
1157 if FromPcd.TokenValue:
1158 ToPcd.TokenValue = FromPcd.TokenValue
1159 if FromPcd.DatumType:
1160 ToPcd.DatumType = FromPcd.DatumType
1161 if FromPcd.SkuInfoList:
1162 ToPcd.SkuInfoList = FromPcd.SkuInfoList
1163 if FromPcd.UserDefinedDefaultStoresFlag:
1164 ToPcd.UserDefinedDefaultStoresFlag = FromPcd.UserDefinedDefaultStoresFlag
1165 # Add Flexible PCD format parse
1166 if ToPcd.DefaultValue:
1167 try:
1168 ToPcd.DefaultValue = ValueExpressionEx(ToPcd.DefaultValue, ToPcd.DatumType, self.Platform._GuidDict)(True)
1169 except BadExpression as Value:
1170 EdkLogger.error('Parser', FORMAT_INVALID, 'PCD [%s.%s] Value "%s", %s' %(ToPcd.TokenSpaceGuidCName, ToPcd.TokenCName, ToPcd.DefaultValue, Value),
1171 File=self.MetaFile)
1172
1173 # check the validation of datum
1174 IsValid, Cause = CheckPcdDatum(ToPcd.DatumType, ToPcd.DefaultValue)
1175 if not IsValid:
1176 EdkLogger.error('build', FORMAT_INVALID, Cause, File=self.MetaFile,
1177 ExtraData="%s.%s" % (ToPcd.TokenSpaceGuidCName, TokenCName))
1178 ToPcd.validateranges = FromPcd.validateranges
1179 ToPcd.validlists = FromPcd.validlists
1180 ToPcd.expressions = FromPcd.expressions
1181 ToPcd.CustomAttribute = FromPcd.CustomAttribute
1182
1183 if FromPcd is not None and ToPcd.DatumType == TAB_VOID and not ToPcd.MaxDatumSize:
1184 EdkLogger.debug(EdkLogger.DEBUG_9, "No MaxDatumSize specified for PCD %s.%s" \
1185 % (ToPcd.TokenSpaceGuidCName, TokenCName))
1186 Value = ToPcd.DefaultValue
1187 if not Value:
1188 ToPcd.MaxDatumSize = '1'
1189 elif Value[0] == 'L':
1190 ToPcd.MaxDatumSize = str((len(Value) - 2) * 2)
1191 elif Value[0] == '{':
1192 ToPcd.MaxDatumSize = str(len(Value.split(',')))
1193 else:
1194 ToPcd.MaxDatumSize = str(len(Value) - 1)
1195
1196 # apply default SKU for dynamic PCDS if specified one is not available
1197 if (ToPcd.Type in PCD_DYNAMIC_TYPE_SET or ToPcd.Type in PCD_DYNAMIC_EX_TYPE_SET) \
1198 and not ToPcd.SkuInfoList:
1199 if self.Platform.SkuName in self.Platform.SkuIds:
1200 SkuName = self.Platform.SkuName
1201 else:
1202 SkuName = TAB_DEFAULT
1203 ToPcd.SkuInfoList = {
1204 SkuName : SkuInfoClass(SkuName, self.Platform.SkuIds[SkuName][0], '', '', '', '', '', ToPcd.DefaultValue)
1205 }
1206
1207 ## Apply PCD setting defined platform to a module
1208 #
1209 # @param Module The module from which the PCD setting will be overridden
1210 #
1211 # @retval PCD_list The list PCDs with settings from platform
1212 #
1213 def ApplyPcdSetting(self, Module, Pcds, Library=""):
1214 # for each PCD in module
1215 for Name, Guid in Pcds:
1216 PcdInModule = Pcds[Name, Guid]
1217 # find out the PCD setting in platform
1218 if (Name, Guid) in self.Platform.Pcds:
1219 PcdInPlatform = self.Platform.Pcds[Name, Guid]
1220 else:
1221 PcdInPlatform = None
1222 # then override the settings if any
1223 self._OverridePcd(PcdInModule, PcdInPlatform, Module, Msg="DSC PCD sections", Library=Library)
1224 # resolve the VariableGuid value
1225 for SkuId in PcdInModule.SkuInfoList:
1226 Sku = PcdInModule.SkuInfoList[SkuId]
1227 if Sku.VariableGuid == '': continue
1228 Sku.VariableGuidValue = GuidValue(Sku.VariableGuid, self.PackageList, self.MetaFile.Path)
1229 if Sku.VariableGuidValue is None:
1230 PackageList = "\n\t".join(str(P) for P in self.PackageList)
1231 EdkLogger.error(
1232 'build',
1233 RESOURCE_NOT_AVAILABLE,
1234 "Value of GUID [%s] is not found in" % Sku.VariableGuid,
1235 ExtraData=PackageList + "\n\t(used with %s.%s from module %s)" \
1236 % (Guid, Name, str(Module)),
1237 File=self.MetaFile
1238 )
1239
1240 # override PCD settings with module specific setting
1241 if Module in self.Platform.Modules:
1242 PlatformModule = self.Platform.Modules[str(Module)]
1243 for Key in PlatformModule.Pcds:
1244 if GlobalData.BuildOptionPcd:
1245 for pcd in GlobalData.BuildOptionPcd:
1246 (TokenSpaceGuidCName, TokenCName, FieldName, pcdvalue, _) = pcd
1247 if (TokenCName, TokenSpaceGuidCName) == Key and FieldName =="":
1248 PlatformModule.Pcds[Key].DefaultValue = pcdvalue
1249 PlatformModule.Pcds[Key].PcdValueFromComm = pcdvalue
1250 break
1251 Flag = False
1252 if Key in Pcds:
1253 ToPcd = Pcds[Key]
1254 Flag = True
1255 elif Key in GlobalData.MixedPcd:
1256 for PcdItem in GlobalData.MixedPcd[Key]:
1257 if PcdItem in Pcds:
1258 ToPcd = Pcds[PcdItem]
1259 Flag = True
1260 break
1261 if Flag:
1262 self._OverridePcd(ToPcd, PlatformModule.Pcds[Key], Module, Msg="DSC Components Module scoped PCD section", Library=Library)
1263 # use PCD value to calculate the MaxDatumSize when it is not specified
1264 for Name, Guid in Pcds:
1265 Pcd = Pcds[Name, Guid]
1266 if Pcd.DatumType == TAB_VOID and not Pcd.MaxDatumSize:
1267 Pcd.MaxSizeUserSet = None
1268 Value = Pcd.DefaultValue
1269 if not Value:
1270 Pcd.MaxDatumSize = '1'
1271 elif Value[0] == 'L':
1272 Pcd.MaxDatumSize = str((len(Value) - 2) * 2)
1273 elif Value[0] == '{':
1274 Pcd.MaxDatumSize = str(len(Value.split(',')))
1275 else:
1276 Pcd.MaxDatumSize = str(len(Value) - 1)
1277 return list(Pcds.values())
1278
1279 ## Append build options in platform to a module
1280 #
1281 # @param Module The module to which the build options will be appended
1282 #
1283 # @retval options The options appended with build options in platform
1284 #
1285 def ApplyBuildOption(self, Module):
1286 # Get the different options for the different style module
1287 PlatformOptions = self.EdkIIBuildOption
1288 ModuleTypeOptions = self.Platform.GetBuildOptionsByModuleType(EDKII_NAME, Module.ModuleType)
1289 ModuleTypeOptions = self._ExpandBuildOption(ModuleTypeOptions)
1290 ModuleOptions = self._ExpandBuildOption(Module.BuildOptions)
1291 if Module in self.Platform.Modules:
1292 PlatformModule = self.Platform.Modules[str(Module)]
1293 PlatformModuleOptions = self._ExpandBuildOption(PlatformModule.BuildOptions)
1294 else:
1295 PlatformModuleOptions = {}
1296
1297 BuildRuleOrder = None
1298 for Options in [self.ToolDefinition, ModuleOptions, PlatformOptions, ModuleTypeOptions, PlatformModuleOptions]:
1299 for Tool in Options:
1300 for Attr in Options[Tool]:
1301 if Attr == TAB_TOD_DEFINES_BUILDRULEORDER:
1302 BuildRuleOrder = Options[Tool][Attr]
1303
1304 AllTools = set(list(ModuleOptions.keys()) + list(PlatformOptions.keys()) +
1305 list(PlatformModuleOptions.keys()) + list(ModuleTypeOptions.keys()) +
1306 list(self.ToolDefinition.keys()))
1307 BuildOptions = defaultdict(lambda: defaultdict(str))
1308 for Tool in AllTools:
1309 for Options in [self.ToolDefinition, ModuleOptions, PlatformOptions, ModuleTypeOptions, PlatformModuleOptions]:
1310 if Tool not in Options:
1311 continue
1312 for Attr in Options[Tool]:
1313 #
1314 # Do not generate it in Makefile
1315 #
1316 if Attr == TAB_TOD_DEFINES_BUILDRULEORDER:
1317 continue
1318 Value = Options[Tool][Attr]
1319 # check if override is indicated
1320 if Value.startswith('='):
1321 BuildOptions[Tool][Attr] = mws.handleWsMacro(Value[1:])
1322 else:
1323 if Attr != 'PATH':
1324 BuildOptions[Tool][Attr] += " " + mws.handleWsMacro(Value)
1325 else:
1326 BuildOptions[Tool][Attr] = mws.handleWsMacro(Value)
1327
1328 return BuildOptions, BuildRuleOrder
1329
1330
1331 def GetGlobalBuildOptions(self,Module):
1332 ModuleTypeOptions = self.Platform.GetBuildOptionsByModuleType(EDKII_NAME, Module.ModuleType)
1333 ModuleTypeOptions = self._ExpandBuildOption(ModuleTypeOptions)
1334
1335 if Module in self.Platform.Modules:
1336 PlatformModule = self.Platform.Modules[str(Module)]
1337 PlatformModuleOptions = self._ExpandBuildOption(PlatformModule.BuildOptions)
1338 else:
1339 PlatformModuleOptions = {}
1340
1341 return ModuleTypeOptions,PlatformModuleOptions
1342 def ModuleGuid(self,Module):
1343 if os.path.basename(Module.MetaFile.File) != os.path.basename(Module.MetaFile.Path):
1344 #
1345 # Length of GUID is 36
1346 #
1347 return os.path.basename(Module.MetaFile.Path)[:36]
1348 return Module.Guid
1349 @cached_property
1350 def UniqueBaseName(self):
1351 retVal ={}
1352 ModuleNameDict = {}
1353 UniqueName = {}
1354 for Module in self._MbList:
1355 unique_base_name = '%s_%s' % (Module.BaseName,self.ModuleGuid(Module))
1356 if unique_base_name not in ModuleNameDict:
1357 ModuleNameDict[unique_base_name] = []
1358 ModuleNameDict[unique_base_name].append(Module.MetaFile)
1359 if Module.BaseName not in UniqueName:
1360 UniqueName[Module.BaseName] = set()
1361 UniqueName[Module.BaseName].add((self.ModuleGuid(Module),Module.MetaFile))
1362 for module_paths in ModuleNameDict.values():
1363 if len(module_paths) > 1 and len(set(module_paths))>1:
1364 samemodules = list(set(module_paths))
1365 EdkLogger.error("build", FILE_DUPLICATED, 'Modules have same BaseName and FILE_GUID:\n'
1366 ' %s\n %s' % (samemodules[0], samemodules[1]))
1367 for name in UniqueName:
1368 Guid_Path = UniqueName[name]
1369 if len(Guid_Path) > 1:
1370 retVal[name] = '%s_%s' % (name,Guid_Path.pop()[0])
1371 return retVal
1372 ## Expand * in build option key
1373 #
1374 # @param Options Options to be expanded
1375 # @param ToolDef Use specified ToolDef instead of full version.
1376 # This is needed during initialization to prevent
1377 # infinite recursion betweeh BuildOptions,
1378 # ToolDefinition, and this function.
1379 #
1380 # @retval options Options expanded
1381 #
1382 def _ExpandBuildOption(self, Options, ModuleStyle=None, ToolDef=None):
1383 if not ToolDef:
1384 ToolDef = self.ToolDefinition
1385 BuildOptions = {}
1386 FamilyMatch = False
1387 FamilyIsNull = True
1388
1389 OverrideList = {}
1390 #
1391 # Construct a list contain the build options which need override.
1392 #
1393 for Key in Options:
1394 #
1395 # Key[0] -- tool family
1396 # Key[1] -- TARGET_TOOLCHAIN_ARCH_COMMANDTYPE_ATTRIBUTE
1397 #
1398 if (Key[0] == self.BuildRuleFamily and
1399 (ModuleStyle is None or len(Key) < 3 or (len(Key) > 2 and Key[2] == ModuleStyle))):
1400 Target, ToolChain, Arch, CommandType, Attr = Key[1].split('_')
1401 if (Target == self.BuildTarget or Target == TAB_STAR) and\
1402 (ToolChain == self.ToolChain or ToolChain == TAB_STAR) and\
1403 (Arch == self.Arch or Arch == TAB_STAR) and\
1404 Options[Key].startswith("="):
1405
1406 if OverrideList.get(Key[1]) is not None:
1407 OverrideList.pop(Key[1])
1408 OverrideList[Key[1]] = Options[Key]
1409
1410 #
1411 # Use the highest priority value.
1412 #
1413 if (len(OverrideList) >= 2):
1414 KeyList = list(OverrideList.keys())
1415 for Index in range(len(KeyList)):
1416 NowKey = KeyList[Index]
1417 Target1, ToolChain1, Arch1, CommandType1, Attr1 = NowKey.split("_")
1418 for Index1 in range(len(KeyList) - Index - 1):
1419 NextKey = KeyList[Index1 + Index + 1]
1420 #
1421 # Compare two Key, if one is included by another, choose the higher priority one
1422 #
1423 Target2, ToolChain2, Arch2, CommandType2, Attr2 = NextKey.split("_")
1424 if (Target1 == Target2 or Target1 == TAB_STAR or Target2 == TAB_STAR) and\
1425 (ToolChain1 == ToolChain2 or ToolChain1 == TAB_STAR or ToolChain2 == TAB_STAR) and\
1426 (Arch1 == Arch2 or Arch1 == TAB_STAR or Arch2 == TAB_STAR) and\
1427 (CommandType1 == CommandType2 or CommandType1 == TAB_STAR or CommandType2 == TAB_STAR) and\
1428 (Attr1 == Attr2 or Attr1 == TAB_STAR or Attr2 == TAB_STAR):
1429
1430 if CalculatePriorityValue(NowKey) > CalculatePriorityValue(NextKey):
1431 if Options.get((self.BuildRuleFamily, NextKey)) is not None:
1432 Options.pop((self.BuildRuleFamily, NextKey))
1433 else:
1434 if Options.get((self.BuildRuleFamily, NowKey)) is not None:
1435 Options.pop((self.BuildRuleFamily, NowKey))
1436
1437 for Key in Options:
1438 if ModuleStyle is not None and len (Key) > 2:
1439 # Check Module style is EDK or EDKII.
1440 # Only append build option for the matched style module.
1441 if ModuleStyle == EDK_NAME and Key[2] != EDK_NAME:
1442 continue
1443 elif ModuleStyle == EDKII_NAME and Key[2] != EDKII_NAME:
1444 continue
1445 Family = Key[0]
1446 Target, Tag, Arch, Tool, Attr = Key[1].split("_")
1447 # if tool chain family doesn't match, skip it
1448 if Tool in ToolDef and Family != "":
1449 FamilyIsNull = False
1450 if ToolDef[Tool].get(TAB_TOD_DEFINES_BUILDRULEFAMILY, "") != "":
1451 if Family != ToolDef[Tool][TAB_TOD_DEFINES_BUILDRULEFAMILY]:
1452 continue
1453 elif Family != ToolDef[Tool][TAB_TOD_DEFINES_FAMILY]:
1454 continue
1455 FamilyMatch = True
1456 # expand any wildcard
1457 if Target == TAB_STAR or Target == self.BuildTarget:
1458 if Tag == TAB_STAR or Tag == self.ToolChain:
1459 if Arch == TAB_STAR or Arch == self.Arch:
1460 if Tool not in BuildOptions:
1461 BuildOptions[Tool] = {}
1462 if Attr != "FLAGS" or Attr not in BuildOptions[Tool] or Options[Key].startswith('='):
1463 BuildOptions[Tool][Attr] = Options[Key]
1464 else:
1465 # append options for the same tool except PATH
1466 if Attr != 'PATH':
1467 BuildOptions[Tool][Attr] += " " + Options[Key]
1468 else:
1469 BuildOptions[Tool][Attr] = Options[Key]
1470 # Build Option Family has been checked, which need't to be checked again for family.
1471 if FamilyMatch or FamilyIsNull:
1472 return BuildOptions
1473
1474 for Key in Options:
1475 if ModuleStyle is not None and len (Key) > 2:
1476 # Check Module style is EDK or EDKII.
1477 # Only append build option for the matched style module.
1478 if ModuleStyle == EDK_NAME and Key[2] != EDK_NAME:
1479 continue
1480 elif ModuleStyle == EDKII_NAME and Key[2] != EDKII_NAME:
1481 continue
1482 Family = Key[0]
1483 Target, Tag, Arch, Tool, Attr = Key[1].split("_")
1484 # if tool chain family doesn't match, skip it
1485 if Tool not in ToolDef or Family == "":
1486 continue
1487 # option has been added before
1488 if Family != ToolDef[Tool][TAB_TOD_DEFINES_FAMILY]:
1489 continue
1490
1491 # expand any wildcard
1492 if Target == TAB_STAR or Target == self.BuildTarget:
1493 if Tag == TAB_STAR or Tag == self.ToolChain:
1494 if Arch == TAB_STAR or Arch == self.Arch:
1495 if Tool not in BuildOptions:
1496 BuildOptions[Tool] = {}
1497 if Attr != "FLAGS" or Attr not in BuildOptions[Tool] or Options[Key].startswith('='):
1498 BuildOptions[Tool][Attr] = Options[Key]
1499 else:
1500 # append options for the same tool except PATH
1501 if Attr != 'PATH':
1502 BuildOptions[Tool][Attr] += " " + Options[Key]
1503 else:
1504 BuildOptions[Tool][Attr] = Options[Key]
1505 return BuildOptions