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