]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/AutoGen/PlatformAutoGen.py
BaseTools: Enable Module Scope Structure Pcd
[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 sorted(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 ModuleList = []
1047 for m in self.Platform.Modules:
1048 component = self.Platform.Modules[m]
1049 module = self.BuildDatabase[m, self.Arch, self.BuildTarget, self.ToolChain]
1050 module.Guid = component.Guid
1051 ModuleList.append(module)
1052 return ModuleList
1053
1054 @cached_property
1055 def _MaList(self):
1056 for ModuleFile in self.Platform.Modules:
1057 Ma = ModuleAutoGen(
1058 self.Workspace,
1059 ModuleFile,
1060 self.BuildTarget,
1061 self.ToolChain,
1062 self.Arch,
1063 self.MetaFile,
1064 self.DataPipe
1065 )
1066 self.Platform.Modules[ModuleFile].M = Ma
1067 return [x.M for x in self.Platform.Modules.values()]
1068
1069 ## Summarize ModuleAutoGen objects of all modules to be built for this platform
1070 @cached_property
1071 def ModuleAutoGenList(self):
1072 RetVal = []
1073 for Ma in self._MaList:
1074 if Ma not in RetVal:
1075 RetVal.append(Ma)
1076 return RetVal
1077
1078 ## Summarize ModuleAutoGen objects of all libraries to be built for this platform
1079 @cached_property
1080 def LibraryAutoGenList(self):
1081 RetVal = []
1082 for Ma in self._MaList:
1083 for La in Ma.LibraryAutoGenList:
1084 if La not in RetVal:
1085 RetVal.append(La)
1086 if Ma not in La.ReferenceModules:
1087 La.ReferenceModules.append(Ma)
1088 return RetVal
1089
1090 ## Test if a module is supported by the platform
1091 #
1092 # An error will be raised directly if the module or its arch is not supported
1093 # by the platform or current configuration
1094 #
1095 def ValidModule(self, Module):
1096 return Module in self.Platform.Modules or Module in self.Platform.LibraryInstances \
1097 or Module in self._AsBuildModuleList
1098 @cached_property
1099 def GetAllModuleInfo(self,WithoutPcd=True):
1100 ModuleLibs = set()
1101 for m in self.Platform.Modules:
1102 module_obj = self.BuildDatabase[m,self.Arch,self.BuildTarget,self.ToolChain]
1103 if not bool(module_obj.LibraryClass):
1104 Libs = GetModuleLibInstances(module_obj, self.Platform, self.BuildDatabase, self.Arch,self.BuildTarget,self.ToolChain,self.MetaFile,EdkLogger)
1105 else:
1106 Libs = []
1107 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]))
1108 if WithoutPcd and module_obj.PcdIsDriver:
1109 continue
1110 ModuleLibs.add((m.File,m.Root,m.Path,m.BaseName,m.OriginalPath,module_obj.Arch,bool(module_obj.LibraryClass)))
1111
1112 return ModuleLibs
1113
1114 ## Resolve the library classes in a module to library instances
1115 #
1116 # This method will not only resolve library classes but also sort the library
1117 # instances according to the dependency-ship.
1118 #
1119 # @param Module The module from which the library classes will be resolved
1120 #
1121 # @retval library_list List of library instances sorted
1122 #
1123 def ApplyLibraryInstance(self, Module):
1124 # Cover the case that the binary INF file is list in the FDF file but not DSC file, return empty list directly
1125 if str(Module) not in self.Platform.Modules:
1126 return []
1127
1128 return GetModuleLibInstances(Module,
1129 self.Platform,
1130 self.BuildDatabase,
1131 self.Arch,
1132 self.BuildTarget,
1133 self.ToolChain,
1134 self.MetaFile,
1135 EdkLogger)
1136
1137 ## Override PCD setting (type, value, ...)
1138 #
1139 # @param ToPcd The PCD to be overridden
1140 # @param FromPcd The PCD overriding from
1141 #
1142 def _OverridePcd(self, ToPcd, FromPcd, Module="", Msg="", Library=""):
1143 #
1144 # in case there's PCDs coming from FDF file, which have no type given.
1145 # at this point, ToPcd.Type has the type found from dependent
1146 # package
1147 #
1148 TokenCName = ToPcd.TokenCName
1149 for PcdItem in GlobalData.MixedPcd:
1150 if (ToPcd.TokenCName, ToPcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
1151 TokenCName = PcdItem[0]
1152 break
1153 if FromPcd is not None:
1154 if ToPcd.Pending and FromPcd.Type:
1155 ToPcd.Type = FromPcd.Type
1156 elif ToPcd.Type and FromPcd.Type\
1157 and ToPcd.Type != FromPcd.Type and ToPcd.Type in FromPcd.Type:
1158 if ToPcd.Type.strip() == TAB_PCDS_DYNAMIC_EX:
1159 ToPcd.Type = FromPcd.Type
1160 elif ToPcd.Type and FromPcd.Type \
1161 and ToPcd.Type != FromPcd.Type:
1162 if Library:
1163 Module = str(Module) + " 's library file (" + str(Library) + ")"
1164 EdkLogger.error("build", OPTION_CONFLICT, "Mismatched PCD type",
1165 ExtraData="%s.%s is used as [%s] in module %s, but as [%s] in %s."\
1166 % (ToPcd.TokenSpaceGuidCName, TokenCName,
1167 ToPcd.Type, Module, FromPcd.Type, Msg),
1168 File=self.MetaFile)
1169
1170 if FromPcd.MaxDatumSize:
1171 ToPcd.MaxDatumSize = FromPcd.MaxDatumSize
1172 ToPcd.MaxSizeUserSet = FromPcd.MaxDatumSize
1173 if FromPcd.DefaultValue:
1174 ToPcd.DefaultValue = FromPcd.DefaultValue
1175 if FromPcd.TokenValue:
1176 ToPcd.TokenValue = FromPcd.TokenValue
1177 if FromPcd.DatumType:
1178 ToPcd.DatumType = FromPcd.DatumType
1179 if FromPcd.SkuInfoList:
1180 ToPcd.SkuInfoList = FromPcd.SkuInfoList
1181 if FromPcd.UserDefinedDefaultStoresFlag:
1182 ToPcd.UserDefinedDefaultStoresFlag = FromPcd.UserDefinedDefaultStoresFlag
1183 # Add Flexible PCD format parse
1184 if ToPcd.DefaultValue:
1185 try:
1186 ToPcd.DefaultValue = ValueExpressionEx(ToPcd.DefaultValue, ToPcd.DatumType, self.Platform._GuidDict)(True)
1187 except BadExpression as Value:
1188 EdkLogger.error('Parser', FORMAT_INVALID, 'PCD [%s.%s] Value "%s", %s' %(ToPcd.TokenSpaceGuidCName, ToPcd.TokenCName, ToPcd.DefaultValue, Value),
1189 File=self.MetaFile)
1190
1191 # check the validation of datum
1192 IsValid, Cause = CheckPcdDatum(ToPcd.DatumType, ToPcd.DefaultValue)
1193 if not IsValid:
1194 EdkLogger.error('build', FORMAT_INVALID, Cause, File=self.MetaFile,
1195 ExtraData="%s.%s" % (ToPcd.TokenSpaceGuidCName, TokenCName))
1196 ToPcd.validateranges = FromPcd.validateranges
1197 ToPcd.validlists = FromPcd.validlists
1198 ToPcd.expressions = FromPcd.expressions
1199 ToPcd.CustomAttribute = FromPcd.CustomAttribute
1200
1201 if FromPcd is not None and ToPcd.DatumType == TAB_VOID and not ToPcd.MaxDatumSize:
1202 EdkLogger.debug(EdkLogger.DEBUG_9, "No MaxDatumSize specified for PCD %s.%s" \
1203 % (ToPcd.TokenSpaceGuidCName, TokenCName))
1204 Value = ToPcd.DefaultValue
1205 if not Value:
1206 ToPcd.MaxDatumSize = '1'
1207 elif Value[0] == 'L':
1208 ToPcd.MaxDatumSize = str((len(Value) - 2) * 2)
1209 elif Value[0] == '{':
1210 ToPcd.MaxDatumSize = str(len(Value.split(',')))
1211 else:
1212 ToPcd.MaxDatumSize = str(len(Value) - 1)
1213
1214 # apply default SKU for dynamic PCDS if specified one is not available
1215 if (ToPcd.Type in PCD_DYNAMIC_TYPE_SET or ToPcd.Type in PCD_DYNAMIC_EX_TYPE_SET) \
1216 and not ToPcd.SkuInfoList:
1217 if self.Platform.SkuName in self.Platform.SkuIds:
1218 SkuName = self.Platform.SkuName
1219 else:
1220 SkuName = TAB_DEFAULT
1221 ToPcd.SkuInfoList = {
1222 SkuName : SkuInfoClass(SkuName, self.Platform.SkuIds[SkuName][0], '', '', '', '', '', ToPcd.DefaultValue)
1223 }
1224
1225 ## Apply PCD setting defined platform to a module
1226 #
1227 # @param Module The module from which the PCD setting will be overridden
1228 #
1229 # @retval PCD_list The list PCDs with settings from platform
1230 #
1231 def ApplyPcdSetting(self, Module, Pcds, Library=""):
1232 # for each PCD in module
1233 for Name, Guid in Pcds:
1234 PcdInModule = Pcds[Name, Guid]
1235 # find out the PCD setting in platform
1236 if (Name, Guid) in self.Platform.Pcds:
1237 PcdInPlatform = self.Platform.Pcds[Name, Guid]
1238 else:
1239 PcdInPlatform = None
1240 # then override the settings if any
1241 self._OverridePcd(PcdInModule, PcdInPlatform, Module, Msg="DSC PCD sections", Library=Library)
1242 # resolve the VariableGuid value
1243 for SkuId in PcdInModule.SkuInfoList:
1244 Sku = PcdInModule.SkuInfoList[SkuId]
1245 if Sku.VariableGuid == '': continue
1246 Sku.VariableGuidValue = GuidValue(Sku.VariableGuid, self.PackageList, self.MetaFile.Path)
1247 if Sku.VariableGuidValue is None:
1248 PackageList = "\n\t".join(str(P) for P in self.PackageList)
1249 EdkLogger.error(
1250 'build',
1251 RESOURCE_NOT_AVAILABLE,
1252 "Value of GUID [%s] is not found in" % Sku.VariableGuid,
1253 ExtraData=PackageList + "\n\t(used with %s.%s from module %s)" \
1254 % (Guid, Name, str(Module)),
1255 File=self.MetaFile
1256 )
1257
1258 # override PCD settings with module specific setting
1259 if Module in self.Platform.Modules:
1260 PlatformModule = self.Platform.Modules[str(Module)]
1261 for Key in PlatformModule.Pcds:
1262 if GlobalData.BuildOptionPcd:
1263 for pcd in GlobalData.BuildOptionPcd:
1264 (TokenSpaceGuidCName, TokenCName, FieldName, pcdvalue, _) = pcd
1265 if (TokenCName, TokenSpaceGuidCName) == Key and FieldName =="":
1266 PlatformModule.Pcds[Key].DefaultValue = pcdvalue
1267 PlatformModule.Pcds[Key].PcdValueFromComm = pcdvalue
1268 break
1269 Flag = False
1270 if Key in Pcds:
1271 ToPcd = Pcds[Key]
1272 Flag = True
1273 elif Key in GlobalData.MixedPcd:
1274 for PcdItem in GlobalData.MixedPcd[Key]:
1275 if PcdItem in Pcds:
1276 ToPcd = Pcds[PcdItem]
1277 Flag = True
1278 break
1279 if Flag:
1280 self._OverridePcd(ToPcd, PlatformModule.Pcds[Key], Module, Msg="DSC Components Module scoped PCD section", Library=Library)
1281 # use PCD value to calculate the MaxDatumSize when it is not specified
1282 for Name, Guid in Pcds:
1283 Pcd = Pcds[Name, Guid]
1284 if Pcd.DatumType == TAB_VOID and not Pcd.MaxDatumSize:
1285 Pcd.MaxSizeUserSet = None
1286 Value = Pcd.DefaultValue
1287 if not Value:
1288 Pcd.MaxDatumSize = '1'
1289 elif Value[0] == 'L':
1290 Pcd.MaxDatumSize = str((len(Value) - 2) * 2)
1291 elif Value[0] == '{':
1292 Pcd.MaxDatumSize = str(len(Value.split(',')))
1293 else:
1294 Pcd.MaxDatumSize = str(len(Value) - 1)
1295 return list(Pcds.values())
1296
1297 ## Append build options in platform to a module
1298 #
1299 # @param Module The module to which the build options will be appended
1300 #
1301 # @retval options The options appended with build options in platform
1302 #
1303 def ApplyBuildOption(self, Module):
1304 # Get the different options for the different style module
1305 PlatformOptions = self.EdkIIBuildOption
1306 ModuleTypeOptions = self.Platform.GetBuildOptionsByModuleType(EDKII_NAME, Module.ModuleType)
1307 ModuleTypeOptions = self._ExpandBuildOption(ModuleTypeOptions)
1308 ModuleOptions = self._ExpandBuildOption(Module.BuildOptions)
1309 if Module in self.Platform.Modules:
1310 PlatformModule = self.Platform.Modules[str(Module)]
1311 PlatformModuleOptions = self._ExpandBuildOption(PlatformModule.BuildOptions)
1312 else:
1313 PlatformModuleOptions = {}
1314
1315 BuildRuleOrder = None
1316 for Options in [self.ToolDefinition, ModuleOptions, PlatformOptions, ModuleTypeOptions, PlatformModuleOptions]:
1317 for Tool in Options:
1318 for Attr in Options[Tool]:
1319 if Attr == TAB_TOD_DEFINES_BUILDRULEORDER:
1320 BuildRuleOrder = Options[Tool][Attr]
1321
1322 AllTools = set(list(ModuleOptions.keys()) + list(PlatformOptions.keys()) +
1323 list(PlatformModuleOptions.keys()) + list(ModuleTypeOptions.keys()) +
1324 list(self.ToolDefinition.keys()))
1325 BuildOptions = defaultdict(lambda: defaultdict(str))
1326 for Tool in AllTools:
1327 for Options in [self.ToolDefinition, ModuleOptions, PlatformOptions, ModuleTypeOptions, PlatformModuleOptions]:
1328 if Tool not in Options:
1329 continue
1330 for Attr in Options[Tool]:
1331 #
1332 # Do not generate it in Makefile
1333 #
1334 if Attr == TAB_TOD_DEFINES_BUILDRULEORDER:
1335 continue
1336 Value = Options[Tool][Attr]
1337 # check if override is indicated
1338 if Value.startswith('='):
1339 BuildOptions[Tool][Attr] = mws.handleWsMacro(Value[1:])
1340 else:
1341 if Attr != 'PATH':
1342 BuildOptions[Tool][Attr] += " " + mws.handleWsMacro(Value)
1343 else:
1344 BuildOptions[Tool][Attr] = mws.handleWsMacro(Value)
1345
1346 return BuildOptions, BuildRuleOrder
1347
1348
1349 def GetGlobalBuildOptions(self,Module):
1350 ModuleTypeOptions = self.Platform.GetBuildOptionsByModuleType(EDKII_NAME, Module.ModuleType)
1351 ModuleTypeOptions = self._ExpandBuildOption(ModuleTypeOptions)
1352
1353 if Module in self.Platform.Modules:
1354 PlatformModule = self.Platform.Modules[str(Module)]
1355 PlatformModuleOptions = self._ExpandBuildOption(PlatformModule.BuildOptions)
1356 else:
1357 PlatformModuleOptions = {}
1358
1359 return ModuleTypeOptions,PlatformModuleOptions
1360 def ModuleGuid(self,Module):
1361 if os.path.basename(Module.MetaFile.File) != os.path.basename(Module.MetaFile.Path):
1362 #
1363 # Length of GUID is 36
1364 #
1365 return os.path.basename(Module.MetaFile.Path)[:36]
1366 return Module.Guid
1367 @cached_property
1368 def UniqueBaseName(self):
1369 retVal ={}
1370 ModuleNameDict = {}
1371 UniqueName = {}
1372 for Module in self._MbList:
1373 unique_base_name = '%s_%s' % (Module.BaseName,self.ModuleGuid(Module))
1374 if unique_base_name not in ModuleNameDict:
1375 ModuleNameDict[unique_base_name] = []
1376 ModuleNameDict[unique_base_name].append(Module.MetaFile)
1377 if Module.BaseName not in UniqueName:
1378 UniqueName[Module.BaseName] = set()
1379 UniqueName[Module.BaseName].add((self.ModuleGuid(Module),Module.MetaFile))
1380 for module_paths in ModuleNameDict.values():
1381 if len(set(module_paths))>1:
1382 samemodules = list(set(module_paths))
1383 EdkLogger.error("build", FILE_DUPLICATED, 'Modules have same BaseName and FILE_GUID:\n'
1384 ' %s\n %s' % (samemodules[0], samemodules[1]))
1385 for name in UniqueName:
1386 Guid_Path = UniqueName[name]
1387 if len(Guid_Path) > 1:
1388 for guid,mpath in Guid_Path:
1389 retVal[(name,mpath)] = '%s_%s' % (name,guid)
1390 return retVal
1391 ## Expand * in build option key
1392 #
1393 # @param Options Options to be expanded
1394 # @param ToolDef Use specified ToolDef instead of full version.
1395 # This is needed during initialization to prevent
1396 # infinite recursion betweeh BuildOptions,
1397 # ToolDefinition, and this function.
1398 #
1399 # @retval options Options expanded
1400 #
1401 def _ExpandBuildOption(self, Options, ModuleStyle=None, ToolDef=None):
1402 if not ToolDef:
1403 ToolDef = self.ToolDefinition
1404 BuildOptions = {}
1405 FamilyMatch = False
1406 FamilyIsNull = True
1407
1408 OverrideList = {}
1409 #
1410 # Construct a list contain the build options which need override.
1411 #
1412 for Key in Options:
1413 #
1414 # Key[0] -- tool family
1415 # Key[1] -- TARGET_TOOLCHAIN_ARCH_COMMANDTYPE_ATTRIBUTE
1416 #
1417 if (Key[0] == self.BuildRuleFamily and
1418 (ModuleStyle is None or len(Key) < 3 or (len(Key) > 2 and Key[2] == ModuleStyle))):
1419 Target, ToolChain, Arch, CommandType, Attr = Key[1].split('_')
1420 if (Target == self.BuildTarget or Target == TAB_STAR) and\
1421 (ToolChain == self.ToolChain or ToolChain == TAB_STAR) and\
1422 (Arch == self.Arch or Arch == TAB_STAR) and\
1423 Options[Key].startswith("="):
1424
1425 if OverrideList.get(Key[1]) is not None:
1426 OverrideList.pop(Key[1])
1427 OverrideList[Key[1]] = Options[Key]
1428
1429 #
1430 # Use the highest priority value.
1431 #
1432 if (len(OverrideList) >= 2):
1433 KeyList = list(OverrideList.keys())
1434 for Index in range(len(KeyList)):
1435 NowKey = KeyList[Index]
1436 Target1, ToolChain1, Arch1, CommandType1, Attr1 = NowKey.split("_")
1437 for Index1 in range(len(KeyList) - Index - 1):
1438 NextKey = KeyList[Index1 + Index + 1]
1439 #
1440 # Compare two Key, if one is included by another, choose the higher priority one
1441 #
1442 Target2, ToolChain2, Arch2, CommandType2, Attr2 = NextKey.split("_")
1443 if (Target1 == Target2 or Target1 == TAB_STAR or Target2 == TAB_STAR) and\
1444 (ToolChain1 == ToolChain2 or ToolChain1 == TAB_STAR or ToolChain2 == TAB_STAR) and\
1445 (Arch1 == Arch2 or Arch1 == TAB_STAR or Arch2 == TAB_STAR) and\
1446 (CommandType1 == CommandType2 or CommandType1 == TAB_STAR or CommandType2 == TAB_STAR) and\
1447 (Attr1 == Attr2 or Attr1 == TAB_STAR or Attr2 == TAB_STAR):
1448
1449 if CalculatePriorityValue(NowKey) > CalculatePriorityValue(NextKey):
1450 if Options.get((self.BuildRuleFamily, NextKey)) is not None:
1451 Options.pop((self.BuildRuleFamily, NextKey))
1452 else:
1453 if Options.get((self.BuildRuleFamily, NowKey)) is not None:
1454 Options.pop((self.BuildRuleFamily, NowKey))
1455
1456 for Key in Options:
1457 if ModuleStyle is not None and len (Key) > 2:
1458 # Check Module style is EDK or EDKII.
1459 # Only append build option for the matched style module.
1460 if ModuleStyle == EDK_NAME and Key[2] != EDK_NAME:
1461 continue
1462 elif ModuleStyle == EDKII_NAME and Key[2] != EDKII_NAME:
1463 continue
1464 Family = Key[0]
1465 Target, Tag, Arch, Tool, Attr = Key[1].split("_")
1466 # if tool chain family doesn't match, skip it
1467 if Tool in ToolDef and Family != "":
1468 FamilyIsNull = False
1469 if ToolDef[Tool].get(TAB_TOD_DEFINES_BUILDRULEFAMILY, "") != "":
1470 if Family != ToolDef[Tool][TAB_TOD_DEFINES_BUILDRULEFAMILY]:
1471 continue
1472 elif Family != ToolDef[Tool][TAB_TOD_DEFINES_FAMILY]:
1473 continue
1474 FamilyMatch = True
1475 # expand any wildcard
1476 if Target == TAB_STAR or Target == self.BuildTarget:
1477 if Tag == TAB_STAR or Tag == self.ToolChain:
1478 if Arch == TAB_STAR or Arch == self.Arch:
1479 if Tool not in BuildOptions:
1480 BuildOptions[Tool] = {}
1481 if Attr != "FLAGS" or Attr not in BuildOptions[Tool] or Options[Key].startswith('='):
1482 BuildOptions[Tool][Attr] = Options[Key]
1483 else:
1484 # append options for the same tool except PATH
1485 if Attr != 'PATH':
1486 BuildOptions[Tool][Attr] += " " + Options[Key]
1487 else:
1488 BuildOptions[Tool][Attr] = Options[Key]
1489 # Build Option Family has been checked, which need't to be checked again for family.
1490 if FamilyMatch or FamilyIsNull:
1491 return BuildOptions
1492
1493 for Key in Options:
1494 if ModuleStyle is not None and len (Key) > 2:
1495 # Check Module style is EDK or EDKII.
1496 # Only append build option for the matched style module.
1497 if ModuleStyle == EDK_NAME and Key[2] != EDK_NAME:
1498 continue
1499 elif ModuleStyle == EDKII_NAME and Key[2] != EDKII_NAME:
1500 continue
1501 Family = Key[0]
1502 Target, Tag, Arch, Tool, Attr = Key[1].split("_")
1503 # if tool chain family doesn't match, skip it
1504 if Tool not in ToolDef or Family == "":
1505 continue
1506 # option has been added before
1507 if Family != ToolDef[Tool][TAB_TOD_DEFINES_FAMILY]:
1508 continue
1509
1510 # expand any wildcard
1511 if Target == TAB_STAR or Target == self.BuildTarget:
1512 if Tag == TAB_STAR or Tag == self.ToolChain:
1513 if Arch == TAB_STAR or Arch == self.Arch:
1514 if Tool not in BuildOptions:
1515 BuildOptions[Tool] = {}
1516 if Attr != "FLAGS" or Attr not in BuildOptions[Tool] or Options[Key].startswith('='):
1517 BuildOptions[Tool][Attr] = Options[Key]
1518 else:
1519 # append options for the same tool except PATH
1520 if Attr != 'PATH':
1521 BuildOptions[Tool][Attr] += " " + Options[Key]
1522 else:
1523 BuildOptions[Tool][Attr] = Options[Key]
1524 return BuildOptions