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