]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/AutoGen/PlatformAutoGen.py
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 - 2021, 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 if "MAKE" in self.EdkIIBuildOption and "PATH" in self.EdkIIBuildOption["MAKE"]:
809 # MAKE_PATH in DSC [BuildOptions] section is higher priority
810 Path = self.EdkIIBuildOption["MAKE"]["PATH"]
811 if Path.startswith('='):
812 Path = Path[1:].strip()
813 RetVal = _SplitOption(Path)
814 elif "MAKE" in self.ToolDefinition and "PATH" in self.ToolDefinition["MAKE"]:
815 RetVal = _SplitOption(self.ToolDefinition["MAKE"]["PATH"])
816 else:
817 return []
818 if "MAKE" in self.ToolDefinition and "FLAGS" in self.ToolDefinition["MAKE"]:
819 NewOption = self.ToolDefinition["MAKE"]["FLAGS"].strip()
820 if NewOption != '':
821 RetVal += _SplitOption(NewOption)
822 if "MAKE" in self.EdkIIBuildOption and "FLAGS" in self.EdkIIBuildOption["MAKE"]:
823 Flags = self.EdkIIBuildOption["MAKE"]["FLAGS"]
824 if Flags.startswith('='):
825 RetVal = [RetVal[0]] + _SplitOption(Flags[1:].strip())
826 else:
827 RetVal = RetVal + _SplitOption(Flags.strip())
828 return RetVal
829
830 ## Compute a tool defintion key priority value in range 0..15
831 #
832 # TARGET_TOOLCHAIN_ARCH_COMMANDTYPE_ATTRIBUTE 15
833 # ******_TOOLCHAIN_ARCH_COMMANDTYPE_ATTRIBUTE 14
834 # TARGET_*********_ARCH_COMMANDTYPE_ATTRIBUTE 13
835 # ******_*********_ARCH_COMMANDTYPE_ATTRIBUTE 12
836 # TARGET_TOOLCHAIN_****_COMMANDTYPE_ATTRIBUTE 11
837 # ******_TOOLCHAIN_****_COMMANDTYPE_ATTRIBUTE 10
838 # TARGET_*********_****_COMMANDTYPE_ATTRIBUTE 9
839 # ******_*********_****_COMMANDTYPE_ATTRIBUTE 8
840 # TARGET_TOOLCHAIN_ARCH_***********_ATTRIBUTE 7
841 # ******_TOOLCHAIN_ARCH_***********_ATTRIBUTE 6
842 # TARGET_*********_ARCH_***********_ATTRIBUTE 5
843 # ******_*********_ARCH_***********_ATTRIBUTE 4
844 # TARGET_TOOLCHAIN_****_***********_ATTRIBUTE 3
845 # ******_TOOLCHAIN_****_***********_ATTRIBUTE 2
846 # TARGET_*********_****_***********_ATTRIBUTE 1
847 # ******_*********_****_***********_ATTRIBUTE 0
848 #
849 def ToolDefinitionPriority (self,Key):
850 KeyList = Key.split('_')
851 Priority = 0
852 for Index in range (0, min(4, len(KeyList))):
853 if KeyList[Index] != '*':
854 Priority += (1 << Index)
855 return Priority
856
857 ## Get tool chain definition
858 #
859 # Get each tool definition for given tool chain from tools_def.txt and platform
860 #
861 @cached_property
862 def ToolDefinition(self):
863 ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDictionary
864 if TAB_TOD_DEFINES_COMMAND_TYPE not in self.Workspace.ToolDef.ToolsDefTxtDatabase:
865 EdkLogger.error('build', RESOURCE_NOT_AVAILABLE, "No tools found in configuration",
866 ExtraData="[%s]" % self.MetaFile)
867 RetVal = OrderedDict()
868 DllPathList = set()
869
870 PrioritizedDefList = sorted(ToolDefinition.keys(), key=self.ToolDefinitionPriority, reverse=True)
871 for Def in PrioritizedDefList:
872 Target, Tag, Arch, Tool, Attr = Def.split("_")
873 if Target == TAB_STAR:
874 Target = self.BuildTarget
875 if Tag == TAB_STAR:
876 Tag = self.ToolChain
877 if Arch == TAB_STAR:
878 Arch = self.Arch
879 if Target != self.BuildTarget or Tag != self.ToolChain or Arch != self.Arch:
880 continue
881
882 Value = ToolDefinition[Def]
883 # don't record the DLL
884 if Attr == "DLL":
885 DllPathList.add(Value)
886 continue
887
888 #
889 # ToolDefinition is sorted from highest priority to lowest priority.
890 # Only add the first(highest priority) match to RetVal
891 #
892 if Tool not in RetVal:
893 RetVal[Tool] = OrderedDict()
894 if Attr not in RetVal[Tool]:
895 RetVal[Tool][Attr] = Value
896
897 ToolsDef = ''
898 if GlobalData.gOptions.SilentMode and "MAKE" in RetVal:
899 if "FLAGS" not in RetVal["MAKE"]:
900 RetVal["MAKE"]["FLAGS"] = ""
901 RetVal["MAKE"]["FLAGS"] += " -s"
902 MakeFlags = ''
903
904 ToolList = list(RetVal.keys())
905 ToolList.sort()
906 for Tool in ToolList:
907 if Tool == TAB_STAR:
908 continue
909 AttrList = list(RetVal[Tool].keys())
910 if TAB_STAR in ToolList:
911 AttrList += list(RetVal[TAB_STAR])
912 AttrList.sort()
913 for Attr in AttrList:
914 if Attr in RetVal[Tool]:
915 Value = RetVal[Tool][Attr]
916 else:
917 Value = RetVal[TAB_STAR][Attr]
918 if Tool in self._BuildOptionWithToolDef(RetVal) and Attr in self._BuildOptionWithToolDef(RetVal)[Tool]:
919 # check if override is indicated
920 if self._BuildOptionWithToolDef(RetVal)[Tool][Attr].startswith('='):
921 Value = self._BuildOptionWithToolDef(RetVal)[Tool][Attr][1:].strip()
922 else:
923 # Do not append PATH or GUID
924 if Attr != 'PATH' and Attr != 'GUID':
925 Value += " " + self._BuildOptionWithToolDef(RetVal)[Tool][Attr]
926 else:
927 Value = self._BuildOptionWithToolDef(RetVal)[Tool][Attr]
928 if Attr == "PATH":
929 # Don't put MAKE definition in the file
930 if Tool != "MAKE":
931 ToolsDef += "%s_%s = %s\n" % (Tool, Attr, Value)
932 elif Attr != "DLL":
933 # Don't put MAKE definition in the file
934 if Tool == "MAKE":
935 if Attr == "FLAGS":
936 MakeFlags = Value
937 else:
938 ToolsDef += "%s_%s = %s\n" % (Tool, Attr, Value)
939 ToolsDef += "\n"
940
941 tool_def_file = os.path.join(self.MakeFileDir, "TOOLS_DEF." + self.Arch)
942 SaveFileOnChange(tool_def_file, ToolsDef, False)
943 for DllPath in DllPathList:
944 os.environ["PATH"] = DllPath + os.pathsep + os.environ["PATH"]
945 os.environ["MAKE_FLAGS"] = MakeFlags
946
947 return RetVal
948
949 ## Return the paths of tools
950 @cached_property
951 def ToolDefinitionFile(self):
952 tool_def_file = os.path.join(self.MakeFileDir, "TOOLS_DEF." + self.Arch)
953 if not os.path.exists(tool_def_file):
954 self.ToolDefinition
955 return tool_def_file
956
957 ## Retrieve the toolchain family of given toolchain tag. Default to 'MSFT'.
958 @cached_property
959 def ToolChainFamily(self):
960 ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDatabase
961 if TAB_TOD_DEFINES_FAMILY not in ToolDefinition \
962 or self.ToolChain not in ToolDefinition[TAB_TOD_DEFINES_FAMILY] \
963 or not ToolDefinition[TAB_TOD_DEFINES_FAMILY][self.ToolChain]:
964 EdkLogger.verbose("No tool chain family found in configuration for %s. Default to MSFT." \
965 % self.ToolChain)
966 RetVal = TAB_COMPILER_MSFT
967 else:
968 RetVal = ToolDefinition[TAB_TOD_DEFINES_FAMILY][self.ToolChain]
969 return RetVal
970
971 @cached_property
972 def BuildRuleFamily(self):
973 ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDatabase
974 if TAB_TOD_DEFINES_BUILDRULEFAMILY not in ToolDefinition \
975 or self.ToolChain not in ToolDefinition[TAB_TOD_DEFINES_BUILDRULEFAMILY] \
976 or not ToolDefinition[TAB_TOD_DEFINES_BUILDRULEFAMILY][self.ToolChain]:
977 EdkLogger.verbose("No tool chain family found in configuration for %s. Default to MSFT." \
978 % self.ToolChain)
979 return TAB_COMPILER_MSFT
980
981 return ToolDefinition[TAB_TOD_DEFINES_BUILDRULEFAMILY][self.ToolChain]
982
983 ## Return the build options specific for all modules in this platform
984 @cached_property
985 def BuildOption(self):
986 return self._ExpandBuildOption(self.Platform.BuildOptions)
987
988 def _BuildOptionWithToolDef(self, ToolDef):
989 return self._ExpandBuildOption(self.Platform.BuildOptions, ToolDef=ToolDef)
990
991 ## Return the build options specific for EDK modules in this platform
992 @cached_property
993 def EdkBuildOption(self):
994 return self._ExpandBuildOption(self.Platform.BuildOptions, EDK_NAME)
995
996 ## Return the build options specific for EDKII modules in this platform
997 @cached_property
998 def EdkIIBuildOption(self):
999 return self._ExpandBuildOption(self.Platform.BuildOptions, EDKII_NAME)
1000
1001 ## Parse build_rule.txt in Conf Directory.
1002 #
1003 # @retval BuildRule object
1004 #
1005 @cached_property
1006 def BuildRule(self):
1007 BuildRuleFile = None
1008 if TAB_TAT_DEFINES_BUILD_RULE_CONF in self.Workspace.TargetTxt.TargetTxtDictionary:
1009 BuildRuleFile = self.Workspace.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_BUILD_RULE_CONF]
1010 if not BuildRuleFile:
1011 BuildRuleFile = gDefaultBuildRuleFile
1012 RetVal = BuildRule(BuildRuleFile)
1013 if RetVal._FileVersion == "":
1014 RetVal._FileVersion = AutoGenReqBuildRuleVerNum
1015 else:
1016 if RetVal._FileVersion < AutoGenReqBuildRuleVerNum :
1017 # If Build Rule's version is less than the version number required by the tools, halting the build.
1018 EdkLogger.error("build", AUTOGEN_ERROR,
1019 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])"\
1020 % (RetVal._FileVersion, AutoGenReqBuildRuleVerNum))
1021 return RetVal
1022
1023 ## Summarize the packages used by modules in this platform
1024 @cached_property
1025 def PackageList(self):
1026 RetVal = set()
1027 for Mb in self._MbList:
1028 RetVal.update(Mb.Packages)
1029 for lb in Mb.LibInstances:
1030 RetVal.update(lb.Packages)
1031 #Collect package set information from INF of FDF
1032 for ModuleFile in self._AsBuildModuleList:
1033 if ModuleFile in self.Platform.Modules:
1034 continue
1035 ModuleData = self.BuildDatabase[ModuleFile, self.Arch, self.BuildTarget, self.ToolChain]
1036 RetVal.update(ModuleData.Packages)
1037 RetVal.update(self.Platform.Packages)
1038 return list(RetVal)
1039
1040 @cached_property
1041 def NonDynamicPcdDict(self):
1042 return {(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):Pcd for Pcd in self.NonDynamicPcdList}
1043
1044 ## Get list of non-dynamic PCDs
1045 @property
1046 def NonDynamicPcdList(self):
1047 if not self._NonDynamicPcdList:
1048 self.CollectPlatformDynamicPcds()
1049 return self._NonDynamicPcdList
1050
1051 ## Get list of dynamic PCDs
1052 @property
1053 def DynamicPcdList(self):
1054 if not self._DynamicPcdList:
1055 self.CollectPlatformDynamicPcds()
1056 return self._DynamicPcdList
1057
1058 ## Generate Token Number for all PCD
1059 @cached_property
1060 def PcdTokenNumber(self):
1061 RetVal = OrderedDict()
1062 TokenNumber = 1
1063 #
1064 # Make the Dynamic and DynamicEx PCD use within different TokenNumber area.
1065 # Such as:
1066 #
1067 # Dynamic PCD:
1068 # TokenNumber 0 ~ 10
1069 # DynamicEx PCD:
1070 # TokeNumber 11 ~ 20
1071 #
1072 for Pcd in self.DynamicPcdList:
1073 if Pcd.Phase == "PEI" and Pcd.Type in PCD_DYNAMIC_TYPE_SET:
1074 EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))
1075 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
1076 TokenNumber += 1
1077
1078 for Pcd in self.DynamicPcdList:
1079 if Pcd.Phase == "PEI" and Pcd.Type in PCD_DYNAMIC_EX_TYPE_SET:
1080 EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))
1081 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
1082 TokenNumber += 1
1083
1084 for Pcd in self.DynamicPcdList:
1085 if Pcd.Phase == "DXE" and Pcd.Type in PCD_DYNAMIC_TYPE_SET:
1086 EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))
1087 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
1088 TokenNumber += 1
1089
1090 for Pcd in self.DynamicPcdList:
1091 if Pcd.Phase == "DXE" and Pcd.Type in PCD_DYNAMIC_EX_TYPE_SET:
1092 EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))
1093 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
1094 TokenNumber += 1
1095
1096 for Pcd in self.NonDynamicPcdList:
1097 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = 0
1098 return RetVal
1099
1100 @cached_property
1101 def _MbList(self):
1102 ModuleList = []
1103 for m in self.Platform.Modules:
1104 component = self.Platform.Modules[m]
1105 module = self.BuildDatabase[m, self.Arch, self.BuildTarget, self.ToolChain]
1106 module.Guid = component.Guid
1107 ModuleList.append(module)
1108 return ModuleList
1109
1110 @cached_property
1111 def _MaList(self):
1112 for ModuleFile in self.Platform.Modules:
1113 Ma = ModuleAutoGen(
1114 self.Workspace,
1115 ModuleFile,
1116 self.BuildTarget,
1117 self.ToolChain,
1118 self.Arch,
1119 self.MetaFile,
1120 self.DataPipe
1121 )
1122 self.Platform.Modules[ModuleFile].M = Ma
1123 return [x.M for x in self.Platform.Modules.values()]
1124
1125 ## Summarize ModuleAutoGen objects of all modules to be built for this platform
1126 @cached_property
1127 def ModuleAutoGenList(self):
1128 RetVal = []
1129 for Ma in self._MaList:
1130 if Ma not in RetVal:
1131 RetVal.append(Ma)
1132 return RetVal
1133
1134 ## Summarize ModuleAutoGen objects of all libraries to be built for this platform
1135 @cached_property
1136 def LibraryAutoGenList(self):
1137 RetVal = []
1138 for Ma in self._MaList:
1139 for La in Ma.LibraryAutoGenList:
1140 if La not in RetVal:
1141 RetVal.append(La)
1142 if Ma not in La.ReferenceModules:
1143 La.ReferenceModules.append(Ma)
1144 return RetVal
1145
1146 ## Test if a module is supported by the platform
1147 #
1148 # An error will be raised directly if the module or its arch is not supported
1149 # by the platform or current configuration
1150 #
1151 def ValidModule(self, Module):
1152 return Module in self.Platform.Modules or Module in self.Platform.LibraryInstances \
1153 or Module in self._AsBuildModuleList
1154 @cached_property
1155 def GetAllModuleInfo(self,WithoutPcd=True):
1156 ModuleLibs = set()
1157 for m in self.Platform.Modules:
1158 module_obj = self.BuildDatabase[m,self.Arch,self.BuildTarget,self.ToolChain]
1159 if not bool(module_obj.LibraryClass):
1160 Libs = GetModuleLibInstances(module_obj, self.Platform, self.BuildDatabase, self.Arch,self.BuildTarget,self.ToolChain,self.MetaFile,EdkLogger)
1161 else:
1162 Libs = []
1163 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]))
1164 if WithoutPcd and module_obj.PcdIsDriver:
1165 continue
1166 ModuleLibs.add((m.File,m.Root,m.Path,m.BaseName,m.OriginalPath,module_obj.Arch,bool(module_obj.LibraryClass)))
1167
1168 return ModuleLibs
1169
1170 ## Resolve the library classes in a module to library instances
1171 #
1172 # This method will not only resolve library classes but also sort the library
1173 # instances according to the dependency-ship.
1174 #
1175 # @param Module The module from which the library classes will be resolved
1176 #
1177 # @retval library_list List of library instances sorted
1178 #
1179 def ApplyLibraryInstance(self, Module):
1180 # Cover the case that the binary INF file is list in the FDF file but not DSC file, return empty list directly
1181 if str(Module) not in self.Platform.Modules:
1182 return []
1183
1184 return GetModuleLibInstances(Module,
1185 self.Platform,
1186 self.BuildDatabase,
1187 self.Arch,
1188 self.BuildTarget,
1189 self.ToolChain,
1190 self.MetaFile,
1191 EdkLogger)
1192
1193 ## Override PCD setting (type, value, ...)
1194 #
1195 # @param ToPcd The PCD to be overridden
1196 # @param FromPcd The PCD overriding from
1197 #
1198 def _OverridePcd(self, ToPcd, FromPcd, Module="", Msg="", Library=""):
1199 #
1200 # in case there's PCDs coming from FDF file, which have no type given.
1201 # at this point, ToPcd.Type has the type found from dependent
1202 # package
1203 #
1204 TokenCName = ToPcd.TokenCName
1205 for PcdItem in GlobalData.MixedPcd:
1206 if (ToPcd.TokenCName, ToPcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
1207 TokenCName = PcdItem[0]
1208 break
1209 if FromPcd is not None:
1210 if ToPcd.Pending and FromPcd.Type:
1211 ToPcd.Type = FromPcd.Type
1212 elif ToPcd.Type and FromPcd.Type\
1213 and ToPcd.Type != FromPcd.Type and ToPcd.Type in FromPcd.Type:
1214 if ToPcd.Type.strip() == TAB_PCDS_DYNAMIC_EX:
1215 ToPcd.Type = FromPcd.Type
1216 elif ToPcd.Type and FromPcd.Type \
1217 and ToPcd.Type != FromPcd.Type:
1218 if Library:
1219 Module = str(Module) + " 's library file (" + str(Library) + ")"
1220 EdkLogger.error("build", OPTION_CONFLICT, "Mismatched PCD type",
1221 ExtraData="%s.%s is used as [%s] in module %s, but as [%s] in %s."\
1222 % (ToPcd.TokenSpaceGuidCName, TokenCName,
1223 ToPcd.Type, Module, FromPcd.Type, Msg),
1224 File=self.MetaFile)
1225
1226 if FromPcd.MaxDatumSize:
1227 ToPcd.MaxDatumSize = FromPcd.MaxDatumSize
1228 ToPcd.MaxSizeUserSet = FromPcd.MaxDatumSize
1229 if FromPcd.DefaultValue:
1230 ToPcd.DefaultValue = FromPcd.DefaultValue
1231 if FromPcd.TokenValue:
1232 ToPcd.TokenValue = FromPcd.TokenValue
1233 if FromPcd.DatumType:
1234 ToPcd.DatumType = FromPcd.DatumType
1235 if FromPcd.SkuInfoList:
1236 ToPcd.SkuInfoList = FromPcd.SkuInfoList
1237 if FromPcd.UserDefinedDefaultStoresFlag:
1238 ToPcd.UserDefinedDefaultStoresFlag = FromPcd.UserDefinedDefaultStoresFlag
1239 # Add Flexible PCD format parse
1240 if ToPcd.DefaultValue:
1241 try:
1242 ToPcd.DefaultValue = ValueExpressionEx(ToPcd.DefaultValue, ToPcd.DatumType, self.Platform._GuidDict)(True)
1243 except BadExpression as Value:
1244 EdkLogger.error('Parser', FORMAT_INVALID, 'PCD [%s.%s] Value "%s", %s' %(ToPcd.TokenSpaceGuidCName, ToPcd.TokenCName, ToPcd.DefaultValue, Value),
1245 File=self.MetaFile)
1246
1247 # check the validation of datum
1248 IsValid, Cause = CheckPcdDatum(ToPcd.DatumType, ToPcd.DefaultValue)
1249 if not IsValid:
1250 EdkLogger.error('build', FORMAT_INVALID, Cause, File=self.MetaFile,
1251 ExtraData="%s.%s" % (ToPcd.TokenSpaceGuidCName, TokenCName))
1252 ToPcd.validateranges = FromPcd.validateranges
1253 ToPcd.validlists = FromPcd.validlists
1254 ToPcd.expressions = FromPcd.expressions
1255 ToPcd.CustomAttribute = FromPcd.CustomAttribute
1256
1257 if FromPcd is not None and ToPcd.DatumType == TAB_VOID and not ToPcd.MaxDatumSize:
1258 EdkLogger.debug(EdkLogger.DEBUG_9, "No MaxDatumSize specified for PCD %s.%s" \
1259 % (ToPcd.TokenSpaceGuidCName, TokenCName))
1260 Value = ToPcd.DefaultValue
1261 if not Value:
1262 ToPcd.MaxDatumSize = '1'
1263 elif Value[0] == 'L':
1264 ToPcd.MaxDatumSize = str((len(Value) - 2) * 2)
1265 elif Value[0] == '{':
1266 ToPcd.MaxDatumSize = str(len(Value.split(',')))
1267 else:
1268 ToPcd.MaxDatumSize = str(len(Value) - 1)
1269
1270 # apply default SKU for dynamic PCDS if specified one is not available
1271 if (ToPcd.Type in PCD_DYNAMIC_TYPE_SET or ToPcd.Type in PCD_DYNAMIC_EX_TYPE_SET) \
1272 and not ToPcd.SkuInfoList:
1273 if self.Platform.SkuName in self.Platform.SkuIds:
1274 SkuName = self.Platform.SkuName
1275 else:
1276 SkuName = TAB_DEFAULT
1277 ToPcd.SkuInfoList = {
1278 SkuName : SkuInfoClass(SkuName, self.Platform.SkuIds[SkuName][0], '', '', '', '', '', ToPcd.DefaultValue)
1279 }
1280
1281 ## Apply PCD setting defined platform to a module
1282 #
1283 # @param Module The module from which the PCD setting will be overridden
1284 #
1285 # @retval PCD_list The list PCDs with settings from platform
1286 #
1287 def ApplyPcdSetting(self, Module, Pcds, Library=""):
1288 # for each PCD in module
1289 for Name, Guid in Pcds:
1290 PcdInModule = Pcds[Name, Guid]
1291 # find out the PCD setting in platform
1292 if (Name, Guid) in self.Platform.Pcds:
1293 PcdInPlatform = self.Platform.Pcds[Name, Guid]
1294 else:
1295 PcdInPlatform = None
1296 # then override the settings if any
1297 self._OverridePcd(PcdInModule, PcdInPlatform, Module, Msg="DSC PCD sections", Library=Library)
1298 # resolve the VariableGuid value
1299 for SkuId in PcdInModule.SkuInfoList:
1300 Sku = PcdInModule.SkuInfoList[SkuId]
1301 if Sku.VariableGuid == '': continue
1302 Sku.VariableGuidValue = GuidValue(Sku.VariableGuid, self.PackageList, self.MetaFile.Path)
1303 if Sku.VariableGuidValue is None:
1304 PackageList = "\n\t".join(str(P) for P in self.PackageList)
1305 EdkLogger.error(
1306 'build',
1307 RESOURCE_NOT_AVAILABLE,
1308 "Value of GUID [%s] is not found in" % Sku.VariableGuid,
1309 ExtraData=PackageList + "\n\t(used with %s.%s from module %s)" \
1310 % (Guid, Name, str(Module)),
1311 File=self.MetaFile
1312 )
1313
1314 # override PCD settings with module specific setting
1315 if Module in self.Platform.Modules:
1316 PlatformModule = self.Platform.Modules[str(Module)]
1317 for Key in PlatformModule.Pcds:
1318 if GlobalData.BuildOptionPcd:
1319 for pcd in GlobalData.BuildOptionPcd:
1320 (TokenSpaceGuidCName, TokenCName, FieldName, pcdvalue, _) = pcd
1321 if (TokenCName, TokenSpaceGuidCName) == Key and FieldName =="":
1322 PlatformModule.Pcds[Key].DefaultValue = pcdvalue
1323 PlatformModule.Pcds[Key].PcdValueFromComm = pcdvalue
1324 break
1325 Flag = False
1326 if Key in Pcds:
1327 ToPcd = Pcds[Key]
1328 Flag = True
1329 elif Key in GlobalData.MixedPcd:
1330 for PcdItem in GlobalData.MixedPcd[Key]:
1331 if PcdItem in Pcds:
1332 ToPcd = Pcds[PcdItem]
1333 Flag = True
1334 break
1335 if Flag:
1336 self._OverridePcd(ToPcd, PlatformModule.Pcds[Key], Module, Msg="DSC Components Module scoped PCD section", Library=Library)
1337 # use PCD value to calculate the MaxDatumSize when it is not specified
1338 for Name, Guid in Pcds:
1339 Pcd = Pcds[Name, Guid]
1340 if Pcd.DatumType == TAB_VOID and not Pcd.MaxDatumSize:
1341 Pcd.MaxSizeUserSet = None
1342 Value = Pcd.DefaultValue
1343 if not Value:
1344 Pcd.MaxDatumSize = '1'
1345 elif Value[0] == 'L':
1346 Pcd.MaxDatumSize = str((len(Value) - 2) * 2)
1347 elif Value[0] == '{':
1348 Pcd.MaxDatumSize = str(len(Value.split(',')))
1349 else:
1350 Pcd.MaxDatumSize = str(len(Value) - 1)
1351 return list(Pcds.values())
1352
1353 ## Append build options in platform to a module
1354 #
1355 # @param Module The module to which the build options will be appended
1356 #
1357 # @retval options The options appended with build options in platform
1358 #
1359 def ApplyBuildOption(self, Module):
1360 # Get the different options for the different style module
1361 PlatformOptions = self.EdkIIBuildOption
1362 ModuleTypeOptions = self.Platform.GetBuildOptionsByModuleType(EDKII_NAME, Module.ModuleType)
1363 ModuleTypeOptions = self._ExpandBuildOption(ModuleTypeOptions)
1364 ModuleOptions = self._ExpandBuildOption(Module.BuildOptions)
1365 if Module in self.Platform.Modules:
1366 PlatformModule = self.Platform.Modules[str(Module)]
1367 PlatformModuleOptions = self._ExpandBuildOption(PlatformModule.BuildOptions)
1368 else:
1369 PlatformModuleOptions = {}
1370
1371 BuildRuleOrder = None
1372 for Options in [self.ToolDefinition, ModuleOptions, PlatformOptions, ModuleTypeOptions, PlatformModuleOptions]:
1373 for Tool in Options:
1374 for Attr in Options[Tool]:
1375 if Attr == TAB_TOD_DEFINES_BUILDRULEORDER:
1376 BuildRuleOrder = Options[Tool][Attr]
1377
1378 AllTools = set(list(ModuleOptions.keys()) + list(PlatformOptions.keys()) +
1379 list(PlatformModuleOptions.keys()) + list(ModuleTypeOptions.keys()) +
1380 list(self.ToolDefinition.keys()))
1381 BuildOptions = defaultdict(lambda: defaultdict(str))
1382 for Tool in AllTools:
1383 for Options in [self.ToolDefinition, ModuleOptions, PlatformOptions, ModuleTypeOptions, PlatformModuleOptions]:
1384 if Tool not in Options:
1385 continue
1386 for Attr in Options[Tool]:
1387 #
1388 # Do not generate it in Makefile
1389 #
1390 if Attr == TAB_TOD_DEFINES_BUILDRULEORDER:
1391 continue
1392 Value = Options[Tool][Attr]
1393 ToolList = [Tool]
1394 if Tool == TAB_STAR:
1395 ToolList = list(AllTools)
1396 ToolList.remove(TAB_STAR)
1397 for ExpandedTool in ToolList:
1398 # check if override is indicated
1399 if Value.startswith('='):
1400 BuildOptions[ExpandedTool][Attr] = mws.handleWsMacro(Value[1:])
1401 else:
1402 if Attr != 'PATH':
1403 BuildOptions[ExpandedTool][Attr] += " " + mws.handleWsMacro(Value)
1404 else:
1405 BuildOptions[ExpandedTool][Attr] = mws.handleWsMacro(Value)
1406
1407 return BuildOptions, BuildRuleOrder
1408
1409
1410 def GetGlobalBuildOptions(self,Module):
1411 ModuleTypeOptions = self.Platform.GetBuildOptionsByModuleType(EDKII_NAME, Module.ModuleType)
1412 ModuleTypeOptions = self._ExpandBuildOption(ModuleTypeOptions)
1413
1414 if Module in self.Platform.Modules:
1415 PlatformModule = self.Platform.Modules[str(Module)]
1416 PlatformModuleOptions = self._ExpandBuildOption(PlatformModule.BuildOptions)
1417 else:
1418 PlatformModuleOptions = {}
1419
1420 return ModuleTypeOptions,PlatformModuleOptions
1421 def ModuleGuid(self,Module):
1422 if os.path.basename(Module.MetaFile.File) != os.path.basename(Module.MetaFile.Path):
1423 #
1424 # Length of GUID is 36
1425 #
1426 return os.path.basename(Module.MetaFile.Path)[:36]
1427 return Module.Guid
1428 @cached_property
1429 def UniqueBaseName(self):
1430 retVal ={}
1431 ModuleNameDict = {}
1432 UniqueName = {}
1433 for Module in self._MbList:
1434 unique_base_name = '%s_%s' % (Module.BaseName,self.ModuleGuid(Module))
1435 if unique_base_name not in ModuleNameDict:
1436 ModuleNameDict[unique_base_name] = []
1437 ModuleNameDict[unique_base_name].append(Module.MetaFile)
1438 if Module.BaseName not in UniqueName:
1439 UniqueName[Module.BaseName] = set()
1440 UniqueName[Module.BaseName].add((self.ModuleGuid(Module),Module.MetaFile))
1441 for module_paths in ModuleNameDict.values():
1442 if len(set(module_paths))>1:
1443 samemodules = list(set(module_paths))
1444 EdkLogger.error("build", FILE_DUPLICATED, 'Modules have same BaseName and FILE_GUID:\n'
1445 ' %s\n %s' % (samemodules[0], samemodules[1]))
1446 for name in UniqueName:
1447 Guid_Path = UniqueName[name]
1448 if len(Guid_Path) > 1:
1449 for guid,mpath in Guid_Path:
1450 retVal[(name,mpath)] = '%s_%s' % (name,guid)
1451 return retVal
1452 ## Expand * in build option key
1453 #
1454 # @param Options Options to be expanded
1455 # @param ToolDef Use specified ToolDef instead of full version.
1456 # This is needed during initialization to prevent
1457 # infinite recursion betweeh BuildOptions,
1458 # ToolDefinition, and this function.
1459 #
1460 # @retval options Options expanded
1461 #
1462 def _ExpandBuildOption(self, Options, ModuleStyle=None, ToolDef=None):
1463 if not ToolDef:
1464 ToolDef = self.ToolDefinition
1465 BuildOptions = {}
1466 FamilyMatch = False
1467 FamilyIsNull = True
1468
1469 OverrideList = {}
1470 #
1471 # Construct a list contain the build options which need override.
1472 #
1473 for Key in Options:
1474 #
1475 # Key[0] -- tool family
1476 # Key[1] -- TARGET_TOOLCHAIN_ARCH_COMMANDTYPE_ATTRIBUTE
1477 #
1478 if (Key[0] == self.BuildRuleFamily and
1479 (ModuleStyle is None or len(Key) < 3 or (len(Key) > 2 and Key[2] == ModuleStyle))):
1480 Target, ToolChain, Arch, CommandType, Attr = Key[1].split('_')
1481 if (Target == self.BuildTarget or Target == TAB_STAR) and\
1482 (ToolChain == self.ToolChain or ToolChain == TAB_STAR) and\
1483 (Arch == self.Arch or Arch == TAB_STAR) and\
1484 Options[Key].startswith("="):
1485
1486 if OverrideList.get(Key[1]) is not None:
1487 OverrideList.pop(Key[1])
1488 OverrideList[Key[1]] = Options[Key]
1489
1490 #
1491 # Use the highest priority value.
1492 #
1493 if (len(OverrideList) >= 2):
1494 KeyList = list(OverrideList.keys())
1495 for Index in range(len(KeyList)):
1496 NowKey = KeyList[Index]
1497 Target1, ToolChain1, Arch1, CommandType1, Attr1 = NowKey.split("_")
1498 for Index1 in range(len(KeyList) - Index - 1):
1499 NextKey = KeyList[Index1 + Index + 1]
1500 #
1501 # Compare two Key, if one is included by another, choose the higher priority one
1502 #
1503 Target2, ToolChain2, Arch2, CommandType2, Attr2 = NextKey.split("_")
1504 if (Target1 == Target2 or Target1 == TAB_STAR or Target2 == TAB_STAR) and\
1505 (ToolChain1 == ToolChain2 or ToolChain1 == TAB_STAR or ToolChain2 == TAB_STAR) and\
1506 (Arch1 == Arch2 or Arch1 == TAB_STAR or Arch2 == TAB_STAR) and\
1507 (CommandType1 == CommandType2 or CommandType1 == TAB_STAR or CommandType2 == TAB_STAR) and\
1508 (Attr1 == Attr2 or Attr1 == TAB_STAR or Attr2 == TAB_STAR):
1509
1510 if CalculatePriorityValue(NowKey) > CalculatePriorityValue(NextKey):
1511 if Options.get((self.BuildRuleFamily, NextKey)) is not None:
1512 Options.pop((self.BuildRuleFamily, NextKey))
1513 else:
1514 if Options.get((self.BuildRuleFamily, NowKey)) is not None:
1515 Options.pop((self.BuildRuleFamily, NowKey))
1516
1517 for Key in Options:
1518 if ModuleStyle is not None and len (Key) > 2:
1519 # Check Module style is EDK or EDKII.
1520 # Only append build option for the matched style module.
1521 if ModuleStyle == EDK_NAME and Key[2] != EDK_NAME:
1522 continue
1523 elif ModuleStyle == EDKII_NAME and Key[2] != EDKII_NAME:
1524 continue
1525 Family = Key[0]
1526 Target, Tag, Arch, Tool, Attr = Key[1].split("_")
1527 # if tool chain family doesn't match, skip it
1528 if Family != "":
1529 Found = False
1530 if Tool in ToolDef:
1531 FamilyIsNull = False
1532 if TAB_TOD_DEFINES_BUILDRULEFAMILY in ToolDef[Tool]:
1533 if Family == ToolDef[Tool][TAB_TOD_DEFINES_BUILDRULEFAMILY]:
1534 FamilyMatch = True
1535 Found = True
1536 if TAB_STAR in ToolDef:
1537 FamilyIsNull = False
1538 if TAB_TOD_DEFINES_BUILDRULEFAMILY in ToolDef[TAB_STAR]:
1539 if Family == ToolDef[TAB_STAR][TAB_TOD_DEFINES_BUILDRULEFAMILY]:
1540 FamilyMatch = True
1541 Found = True
1542 if not Found:
1543 continue
1544
1545 # expand any wildcard
1546 if Target == TAB_STAR or Target == self.BuildTarget:
1547 if Tag == TAB_STAR or Tag == self.ToolChain:
1548 if Arch == TAB_STAR or Arch == self.Arch:
1549 if Tool not in BuildOptions:
1550 BuildOptions[Tool] = {}
1551 if Attr != "FLAGS" or Attr not in BuildOptions[Tool] or Options[Key].startswith('='):
1552 BuildOptions[Tool][Attr] = Options[Key]
1553 else:
1554 # append options for the same tool except PATH
1555 if Attr != 'PATH':
1556 BuildOptions[Tool][Attr] += " " + Options[Key]
1557 else:
1558 BuildOptions[Tool][Attr] = Options[Key]
1559 # Build Option Family has been checked, which need't to be checked again for family.
1560 if FamilyMatch or FamilyIsNull:
1561 return BuildOptions
1562
1563 for Key in Options:
1564 if ModuleStyle is not None and len (Key) > 2:
1565 # Check Module style is EDK or EDKII.
1566 # Only append build option for the matched style module.
1567 if ModuleStyle == EDK_NAME and Key[2] != EDK_NAME:
1568 continue
1569 elif ModuleStyle == EDKII_NAME and Key[2] != EDKII_NAME:
1570 continue
1571 Family = Key[0]
1572 Target, Tag, Arch, Tool, Attr = Key[1].split("_")
1573 # if tool chain family doesn't match, skip it
1574 if Family == "":
1575 continue
1576 # option has been added before
1577 Found = False
1578 if Tool in ToolDef:
1579 if TAB_TOD_DEFINES_FAMILY in ToolDef[Tool]:
1580 if Family == ToolDef[Tool][TAB_TOD_DEFINES_FAMILY]:
1581 Found = True
1582 if TAB_STAR in ToolDef:
1583 if TAB_TOD_DEFINES_FAMILY in ToolDef[TAB_STAR]:
1584 if Family == ToolDef[TAB_STAR][TAB_TOD_DEFINES_FAMILY]:
1585 Found = True
1586 if not Found:
1587 continue
1588
1589 # expand any wildcard
1590 if Target == TAB_STAR or Target == self.BuildTarget:
1591 if Tag == TAB_STAR or Tag == self.ToolChain:
1592 if Arch == TAB_STAR or Arch == self.Arch:
1593 if Tool not in BuildOptions:
1594 BuildOptions[Tool] = {}
1595 if Attr != "FLAGS" or Attr not in BuildOptions[Tool] or Options[Key].startswith('='):
1596 BuildOptions[Tool][Attr] = Options[Key]
1597 else:
1598 # append options for the same tool except PATH
1599 if Attr != 'PATH':
1600 BuildOptions[Tool][Attr] += " " + Options[Key]
1601 else:
1602 BuildOptions[Tool][Attr] = Options[Key]
1603 return BuildOptions