]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/AutoGen/AutoGen.py
BaseTools: remove the super() function argument
[mirror_edk2.git] / BaseTools / Source / Python / AutoGen / AutoGen.py
1 ## @file
2 # Generate AutoGen.h, AutoGen.c and *.depex files
3 #
4 # Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5 # Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.<BR>
6 #
7 # This program and the accompanying materials
8 # are licensed and made available under the terms and conditions of the BSD License
9 # which accompanies this distribution. The full text of the license may be found at
10 # http://opensource.org/licenses/bsd-license.php
11 #
12 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 #
15
16 ## Import Modules
17 #
18 import Common.LongFilePathOs as os
19 import re
20 import os.path as path
21 import copy
22 import uuid
23
24 from . import GenC
25 from . import GenMake
26 from . import GenDepex
27 from io import BytesIO
28
29 from .StrGather import *
30 from .BuildEngine import BuildRule
31
32 from Common.LongFilePathSupport import CopyLongFilePath
33 from Common.BuildToolError import *
34 from Common.DataType import *
35 from Common.Misc import *
36 from Common.StringUtils import *
37 import Common.GlobalData as GlobalData
38 from GenFds.FdfParser import *
39 from CommonDataClass.CommonClass import SkuInfoClass
40 from GenPatchPcdTable.GenPatchPcdTable import parsePcdInfoFromMapFile
41 import Common.VpdInfoFile as VpdInfoFile
42 from .GenPcdDb import CreatePcdDatabaseCode
43 from Workspace.MetaFileCommentParser import UsageList
44 from Workspace.WorkspaceCommon import GetModuleLibInstances
45 from Common.MultipleWorkspace import MultipleWorkspace as mws
46 from . import InfSectionParser
47 import datetime
48 import hashlib
49 from .GenVar import VariableMgr, var_info
50 from collections import OrderedDict
51 from collections import defaultdict
52 from Workspace.WorkspaceCommon import OrderedListDict
53
54 from Common.caching import cached_property, cached_class_function
55
56 ## Regular expression for splitting Dependency Expression string into tokens
57 gDepexTokenPattern = re.compile("(\(|\)|\w+| \S+\.inf)")
58
59 ## Regular expression for match: PCD(xxxx.yyy)
60 gPCDAsGuidPattern = re.compile(r"^PCD\(.+\..+\)$")
61
62 #
63 # Regular expression for finding Include Directories, the difference between MSFT and INTEL/GCC/RVCT
64 # is the former use /I , the Latter used -I to specify include directories
65 #
66 gBuildOptIncludePatternMsft = re.compile(r"(?:.*?)/I[ \t]*([^ ]*)", re.MULTILINE | re.DOTALL)
67 gBuildOptIncludePatternOther = re.compile(r"(?:.*?)-I[ \t]*([^ ]*)", re.MULTILINE | re.DOTALL)
68
69 #
70 # Match name = variable
71 #
72 gEfiVarStoreNamePattern = re.compile("\s*name\s*=\s*(\w+)")
73 #
74 # The format of guid in efivarstore statement likes following and must be correct:
75 # guid = {0xA04A27f4, 0xDF00, 0x4D42, {0xB5, 0x52, 0x39, 0x51, 0x13, 0x02, 0x11, 0x3D}}
76 #
77 gEfiVarStoreGuidPattern = re.compile("\s*guid\s*=\s*({.*?{.*?}\s*})")
78
79 ## Mapping Makefile type
80 gMakeTypeMap = {TAB_COMPILER_MSFT:"nmake", "GCC":"gmake"}
81
82
83 ## Build rule configuration file
84 gDefaultBuildRuleFile = 'build_rule.txt'
85
86 ## Tools definition configuration file
87 gDefaultToolsDefFile = 'tools_def.txt'
88
89 ## Build rule default version
90 AutoGenReqBuildRuleVerNum = "0.1"
91
92 ## default file name for AutoGen
93 gAutoGenCodeFileName = "AutoGen.c"
94 gAutoGenHeaderFileName = "AutoGen.h"
95 gAutoGenStringFileName = "%(module_name)sStrDefs.h"
96 gAutoGenStringFormFileName = "%(module_name)sStrDefs.hpk"
97 gAutoGenDepexFileName = "%(module_name)s.depex"
98 gAutoGenImageDefFileName = "%(module_name)sImgDefs.h"
99 gAutoGenIdfFileName = "%(module_name)sIdf.hpk"
100 gInfSpecVersion = "0x00010017"
101
102 #
103 # Template string to generic AsBuilt INF
104 #
105 gAsBuiltInfHeaderString = TemplateString("""${header_comments}
106
107 # DO NOT EDIT
108 # FILE auto-generated
109
110 [Defines]
111 INF_VERSION = ${module_inf_version}
112 BASE_NAME = ${module_name}
113 FILE_GUID = ${module_guid}
114 MODULE_TYPE = ${module_module_type}${BEGIN}
115 VERSION_STRING = ${module_version_string}${END}${BEGIN}
116 PCD_IS_DRIVER = ${pcd_is_driver_string}${END}${BEGIN}
117 UEFI_SPECIFICATION_VERSION = ${module_uefi_specification_version}${END}${BEGIN}
118 PI_SPECIFICATION_VERSION = ${module_pi_specification_version}${END}${BEGIN}
119 ENTRY_POINT = ${module_entry_point}${END}${BEGIN}
120 UNLOAD_IMAGE = ${module_unload_image}${END}${BEGIN}
121 CONSTRUCTOR = ${module_constructor}${END}${BEGIN}
122 DESTRUCTOR = ${module_destructor}${END}${BEGIN}
123 SHADOW = ${module_shadow}${END}${BEGIN}
124 PCI_VENDOR_ID = ${module_pci_vendor_id}${END}${BEGIN}
125 PCI_DEVICE_ID = ${module_pci_device_id}${END}${BEGIN}
126 PCI_CLASS_CODE = ${module_pci_class_code}${END}${BEGIN}
127 PCI_REVISION = ${module_pci_revision}${END}${BEGIN}
128 BUILD_NUMBER = ${module_build_number}${END}${BEGIN}
129 SPEC = ${module_spec}${END}${BEGIN}
130 UEFI_HII_RESOURCE_SECTION = ${module_uefi_hii_resource_section}${END}${BEGIN}
131 MODULE_UNI_FILE = ${module_uni_file}${END}
132
133 [Packages.${module_arch}]${BEGIN}
134 ${package_item}${END}
135
136 [Binaries.${module_arch}]${BEGIN}
137 ${binary_item}${END}
138
139 [PatchPcd.${module_arch}]${BEGIN}
140 ${patchablepcd_item}
141 ${END}
142
143 [Protocols.${module_arch}]${BEGIN}
144 ${protocol_item}
145 ${END}
146
147 [Ppis.${module_arch}]${BEGIN}
148 ${ppi_item}
149 ${END}
150
151 [Guids.${module_arch}]${BEGIN}
152 ${guid_item}
153 ${END}
154
155 [PcdEx.${module_arch}]${BEGIN}
156 ${pcd_item}
157 ${END}
158
159 [LibraryClasses.${module_arch}]
160 ## @LIB_INSTANCES${BEGIN}
161 # ${libraryclasses_item}${END}
162
163 ${depexsection_item}
164
165 ${userextension_tianocore_item}
166
167 ${tail_comments}
168
169 [BuildOptions.${module_arch}]
170 ## @AsBuilt${BEGIN}
171 ## ${flags_item}${END}
172 """)
173
174 ## Base class for AutoGen
175 #
176 # This class just implements the cache mechanism of AutoGen objects.
177 #
178 class AutoGen(object):
179 # database to maintain the objects in each child class
180 __ObjectCache = {} # (BuildTarget, ToolChain, ARCH, platform file): AutoGen object
181
182 ## Factory method
183 #
184 # @param Class class object of real AutoGen class
185 # (WorkspaceAutoGen, ModuleAutoGen or PlatformAutoGen)
186 # @param Workspace Workspace directory or WorkspaceAutoGen object
187 # @param MetaFile The path of meta file
188 # @param Target Build target
189 # @param Toolchain Tool chain name
190 # @param Arch Target arch
191 # @param *args The specific class related parameters
192 # @param **kwargs The specific class related dict parameters
193 #
194 def __new__(cls, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs):
195 # check if the object has been created
196 Key = (Target, Toolchain, Arch, MetaFile)
197 if Key in cls.__ObjectCache:
198 # if it exists, just return it directly
199 return cls.__ObjectCache[Key]
200 # it didnt exist. create it, cache it, then return it
201 RetVal = cls.__ObjectCache[Key] = super().__new__(cls)
202 return RetVal
203
204 def __init__ (self, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs):
205 super().__init__()
206
207 ## hash() operator
208 #
209 # The file path of platform file will be used to represent hash value of this object
210 #
211 # @retval int Hash value of the file path of platform file
212 #
213 def __hash__(self):
214 return hash(self.MetaFile)
215
216 ## str() operator
217 #
218 # The file path of platform file will be used to represent this object
219 #
220 # @retval string String of platform file path
221 #
222 def __str__(self):
223 return str(self.MetaFile)
224
225 ## "==" operator
226 def __eq__(self, Other):
227 return Other and self.MetaFile == Other
228
229 ## Workspace AutoGen class
230 #
231 # This class is used mainly to control the whole platform build for different
232 # architecture. This class will generate top level makefile.
233 #
234 class WorkspaceAutoGen(AutoGen):
235 # call super().__init__ then call the worker function with different parameter count
236 def __init__(self, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs):
237 if not hasattr(self, "_Init"):
238 super().__init__(Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs)
239 self._InitWorker(Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs)
240 self._Init = True
241
242 ## Initialize WorkspaceAutoGen
243 #
244 # @param WorkspaceDir Root directory of workspace
245 # @param ActivePlatform Meta-file of active platform
246 # @param Target Build target
247 # @param Toolchain Tool chain name
248 # @param ArchList List of architecture of current build
249 # @param MetaFileDb Database containing meta-files
250 # @param BuildConfig Configuration of build
251 # @param ToolDefinition Tool chain definitions
252 # @param FlashDefinitionFile File of flash definition
253 # @param Fds FD list to be generated
254 # @param Fvs FV list to be generated
255 # @param Caps Capsule list to be generated
256 # @param SkuId SKU id from command line
257 #
258 def _InitWorker(self, WorkspaceDir, ActivePlatform, Target, Toolchain, ArchList, MetaFileDb,
259 BuildConfig, ToolDefinition, FlashDefinitionFile='', Fds=None, Fvs=None, Caps=None, SkuId='', UniFlag=None,
260 Progress=None, BuildModule=None):
261 self.BuildDatabase = MetaFileDb
262 self.MetaFile = ActivePlatform
263 self.WorkspaceDir = WorkspaceDir
264 self.Platform = self.BuildDatabase[self.MetaFile, TAB_ARCH_COMMON, Target, Toolchain]
265 GlobalData.gActivePlatform = self.Platform
266 self.BuildTarget = Target
267 self.ToolChain = Toolchain
268 self.ArchList = ArchList
269 self.SkuId = SkuId
270 self.UniFlag = UniFlag
271
272 self.TargetTxt = BuildConfig
273 self.ToolDef = ToolDefinition
274 self.FdfFile = FlashDefinitionFile
275 self.FdTargetList = Fds if Fds else []
276 self.FvTargetList = Fvs if Fvs else []
277 self.CapTargetList = Caps if Caps else []
278 self.AutoGenObjectList = []
279 self._GuidDict = {}
280
281 # there's many relative directory operations, so ...
282 os.chdir(self.WorkspaceDir)
283
284 #
285 # Merge Arch
286 #
287 if not self.ArchList:
288 ArchList = set(self.Platform.SupArchList)
289 else:
290 ArchList = set(self.ArchList) & set(self.Platform.SupArchList)
291 if not ArchList:
292 EdkLogger.error("build", PARAMETER_INVALID,
293 ExtraData = "Invalid ARCH specified. [Valid ARCH: %s]" % (" ".join(self.Platform.SupArchList)))
294 elif self.ArchList and len(ArchList) != len(self.ArchList):
295 SkippedArchList = set(self.ArchList).symmetric_difference(set(self.Platform.SupArchList))
296 EdkLogger.verbose("\nArch [%s] is ignored because the platform supports [%s] only!"
297 % (" ".join(SkippedArchList), " ".join(self.Platform.SupArchList)))
298 self.ArchList = tuple(ArchList)
299
300 # Validate build target
301 if self.BuildTarget not in self.Platform.BuildTargets:
302 EdkLogger.error("build", PARAMETER_INVALID,
303 ExtraData="Build target [%s] is not supported by the platform. [Valid target: %s]"
304 % (self.BuildTarget, " ".join(self.Platform.BuildTargets)))
305
306
307 # parse FDF file to get PCDs in it, if any
308 if not self.FdfFile:
309 self.FdfFile = self.Platform.FlashDefinition
310
311 EdkLogger.info("")
312 if self.ArchList:
313 EdkLogger.info('%-16s = %s' % ("Architecture(s)", ' '.join(self.ArchList)))
314 EdkLogger.info('%-16s = %s' % ("Build target", self.BuildTarget))
315 EdkLogger.info('%-16s = %s' % ("Toolchain", self.ToolChain))
316
317 EdkLogger.info('\n%-24s = %s' % ("Active Platform", self.Platform))
318 if BuildModule:
319 EdkLogger.info('%-24s = %s' % ("Active Module", BuildModule))
320
321 if self.FdfFile:
322 EdkLogger.info('%-24s = %s' % ("Flash Image Definition", self.FdfFile))
323
324 EdkLogger.verbose("\nFLASH_DEFINITION = %s" % self.FdfFile)
325
326 if Progress:
327 Progress.Start("\nProcessing meta-data")
328
329 if self.FdfFile:
330 #
331 # Mark now build in AutoGen Phase
332 #
333 GlobalData.gAutoGenPhase = True
334 Fdf = FdfParser(self.FdfFile.Path)
335 Fdf.ParseFile()
336 GlobalData.gFdfParser = Fdf
337 GlobalData.gAutoGenPhase = False
338 PcdSet = Fdf.Profile.PcdDict
339 if Fdf.CurrentFdName and Fdf.CurrentFdName in Fdf.Profile.FdDict:
340 FdDict = Fdf.Profile.FdDict[Fdf.CurrentFdName]
341 for FdRegion in FdDict.RegionList:
342 if str(FdRegion.RegionType) is 'FILE' and self.Platform.VpdToolGuid in str(FdRegion.RegionDataList):
343 if int(FdRegion.Offset) % 8 != 0:
344 EdkLogger.error("build", FORMAT_INVALID, 'The VPD Base Address %s must be 8-byte aligned.' % (FdRegion.Offset))
345 ModuleList = Fdf.Profile.InfList
346 self.FdfProfile = Fdf.Profile
347 for fvname in self.FvTargetList:
348 if fvname.upper() not in self.FdfProfile.FvDict:
349 EdkLogger.error("build", OPTION_VALUE_INVALID,
350 "No such an FV in FDF file: %s" % fvname)
351
352 # In DSC file may use FILE_GUID to override the module, then in the Platform.Modules use FILE_GUIDmodule.inf as key,
353 # but the path (self.MetaFile.Path) is the real path
354 for key in self.FdfProfile.InfDict:
355 if key == 'ArchTBD':
356 MetaFile_cache = defaultdict(set)
357 for Arch in self.ArchList:
358 Current_Platform_cache = self.BuildDatabase[self.MetaFile, Arch, Target, Toolchain]
359 for Pkey in Current_Platform_cache.Modules:
360 MetaFile_cache[Arch].add(Current_Platform_cache.Modules[Pkey].MetaFile)
361 for Inf in self.FdfProfile.InfDict[key]:
362 ModuleFile = PathClass(NormPath(Inf), GlobalData.gWorkspace, Arch)
363 for Arch in self.ArchList:
364 if ModuleFile in MetaFile_cache[Arch]:
365 break
366 else:
367 ModuleData = self.BuildDatabase[ModuleFile, Arch, Target, Toolchain]
368 if not ModuleData.IsBinaryModule:
369 EdkLogger.error('build', PARSER_ERROR, "Module %s NOT found in DSC file; Is it really a binary module?" % ModuleFile)
370
371 else:
372 for Arch in self.ArchList:
373 if Arch == key:
374 Platform = self.BuildDatabase[self.MetaFile, Arch, Target, Toolchain]
375 MetaFileList = set()
376 for Pkey in Platform.Modules:
377 MetaFileList.add(Platform.Modules[Pkey].MetaFile)
378 for Inf in self.FdfProfile.InfDict[key]:
379 ModuleFile = PathClass(NormPath(Inf), GlobalData.gWorkspace, Arch)
380 if ModuleFile in MetaFileList:
381 continue
382 ModuleData = self.BuildDatabase[ModuleFile, Arch, Target, Toolchain]
383 if not ModuleData.IsBinaryModule:
384 EdkLogger.error('build', PARSER_ERROR, "Module %s NOT found in DSC file; Is it really a binary module?" % ModuleFile)
385
386 else:
387 PcdSet = {}
388 ModuleList = []
389 self.FdfProfile = None
390 if self.FdTargetList:
391 EdkLogger.info("No flash definition file found. FD [%s] will be ignored." % " ".join(self.FdTargetList))
392 self.FdTargetList = []
393 if self.FvTargetList:
394 EdkLogger.info("No flash definition file found. FV [%s] will be ignored." % " ".join(self.FvTargetList))
395 self.FvTargetList = []
396 if self.CapTargetList:
397 EdkLogger.info("No flash definition file found. Capsule [%s] will be ignored." % " ".join(self.CapTargetList))
398 self.CapTargetList = []
399
400 # apply SKU and inject PCDs from Flash Definition file
401 for Arch in self.ArchList:
402 Platform = self.BuildDatabase[self.MetaFile, Arch, Target, Toolchain]
403 PlatformPcds = Platform.Pcds
404 self._GuidDict = Platform._GuidDict
405 SourcePcdDict = {TAB_PCDS_DYNAMIC_EX:set(), TAB_PCDS_PATCHABLE_IN_MODULE:set(),TAB_PCDS_DYNAMIC:set(),TAB_PCDS_FIXED_AT_BUILD:set()}
406 BinaryPcdDict = {TAB_PCDS_DYNAMIC_EX:set(), TAB_PCDS_PATCHABLE_IN_MODULE:set()}
407 SourcePcdDict_Keys = SourcePcdDict.keys()
408 BinaryPcdDict_Keys = BinaryPcdDict.keys()
409
410 # generate the SourcePcdDict and BinaryPcdDict
411 PGen = PlatformAutoGen(self, self.MetaFile, Target, Toolchain, Arch)
412 for BuildData in PGen.BuildDatabase._CACHE_.values():
413 if BuildData.Arch != Arch:
414 continue
415 if BuildData.MetaFile.Ext == '.inf':
416 for key in BuildData.Pcds:
417 if BuildData.Pcds[key].Pending:
418 if key in Platform.Pcds:
419 PcdInPlatform = Platform.Pcds[key]
420 if PcdInPlatform.Type:
421 BuildData.Pcds[key].Type = PcdInPlatform.Type
422 BuildData.Pcds[key].Pending = False
423
424 if BuildData.MetaFile in Platform.Modules:
425 PlatformModule = Platform.Modules[str(BuildData.MetaFile)]
426 if key in PlatformModule.Pcds:
427 PcdInPlatform = PlatformModule.Pcds[key]
428 if PcdInPlatform.Type:
429 BuildData.Pcds[key].Type = PcdInPlatform.Type
430 BuildData.Pcds[key].Pending = False
431 else:
432 #Pcd used in Library, Pcd Type from reference module if Pcd Type is Pending
433 if BuildData.Pcds[key].Pending:
434 MGen = ModuleAutoGen(self, BuildData.MetaFile, Target, Toolchain, Arch, self.MetaFile)
435 if MGen and MGen.IsLibrary:
436 if MGen in PGen.LibraryAutoGenList:
437 ReferenceModules = MGen.ReferenceModules
438 for ReferenceModule in ReferenceModules:
439 if ReferenceModule.MetaFile in Platform.Modules:
440 RefPlatformModule = Platform.Modules[str(ReferenceModule.MetaFile)]
441 if key in RefPlatformModule.Pcds:
442 PcdInReferenceModule = RefPlatformModule.Pcds[key]
443 if PcdInReferenceModule.Type:
444 BuildData.Pcds[key].Type = PcdInReferenceModule.Type
445 BuildData.Pcds[key].Pending = False
446 break
447
448 if TAB_PCDS_DYNAMIC_EX in BuildData.Pcds[key].Type:
449 if BuildData.IsBinaryModule:
450 BinaryPcdDict[TAB_PCDS_DYNAMIC_EX].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
451 else:
452 SourcePcdDict[TAB_PCDS_DYNAMIC_EX].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
453
454 elif TAB_PCDS_PATCHABLE_IN_MODULE in BuildData.Pcds[key].Type:
455 if BuildData.MetaFile.Ext == '.inf':
456 if BuildData.IsBinaryModule:
457 BinaryPcdDict[TAB_PCDS_PATCHABLE_IN_MODULE].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
458 else:
459 SourcePcdDict[TAB_PCDS_PATCHABLE_IN_MODULE].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
460
461 elif TAB_PCDS_DYNAMIC in BuildData.Pcds[key].Type:
462 SourcePcdDict[TAB_PCDS_DYNAMIC].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
463 elif TAB_PCDS_FIXED_AT_BUILD in BuildData.Pcds[key].Type:
464 SourcePcdDict[TAB_PCDS_FIXED_AT_BUILD].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
465 else:
466 pass
467 #
468 # A PCD can only use one type for all source modules
469 #
470 for i in SourcePcdDict_Keys:
471 for j in SourcePcdDict_Keys:
472 if i != j:
473 Intersections = SourcePcdDict[i].intersection(SourcePcdDict[j])
474 if len(Intersections) > 0:
475 EdkLogger.error(
476 'build',
477 FORMAT_INVALID,
478 "Building modules from source INFs, following PCD use %s and %s access method. It must be corrected to use only one access method." % (i, j),
479 ExtraData='\n\t'.join(str(P[1]+'.'+P[0]) for P in Intersections)
480 )
481
482 #
483 # intersection the BinaryPCD for Mixed PCD
484 #
485 for i in BinaryPcdDict_Keys:
486 for j in BinaryPcdDict_Keys:
487 if i != j:
488 Intersections = BinaryPcdDict[i].intersection(BinaryPcdDict[j])
489 for item in Intersections:
490 NewPcd1 = (item[0] + '_' + i, item[1])
491 NewPcd2 = (item[0] + '_' + j, item[1])
492 if item not in GlobalData.MixedPcd:
493 GlobalData.MixedPcd[item] = [NewPcd1, NewPcd2]
494 else:
495 if NewPcd1 not in GlobalData.MixedPcd[item]:
496 GlobalData.MixedPcd[item].append(NewPcd1)
497 if NewPcd2 not in GlobalData.MixedPcd[item]:
498 GlobalData.MixedPcd[item].append(NewPcd2)
499
500 #
501 # intersection the SourcePCD and BinaryPCD for Mixed PCD
502 #
503 for i in SourcePcdDict_Keys:
504 for j in BinaryPcdDict_Keys:
505 if i != j:
506 Intersections = SourcePcdDict[i].intersection(BinaryPcdDict[j])
507 for item in Intersections:
508 NewPcd1 = (item[0] + '_' + i, item[1])
509 NewPcd2 = (item[0] + '_' + j, item[1])
510 if item not in GlobalData.MixedPcd:
511 GlobalData.MixedPcd[item] = [NewPcd1, NewPcd2]
512 else:
513 if NewPcd1 not in GlobalData.MixedPcd[item]:
514 GlobalData.MixedPcd[item].append(NewPcd1)
515 if NewPcd2 not in GlobalData.MixedPcd[item]:
516 GlobalData.MixedPcd[item].append(NewPcd2)
517
518 for BuildData in PGen.BuildDatabase._CACHE_.values():
519 if BuildData.Arch != Arch:
520 continue
521 for key in BuildData.Pcds:
522 for SinglePcd in GlobalData.MixedPcd:
523 if (BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName) == SinglePcd:
524 for item in GlobalData.MixedPcd[SinglePcd]:
525 Pcd_Type = item[0].split('_')[-1]
526 if (Pcd_Type == BuildData.Pcds[key].Type) or (Pcd_Type == TAB_PCDS_DYNAMIC_EX and BuildData.Pcds[key].Type in PCD_DYNAMIC_EX_TYPE_SET) or \
527 (Pcd_Type == TAB_PCDS_DYNAMIC and BuildData.Pcds[key].Type in PCD_DYNAMIC_TYPE_SET):
528 Value = BuildData.Pcds[key]
529 Value.TokenCName = BuildData.Pcds[key].TokenCName + '_' + Pcd_Type
530 if len(key) == 2:
531 newkey = (Value.TokenCName, key[1])
532 elif len(key) == 3:
533 newkey = (Value.TokenCName, key[1], key[2])
534 del BuildData.Pcds[key]
535 BuildData.Pcds[newkey] = Value
536 break
537 break
538
539 # handle the mixed pcd in FDF file
540 for key in PcdSet:
541 if key in GlobalData.MixedPcd:
542 Value = PcdSet[key]
543 del PcdSet[key]
544 for item in GlobalData.MixedPcd[key]:
545 PcdSet[item] = Value
546
547 #Collect package set information from INF of FDF
548 PkgSet = set()
549 for Inf in ModuleList:
550 ModuleFile = PathClass(NormPath(Inf), GlobalData.gWorkspace, Arch)
551 if ModuleFile in Platform.Modules:
552 continue
553 ModuleData = self.BuildDatabase[ModuleFile, Arch, Target, Toolchain]
554 PkgSet.update(ModuleData.Packages)
555 Pkgs = list(PkgSet) + list(PGen.PackageList)
556 DecPcds = set()
557 DecPcdsKey = set()
558 for Pkg in Pkgs:
559 for Pcd in Pkg.Pcds:
560 DecPcds.add((Pcd[0], Pcd[1]))
561 DecPcdsKey.add((Pcd[0], Pcd[1], Pcd[2]))
562
563 Platform.SkuName = self.SkuId
564 for Name, Guid,Fileds in PcdSet:
565 if (Name, Guid) not in DecPcds:
566 EdkLogger.error(
567 'build',
568 PARSER_ERROR,
569 "PCD (%s.%s) used in FDF is not declared in DEC files." % (Guid, Name),
570 File = self.FdfProfile.PcdFileLineDict[Name, Guid][0],
571 Line = self.FdfProfile.PcdFileLineDict[Name, Guid][1]
572 )
573 else:
574 # Check whether Dynamic or DynamicEx PCD used in FDF file. If used, build break and give a error message.
575 if (Name, Guid, TAB_PCDS_FIXED_AT_BUILD) in DecPcdsKey \
576 or (Name, Guid, TAB_PCDS_PATCHABLE_IN_MODULE) in DecPcdsKey \
577 or (Name, Guid, TAB_PCDS_FEATURE_FLAG) in DecPcdsKey:
578 continue
579 elif (Name, Guid, TAB_PCDS_DYNAMIC) in DecPcdsKey or (Name, Guid, TAB_PCDS_DYNAMIC_EX) in DecPcdsKey:
580 EdkLogger.error(
581 'build',
582 PARSER_ERROR,
583 "Using Dynamic or DynamicEx type of PCD [%s.%s] in FDF file is not allowed." % (Guid, Name),
584 File = self.FdfProfile.PcdFileLineDict[Name, Guid][0],
585 Line = self.FdfProfile.PcdFileLineDict[Name, Guid][1]
586 )
587
588 Pa = PlatformAutoGen(self, self.MetaFile, Target, Toolchain, Arch)
589 #
590 # Explicitly collect platform's dynamic PCDs
591 #
592 Pa.CollectPlatformDynamicPcds()
593 Pa.CollectFixedAtBuildPcds()
594 self.AutoGenObjectList.append(Pa)
595
596 #
597 # Generate Package level hash value
598 #
599 GlobalData.gPackageHash[Arch] = {}
600 if GlobalData.gUseHashCache:
601 for Pkg in Pkgs:
602 self._GenPkgLevelHash(Pkg)
603
604 #
605 # Check PCDs token value conflict in each DEC file.
606 #
607 self._CheckAllPcdsTokenValueConflict()
608
609 #
610 # Check PCD type and definition between DSC and DEC
611 #
612 self._CheckPcdDefineAndType()
613
614 #
615 # Create BuildOptions Macro & PCD metafile, also add the Active Platform and FDF file.
616 #
617 content = 'gCommandLineDefines: '
618 content += str(GlobalData.gCommandLineDefines)
619 content += os.linesep
620 content += 'BuildOptionPcd: '
621 content += str(GlobalData.BuildOptionPcd)
622 content += os.linesep
623 content += 'Active Platform: '
624 content += str(self.Platform)
625 content += os.linesep
626 if self.FdfFile:
627 content += 'Flash Image Definition: '
628 content += str(self.FdfFile)
629 content += os.linesep
630 SaveFileOnChange(os.path.join(self.BuildDir, 'BuildOptions'), content, False)
631
632 #
633 # Create PcdToken Number file for Dynamic/DynamicEx Pcd.
634 #
635 PcdTokenNumber = 'PcdTokenNumber: '
636 if Pa.PcdTokenNumber:
637 if Pa.DynamicPcdList:
638 for Pcd in Pa.DynamicPcdList:
639 PcdTokenNumber += os.linesep
640 PcdTokenNumber += str((Pcd.TokenCName, Pcd.TokenSpaceGuidCName))
641 PcdTokenNumber += ' : '
642 PcdTokenNumber += str(Pa.PcdTokenNumber[Pcd.TokenCName, Pcd.TokenSpaceGuidCName])
643 SaveFileOnChange(os.path.join(self.BuildDir, 'PcdTokenNumber'), PcdTokenNumber, False)
644
645 #
646 # Get set of workspace metafiles
647 #
648 AllWorkSpaceMetaFiles = self._GetMetaFiles(Target, Toolchain, Arch)
649
650 #
651 # Retrieve latest modified time of all metafiles
652 #
653 SrcTimeStamp = 0
654 for f in AllWorkSpaceMetaFiles:
655 if os.stat(f)[8] > SrcTimeStamp:
656 SrcTimeStamp = os.stat(f)[8]
657 self._SrcTimeStamp = SrcTimeStamp
658
659 if GlobalData.gUseHashCache:
660 m = hashlib.md5()
661 for files in AllWorkSpaceMetaFiles:
662 if files.endswith('.dec'):
663 continue
664 f = open(files, 'r')
665 Content = f.read()
666 f.close()
667 m.update(Content)
668 SaveFileOnChange(os.path.join(self.BuildDir, 'AutoGen.hash'), m.hexdigest(), True)
669 GlobalData.gPlatformHash = m.hexdigest()
670
671 #
672 # Write metafile list to build directory
673 #
674 AutoGenFilePath = os.path.join(self.BuildDir, 'AutoGen')
675 if os.path.exists (AutoGenFilePath):
676 os.remove(AutoGenFilePath)
677 if not os.path.exists(self.BuildDir):
678 os.makedirs(self.BuildDir)
679 with open(os.path.join(self.BuildDir, 'AutoGen'), 'w+') as file:
680 for f in AllWorkSpaceMetaFiles:
681 print(f, file=file)
682 return True
683
684 def _GenPkgLevelHash(self, Pkg):
685 if Pkg.PackageName in GlobalData.gPackageHash[Pkg.Arch]:
686 return
687
688 PkgDir = os.path.join(self.BuildDir, Pkg.Arch, Pkg.PackageName)
689 CreateDirectory(PkgDir)
690 HashFile = os.path.join(PkgDir, Pkg.PackageName + '.hash')
691 m = hashlib.md5()
692 # Get .dec file's hash value
693 f = open(Pkg.MetaFile.Path, 'r')
694 Content = f.read()
695 f.close()
696 m.update(Content)
697 # Get include files hash value
698 if Pkg.Includes:
699 for inc in sorted(Pkg.Includes, key=lambda x: str(x)):
700 for Root, Dirs, Files in os.walk(str(inc)):
701 for File in sorted(Files):
702 File_Path = os.path.join(Root, File)
703 f = open(File_Path, 'r')
704 Content = f.read()
705 f.close()
706 m.update(Content)
707 SaveFileOnChange(HashFile, m.hexdigest(), True)
708 GlobalData.gPackageHash[Pkg.Arch][Pkg.PackageName] = m.hexdigest()
709
710 def _GetMetaFiles(self, Target, Toolchain, Arch):
711 AllWorkSpaceMetaFiles = set()
712 #
713 # add fdf
714 #
715 if self.FdfFile:
716 AllWorkSpaceMetaFiles.add (self.FdfFile.Path)
717 for f in GlobalData.gFdfParser.GetAllIncludedFile():
718 AllWorkSpaceMetaFiles.add (f.FileName)
719 #
720 # add dsc
721 #
722 AllWorkSpaceMetaFiles.add(self.MetaFile.Path)
723
724 #
725 # add build_rule.txt & tools_def.txt
726 #
727 AllWorkSpaceMetaFiles.add(os.path.join(GlobalData.gConfDirectory, gDefaultBuildRuleFile))
728 AllWorkSpaceMetaFiles.add(os.path.join(GlobalData.gConfDirectory, gDefaultToolsDefFile))
729
730 # add BuildOption metafile
731 #
732 AllWorkSpaceMetaFiles.add(os.path.join(self.BuildDir, 'BuildOptions'))
733
734 # add PcdToken Number file for Dynamic/DynamicEx Pcd
735 #
736 AllWorkSpaceMetaFiles.add(os.path.join(self.BuildDir, 'PcdTokenNumber'))
737
738 for Arch in self.ArchList:
739 #
740 # add dec
741 #
742 for Package in PlatformAutoGen(self, self.MetaFile, Target, Toolchain, Arch).PackageList:
743 AllWorkSpaceMetaFiles.add(Package.MetaFile.Path)
744
745 #
746 # add included dsc
747 #
748 for filePath in self.BuildDatabase[self.MetaFile, Arch, Target, Toolchain]._RawData.IncludedFiles:
749 AllWorkSpaceMetaFiles.add(filePath.Path)
750
751 return AllWorkSpaceMetaFiles
752
753 def _CheckPcdDefineAndType(self):
754 PcdTypeSet = {TAB_PCDS_FIXED_AT_BUILD,
755 TAB_PCDS_PATCHABLE_IN_MODULE,
756 TAB_PCDS_FEATURE_FLAG,
757 TAB_PCDS_DYNAMIC,
758 TAB_PCDS_DYNAMIC_EX}
759
760 # This dict store PCDs which are not used by any modules with specified arches
761 UnusedPcd = OrderedDict()
762 for Pa in self.AutoGenObjectList:
763 # Key of DSC's Pcds dictionary is PcdCName, TokenSpaceGuid
764 for Pcd in Pa.Platform.Pcds:
765 PcdType = Pa.Platform.Pcds[Pcd].Type
766
767 # If no PCD type, this PCD comes from FDF
768 if not PcdType:
769 continue
770
771 # Try to remove Hii and Vpd suffix
772 if PcdType.startswith(TAB_PCDS_DYNAMIC_EX):
773 PcdType = TAB_PCDS_DYNAMIC_EX
774 elif PcdType.startswith(TAB_PCDS_DYNAMIC):
775 PcdType = TAB_PCDS_DYNAMIC
776
777 for Package in Pa.PackageList:
778 # Key of DEC's Pcds dictionary is PcdCName, TokenSpaceGuid, PcdType
779 if (Pcd[0], Pcd[1], PcdType) in Package.Pcds:
780 break
781 for Type in PcdTypeSet:
782 if (Pcd[0], Pcd[1], Type) in Package.Pcds:
783 EdkLogger.error(
784 'build',
785 FORMAT_INVALID,
786 "Type [%s] of PCD [%s.%s] in DSC file doesn't match the type [%s] defined in DEC file." \
787 % (Pa.Platform.Pcds[Pcd].Type, Pcd[1], Pcd[0], Type),
788 ExtraData=None
789 )
790 return
791 else:
792 UnusedPcd.setdefault(Pcd, []).append(Pa.Arch)
793
794 for Pcd in UnusedPcd:
795 EdkLogger.warn(
796 'build',
797 "The PCD was not specified by any INF module in the platform for the given architecture.\n"
798 "\tPCD: [%s.%s]\n\tPlatform: [%s]\n\tArch: %s"
799 % (Pcd[1], Pcd[0], os.path.basename(str(self.MetaFile)), str(UnusedPcd[Pcd])),
800 ExtraData=None
801 )
802
803 def __repr__(self):
804 return "%s [%s]" % (self.MetaFile, ", ".join(self.ArchList))
805
806 ## Return the directory to store FV files
807 @cached_property
808 def FvDir(self):
809 return path.join(self.BuildDir, TAB_FV_DIRECTORY)
810
811 ## Return the directory to store all intermediate and final files built
812 @cached_property
813 def BuildDir(self):
814 return self.AutoGenObjectList[0].BuildDir
815
816 ## Return the build output directory platform specifies
817 @cached_property
818 def OutputDir(self):
819 return self.Platform.OutputDirectory
820
821 ## Return platform name
822 @cached_property
823 def Name(self):
824 return self.Platform.PlatformName
825
826 ## Return meta-file GUID
827 @cached_property
828 def Guid(self):
829 return self.Platform.Guid
830
831 ## Return platform version
832 @cached_property
833 def Version(self):
834 return self.Platform.Version
835
836 ## Return paths of tools
837 @cached_property
838 def ToolDefinition(self):
839 return self.AutoGenObjectList[0].ToolDefinition
840
841 ## Return directory of platform makefile
842 #
843 # @retval string Makefile directory
844 #
845 @cached_property
846 def MakeFileDir(self):
847 return self.BuildDir
848
849 ## Return build command string
850 #
851 # @retval string Build command string
852 #
853 @cached_property
854 def BuildCommand(self):
855 # BuildCommand should be all the same. So just get one from platform AutoGen
856 return self.AutoGenObjectList[0].BuildCommand
857
858 ## Check the PCDs token value conflict in each DEC file.
859 #
860 # Will cause build break and raise error message while two PCDs conflict.
861 #
862 # @return None
863 #
864 def _CheckAllPcdsTokenValueConflict(self):
865 for Pa in self.AutoGenObjectList:
866 for Package in Pa.PackageList:
867 PcdList = Package.Pcds.values()
868 PcdList.sort(key=lambda x: int(x.TokenValue, 0))
869 Count = 0
870 while (Count < len(PcdList) - 1) :
871 Item = PcdList[Count]
872 ItemNext = PcdList[Count + 1]
873 #
874 # Make sure in the same token space the TokenValue should be unique
875 #
876 if (int(Item.TokenValue, 0) == int(ItemNext.TokenValue, 0)):
877 SameTokenValuePcdList = []
878 SameTokenValuePcdList.append(Item)
879 SameTokenValuePcdList.append(ItemNext)
880 RemainPcdListLength = len(PcdList) - Count - 2
881 for ValueSameCount in range(RemainPcdListLength):
882 if int(PcdList[len(PcdList) - RemainPcdListLength + ValueSameCount].TokenValue, 0) == int(Item.TokenValue, 0):
883 SameTokenValuePcdList.append(PcdList[len(PcdList) - RemainPcdListLength + ValueSameCount])
884 else:
885 break;
886 #
887 # Sort same token value PCD list with TokenGuid and TokenCName
888 #
889 SameTokenValuePcdList.sort(key=lambda x: "%s.%s" % (x.TokenSpaceGuidCName, x.TokenCName))
890 SameTokenValuePcdListCount = 0
891 while (SameTokenValuePcdListCount < len(SameTokenValuePcdList) - 1):
892 Flag = False
893 TemListItem = SameTokenValuePcdList[SameTokenValuePcdListCount]
894 TemListItemNext = SameTokenValuePcdList[SameTokenValuePcdListCount + 1]
895
896 if (TemListItem.TokenSpaceGuidCName == TemListItemNext.TokenSpaceGuidCName) and (TemListItem.TokenCName != TemListItemNext.TokenCName):
897 for PcdItem in GlobalData.MixedPcd:
898 if (TemListItem.TokenCName, TemListItem.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem] or \
899 (TemListItemNext.TokenCName, TemListItemNext.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
900 Flag = True
901 if not Flag:
902 EdkLogger.error(
903 'build',
904 FORMAT_INVALID,
905 "The TokenValue [%s] of PCD [%s.%s] is conflict with: [%s.%s] in %s"\
906 % (TemListItem.TokenValue, TemListItem.TokenSpaceGuidCName, TemListItem.TokenCName, TemListItemNext.TokenSpaceGuidCName, TemListItemNext.TokenCName, Package),
907 ExtraData=None
908 )
909 SameTokenValuePcdListCount += 1
910 Count += SameTokenValuePcdListCount
911 Count += 1
912
913 PcdList = Package.Pcds.values()
914 PcdList.sort(key=lambda x: "%s.%s" % (x.TokenSpaceGuidCName, x.TokenCName))
915 Count = 0
916 while (Count < len(PcdList) - 1) :
917 Item = PcdList[Count]
918 ItemNext = PcdList[Count + 1]
919 #
920 # Check PCDs with same TokenSpaceGuidCName.TokenCName have same token value as well.
921 #
922 if (Item.TokenSpaceGuidCName == ItemNext.TokenSpaceGuidCName) and (Item.TokenCName == ItemNext.TokenCName) and (int(Item.TokenValue, 0) != int(ItemNext.TokenValue, 0)):
923 EdkLogger.error(
924 'build',
925 FORMAT_INVALID,
926 "The TokenValue [%s] of PCD [%s.%s] in %s defined in two places should be same as well."\
927 % (Item.TokenValue, Item.TokenSpaceGuidCName, Item.TokenCName, Package),
928 ExtraData=None
929 )
930 Count += 1
931 ## Generate fds command
932 @property
933 def GenFdsCommand(self):
934 return (GenMake.TopLevelMakefile(self)._TEMPLATE_.Replace(GenMake.TopLevelMakefile(self)._TemplateDict)).strip()
935
936 ## Create makefile for the platform and modules in it
937 #
938 # @param CreateDepsMakeFile Flag indicating if the makefile for
939 # modules will be created as well
940 #
941 def CreateMakeFile(self, CreateDepsMakeFile=False):
942 if not CreateDepsMakeFile:
943 return
944 for Pa in self.AutoGenObjectList:
945 Pa.CreateMakeFile(True)
946
947 ## Create autogen code for platform and modules
948 #
949 # Since there's no autogen code for platform, this method will do nothing
950 # if CreateModuleCodeFile is set to False.
951 #
952 # @param CreateDepsCodeFile Flag indicating if creating module's
953 # autogen code file or not
954 #
955 def CreateCodeFile(self, CreateDepsCodeFile=False):
956 if not CreateDepsCodeFile:
957 return
958 for Pa in self.AutoGenObjectList:
959 Pa.CreateCodeFile(True)
960
961 ## Create AsBuilt INF file the platform
962 #
963 def CreateAsBuiltInf(self):
964 return
965
966
967 ## AutoGen class for platform
968 #
969 # PlatformAutoGen class will process the original information in platform
970 # file in order to generate makefile for platform.
971 #
972 class PlatformAutoGen(AutoGen):
973 # call super().__init__ then call the worker function with different parameter count
974 def __init__(self, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs):
975 if not hasattr(self, "_Init"):
976 super().__init__(self, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs)
977 self._InitWorker(Workspace, MetaFile, Target, Toolchain, Arch)
978 self._Init = True
979 #
980 # Used to store all PCDs for both PEI and DXE phase, in order to generate
981 # correct PCD database
982 #
983 _DynaPcdList_ = []
984 _NonDynaPcdList_ = []
985 _PlatformPcds = {}
986
987 #
988 # The priority list while override build option
989 #
990 PrioList = {"0x11111" : 16, # TARGET_TOOLCHAIN_ARCH_COMMANDTYPE_ATTRIBUTE (Highest)
991 "0x01111" : 15, # ******_TOOLCHAIN_ARCH_COMMANDTYPE_ATTRIBUTE
992 "0x10111" : 14, # TARGET_*********_ARCH_COMMANDTYPE_ATTRIBUTE
993 "0x00111" : 13, # ******_*********_ARCH_COMMANDTYPE_ATTRIBUTE
994 "0x11011" : 12, # TARGET_TOOLCHAIN_****_COMMANDTYPE_ATTRIBUTE
995 "0x01011" : 11, # ******_TOOLCHAIN_****_COMMANDTYPE_ATTRIBUTE
996 "0x10011" : 10, # TARGET_*********_****_COMMANDTYPE_ATTRIBUTE
997 "0x00011" : 9, # ******_*********_****_COMMANDTYPE_ATTRIBUTE
998 "0x11101" : 8, # TARGET_TOOLCHAIN_ARCH_***********_ATTRIBUTE
999 "0x01101" : 7, # ******_TOOLCHAIN_ARCH_***********_ATTRIBUTE
1000 "0x10101" : 6, # TARGET_*********_ARCH_***********_ATTRIBUTE
1001 "0x00101" : 5, # ******_*********_ARCH_***********_ATTRIBUTE
1002 "0x11001" : 4, # TARGET_TOOLCHAIN_****_***********_ATTRIBUTE
1003 "0x01001" : 3, # ******_TOOLCHAIN_****_***********_ATTRIBUTE
1004 "0x10001" : 2, # TARGET_*********_****_***********_ATTRIBUTE
1005 "0x00001" : 1} # ******_*********_****_***********_ATTRIBUTE (Lowest)
1006
1007 ## Initialize PlatformAutoGen
1008 #
1009 #
1010 # @param Workspace WorkspaceAutoGen object
1011 # @param PlatformFile Platform file (DSC file)
1012 # @param Target Build target (DEBUG, RELEASE)
1013 # @param Toolchain Name of tool chain
1014 # @param Arch arch of the platform supports
1015 #
1016 def _InitWorker(self, Workspace, PlatformFile, Target, Toolchain, Arch):
1017 EdkLogger.debug(EdkLogger.DEBUG_9, "AutoGen platform [%s] [%s]" % (PlatformFile, Arch))
1018 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (PlatformFile, Arch, Toolchain, Target)
1019
1020 self.MetaFile = PlatformFile
1021 self.Workspace = Workspace
1022 self.WorkspaceDir = Workspace.WorkspaceDir
1023 self.ToolChain = Toolchain
1024 self.BuildTarget = Target
1025 self.Arch = Arch
1026 self.SourceDir = PlatformFile.SubDir
1027 self.SourceOverrideDir = None
1028 self.FdTargetList = self.Workspace.FdTargetList
1029 self.FvTargetList = self.Workspace.FvTargetList
1030 self.AllPcdList = []
1031 # get the original module/package/platform objects
1032 self.BuildDatabase = Workspace.BuildDatabase
1033 self.DscBuildDataObj = Workspace.Platform
1034
1035 # flag indicating if the makefile/C-code file has been created or not
1036 self.IsMakeFileCreated = False
1037
1038 self._DynamicPcdList = None # [(TokenCName1, TokenSpaceGuidCName1), (TokenCName2, TokenSpaceGuidCName2), ...]
1039 self._NonDynamicPcdList = None # [(TokenCName1, TokenSpaceGuidCName1), (TokenCName2, TokenSpaceGuidCName2), ...]
1040
1041 self._AsBuildInfList = []
1042 self._AsBuildModuleList = []
1043
1044 self.VariableInfo = None
1045
1046 if GlobalData.gFdfParser is not None:
1047 self._AsBuildInfList = GlobalData.gFdfParser.Profile.InfList
1048 for Inf in self._AsBuildInfList:
1049 InfClass = PathClass(NormPath(Inf), GlobalData.gWorkspace, self.Arch)
1050 M = self.BuildDatabase[InfClass, self.Arch, self.BuildTarget, self.ToolChain]
1051 if not M.IsBinaryModule:
1052 continue
1053 self._AsBuildModuleList.append(InfClass)
1054 # get library/modules for build
1055 self.LibraryBuildDirectoryList = []
1056 self.ModuleBuildDirectoryList = []
1057
1058 return True
1059
1060 @cached_class_function
1061 def __repr__(self):
1062 return "%s [%s]" % (self.MetaFile, self.Arch)
1063
1064 ## Create autogen code for platform and modules
1065 #
1066 # Since there's no autogen code for platform, this method will do nothing
1067 # if CreateModuleCodeFile is set to False.
1068 #
1069 # @param CreateModuleCodeFile Flag indicating if creating module's
1070 # autogen code file or not
1071 #
1072 @cached_class_function
1073 def CreateCodeFile(self, CreateModuleCodeFile=False):
1074 # only module has code to be greated, so do nothing if CreateModuleCodeFile is False
1075 if not CreateModuleCodeFile:
1076 return
1077
1078 for Ma in self.ModuleAutoGenList:
1079 Ma.CreateCodeFile(True)
1080
1081 ## Generate Fds Command
1082 @cached_property
1083 def GenFdsCommand(self):
1084 return self.Workspace.GenFdsCommand
1085
1086 ## Create makefile for the platform and modules in it
1087 #
1088 # @param CreateModuleMakeFile Flag indicating if the makefile for
1089 # modules will be created as well
1090 #
1091 def CreateMakeFile(self, CreateModuleMakeFile=False, FfsCommand = {}):
1092 if CreateModuleMakeFile:
1093 for Ma in self._MaList:
1094 key = (Ma.MetaFile.File, self.Arch)
1095 if key in FfsCommand:
1096 Ma.CreateMakeFile(True, FfsCommand[key])
1097 else:
1098 Ma.CreateMakeFile(True)
1099
1100 # no need to create makefile for the platform more than once
1101 if self.IsMakeFileCreated:
1102 return
1103
1104 # create library/module build dirs for platform
1105 Makefile = GenMake.PlatformMakefile(self)
1106 self.LibraryBuildDirectoryList = Makefile.GetLibraryBuildDirectoryList()
1107 self.ModuleBuildDirectoryList = Makefile.GetModuleBuildDirectoryList()
1108
1109 self.IsMakeFileCreated = True
1110
1111 ## Deal with Shared FixedAtBuild Pcds
1112 #
1113 def CollectFixedAtBuildPcds(self):
1114 for LibAuto in self.LibraryAutoGenList:
1115 FixedAtBuildPcds = {}
1116 ShareFixedAtBuildPcdsSameValue = {}
1117 for Module in LibAuto.ReferenceModules:
1118 for Pcd in set(Module.FixedAtBuildPcds + LibAuto.FixedAtBuildPcds):
1119 DefaultValue = Pcd.DefaultValue
1120 # Cover the case: DSC component override the Pcd value and the Pcd only used in one Lib
1121 if Pcd in Module.LibraryPcdList:
1122 Index = Module.LibraryPcdList.index(Pcd)
1123 DefaultValue = Module.LibraryPcdList[Index].DefaultValue
1124 key = ".".join((Pcd.TokenSpaceGuidCName, Pcd.TokenCName))
1125 if key not in FixedAtBuildPcds:
1126 ShareFixedAtBuildPcdsSameValue[key] = True
1127 FixedAtBuildPcds[key] = DefaultValue
1128 else:
1129 if FixedAtBuildPcds[key] != DefaultValue:
1130 ShareFixedAtBuildPcdsSameValue[key] = False
1131 for Pcd in LibAuto.FixedAtBuildPcds:
1132 key = ".".join((Pcd.TokenSpaceGuidCName, Pcd.TokenCName))
1133 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) not in self.NonDynamicPcdDict:
1134 continue
1135 else:
1136 DscPcd = self.NonDynamicPcdDict[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName)]
1137 if DscPcd.Type != TAB_PCDS_FIXED_AT_BUILD:
1138 continue
1139 if key in ShareFixedAtBuildPcdsSameValue and ShareFixedAtBuildPcdsSameValue[key]:
1140 LibAuto.ConstPcd[key] = FixedAtBuildPcds[key]
1141
1142 def CollectVariables(self, DynamicPcdSet):
1143 VpdRegionSize = 0
1144 VpdRegionBase = 0
1145 if self.Workspace.FdfFile:
1146 FdDict = self.Workspace.FdfProfile.FdDict[GlobalData.gFdfParser.CurrentFdName]
1147 for FdRegion in FdDict.RegionList:
1148 for item in FdRegion.RegionDataList:
1149 if self.Platform.VpdToolGuid.strip() and self.Platform.VpdToolGuid in item:
1150 VpdRegionSize = FdRegion.Size
1151 VpdRegionBase = FdRegion.Offset
1152 break
1153
1154 VariableInfo = VariableMgr(self.DscBuildDataObj._GetDefaultStores(), self.DscBuildDataObj.SkuIds)
1155 VariableInfo.SetVpdRegionMaxSize(VpdRegionSize)
1156 VariableInfo.SetVpdRegionOffset(VpdRegionBase)
1157 Index = 0
1158 for Pcd in DynamicPcdSet:
1159 pcdname = ".".join((Pcd.TokenSpaceGuidCName, Pcd.TokenCName))
1160 for SkuName in Pcd.SkuInfoList:
1161 Sku = Pcd.SkuInfoList[SkuName]
1162 SkuId = Sku.SkuId
1163 if SkuId is None or SkuId == '':
1164 continue
1165 if len(Sku.VariableName) > 0:
1166 VariableGuidStructure = Sku.VariableGuidValue
1167 VariableGuid = GuidStructureStringToGuidString(VariableGuidStructure)
1168 for StorageName in Sku.DefaultStoreDict:
1169 VariableInfo.append_variable(var_info(Index, pcdname, StorageName, SkuName, StringToArray(Sku.VariableName), VariableGuid, Sku.VariableOffset, Sku.VariableAttribute, Sku.HiiDefaultValue, Sku.DefaultStoreDict[StorageName], Pcd.DatumType, Pcd.CustomAttribute['DscPosition'], Pcd.CustomAttribute.get('IsStru',False)))
1170 Index += 1
1171 return VariableInfo
1172
1173 def UpdateNVStoreMaxSize(self, OrgVpdFile):
1174 if self.VariableInfo:
1175 VpdMapFilePath = os.path.join(self.BuildDir, TAB_FV_DIRECTORY, "%s.map" % self.Platform.VpdToolGuid)
1176 PcdNvStoreDfBuffer = [item for item in self._DynamicPcdList if item.TokenCName == "PcdNvStoreDefaultValueBuffer" and item.TokenSpaceGuidCName == "gEfiMdeModulePkgTokenSpaceGuid"]
1177
1178 if PcdNvStoreDfBuffer:
1179 if os.path.exists(VpdMapFilePath):
1180 OrgVpdFile.Read(VpdMapFilePath)
1181 PcdItems = OrgVpdFile.GetOffset(PcdNvStoreDfBuffer[0])
1182 NvStoreOffset = PcdItems.values()[0].strip() if PcdItems else '0'
1183 else:
1184 EdkLogger.error("build", FILE_READ_FAILURE, "Can not find VPD map file %s to fix up VPD offset." % VpdMapFilePath)
1185
1186 NvStoreOffset = int(NvStoreOffset, 16) if NvStoreOffset.upper().startswith("0X") else int(NvStoreOffset)
1187 default_skuobj = PcdNvStoreDfBuffer[0].SkuInfoList.get(TAB_DEFAULT)
1188 maxsize = self.VariableInfo.VpdRegionSize - NvStoreOffset if self.VariableInfo.VpdRegionSize else len(default_skuobj.DefaultValue.split(","))
1189 var_data = self.VariableInfo.PatchNVStoreDefaultMaxSize(maxsize)
1190
1191 if var_data and default_skuobj:
1192 default_skuobj.DefaultValue = var_data
1193 PcdNvStoreDfBuffer[0].DefaultValue = var_data
1194 PcdNvStoreDfBuffer[0].SkuInfoList.clear()
1195 PcdNvStoreDfBuffer[0].SkuInfoList[TAB_DEFAULT] = default_skuobj
1196 PcdNvStoreDfBuffer[0].MaxDatumSize = str(len(default_skuobj.DefaultValue.split(",")))
1197
1198 return OrgVpdFile
1199
1200 ## Collect dynamic PCDs
1201 #
1202 # Gather dynamic PCDs list from each module and their settings from platform
1203 # This interface should be invoked explicitly when platform action is created.
1204 #
1205 def CollectPlatformDynamicPcds(self):
1206 for key in self.Platform.Pcds:
1207 for SinglePcd in GlobalData.MixedPcd:
1208 if (self.Platform.Pcds[key].TokenCName, self.Platform.Pcds[key].TokenSpaceGuidCName) == SinglePcd:
1209 for item in GlobalData.MixedPcd[SinglePcd]:
1210 Pcd_Type = item[0].split('_')[-1]
1211 if (Pcd_Type == self.Platform.Pcds[key].Type) or (Pcd_Type == TAB_PCDS_DYNAMIC_EX and self.Platform.Pcds[key].Type in PCD_DYNAMIC_EX_TYPE_SET) or \
1212 (Pcd_Type == TAB_PCDS_DYNAMIC and self.Platform.Pcds[key].Type in PCD_DYNAMIC_TYPE_SET):
1213 Value = self.Platform.Pcds[key]
1214 Value.TokenCName = self.Platform.Pcds[key].TokenCName + '_' + Pcd_Type
1215 if len(key) == 2:
1216 newkey = (Value.TokenCName, key[1])
1217 elif len(key) == 3:
1218 newkey = (Value.TokenCName, key[1], key[2])
1219 del self.Platform.Pcds[key]
1220 self.Platform.Pcds[newkey] = Value
1221 break
1222 break
1223
1224 # for gathering error information
1225 NoDatumTypePcdList = set()
1226 FdfModuleList = []
1227 for InfName in self._AsBuildInfList:
1228 InfName = mws.join(self.WorkspaceDir, InfName)
1229 FdfModuleList.append(os.path.normpath(InfName))
1230 for M in self._MaList:
1231 # F is the Module for which M is the module autogen
1232 for PcdFromModule in M.ModulePcdList + M.LibraryPcdList:
1233 # make sure that the "VOID*" kind of datum has MaxDatumSize set
1234 if PcdFromModule.DatumType == TAB_VOID and not PcdFromModule.MaxDatumSize:
1235 NoDatumTypePcdList.add("%s.%s [%s]" % (PcdFromModule.TokenSpaceGuidCName, PcdFromModule.TokenCName, M.MetaFile))
1236
1237 # Check the PCD from Binary INF or Source INF
1238 if M.IsBinaryModule == True:
1239 PcdFromModule.IsFromBinaryInf = True
1240
1241 # Check the PCD from DSC or not
1242 PcdFromModule.IsFromDsc = (PcdFromModule.TokenCName, PcdFromModule.TokenSpaceGuidCName) in self.Platform.Pcds
1243
1244 if PcdFromModule.Type in PCD_DYNAMIC_TYPE_SET or PcdFromModule.Type in PCD_DYNAMIC_EX_TYPE_SET:
1245 if M.MetaFile.Path not in FdfModuleList:
1246 # If one of the Source built modules listed in the DSC is not listed
1247 # in FDF modules, and the INF lists a PCD can only use the PcdsDynamic
1248 # access method (it is only listed in the DEC file that declares the
1249 # PCD as PcdsDynamic), then build tool will report warning message
1250 # notify the PI that they are attempting to build a module that must
1251 # be included in a flash image in order to be functional. These Dynamic
1252 # PCD will not be added into the Database unless it is used by other
1253 # modules that are included in the FDF file.
1254 if PcdFromModule.Type in PCD_DYNAMIC_TYPE_SET and \
1255 PcdFromModule.IsFromBinaryInf == False:
1256 # Print warning message to let the developer make a determine.
1257 continue
1258 # If one of the Source built modules listed in the DSC is not listed in
1259 # FDF modules, and the INF lists a PCD can only use the PcdsDynamicEx
1260 # access method (it is only listed in the DEC file that declares the
1261 # PCD as PcdsDynamicEx), then DO NOT break the build; DO NOT add the
1262 # PCD to the Platform's PCD Database.
1263 if PcdFromModule.Type in PCD_DYNAMIC_EX_TYPE_SET:
1264 continue
1265 #
1266 # If a dynamic PCD used by a PEM module/PEI module & DXE module,
1267 # it should be stored in Pcd PEI database, If a dynamic only
1268 # used by DXE module, it should be stored in DXE PCD database.
1269 # The default Phase is DXE
1270 #
1271 if M.ModuleType in SUP_MODULE_SET_PEI:
1272 PcdFromModule.Phase = "PEI"
1273 if PcdFromModule not in self._DynaPcdList_:
1274 self._DynaPcdList_.append(PcdFromModule)
1275 elif PcdFromModule.Phase == 'PEI':
1276 # overwrite any the same PCD existing, if Phase is PEI
1277 Index = self._DynaPcdList_.index(PcdFromModule)
1278 self._DynaPcdList_[Index] = PcdFromModule
1279 elif PcdFromModule not in self._NonDynaPcdList_:
1280 self._NonDynaPcdList_.append(PcdFromModule)
1281 elif PcdFromModule in self._NonDynaPcdList_ and PcdFromModule.IsFromBinaryInf == True:
1282 Index = self._NonDynaPcdList_.index(PcdFromModule)
1283 if self._NonDynaPcdList_[Index].IsFromBinaryInf == False:
1284 #The PCD from Binary INF will override the same one from source INF
1285 self._NonDynaPcdList_.remove (self._NonDynaPcdList_[Index])
1286 PcdFromModule.Pending = False
1287 self._NonDynaPcdList_.append (PcdFromModule)
1288 DscModuleSet = {os.path.normpath(ModuleInf.Path) for ModuleInf in self.Platform.Modules}
1289 # add the PCD from modules that listed in FDF but not in DSC to Database
1290 for InfName in FdfModuleList:
1291 if InfName not in DscModuleSet:
1292 InfClass = PathClass(InfName)
1293 M = self.BuildDatabase[InfClass, self.Arch, self.BuildTarget, self.ToolChain]
1294 # If a module INF in FDF but not in current arch's DSC module list, it must be module (either binary or source)
1295 # for different Arch. PCDs in source module for different Arch is already added before, so skip the source module here.
1296 # For binary module, if in current arch, we need to list the PCDs into database.
1297 if not M.IsBinaryModule:
1298 continue
1299 # Override the module PCD setting by platform setting
1300 ModulePcdList = self.ApplyPcdSetting(M, M.Pcds)
1301 for PcdFromModule in ModulePcdList:
1302 PcdFromModule.IsFromBinaryInf = True
1303 PcdFromModule.IsFromDsc = False
1304 # Only allow the DynamicEx and Patchable PCD in AsBuild INF
1305 if PcdFromModule.Type not in PCD_DYNAMIC_EX_TYPE_SET and PcdFromModule.Type not in TAB_PCDS_PATCHABLE_IN_MODULE:
1306 EdkLogger.error("build", AUTOGEN_ERROR, "PCD setting error",
1307 File=self.MetaFile,
1308 ExtraData="\n\tExisted %s PCD %s in:\n\t\t%s\n"
1309 % (PcdFromModule.Type, PcdFromModule.TokenCName, InfName))
1310 # make sure that the "VOID*" kind of datum has MaxDatumSize set
1311 if PcdFromModule.DatumType == TAB_VOID and not PcdFromModule.MaxDatumSize:
1312 NoDatumTypePcdList.add("%s.%s [%s]" % (PcdFromModule.TokenSpaceGuidCName, PcdFromModule.TokenCName, InfName))
1313 if M.ModuleType in SUP_MODULE_SET_PEI:
1314 PcdFromModule.Phase = "PEI"
1315 if PcdFromModule not in self._DynaPcdList_ and PcdFromModule.Type in PCD_DYNAMIC_EX_TYPE_SET:
1316 self._DynaPcdList_.append(PcdFromModule)
1317 elif PcdFromModule not in self._NonDynaPcdList_ and PcdFromModule.Type in TAB_PCDS_PATCHABLE_IN_MODULE:
1318 self._NonDynaPcdList_.append(PcdFromModule)
1319 if PcdFromModule in self._DynaPcdList_ and PcdFromModule.Phase == 'PEI' and PcdFromModule.Type in PCD_DYNAMIC_EX_TYPE_SET:
1320 # Overwrite the phase of any the same PCD existing, if Phase is PEI.
1321 # It is to solve the case that a dynamic PCD used by a PEM module/PEI
1322 # module & DXE module at a same time.
1323 # Overwrite the type of the PCDs in source INF by the type of AsBuild
1324 # INF file as DynamicEx.
1325 Index = self._DynaPcdList_.index(PcdFromModule)
1326 self._DynaPcdList_[Index].Phase = PcdFromModule.Phase
1327 self._DynaPcdList_[Index].Type = PcdFromModule.Type
1328 for PcdFromModule in self._NonDynaPcdList_:
1329 # If a PCD is not listed in the DSC file, but binary INF files used by
1330 # this platform all (that use this PCD) list the PCD in a [PatchPcds]
1331 # section, AND all source INF files used by this platform the build
1332 # that use the PCD list the PCD in either a [Pcds] or [PatchPcds]
1333 # section, then the tools must NOT add the PCD to the Platform's PCD
1334 # Database; the build must assign the access method for this PCD as
1335 # PcdsPatchableInModule.
1336 if PcdFromModule not in self._DynaPcdList_:
1337 continue
1338 Index = self._DynaPcdList_.index(PcdFromModule)
1339 if PcdFromModule.IsFromDsc == False and \
1340 PcdFromModule.Type in TAB_PCDS_PATCHABLE_IN_MODULE and \
1341 PcdFromModule.IsFromBinaryInf == True and \
1342 self._DynaPcdList_[Index].IsFromBinaryInf == False:
1343 Index = self._DynaPcdList_.index(PcdFromModule)
1344 self._DynaPcdList_.remove (self._DynaPcdList_[Index])
1345
1346 # print out error information and break the build, if error found
1347 if len(NoDatumTypePcdList) > 0:
1348 NoDatumTypePcdListString = "\n\t\t".join(NoDatumTypePcdList)
1349 EdkLogger.error("build", AUTOGEN_ERROR, "PCD setting error",
1350 File=self.MetaFile,
1351 ExtraData="\n\tPCD(s) without MaxDatumSize:\n\t\t%s\n"
1352 % NoDatumTypePcdListString)
1353 self._NonDynamicPcdList = self._NonDynaPcdList_
1354 self._DynamicPcdList = self._DynaPcdList_
1355 #
1356 # Sort dynamic PCD list to:
1357 # 1) If PCD's datum type is VOID* and value is unicode string which starts with L, the PCD item should
1358 # try to be put header of dynamicd List
1359 # 2) If PCD is HII type, the PCD item should be put after unicode type PCD
1360 #
1361 # The reason of sorting is make sure the unicode string is in double-byte alignment in string table.
1362 #
1363 UnicodePcdArray = set()
1364 HiiPcdArray = set()
1365 OtherPcdArray = set()
1366 VpdPcdDict = {}
1367 VpdFile = VpdInfoFile.VpdInfoFile()
1368 NeedProcessVpdMapFile = False
1369
1370 for pcd in self.Platform.Pcds:
1371 if pcd not in self._PlatformPcds:
1372 self._PlatformPcds[pcd] = self.Platform.Pcds[pcd]
1373
1374 for item in self._PlatformPcds:
1375 if self._PlatformPcds[item].DatumType and self._PlatformPcds[item].DatumType not in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64, TAB_VOID, "BOOLEAN"]:
1376 self._PlatformPcds[item].DatumType = TAB_VOID
1377
1378 if (self.Workspace.ArchList[-1] == self.Arch):
1379 for Pcd in self._DynamicPcdList:
1380 # just pick the a value to determine whether is unicode string type
1381 Sku = Pcd.SkuInfoList.values()[0]
1382 Sku.VpdOffset = Sku.VpdOffset.strip()
1383
1384 if Pcd.DatumType not in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64, TAB_VOID, "BOOLEAN"]:
1385 Pcd.DatumType = TAB_VOID
1386
1387 # if found PCD which datum value is unicode string the insert to left size of UnicodeIndex
1388 # if found HII type PCD then insert to right of UnicodeIndex
1389 if Pcd.Type in [TAB_PCDS_DYNAMIC_VPD, TAB_PCDS_DYNAMIC_EX_VPD]:
1390 VpdPcdDict[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName)] = Pcd
1391
1392 #Collect DynamicHii PCD values and assign it to DynamicExVpd PCD gEfiMdeModulePkgTokenSpaceGuid.PcdNvStoreDefaultValueBuffer
1393 PcdNvStoreDfBuffer = VpdPcdDict.get(("PcdNvStoreDefaultValueBuffer", "gEfiMdeModulePkgTokenSpaceGuid"))
1394 if PcdNvStoreDfBuffer:
1395 self.VariableInfo = self.CollectVariables(self._DynamicPcdList)
1396 vardump = self.VariableInfo.dump()
1397 if vardump:
1398 PcdNvStoreDfBuffer.DefaultValue = vardump
1399 for skuname in PcdNvStoreDfBuffer.SkuInfoList:
1400 PcdNvStoreDfBuffer.SkuInfoList[skuname].DefaultValue = vardump
1401 PcdNvStoreDfBuffer.MaxDatumSize = str(len(vardump.split(",")))
1402 else:
1403 #If the end user define [DefaultStores] and [XXX.Menufacturing] in DSC, but forget to configure PcdNvStoreDefaultValueBuffer to PcdsDynamicVpd
1404 if [Pcd for Pcd in self._DynamicPcdList if Pcd.UserDefinedDefaultStoresFlag]:
1405 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)
1406 PlatformPcds = sorted(self._PlatformPcds.keys())
1407 #
1408 # Add VPD type PCD into VpdFile and determine whether the VPD PCD need to be fixed up.
1409 #
1410 VpdSkuMap = {}
1411 for PcdKey in PlatformPcds:
1412 Pcd = self._PlatformPcds[PcdKey]
1413 if Pcd.Type in [TAB_PCDS_DYNAMIC_VPD, TAB_PCDS_DYNAMIC_EX_VPD] and \
1414 PcdKey in VpdPcdDict:
1415 Pcd = VpdPcdDict[PcdKey]
1416 SkuValueMap = {}
1417 DefaultSku = Pcd.SkuInfoList.get(TAB_DEFAULT)
1418 if DefaultSku:
1419 PcdValue = DefaultSku.DefaultValue
1420 if PcdValue not in SkuValueMap:
1421 SkuValueMap[PcdValue] = []
1422 VpdFile.Add(Pcd, TAB_DEFAULT, DefaultSku.VpdOffset)
1423 SkuValueMap[PcdValue].append(DefaultSku)
1424
1425 for (SkuName, Sku) in Pcd.SkuInfoList.items():
1426 Sku.VpdOffset = Sku.VpdOffset.strip()
1427 PcdValue = Sku.DefaultValue
1428 if PcdValue == "":
1429 PcdValue = Pcd.DefaultValue
1430 if Sku.VpdOffset != '*':
1431 if PcdValue.startswith("{"):
1432 Alignment = 8
1433 elif PcdValue.startswith("L"):
1434 Alignment = 2
1435 else:
1436 Alignment = 1
1437 try:
1438 VpdOffset = int(Sku.VpdOffset)
1439 except:
1440 try:
1441 VpdOffset = int(Sku.VpdOffset, 16)
1442 except:
1443 EdkLogger.error("build", FORMAT_INVALID, "Invalid offset value %s for PCD %s.%s." % (Sku.VpdOffset, Pcd.TokenSpaceGuidCName, Pcd.TokenCName))
1444 if VpdOffset % Alignment != 0:
1445 if PcdValue.startswith("{"):
1446 EdkLogger.warn("build", "The offset value of PCD %s.%s is not 8-byte aligned!" %(Pcd.TokenSpaceGuidCName, Pcd.TokenCName), File=self.MetaFile)
1447 else:
1448 EdkLogger.error("build", FORMAT_INVALID, 'The offset value of PCD %s.%s should be %s-byte aligned.' % (Pcd.TokenSpaceGuidCName, Pcd.TokenCName, Alignment))
1449 if PcdValue not in SkuValueMap:
1450 SkuValueMap[PcdValue] = []
1451 VpdFile.Add(Pcd, SkuName, Sku.VpdOffset)
1452 SkuValueMap[PcdValue].append(Sku)
1453 # if the offset of a VPD is *, then it need to be fixed up by third party tool.
1454 if not NeedProcessVpdMapFile and Sku.VpdOffset == "*":
1455 NeedProcessVpdMapFile = True
1456 if self.Platform.VpdToolGuid is None or self.Platform.VpdToolGuid == '':
1457 EdkLogger.error("Build", FILE_NOT_FOUND, \
1458 "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.")
1459
1460 VpdSkuMap[PcdKey] = SkuValueMap
1461 #
1462 # Fix the PCDs define in VPD PCD section that never referenced by module.
1463 # An example is PCD for signature usage.
1464 #
1465 for DscPcd in PlatformPcds:
1466 DscPcdEntry = self._PlatformPcds[DscPcd]
1467 if DscPcdEntry.Type in [TAB_PCDS_DYNAMIC_VPD, TAB_PCDS_DYNAMIC_EX_VPD]:
1468 if not (self.Platform.VpdToolGuid is None or self.Platform.VpdToolGuid == ''):
1469 FoundFlag = False
1470 for VpdPcd in VpdFile._VpdArray:
1471 # This PCD has been referenced by module
1472 if (VpdPcd.TokenSpaceGuidCName == DscPcdEntry.TokenSpaceGuidCName) and \
1473 (VpdPcd.TokenCName == DscPcdEntry.TokenCName):
1474 FoundFlag = True
1475
1476 # Not found, it should be signature
1477 if not FoundFlag :
1478 # just pick the a value to determine whether is unicode string type
1479 SkuValueMap = {}
1480 SkuObjList = DscPcdEntry.SkuInfoList.items()
1481 DefaultSku = DscPcdEntry.SkuInfoList.get(TAB_DEFAULT)
1482 if DefaultSku:
1483 defaultindex = SkuObjList.index((TAB_DEFAULT, DefaultSku))
1484 SkuObjList[0], SkuObjList[defaultindex] = SkuObjList[defaultindex], SkuObjList[0]
1485 for (SkuName, Sku) in SkuObjList:
1486 Sku.VpdOffset = Sku.VpdOffset.strip()
1487
1488 # Need to iterate DEC pcd information to get the value & datumtype
1489 for eachDec in self.PackageList:
1490 for DecPcd in eachDec.Pcds:
1491 DecPcdEntry = eachDec.Pcds[DecPcd]
1492 if (DecPcdEntry.TokenSpaceGuidCName == DscPcdEntry.TokenSpaceGuidCName) and \
1493 (DecPcdEntry.TokenCName == DscPcdEntry.TokenCName):
1494 # Print warning message to let the developer make a determine.
1495 EdkLogger.warn("build", "Unreferenced vpd pcd used!",
1496 File=self.MetaFile, \
1497 ExtraData = "PCD: %s.%s used in the DSC file %s is unreferenced." \
1498 %(DscPcdEntry.TokenSpaceGuidCName, DscPcdEntry.TokenCName, self.Platform.MetaFile.Path))
1499
1500 DscPcdEntry.DatumType = DecPcdEntry.DatumType
1501 DscPcdEntry.DefaultValue = DecPcdEntry.DefaultValue
1502 DscPcdEntry.TokenValue = DecPcdEntry.TokenValue
1503 DscPcdEntry.TokenSpaceGuidValue = eachDec.Guids[DecPcdEntry.TokenSpaceGuidCName]
1504 # Only fix the value while no value provided in DSC file.
1505 if not Sku.DefaultValue:
1506 DscPcdEntry.SkuInfoList[DscPcdEntry.SkuInfoList.keys()[0]].DefaultValue = DecPcdEntry.DefaultValue
1507
1508 if DscPcdEntry not in self._DynamicPcdList:
1509 self._DynamicPcdList.append(DscPcdEntry)
1510 Sku.VpdOffset = Sku.VpdOffset.strip()
1511 PcdValue = Sku.DefaultValue
1512 if PcdValue == "":
1513 PcdValue = DscPcdEntry.DefaultValue
1514 if Sku.VpdOffset != '*':
1515 if PcdValue.startswith("{"):
1516 Alignment = 8
1517 elif PcdValue.startswith("L"):
1518 Alignment = 2
1519 else:
1520 Alignment = 1
1521 try:
1522 VpdOffset = int(Sku.VpdOffset)
1523 except:
1524 try:
1525 VpdOffset = int(Sku.VpdOffset, 16)
1526 except:
1527 EdkLogger.error("build", FORMAT_INVALID, "Invalid offset value %s for PCD %s.%s." % (Sku.VpdOffset, DscPcdEntry.TokenSpaceGuidCName, DscPcdEntry.TokenCName))
1528 if VpdOffset % Alignment != 0:
1529 if PcdValue.startswith("{"):
1530 EdkLogger.warn("build", "The offset value of PCD %s.%s is not 8-byte aligned!" %(DscPcdEntry.TokenSpaceGuidCName, DscPcdEntry.TokenCName), File=self.MetaFile)
1531 else:
1532 EdkLogger.error("build", FORMAT_INVALID, 'The offset value of PCD %s.%s should be %s-byte aligned.' % (DscPcdEntry.TokenSpaceGuidCName, DscPcdEntry.TokenCName, Alignment))
1533 if PcdValue not in SkuValueMap:
1534 SkuValueMap[PcdValue] = []
1535 VpdFile.Add(DscPcdEntry, SkuName, Sku.VpdOffset)
1536 SkuValueMap[PcdValue].append(Sku)
1537 if not NeedProcessVpdMapFile and Sku.VpdOffset == "*":
1538 NeedProcessVpdMapFile = True
1539 if DscPcdEntry.DatumType == TAB_VOID and PcdValue.startswith("L"):
1540 UnicodePcdArray.add(DscPcdEntry)
1541 elif len(Sku.VariableName) > 0:
1542 HiiPcdArray.add(DscPcdEntry)
1543 else:
1544 OtherPcdArray.add(DscPcdEntry)
1545
1546 # if the offset of a VPD is *, then it need to be fixed up by third party tool.
1547 VpdSkuMap[DscPcd] = SkuValueMap
1548 if (self.Platform.FlashDefinition is None or self.Platform.FlashDefinition == '') and \
1549 VpdFile.GetCount() != 0:
1550 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE,
1551 "Fail to get FLASH_DEFINITION definition in DSC file %s which is required when DSC contains VPD PCD." % str(self.Platform.MetaFile))
1552
1553 if VpdFile.GetCount() != 0:
1554
1555 self.FixVpdOffset(VpdFile)
1556
1557 self.FixVpdOffset(self.UpdateNVStoreMaxSize(VpdFile))
1558
1559 # Process VPD map file generated by third party BPDG tool
1560 if NeedProcessVpdMapFile:
1561 VpdMapFilePath = os.path.join(self.BuildDir, TAB_FV_DIRECTORY, "%s.map" % self.Platform.VpdToolGuid)
1562 if os.path.exists(VpdMapFilePath):
1563 VpdFile.Read(VpdMapFilePath)
1564
1565 # Fixup "*" offset
1566 for pcd in VpdSkuMap:
1567 vpdinfo = VpdFile.GetVpdInfo(pcd)
1568 if vpdinfo is None:
1569 # just pick the a value to determine whether is unicode string type
1570 continue
1571 for pcdvalue in VpdSkuMap[pcd]:
1572 for sku in VpdSkuMap[pcd][pcdvalue]:
1573 for item in vpdinfo:
1574 if item[2] == pcdvalue:
1575 sku.VpdOffset = item[1]
1576 else:
1577 EdkLogger.error("build", FILE_READ_FAILURE, "Can not find VPD map file %s to fix up VPD offset." % VpdMapFilePath)
1578
1579 # Delete the DynamicPcdList At the last time enter into this function
1580 for Pcd in self._DynamicPcdList:
1581 # just pick the a value to determine whether is unicode string type
1582 Sku = Pcd.SkuInfoList.values()[0]
1583 Sku.VpdOffset = Sku.VpdOffset.strip()
1584
1585 if Pcd.DatumType not in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64, TAB_VOID, "BOOLEAN"]:
1586 Pcd.DatumType = TAB_VOID
1587
1588 PcdValue = Sku.DefaultValue
1589 if Pcd.DatumType == TAB_VOID and PcdValue.startswith("L"):
1590 # if found PCD which datum value is unicode string the insert to left size of UnicodeIndex
1591 UnicodePcdArray.add(Pcd)
1592 elif len(Sku.VariableName) > 0:
1593 # if found HII type PCD then insert to right of UnicodeIndex
1594 HiiPcdArray.add(Pcd)
1595 else:
1596 OtherPcdArray.add(Pcd)
1597 del self._DynamicPcdList[:]
1598 self._DynamicPcdList.extend(list(UnicodePcdArray))
1599 self._DynamicPcdList.extend(list(HiiPcdArray))
1600 self._DynamicPcdList.extend(list(OtherPcdArray))
1601 allskuset = [(SkuName, Sku.SkuId) for pcd in self._DynamicPcdList for (SkuName, Sku) in pcd.SkuInfoList.items()]
1602 for pcd in self._DynamicPcdList:
1603 if len(pcd.SkuInfoList) == 1:
1604 for (SkuName, SkuId) in allskuset:
1605 if type(SkuId) in (str, unicode) and eval(SkuId) == 0 or SkuId == 0:
1606 continue
1607 pcd.SkuInfoList[SkuName] = copy.deepcopy(pcd.SkuInfoList[TAB_DEFAULT])
1608 pcd.SkuInfoList[SkuName].SkuId = SkuId
1609 pcd.SkuInfoList[SkuName].SkuIdName = SkuName
1610 self.AllPcdList = self._NonDynamicPcdList + self._DynamicPcdList
1611
1612 def FixVpdOffset(self, VpdFile ):
1613 FvPath = os.path.join(self.BuildDir, TAB_FV_DIRECTORY)
1614 if not os.path.exists(FvPath):
1615 try:
1616 os.makedirs(FvPath)
1617 except:
1618 EdkLogger.error("build", FILE_WRITE_FAILURE, "Fail to create FV folder under %s" % self.BuildDir)
1619
1620 VpdFilePath = os.path.join(FvPath, "%s.txt" % self.Platform.VpdToolGuid)
1621
1622 if VpdFile.Write(VpdFilePath):
1623 # retrieve BPDG tool's path from tool_def.txt according to VPD_TOOL_GUID defined in DSC file.
1624 BPDGToolName = None
1625 for ToolDef in self.ToolDefinition.values():
1626 if TAB_GUID in ToolDef and ToolDef[TAB_GUID] == self.Platform.VpdToolGuid:
1627 if "PATH" not in ToolDef:
1628 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "PATH attribute was not provided for BPDG guid tool %s in tools_def.txt" % self.Platform.VpdToolGuid)
1629 BPDGToolName = ToolDef["PATH"]
1630 break
1631 # Call third party GUID BPDG tool.
1632 if BPDGToolName is not None:
1633 VpdInfoFile.CallExtenalBPDGTool(BPDGToolName, VpdFilePath)
1634 else:
1635 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.")
1636
1637 ## Return the platform build data object
1638 @cached_property
1639 def Platform(self):
1640 return self.BuildDatabase[self.MetaFile, self.Arch, self.BuildTarget, self.ToolChain]
1641
1642 ## Return platform name
1643 @cached_property
1644 def Name(self):
1645 return self.Platform.PlatformName
1646
1647 ## Return the meta file GUID
1648 @cached_property
1649 def Guid(self):
1650 return self.Platform.Guid
1651
1652 ## Return the platform version
1653 @cached_property
1654 def Version(self):
1655 return self.Platform.Version
1656
1657 ## Return the FDF file name
1658 @cached_property
1659 def FdfFile(self):
1660 if self.Workspace.FdfFile:
1661 RetVal= mws.join(self.WorkspaceDir, self.Workspace.FdfFile)
1662 else:
1663 RetVal = ''
1664 return RetVal
1665
1666 ## Return the build output directory platform specifies
1667 @cached_property
1668 def OutputDir(self):
1669 return self.Platform.OutputDirectory
1670
1671 ## Return the directory to store all intermediate and final files built
1672 @cached_property
1673 def BuildDir(self):
1674 if os.path.isabs(self.OutputDir):
1675 GlobalData.gBuildDirectory = RetVal = path.join(
1676 path.abspath(self.OutputDir),
1677 self.BuildTarget + "_" + self.ToolChain,
1678 )
1679 else:
1680 GlobalData.gBuildDirectory = RetVal = path.join(
1681 self.WorkspaceDir,
1682 self.OutputDir,
1683 self.BuildTarget + "_" + self.ToolChain,
1684 )
1685 return RetVal
1686
1687 ## Return directory of platform makefile
1688 #
1689 # @retval string Makefile directory
1690 #
1691 @cached_property
1692 def MakeFileDir(self):
1693 return path.join(self.BuildDir, self.Arch)
1694
1695 ## Return build command string
1696 #
1697 # @retval string Build command string
1698 #
1699 @cached_property
1700 def BuildCommand(self):
1701 RetVal = []
1702 if "MAKE" in self.ToolDefinition and "PATH" in self.ToolDefinition["MAKE"]:
1703 RetVal += SplitOption(self.ToolDefinition["MAKE"]["PATH"])
1704 if "FLAGS" in self.ToolDefinition["MAKE"]:
1705 NewOption = self.ToolDefinition["MAKE"]["FLAGS"].strip()
1706 if NewOption != '':
1707 RetVal += SplitOption(NewOption)
1708 if "MAKE" in self.EdkIIBuildOption:
1709 if "FLAGS" in self.EdkIIBuildOption["MAKE"]:
1710 Flags = self.EdkIIBuildOption["MAKE"]["FLAGS"]
1711 if Flags.startswith('='):
1712 RetVal = [RetVal[0]] + [Flags[1:]]
1713 else:
1714 RetVal.append(Flags)
1715 return RetVal
1716
1717 ## Get tool chain definition
1718 #
1719 # Get each tool defition for given tool chain from tools_def.txt and platform
1720 #
1721 @cached_property
1722 def ToolDefinition(self):
1723 ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDictionary
1724 if TAB_TOD_DEFINES_COMMAND_TYPE not in self.Workspace.ToolDef.ToolsDefTxtDatabase:
1725 EdkLogger.error('build', RESOURCE_NOT_AVAILABLE, "No tools found in configuration",
1726 ExtraData="[%s]" % self.MetaFile)
1727 RetVal = {}
1728 DllPathList = set()
1729 for Def in ToolDefinition:
1730 Target, Tag, Arch, Tool, Attr = Def.split("_")
1731 if Target != self.BuildTarget or Tag != self.ToolChain or Arch != self.Arch:
1732 continue
1733
1734 Value = ToolDefinition[Def]
1735 # don't record the DLL
1736 if Attr == "DLL":
1737 DllPathList.add(Value)
1738 continue
1739
1740 if Tool not in RetVal:
1741 RetVal[Tool] = {}
1742 RetVal[Tool][Attr] = Value
1743
1744 ToolsDef = ''
1745 if GlobalData.gOptions.SilentMode and "MAKE" in RetVal:
1746 if "FLAGS" not in RetVal["MAKE"]:
1747 RetVal["MAKE"]["FLAGS"] = ""
1748 RetVal["MAKE"]["FLAGS"] += " -s"
1749 MakeFlags = ''
1750 for Tool in RetVal:
1751 for Attr in RetVal[Tool]:
1752 Value = RetVal[Tool][Attr]
1753 if Tool in self._BuildOptionWithToolDef(RetVal) and Attr in self._BuildOptionWithToolDef(RetVal)[Tool]:
1754 # check if override is indicated
1755 if self._BuildOptionWithToolDef(RetVal)[Tool][Attr].startswith('='):
1756 Value = self._BuildOptionWithToolDef(RetVal)[Tool][Attr][1:]
1757 else:
1758 if Attr != 'PATH':
1759 Value += " " + self._BuildOptionWithToolDef(RetVal)[Tool][Attr]
1760 else:
1761 Value = self._BuildOptionWithToolDef(RetVal)[Tool][Attr]
1762
1763 if Attr == "PATH":
1764 # Don't put MAKE definition in the file
1765 if Tool != "MAKE":
1766 ToolsDef += "%s = %s\n" % (Tool, Value)
1767 elif Attr != "DLL":
1768 # Don't put MAKE definition in the file
1769 if Tool == "MAKE":
1770 if Attr == "FLAGS":
1771 MakeFlags = Value
1772 else:
1773 ToolsDef += "%s_%s = %s\n" % (Tool, Attr, Value)
1774 ToolsDef += "\n"
1775
1776 SaveFileOnChange(self.ToolDefinitionFile, ToolsDef)
1777 for DllPath in DllPathList:
1778 os.environ["PATH"] = DllPath + os.pathsep + os.environ["PATH"]
1779 os.environ["MAKE_FLAGS"] = MakeFlags
1780
1781 return RetVal
1782
1783 ## Return the paths of tools
1784 @cached_property
1785 def ToolDefinitionFile(self):
1786 return os.path.join(self.MakeFileDir, "TOOLS_DEF." + self.Arch)
1787
1788 ## Retrieve the toolchain family of given toolchain tag. Default to 'MSFT'.
1789 @cached_property
1790 def ToolChainFamily(self):
1791 ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDatabase
1792 if TAB_TOD_DEFINES_FAMILY not in ToolDefinition \
1793 or self.ToolChain not in ToolDefinition[TAB_TOD_DEFINES_FAMILY] \
1794 or not ToolDefinition[TAB_TOD_DEFINES_FAMILY][self.ToolChain]:
1795 EdkLogger.verbose("No tool chain family found in configuration for %s. Default to MSFT." \
1796 % self.ToolChain)
1797 RetVal = TAB_COMPILER_MSFT
1798 else:
1799 RetVal = ToolDefinition[TAB_TOD_DEFINES_FAMILY][self.ToolChain]
1800 return RetVal
1801
1802 @cached_property
1803 def BuildRuleFamily(self):
1804 ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDatabase
1805 if TAB_TOD_DEFINES_BUILDRULEFAMILY not in ToolDefinition \
1806 or self.ToolChain not in ToolDefinition[TAB_TOD_DEFINES_BUILDRULEFAMILY] \
1807 or not ToolDefinition[TAB_TOD_DEFINES_BUILDRULEFAMILY][self.ToolChain]:
1808 EdkLogger.verbose("No tool chain family found in configuration for %s. Default to MSFT." \
1809 % self.ToolChain)
1810 return TAB_COMPILER_MSFT
1811
1812 return ToolDefinition[TAB_TOD_DEFINES_BUILDRULEFAMILY][self.ToolChain]
1813
1814 ## Return the build options specific for all modules in this platform
1815 @cached_property
1816 def BuildOption(self):
1817 return self._ExpandBuildOption(self.Platform.BuildOptions)
1818
1819 def _BuildOptionWithToolDef(self, ToolDef):
1820 return self._ExpandBuildOption(self.Platform.BuildOptions, ToolDef=ToolDef)
1821
1822 ## Return the build options specific for EDK modules in this platform
1823 @cached_property
1824 def EdkBuildOption(self):
1825 return self._ExpandBuildOption(self.Platform.BuildOptions, EDK_NAME)
1826
1827 ## Return the build options specific for EDKII modules in this platform
1828 @cached_property
1829 def EdkIIBuildOption(self):
1830 return self._ExpandBuildOption(self.Platform.BuildOptions, EDKII_NAME)
1831
1832 ## Parse build_rule.txt in Conf Directory.
1833 #
1834 # @retval BuildRule object
1835 #
1836 @cached_property
1837 def BuildRule(self):
1838 BuildRuleFile = None
1839 if TAB_TAT_DEFINES_BUILD_RULE_CONF in self.Workspace.TargetTxt.TargetTxtDictionary:
1840 BuildRuleFile = self.Workspace.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_BUILD_RULE_CONF]
1841 if not BuildRuleFile:
1842 BuildRuleFile = gDefaultBuildRuleFile
1843 RetVal = BuildRule(BuildRuleFile)
1844 if RetVal._FileVersion == "":
1845 RetVal._FileVersion = AutoGenReqBuildRuleVerNum
1846 else:
1847 if RetVal._FileVersion < AutoGenReqBuildRuleVerNum :
1848 # If Build Rule's version is less than the version number required by the tools, halting the build.
1849 EdkLogger.error("build", AUTOGEN_ERROR,
1850 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])"\
1851 % (RetVal._FileVersion, AutoGenReqBuildRuleVerNum))
1852 return RetVal
1853
1854 ## Summarize the packages used by modules in this platform
1855 @cached_property
1856 def PackageList(self):
1857 RetVal = set()
1858 for La in self.LibraryAutoGenList:
1859 RetVal.update(La.DependentPackageList)
1860 for Ma in self.ModuleAutoGenList:
1861 RetVal.update(Ma.DependentPackageList)
1862 #Collect package set information from INF of FDF
1863 for ModuleFile in self._AsBuildModuleList:
1864 if ModuleFile in self.Platform.Modules:
1865 continue
1866 ModuleData = self.BuildDatabase[ModuleFile, self.Arch, self.BuildTarget, self.ToolChain]
1867 RetVal.update(ModuleData.Packages)
1868 return list(RetVal)
1869
1870 @cached_property
1871 def NonDynamicPcdDict(self):
1872 return {(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):Pcd for Pcd in self.NonDynamicPcdList}
1873
1874 ## Get list of non-dynamic PCDs
1875 @cached_property
1876 def NonDynamicPcdList(self):
1877 self.CollectPlatformDynamicPcds()
1878 return self._NonDynamicPcdList
1879
1880 ## Get list of dynamic PCDs
1881 @cached_property
1882 def DynamicPcdList(self):
1883 self.CollectPlatformDynamicPcds()
1884 return self._DynamicPcdList
1885
1886 ## Generate Token Number for all PCD
1887 @cached_property
1888 def PcdTokenNumber(self):
1889 RetVal = OrderedDict()
1890 TokenNumber = 1
1891 #
1892 # Make the Dynamic and DynamicEx PCD use within different TokenNumber area.
1893 # Such as:
1894 #
1895 # Dynamic PCD:
1896 # TokenNumber 0 ~ 10
1897 # DynamicEx PCD:
1898 # TokeNumber 11 ~ 20
1899 #
1900 for Pcd in self.DynamicPcdList:
1901 if Pcd.Phase == "PEI" and Pcd.Type in PCD_DYNAMIC_TYPE_SET:
1902 EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))
1903 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
1904 TokenNumber += 1
1905
1906 for Pcd in self.DynamicPcdList:
1907 if Pcd.Phase == "PEI" and Pcd.Type in PCD_DYNAMIC_EX_TYPE_SET:
1908 EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))
1909 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
1910 TokenNumber += 1
1911
1912 for Pcd in self.DynamicPcdList:
1913 if Pcd.Phase == "DXE" and Pcd.Type in PCD_DYNAMIC_TYPE_SET:
1914 EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))
1915 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
1916 TokenNumber += 1
1917
1918 for Pcd in self.DynamicPcdList:
1919 if Pcd.Phase == "DXE" and Pcd.Type in PCD_DYNAMIC_EX_TYPE_SET:
1920 EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))
1921 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
1922 TokenNumber += 1
1923
1924 for Pcd in self.NonDynamicPcdList:
1925 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
1926 TokenNumber += 1
1927 return RetVal
1928
1929 @cached_property
1930 def _MaList(self):
1931 for ModuleFile in self.Platform.Modules:
1932 Ma = ModuleAutoGen(
1933 self.Workspace,
1934 ModuleFile,
1935 self.BuildTarget,
1936 self.ToolChain,
1937 self.Arch,
1938 self.MetaFile
1939 )
1940 self.Platform.Modules[ModuleFile].M = Ma
1941 return [x.M for x in self.Platform.Modules.values()]
1942
1943 ## Summarize ModuleAutoGen objects of all modules to be built for this platform
1944 @cached_property
1945 def ModuleAutoGenList(self):
1946 RetVal = []
1947 for Ma in self._MaList:
1948 if Ma not in RetVal:
1949 RetVal.append(Ma)
1950 return RetVal
1951
1952 ## Summarize ModuleAutoGen objects of all libraries to be built for this platform
1953 @cached_property
1954 def LibraryAutoGenList(self):
1955 RetVal = []
1956 for Ma in self._MaList:
1957 for La in Ma.LibraryAutoGenList:
1958 if La not in RetVal:
1959 RetVal.append(La)
1960 if Ma not in La.ReferenceModules:
1961 La.ReferenceModules.append(Ma)
1962 return RetVal
1963
1964 ## Test if a module is supported by the platform
1965 #
1966 # An error will be raised directly if the module or its arch is not supported
1967 # by the platform or current configuration
1968 #
1969 def ValidModule(self, Module):
1970 return Module in self.Platform.Modules or Module in self.Platform.LibraryInstances \
1971 or Module in self._AsBuildModuleList
1972
1973 ## Resolve the library classes in a module to library instances
1974 #
1975 # This method will not only resolve library classes but also sort the library
1976 # instances according to the dependency-ship.
1977 #
1978 # @param Module The module from which the library classes will be resolved
1979 #
1980 # @retval library_list List of library instances sorted
1981 #
1982 def ApplyLibraryInstance(self, Module):
1983 # Cover the case that the binary INF file is list in the FDF file but not DSC file, return empty list directly
1984 if str(Module) not in self.Platform.Modules:
1985 return []
1986
1987 return GetModuleLibInstances(Module,
1988 self.Platform,
1989 self.BuildDatabase,
1990 self.Arch,
1991 self.BuildTarget,
1992 self.ToolChain,
1993 self.MetaFile,
1994 EdkLogger)
1995
1996 ## Override PCD setting (type, value, ...)
1997 #
1998 # @param ToPcd The PCD to be overrided
1999 # @param FromPcd The PCD overrideing from
2000 #
2001 def _OverridePcd(self, ToPcd, FromPcd, Module="", Msg="", Library=""):
2002 #
2003 # in case there's PCDs coming from FDF file, which have no type given.
2004 # at this point, ToPcd.Type has the type found from dependent
2005 # package
2006 #
2007 TokenCName = ToPcd.TokenCName
2008 for PcdItem in GlobalData.MixedPcd:
2009 if (ToPcd.TokenCName, ToPcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
2010 TokenCName = PcdItem[0]
2011 break
2012 if FromPcd is not None:
2013 if ToPcd.Pending and FromPcd.Type:
2014 ToPcd.Type = FromPcd.Type
2015 elif ToPcd.Type and FromPcd.Type\
2016 and ToPcd.Type != FromPcd.Type and ToPcd.Type in FromPcd.Type:
2017 if ToPcd.Type.strip() == TAB_PCDS_DYNAMIC_EX:
2018 ToPcd.Type = FromPcd.Type
2019 elif ToPcd.Type and FromPcd.Type \
2020 and ToPcd.Type != FromPcd.Type:
2021 if Library:
2022 Module = str(Module) + " 's library file (" + str(Library) + ")"
2023 EdkLogger.error("build", OPTION_CONFLICT, "Mismatched PCD type",
2024 ExtraData="%s.%s is used as [%s] in module %s, but as [%s] in %s."\
2025 % (ToPcd.TokenSpaceGuidCName, TokenCName,
2026 ToPcd.Type, Module, FromPcd.Type, Msg),
2027 File=self.MetaFile)
2028
2029 if FromPcd.MaxDatumSize:
2030 ToPcd.MaxDatumSize = FromPcd.MaxDatumSize
2031 ToPcd.MaxSizeUserSet = FromPcd.MaxDatumSize
2032 if FromPcd.DefaultValue:
2033 ToPcd.DefaultValue = FromPcd.DefaultValue
2034 if FromPcd.TokenValue:
2035 ToPcd.TokenValue = FromPcd.TokenValue
2036 if FromPcd.DatumType:
2037 ToPcd.DatumType = FromPcd.DatumType
2038 if FromPcd.SkuInfoList:
2039 ToPcd.SkuInfoList = FromPcd.SkuInfoList
2040 if FromPcd.UserDefinedDefaultStoresFlag:
2041 ToPcd.UserDefinedDefaultStoresFlag = FromPcd.UserDefinedDefaultStoresFlag
2042 # Add Flexible PCD format parse
2043 if ToPcd.DefaultValue:
2044 try:
2045 ToPcd.DefaultValue = ValueExpressionEx(ToPcd.DefaultValue, ToPcd.DatumType, self.Workspace._GuidDict)(True)
2046 except BadExpression as Value:
2047 EdkLogger.error('Parser', FORMAT_INVALID, 'PCD [%s.%s] Value "%s", %s' %(ToPcd.TokenSpaceGuidCName, ToPcd.TokenCName, ToPcd.DefaultValue, Value),
2048 File=self.MetaFile)
2049
2050 # check the validation of datum
2051 IsValid, Cause = CheckPcdDatum(ToPcd.DatumType, ToPcd.DefaultValue)
2052 if not IsValid:
2053 EdkLogger.error('build', FORMAT_INVALID, Cause, File=self.MetaFile,
2054 ExtraData="%s.%s" % (ToPcd.TokenSpaceGuidCName, TokenCName))
2055 ToPcd.validateranges = FromPcd.validateranges
2056 ToPcd.validlists = FromPcd.validlists
2057 ToPcd.expressions = FromPcd.expressions
2058 ToPcd.CustomAttribute = FromPcd.CustomAttribute
2059
2060 if FromPcd is not None and ToPcd.DatumType == TAB_VOID and not ToPcd.MaxDatumSize:
2061 EdkLogger.debug(EdkLogger.DEBUG_9, "No MaxDatumSize specified for PCD %s.%s" \
2062 % (ToPcd.TokenSpaceGuidCName, TokenCName))
2063 Value = ToPcd.DefaultValue
2064 if not Value:
2065 ToPcd.MaxDatumSize = '1'
2066 elif Value[0] == 'L':
2067 ToPcd.MaxDatumSize = str((len(Value) - 2) * 2)
2068 elif Value[0] == '{':
2069 ToPcd.MaxDatumSize = str(len(Value.split(',')))
2070 else:
2071 ToPcd.MaxDatumSize = str(len(Value) - 1)
2072
2073 # apply default SKU for dynamic PCDS if specified one is not available
2074 if (ToPcd.Type in PCD_DYNAMIC_TYPE_SET or ToPcd.Type in PCD_DYNAMIC_EX_TYPE_SET) \
2075 and not ToPcd.SkuInfoList:
2076 if self.Platform.SkuName in self.Platform.SkuIds:
2077 SkuName = self.Platform.SkuName
2078 else:
2079 SkuName = TAB_DEFAULT
2080 ToPcd.SkuInfoList = {
2081 SkuName : SkuInfoClass(SkuName, self.Platform.SkuIds[SkuName][0], '', '', '', '', '', ToPcd.DefaultValue)
2082 }
2083
2084 ## Apply PCD setting defined platform to a module
2085 #
2086 # @param Module The module from which the PCD setting will be overrided
2087 #
2088 # @retval PCD_list The list PCDs with settings from platform
2089 #
2090 def ApplyPcdSetting(self, Module, Pcds, Library=""):
2091 # for each PCD in module
2092 for Name, Guid in Pcds:
2093 PcdInModule = Pcds[Name, Guid]
2094 # find out the PCD setting in platform
2095 if (Name, Guid) in self.Platform.Pcds:
2096 PcdInPlatform = self.Platform.Pcds[Name, Guid]
2097 else:
2098 PcdInPlatform = None
2099 # then override the settings if any
2100 self._OverridePcd(PcdInModule, PcdInPlatform, Module, Msg="DSC PCD sections", Library=Library)
2101 # resolve the VariableGuid value
2102 for SkuId in PcdInModule.SkuInfoList:
2103 Sku = PcdInModule.SkuInfoList[SkuId]
2104 if Sku.VariableGuid == '': continue
2105 Sku.VariableGuidValue = GuidValue(Sku.VariableGuid, self.PackageList, self.MetaFile.Path)
2106 if Sku.VariableGuidValue is None:
2107 PackageList = "\n\t".join(str(P) for P in self.PackageList)
2108 EdkLogger.error(
2109 'build',
2110 RESOURCE_NOT_AVAILABLE,
2111 "Value of GUID [%s] is not found in" % Sku.VariableGuid,
2112 ExtraData=PackageList + "\n\t(used with %s.%s from module %s)" \
2113 % (Guid, Name, str(Module)),
2114 File=self.MetaFile
2115 )
2116
2117 # override PCD settings with module specific setting
2118 if Module in self.Platform.Modules:
2119 PlatformModule = self.Platform.Modules[str(Module)]
2120 for Key in PlatformModule.Pcds:
2121 Flag = False
2122 if Key in Pcds:
2123 ToPcd = Pcds[Key]
2124 Flag = True
2125 elif Key in GlobalData.MixedPcd:
2126 for PcdItem in GlobalData.MixedPcd[Key]:
2127 if PcdItem in Pcds:
2128 ToPcd = Pcds[PcdItem]
2129 Flag = True
2130 break
2131 if Flag:
2132 self._OverridePcd(ToPcd, PlatformModule.Pcds[Key], Module, Msg="DSC Components Module scoped PCD section", Library=Library)
2133 # use PCD value to calculate the MaxDatumSize when it is not specified
2134 for Name, Guid in Pcds:
2135 Pcd = Pcds[Name, Guid]
2136 if Pcd.DatumType == TAB_VOID and not Pcd.MaxDatumSize:
2137 Pcd.MaxSizeUserSet = None
2138 Value = Pcd.DefaultValue
2139 if not Value:
2140 Pcd.MaxDatumSize = '1'
2141 elif Value[0] == 'L':
2142 Pcd.MaxDatumSize = str((len(Value) - 2) * 2)
2143 elif Value[0] == '{':
2144 Pcd.MaxDatumSize = str(len(Value.split(',')))
2145 else:
2146 Pcd.MaxDatumSize = str(len(Value) - 1)
2147 return Pcds.values()
2148
2149 ## Resolve library names to library modules
2150 #
2151 # (for Edk.x modules)
2152 #
2153 # @param Module The module from which the library names will be resolved
2154 #
2155 # @retval library_list The list of library modules
2156 #
2157 def ResolveLibraryReference(self, Module):
2158 EdkLogger.verbose("")
2159 EdkLogger.verbose("Library instances of module [%s] [%s]:" % (str(Module), self.Arch))
2160 LibraryConsumerList = [Module]
2161
2162 # "CompilerStub" is a must for Edk modules
2163 if Module.Libraries:
2164 Module.Libraries.append("CompilerStub")
2165 LibraryList = []
2166 while len(LibraryConsumerList) > 0:
2167 M = LibraryConsumerList.pop()
2168 for LibraryName in M.Libraries:
2169 Library = self.Platform.LibraryClasses[LibraryName, ':dummy:']
2170 if Library is None:
2171 for Key in self.Platform.LibraryClasses.data:
2172 if LibraryName.upper() == Key.upper():
2173 Library = self.Platform.LibraryClasses[Key, ':dummy:']
2174 break
2175 if Library is None:
2176 EdkLogger.warn("build", "Library [%s] is not found" % LibraryName, File=str(M),
2177 ExtraData="\t%s [%s]" % (str(Module), self.Arch))
2178 continue
2179
2180 if Library not in LibraryList:
2181 LibraryList.append(Library)
2182 LibraryConsumerList.append(Library)
2183 EdkLogger.verbose("\t" + LibraryName + " : " + str(Library) + ' ' + str(type(Library)))
2184 return LibraryList
2185
2186 ## Calculate the priority value of the build option
2187 #
2188 # @param Key Build option definition contain: TARGET_TOOLCHAIN_ARCH_COMMANDTYPE_ATTRIBUTE
2189 #
2190 # @retval Value Priority value based on the priority list.
2191 #
2192 def CalculatePriorityValue(self, Key):
2193 Target, ToolChain, Arch, CommandType, Attr = Key.split('_')
2194 PriorityValue = 0x11111
2195 if Target == "*":
2196 PriorityValue &= 0x01111
2197 if ToolChain == "*":
2198 PriorityValue &= 0x10111
2199 if Arch == "*":
2200 PriorityValue &= 0x11011
2201 if CommandType == "*":
2202 PriorityValue &= 0x11101
2203 if Attr == "*":
2204 PriorityValue &= 0x11110
2205
2206 return self.PrioList["0x%0.5x" % PriorityValue]
2207
2208
2209 ## Expand * in build option key
2210 #
2211 # @param Options Options to be expanded
2212 # @param ToolDef Use specified ToolDef instead of full version.
2213 # This is needed during initialization to prevent
2214 # infinite recursion betweeh BuildOptions,
2215 # ToolDefinition, and this function.
2216 #
2217 # @retval options Options expanded
2218 #
2219 def _ExpandBuildOption(self, Options, ModuleStyle=None, ToolDef=None):
2220 if not ToolDef:
2221 ToolDef = self.ToolDefinition
2222 BuildOptions = {}
2223 FamilyMatch = False
2224 FamilyIsNull = True
2225
2226 OverrideList = {}
2227 #
2228 # Construct a list contain the build options which need override.
2229 #
2230 for Key in Options:
2231 #
2232 # Key[0] -- tool family
2233 # Key[1] -- TARGET_TOOLCHAIN_ARCH_COMMANDTYPE_ATTRIBUTE
2234 #
2235 if (Key[0] == self.BuildRuleFamily and
2236 (ModuleStyle is None or len(Key) < 3 or (len(Key) > 2 and Key[2] == ModuleStyle))):
2237 Target, ToolChain, Arch, CommandType, Attr = Key[1].split('_')
2238 if (Target == self.BuildTarget or Target == "*") and\
2239 (ToolChain == self.ToolChain or ToolChain == "*") and\
2240 (Arch == self.Arch or Arch == "*") and\
2241 Options[Key].startswith("="):
2242
2243 if OverrideList.get(Key[1]) is not None:
2244 OverrideList.pop(Key[1])
2245 OverrideList[Key[1]] = Options[Key]
2246
2247 #
2248 # Use the highest priority value.
2249 #
2250 if (len(OverrideList) >= 2):
2251 KeyList = OverrideList.keys()
2252 for Index in range(len(KeyList)):
2253 NowKey = KeyList[Index]
2254 Target1, ToolChain1, Arch1, CommandType1, Attr1 = NowKey.split("_")
2255 for Index1 in range(len(KeyList) - Index - 1):
2256 NextKey = KeyList[Index1 + Index + 1]
2257 #
2258 # Compare two Key, if one is included by another, choose the higher priority one
2259 #
2260 Target2, ToolChain2, Arch2, CommandType2, Attr2 = NextKey.split("_")
2261 if (Target1 == Target2 or Target1 == "*" or Target2 == "*") and\
2262 (ToolChain1 == ToolChain2 or ToolChain1 == "*" or ToolChain2 == "*") and\
2263 (Arch1 == Arch2 or Arch1 == "*" or Arch2 == "*") and\
2264 (CommandType1 == CommandType2 or CommandType1 == "*" or CommandType2 == "*") and\
2265 (Attr1 == Attr2 or Attr1 == "*" or Attr2 == "*"):
2266
2267 if self.CalculatePriorityValue(NowKey) > self.CalculatePriorityValue(NextKey):
2268 if Options.get((self.BuildRuleFamily, NextKey)) is not None:
2269 Options.pop((self.BuildRuleFamily, NextKey))
2270 else:
2271 if Options.get((self.BuildRuleFamily, NowKey)) is not None:
2272 Options.pop((self.BuildRuleFamily, NowKey))
2273
2274 for Key in Options:
2275 if ModuleStyle is not None and len (Key) > 2:
2276 # Check Module style is EDK or EDKII.
2277 # Only append build option for the matched style module.
2278 if ModuleStyle == EDK_NAME and Key[2] != EDK_NAME:
2279 continue
2280 elif ModuleStyle == EDKII_NAME and Key[2] != EDKII_NAME:
2281 continue
2282 Family = Key[0]
2283 Target, Tag, Arch, Tool, Attr = Key[1].split("_")
2284 # if tool chain family doesn't match, skip it
2285 if Tool in ToolDef and Family != "":
2286 FamilyIsNull = False
2287 if ToolDef[Tool].get(TAB_TOD_DEFINES_BUILDRULEFAMILY, "") != "":
2288 if Family != ToolDef[Tool][TAB_TOD_DEFINES_BUILDRULEFAMILY]:
2289 continue
2290 elif Family != ToolDef[Tool][TAB_TOD_DEFINES_FAMILY]:
2291 continue
2292 FamilyMatch = True
2293 # expand any wildcard
2294 if Target == "*" or Target == self.BuildTarget:
2295 if Tag == "*" or Tag == self.ToolChain:
2296 if Arch == "*" or Arch == self.Arch:
2297 if Tool not in BuildOptions:
2298 BuildOptions[Tool] = {}
2299 if Attr != "FLAGS" or Attr not in BuildOptions[Tool] or Options[Key].startswith('='):
2300 BuildOptions[Tool][Attr] = Options[Key]
2301 else:
2302 # append options for the same tool except PATH
2303 if Attr != 'PATH':
2304 BuildOptions[Tool][Attr] += " " + Options[Key]
2305 else:
2306 BuildOptions[Tool][Attr] = Options[Key]
2307 # Build Option Family has been checked, which need't to be checked again for family.
2308 if FamilyMatch or FamilyIsNull:
2309 return BuildOptions
2310
2311 for Key in Options:
2312 if ModuleStyle is not None and len (Key) > 2:
2313 # Check Module style is EDK or EDKII.
2314 # Only append build option for the matched style module.
2315 if ModuleStyle == EDK_NAME and Key[2] != EDK_NAME:
2316 continue
2317 elif ModuleStyle == EDKII_NAME and Key[2] != EDKII_NAME:
2318 continue
2319 Family = Key[0]
2320 Target, Tag, Arch, Tool, Attr = Key[1].split("_")
2321 # if tool chain family doesn't match, skip it
2322 if Tool not in ToolDef or Family == "":
2323 continue
2324 # option has been added before
2325 if Family != ToolDef[Tool][TAB_TOD_DEFINES_FAMILY]:
2326 continue
2327
2328 # expand any wildcard
2329 if Target == "*" or Target == self.BuildTarget:
2330 if Tag == "*" or Tag == self.ToolChain:
2331 if Arch == "*" or Arch == self.Arch:
2332 if Tool not in BuildOptions:
2333 BuildOptions[Tool] = {}
2334 if Attr != "FLAGS" or Attr not in BuildOptions[Tool] or Options[Key].startswith('='):
2335 BuildOptions[Tool][Attr] = Options[Key]
2336 else:
2337 # append options for the same tool except PATH
2338 if Attr != 'PATH':
2339 BuildOptions[Tool][Attr] += " " + Options[Key]
2340 else:
2341 BuildOptions[Tool][Attr] = Options[Key]
2342 return BuildOptions
2343
2344 ## Append build options in platform to a module
2345 #
2346 # @param Module The module to which the build options will be appened
2347 #
2348 # @retval options The options appended with build options in platform
2349 #
2350 def ApplyBuildOption(self, Module):
2351 # Get the different options for the different style module
2352 if Module.AutoGenVersion < 0x00010005:
2353 PlatformOptions = self.EdkBuildOption
2354 ModuleTypeOptions = self.Platform.GetBuildOptionsByModuleType(EDK_NAME, Module.ModuleType)
2355 else:
2356 PlatformOptions = self.EdkIIBuildOption
2357 ModuleTypeOptions = self.Platform.GetBuildOptionsByModuleType(EDKII_NAME, Module.ModuleType)
2358 ModuleTypeOptions = self._ExpandBuildOption(ModuleTypeOptions)
2359 ModuleOptions = self._ExpandBuildOption(Module.BuildOptions)
2360 if Module in self.Platform.Modules:
2361 PlatformModule = self.Platform.Modules[str(Module)]
2362 PlatformModuleOptions = self._ExpandBuildOption(PlatformModule.BuildOptions)
2363 else:
2364 PlatformModuleOptions = {}
2365
2366 BuildRuleOrder = None
2367 for Options in [self.ToolDefinition, ModuleOptions, PlatformOptions, ModuleTypeOptions, PlatformModuleOptions]:
2368 for Tool in Options:
2369 for Attr in Options[Tool]:
2370 if Attr == TAB_TOD_DEFINES_BUILDRULEORDER:
2371 BuildRuleOrder = Options[Tool][Attr]
2372
2373 AllTools = set(ModuleOptions.keys() + PlatformOptions.keys() +
2374 PlatformModuleOptions.keys() + ModuleTypeOptions.keys() +
2375 self.ToolDefinition.keys())
2376 BuildOptions = defaultdict(lambda: defaultdict(str))
2377 for Tool in AllTools:
2378 for Options in [self.ToolDefinition, ModuleOptions, PlatformOptions, ModuleTypeOptions, PlatformModuleOptions]:
2379 if Tool not in Options:
2380 continue
2381 for Attr in Options[Tool]:
2382 #
2383 # Do not generate it in Makefile
2384 #
2385 if Attr == TAB_TOD_DEFINES_BUILDRULEORDER:
2386 continue
2387 Value = Options[Tool][Attr]
2388 # check if override is indicated
2389 if Value.startswith('='):
2390 BuildOptions[Tool][Attr] = mws.handleWsMacro(Value[1:])
2391 else:
2392 if Attr != 'PATH':
2393 BuildOptions[Tool][Attr] += " " + mws.handleWsMacro(Value)
2394 else:
2395 BuildOptions[Tool][Attr] = mws.handleWsMacro(Value)
2396
2397 if Module.AutoGenVersion < 0x00010005 and self.Workspace.UniFlag is not None:
2398 #
2399 # Override UNI flag only for EDK module.
2400 #
2401 BuildOptions['BUILD']['FLAGS'] = self.Workspace.UniFlag
2402 return BuildOptions, BuildRuleOrder
2403
2404 #
2405 # extend lists contained in a dictionary with lists stored in another dictionary
2406 # if CopyToDict is not derived from DefaultDict(list) then this may raise exception
2407 #
2408 def ExtendCopyDictionaryLists(CopyToDict, CopyFromDict):
2409 for Key in CopyFromDict:
2410 CopyToDict[Key].extend(CopyFromDict[Key])
2411
2412 # Create a directory specified by a set of path elements and return the full path
2413 def _MakeDir(PathList):
2414 RetVal = path.join(*PathList)
2415 CreateDirectory(RetVal)
2416 return RetVal
2417
2418 ## ModuleAutoGen class
2419 #
2420 # This class encapsules the AutoGen behaviors for the build tools. In addition to
2421 # the generation of AutoGen.h and AutoGen.c, it will generate *.depex file according
2422 # to the [depex] section in module's inf file.
2423 #
2424 class ModuleAutoGen(AutoGen):
2425 # call super().__init__ then call the worker function with different parameter count
2426 def __init__(self, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs):
2427 if not hasattr(self, "_Init"):
2428 super().__init__(Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs)
2429 self._InitWorker(Workspace, MetaFile, Target, Toolchain, Arch, *args)
2430 self._Init = True
2431
2432 ## Cache the timestamps of metafiles of every module in a class attribute
2433 #
2434 TimeDict = {}
2435
2436 def __new__(cls, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs):
2437 # check if this module is employed by active platform
2438 if not PlatformAutoGen(Workspace, args[0], Target, Toolchain, Arch).ValidModule(MetaFile):
2439 EdkLogger.verbose("Module [%s] for [%s] is not employed by active platform\n" \
2440 % (MetaFile, Arch))
2441 return None
2442 return super().__new__(cls, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs)
2443
2444 ## Initialize ModuleAutoGen
2445 #
2446 # @param Workspace EdkIIWorkspaceBuild object
2447 # @param ModuleFile The path of module file
2448 # @param Target Build target (DEBUG, RELEASE)
2449 # @param Toolchain Name of tool chain
2450 # @param Arch The arch the module supports
2451 # @param PlatformFile Platform meta-file
2452 #
2453 def _InitWorker(self, Workspace, ModuleFile, Target, Toolchain, Arch, PlatformFile):
2454 EdkLogger.debug(EdkLogger.DEBUG_9, "AutoGen module [%s] [%s]" % (ModuleFile, Arch))
2455 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (ModuleFile, Arch, Toolchain, Target)
2456
2457 self.Workspace = Workspace
2458 self.WorkspaceDir = Workspace.WorkspaceDir
2459 self.MetaFile = ModuleFile
2460 self.PlatformInfo = PlatformAutoGen(Workspace, PlatformFile, Target, Toolchain, Arch)
2461
2462 self.SourceDir = self.MetaFile.SubDir
2463 self.SourceDir = mws.relpath(self.SourceDir, self.WorkspaceDir)
2464
2465 self.SourceOverrideDir = None
2466 # use overrided path defined in DSC file
2467 if self.MetaFile.Key in GlobalData.gOverrideDir:
2468 self.SourceOverrideDir = GlobalData.gOverrideDir[self.MetaFile.Key]
2469
2470 self.ToolChain = Toolchain
2471 self.BuildTarget = Target
2472 self.Arch = Arch
2473 self.ToolChainFamily = self.PlatformInfo.ToolChainFamily
2474 self.BuildRuleFamily = self.PlatformInfo.BuildRuleFamily
2475
2476 self.IsCodeFileCreated = False
2477 self.IsAsBuiltInfCreated = False
2478 self.DepexGenerated = False
2479
2480 self.BuildDatabase = self.Workspace.BuildDatabase
2481 self.BuildRuleOrder = None
2482 self.BuildTime = 0
2483
2484 self._PcdComments = OrderedListDict()
2485 self._GuidComments = OrderedListDict()
2486 self._ProtocolComments = OrderedListDict()
2487 self._PpiComments = OrderedListDict()
2488 self._BuildTargets = None
2489 self._IntroBuildTargetList = None
2490 self._FinalBuildTargetList = None
2491 self._FileTypes = None
2492
2493 self.AutoGenDepSet = set()
2494 self.ReferenceModules = []
2495 self.ConstPcd = {}
2496
2497
2498 def __repr__(self):
2499 return "%s [%s]" % (self.MetaFile, self.Arch)
2500
2501 # Get FixedAtBuild Pcds of this Module
2502 @cached_property
2503 def FixedAtBuildPcds(self):
2504 RetVal = []
2505 for Pcd in self.ModulePcdList:
2506 if Pcd.Type != TAB_PCDS_FIXED_AT_BUILD:
2507 continue
2508 if Pcd not in RetVal:
2509 RetVal.append(Pcd)
2510 return RetVal
2511
2512 @cached_property
2513 def FixedVoidTypePcds(self):
2514 RetVal = {}
2515 for Pcd in self.FixedAtBuildPcds:
2516 if Pcd.DatumType == TAB_VOID:
2517 if '{}.{}'.format(Pcd.TokenSpaceGuidCName, Pcd.TokenCName) not in RetVal:
2518 RetVal['{}.{}'.format(Pcd.TokenSpaceGuidCName, Pcd.TokenCName)] = Pcd.DefaultValue
2519 return RetVal
2520
2521 @property
2522 def UniqueBaseName(self):
2523 BaseName = self.Name
2524 for Module in self.PlatformInfo.ModuleAutoGenList:
2525 if Module.MetaFile == self.MetaFile:
2526 continue
2527 if Module.Name == self.Name:
2528 if uuid.UUID(Module.Guid) == uuid.UUID(self.Guid):
2529 EdkLogger.error("build", FILE_DUPLICATED, 'Modules have same BaseName and FILE_GUID:\n'
2530 ' %s\n %s' % (Module.MetaFile, self.MetaFile))
2531 BaseName = '%s_%s' % (self.Name, self.Guid)
2532 return BaseName
2533
2534 # Macros could be used in build_rule.txt (also Makefile)
2535 @cached_property
2536 def Macros(self):
2537 return OrderedDict((
2538 ("WORKSPACE" ,self.WorkspaceDir),
2539 ("MODULE_NAME" ,self.Name),
2540 ("MODULE_NAME_GUID" ,self.UniqueBaseName),
2541 ("MODULE_GUID" ,self.Guid),
2542 ("MODULE_VERSION" ,self.Version),
2543 ("MODULE_TYPE" ,self.ModuleType),
2544 ("MODULE_FILE" ,str(self.MetaFile)),
2545 ("MODULE_FILE_BASE_NAME" ,self.MetaFile.BaseName),
2546 ("MODULE_RELATIVE_DIR" ,self.SourceDir),
2547 ("MODULE_DIR" ,self.SourceDir),
2548 ("BASE_NAME" ,self.Name),
2549 ("ARCH" ,self.Arch),
2550 ("TOOLCHAIN" ,self.ToolChain),
2551 ("TOOLCHAIN_TAG" ,self.ToolChain),
2552 ("TOOL_CHAIN_TAG" ,self.ToolChain),
2553 ("TARGET" ,self.BuildTarget),
2554 ("BUILD_DIR" ,self.PlatformInfo.BuildDir),
2555 ("BIN_DIR" ,os.path.join(self.PlatformInfo.BuildDir, self.Arch)),
2556 ("LIB_DIR" ,os.path.join(self.PlatformInfo.BuildDir, self.Arch)),
2557 ("MODULE_BUILD_DIR" ,self.BuildDir),
2558 ("OUTPUT_DIR" ,self.OutputDir),
2559 ("DEBUG_DIR" ,self.DebugDir),
2560 ("DEST_DIR_OUTPUT" ,self.OutputDir),
2561 ("DEST_DIR_DEBUG" ,self.DebugDir),
2562 ("PLATFORM_NAME" ,self.PlatformInfo.Name),
2563 ("PLATFORM_GUID" ,self.PlatformInfo.Guid),
2564 ("PLATFORM_VERSION" ,self.PlatformInfo.Version),
2565 ("PLATFORM_RELATIVE_DIR" ,self.PlatformInfo.SourceDir),
2566 ("PLATFORM_DIR" ,mws.join(self.WorkspaceDir, self.PlatformInfo.SourceDir)),
2567 ("PLATFORM_OUTPUT_DIR" ,self.PlatformInfo.OutputDir),
2568 ("FFS_OUTPUT_DIR" ,self.FfsOutputDir)
2569 ))
2570
2571 ## Return the module build data object
2572 @cached_property
2573 def Module(self):
2574 return self.BuildDatabase[self.MetaFile, self.Arch, self.BuildTarget, self.ToolChain]
2575
2576 ## Return the module name
2577 @cached_property
2578 def Name(self):
2579 return self.Module.BaseName
2580
2581 ## Return the module DxsFile if exist
2582 @cached_property
2583 def DxsFile(self):
2584 return self.Module.DxsFile
2585
2586 ## Return the module meta-file GUID
2587 @cached_property
2588 def Guid(self):
2589 #
2590 # To build same module more than once, the module path with FILE_GUID overridden has
2591 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the realy path
2592 # in DSC. The overridden GUID can be retrieved from file name
2593 #
2594 if os.path.basename(self.MetaFile.File) != os.path.basename(self.MetaFile.Path):
2595 #
2596 # Length of GUID is 36
2597 #
2598 return os.path.basename(self.MetaFile.Path)[:36]
2599 return self.Module.Guid
2600
2601 ## Return the module version
2602 @cached_property
2603 def Version(self):
2604 return self.Module.Version
2605
2606 ## Return the module type
2607 @cached_property
2608 def ModuleType(self):
2609 return self.Module.ModuleType
2610
2611 ## Return the component type (for Edk.x style of module)
2612 @cached_property
2613 def ComponentType(self):
2614 return self.Module.ComponentType
2615
2616 ## Return the build type
2617 @cached_property
2618 def BuildType(self):
2619 return self.Module.BuildType
2620
2621 ## Return the PCD_IS_DRIVER setting
2622 @cached_property
2623 def PcdIsDriver(self):
2624 return self.Module.PcdIsDriver
2625
2626 ## Return the autogen version, i.e. module meta-file version
2627 @cached_property
2628 def AutoGenVersion(self):
2629 return self.Module.AutoGenVersion
2630
2631 ## Check if the module is library or not
2632 @cached_property
2633 def IsLibrary(self):
2634 return bool(self.Module.LibraryClass)
2635
2636 ## Check if the module is binary module or not
2637 @cached_property
2638 def IsBinaryModule(self):
2639 return self.Module.IsBinaryModule
2640
2641 ## Return the directory to store intermediate files of the module
2642 @cached_property
2643 def BuildDir(self):
2644 return _MakeDir((
2645 self.PlatformInfo.BuildDir,
2646 self.Arch,
2647 self.SourceDir,
2648 self.MetaFile.BaseName
2649 ))
2650
2651 ## Return the directory to store the intermediate object files of the mdoule
2652 @cached_property
2653 def OutputDir(self):
2654 return _MakeDir((self.BuildDir, "OUTPUT"))
2655
2656 ## Return the directory path to store ffs file
2657 @cached_property
2658 def FfsOutputDir(self):
2659 if GlobalData.gFdfParser:
2660 return path.join(self.PlatformInfo.BuildDir, TAB_FV_DIRECTORY, "Ffs", self.Guid + self.Name)
2661 return ''
2662
2663 ## Return the directory to store auto-gened source files of the mdoule
2664 @cached_property
2665 def DebugDir(self):
2666 return _MakeDir((self.BuildDir, "DEBUG"))
2667
2668 ## Return the path of custom file
2669 @cached_property
2670 def CustomMakefile(self):
2671 RetVal = {}
2672 for Type in self.Module.CustomMakefile:
2673 MakeType = gMakeTypeMap[Type] if Type in gMakeTypeMap else 'nmake'
2674 if self.SourceOverrideDir is not None:
2675 File = os.path.join(self.SourceOverrideDir, self.Module.CustomMakefile[Type])
2676 if not os.path.exists(File):
2677 File = os.path.join(self.SourceDir, self.Module.CustomMakefile[Type])
2678 else:
2679 File = os.path.join(self.SourceDir, self.Module.CustomMakefile[Type])
2680 RetVal[MakeType] = File
2681 return RetVal
2682
2683 ## Return the directory of the makefile
2684 #
2685 # @retval string The directory string of module's makefile
2686 #
2687 @cached_property
2688 def MakeFileDir(self):
2689 return self.BuildDir
2690
2691 ## Return build command string
2692 #
2693 # @retval string Build command string
2694 #
2695 @cached_property
2696 def BuildCommand(self):
2697 return self.PlatformInfo.BuildCommand
2698
2699 ## Get object list of all packages the module and its dependent libraries belong to
2700 #
2701 # @retval list The list of package object
2702 #
2703 @cached_property
2704 def DerivedPackageList(self):
2705 PackageList = []
2706 for M in [self.Module] + self.DependentLibraryList:
2707 for Package in M.Packages:
2708 if Package in PackageList:
2709 continue
2710 PackageList.append(Package)
2711 return PackageList
2712
2713 ## Get the depex string
2714 #
2715 # @return : a string contain all depex expresion.
2716 def _GetDepexExpresionString(self):
2717 DepexStr = ''
2718 DepexList = []
2719 ## DPX_SOURCE IN Define section.
2720 if self.Module.DxsFile:
2721 return DepexStr
2722 for M in [self.Module] + self.DependentLibraryList:
2723 Filename = M.MetaFile.Path
2724 InfObj = InfSectionParser.InfSectionParser(Filename)
2725 DepexExpresionList = InfObj.GetDepexExpresionList()
2726 for DepexExpresion in DepexExpresionList:
2727 for key in DepexExpresion:
2728 Arch, ModuleType = key
2729 DepexExpr = [x for x in DepexExpresion[key] if not str(x).startswith('#')]
2730 # the type of build module is USER_DEFINED.
2731 # All different DEPEX section tags would be copied into the As Built INF file
2732 # and there would be separate DEPEX section tags
2733 if self.ModuleType.upper() == SUP_MODULE_USER_DEFINED:
2734 if (Arch.upper() == self.Arch.upper()) and (ModuleType.upper() != TAB_ARCH_COMMON):
2735 DepexList.append({(Arch, ModuleType): DepexExpr})
2736 else:
2737 if Arch.upper() == TAB_ARCH_COMMON or \
2738 (Arch.upper() == self.Arch.upper() and \
2739 ModuleType.upper() in [TAB_ARCH_COMMON, self.ModuleType.upper()]):
2740 DepexList.append({(Arch, ModuleType): DepexExpr})
2741
2742 #the type of build module is USER_DEFINED.
2743 if self.ModuleType.upper() == SUP_MODULE_USER_DEFINED:
2744 for Depex in DepexList:
2745 for key in Depex:
2746 DepexStr += '[Depex.%s.%s]\n' % key
2747 DepexStr += '\n'.join('# '+ val for val in Depex[key])
2748 DepexStr += '\n\n'
2749 if not DepexStr:
2750 return '[Depex.%s]\n' % self.Arch
2751 return DepexStr
2752
2753 #the type of build module not is USER_DEFINED.
2754 Count = 0
2755 for Depex in DepexList:
2756 Count += 1
2757 if DepexStr != '':
2758 DepexStr += ' AND '
2759 DepexStr += '('
2760 for D in Depex.values():
2761 DepexStr += ' '.join(val for val in D)
2762 Index = DepexStr.find('END')
2763 if Index > -1 and Index == len(DepexStr) - 3:
2764 DepexStr = DepexStr[:-3]
2765 DepexStr = DepexStr.strip()
2766 DepexStr += ')'
2767 if Count == 1:
2768 DepexStr = DepexStr.lstrip('(').rstrip(')').strip()
2769 if not DepexStr:
2770 return '[Depex.%s]\n' % self.Arch
2771 return '[Depex.%s]\n# ' % self.Arch + DepexStr
2772
2773 ## Merge dependency expression
2774 #
2775 # @retval list The token list of the dependency expression after parsed
2776 #
2777 @cached_property
2778 def DepexList(self):
2779 if self.DxsFile or self.IsLibrary or TAB_DEPENDENCY_EXPRESSION_FILE in self.FileTypes:
2780 return {}
2781
2782 DepexList = []
2783 #
2784 # Append depex from dependent libraries, if not "BEFORE", "AFTER" expresion
2785 #
2786 for M in [self.Module] + self.DependentLibraryList:
2787 Inherited = False
2788 for D in M.Depex[self.Arch, self.ModuleType]:
2789 if DepexList != []:
2790 DepexList.append('AND')
2791 DepexList.append('(')
2792 #replace D with value if D is FixedAtBuild PCD
2793 NewList = []
2794 for item in D:
2795 if '.' not in item:
2796 NewList.append(item)
2797 else:
2798 if item not in self._FixedPcdVoidTypeDict:
2799 EdkLogger.error("build", FORMAT_INVALID, "{} used in [Depex] section should be used as FixedAtBuild type and VOID* datum type in the module.".format(item))
2800 else:
2801 Value = self._FixedPcdVoidTypeDict[item]
2802 if len(Value.split(',')) != 16:
2803 EdkLogger.error("build", FORMAT_INVALID,
2804 "{} used in [Depex] section should be used as FixedAtBuild type and VOID* datum type and 16 bytes in the module.".format(item))
2805 NewList.append(Value)
2806 DepexList.extend(NewList)
2807 if DepexList[-1] == 'END': # no need of a END at this time
2808 DepexList.pop()
2809 DepexList.append(')')
2810 Inherited = True
2811 if Inherited:
2812 EdkLogger.verbose("DEPEX[%s] (+%s) = %s" % (self.Name, M.BaseName, DepexList))
2813 if 'BEFORE' in DepexList or 'AFTER' in DepexList:
2814 break
2815 if len(DepexList) > 0:
2816 EdkLogger.verbose('')
2817 return {self.ModuleType:DepexList}
2818
2819 ## Merge dependency expression
2820 #
2821 # @retval list The token list of the dependency expression after parsed
2822 #
2823 @cached_property
2824 def DepexExpressionDict(self):
2825 if self.DxsFile or self.IsLibrary or TAB_DEPENDENCY_EXPRESSION_FILE in self.FileTypes:
2826 return {}
2827
2828 DepexExpressionString = ''
2829 #
2830 # Append depex from dependent libraries, if not "BEFORE", "AFTER" expresion
2831 #
2832 for M in [self.Module] + self.DependentLibraryList:
2833 Inherited = False
2834 for D in M.DepexExpression[self.Arch, self.ModuleType]:
2835 if DepexExpressionString != '':
2836 DepexExpressionString += ' AND '
2837 DepexExpressionString += '('
2838 DepexExpressionString += D
2839 DepexExpressionString = DepexExpressionString.rstrip('END').strip()
2840 DepexExpressionString += ')'
2841 Inherited = True
2842 if Inherited:
2843 EdkLogger.verbose("DEPEX[%s] (+%s) = %s" % (self.Name, M.BaseName, DepexExpressionString))
2844 if 'BEFORE' in DepexExpressionString or 'AFTER' in DepexExpressionString:
2845 break
2846 if len(DepexExpressionString) > 0:
2847 EdkLogger.verbose('')
2848
2849 return {self.ModuleType:DepexExpressionString}
2850
2851 # Get the tiano core user extension, it is contain dependent library.
2852 # @retval: a list contain tiano core userextension.
2853 #
2854 def _GetTianoCoreUserExtensionList(self):
2855 TianoCoreUserExtentionList = []
2856 for M in [self.Module] + self.DependentLibraryList:
2857 Filename = M.MetaFile.Path
2858 InfObj = InfSectionParser.InfSectionParser(Filename)
2859 TianoCoreUserExtenList = InfObj.GetUserExtensionTianoCore()
2860 for TianoCoreUserExtent in TianoCoreUserExtenList:
2861 for Section in TianoCoreUserExtent:
2862 ItemList = Section.split(TAB_SPLIT)
2863 Arch = self.Arch
2864 if len(ItemList) == 4:
2865 Arch = ItemList[3]
2866 if Arch.upper() == TAB_ARCH_COMMON or Arch.upper() == self.Arch.upper():
2867 TianoCoreList = []
2868 TianoCoreList.extend([TAB_SECTION_START + Section + TAB_SECTION_END])
2869 TianoCoreList.extend(TianoCoreUserExtent[Section][:])
2870 TianoCoreList.append('\n')
2871 TianoCoreUserExtentionList.append(TianoCoreList)
2872
2873 return TianoCoreUserExtentionList
2874
2875 ## Return the list of specification version required for the module
2876 #
2877 # @retval list The list of specification defined in module file
2878 #
2879 @cached_property
2880 def Specification(self):
2881 return self.Module.Specification
2882
2883 ## Tool option for the module build
2884 #
2885 # @param PlatformInfo The object of PlatformBuildInfo
2886 # @retval dict The dict containing valid options
2887 #
2888 @cached_property
2889 def BuildOption(self):
2890 RetVal, self.BuildRuleOrder = self.PlatformInfo.ApplyBuildOption(self.Module)
2891 if self.BuildRuleOrder:
2892 self.BuildRuleOrder = ['.%s' % Ext for Ext in self.BuildRuleOrder.split()]
2893 return RetVal
2894
2895 ## Get include path list from tool option for the module build
2896 #
2897 # @retval list The include path list
2898 #
2899 @cached_property
2900 def BuildOptionIncPathList(self):
2901 #
2902 # Regular expression for finding Include Directories, the difference between MSFT and INTEL/GCC/RVCT
2903 # is the former use /I , the Latter used -I to specify include directories
2904 #
2905 if self.PlatformInfo.ToolChainFamily in (TAB_COMPILER_MSFT):
2906 BuildOptIncludeRegEx = gBuildOptIncludePatternMsft
2907 elif self.PlatformInfo.ToolChainFamily in ('INTEL', 'GCC', 'RVCT'):
2908 BuildOptIncludeRegEx = gBuildOptIncludePatternOther
2909 else:
2910 #
2911 # New ToolChainFamily, don't known whether there is option to specify include directories
2912 #
2913 return []
2914
2915 RetVal = []
2916 for Tool in ('CC', 'PP', 'VFRPP', 'ASLPP', 'ASLCC', 'APP', 'ASM'):
2917 try:
2918 FlagOption = self.BuildOption[Tool]['FLAGS']
2919 except KeyError:
2920 FlagOption = ''
2921
2922 if self.ToolChainFamily != 'RVCT':
2923 IncPathList = [NormPath(Path, self.Macros) for Path in BuildOptIncludeRegEx.findall(FlagOption)]
2924 else:
2925 #
2926 # RVCT may specify a list of directory seperated by commas
2927 #
2928 IncPathList = []
2929 for Path in BuildOptIncludeRegEx.findall(FlagOption):
2930 PathList = GetSplitList(Path, TAB_COMMA_SPLIT)
2931 IncPathList.extend(NormPath(PathEntry, self.Macros) for PathEntry in PathList)
2932
2933 #
2934 # EDK II modules must not reference header files outside of the packages they depend on or
2935 # within the module's directory tree. Report error if violation.
2936 #
2937 if self.AutoGenVersion >= 0x00010005:
2938 for Path in IncPathList:
2939 if (Path not in self.IncludePathList) and (CommonPath([Path, self.MetaFile.Dir]) != self.MetaFile.Dir):
2940 ErrMsg = "The include directory for the EDK II module in this line is invalid %s specified in %s FLAGS '%s'" % (Path, Tool, FlagOption)
2941 EdkLogger.error("build",
2942 PARAMETER_INVALID,
2943 ExtraData=ErrMsg,
2944 File=str(self.MetaFile))
2945 RetVal += IncPathList
2946 return RetVal
2947
2948 ## Return a list of files which can be built from source
2949 #
2950 # What kind of files can be built is determined by build rules in
2951 # $(CONF_DIRECTORY)/build_rule.txt and toolchain family.
2952 #
2953 @cached_property
2954 def SourceFileList(self):
2955 RetVal = []
2956 ToolChainTagSet = {"", "*", self.ToolChain}
2957 ToolChainFamilySet = {"", "*", self.ToolChainFamily, self.BuildRuleFamily}
2958 for F in self.Module.Sources:
2959 # match tool chain
2960 if F.TagName not in ToolChainTagSet:
2961 EdkLogger.debug(EdkLogger.DEBUG_9, "The toolchain [%s] for processing file [%s] is found, "
2962 "but [%s] is currently used" % (F.TagName, str(F), self.ToolChain))
2963 continue
2964 # match tool chain family or build rule family
2965 if F.ToolChainFamily not in ToolChainFamilySet:
2966 EdkLogger.debug(
2967 EdkLogger.DEBUG_0,
2968 "The file [%s] must be built by tools of [%s], " \
2969 "but current toolchain family is [%s], buildrule family is [%s]" \
2970 % (str(F), F.ToolChainFamily, self.ToolChainFamily, self.BuildRuleFamily))
2971 continue
2972
2973 # add the file path into search path list for file including
2974 if F.Dir not in self.IncludePathList and self.AutoGenVersion >= 0x00010005:
2975 self.IncludePathList.insert(0, F.Dir)
2976 RetVal.append(F)
2977
2978 self._MatchBuildRuleOrder(RetVal)
2979
2980 for F in RetVal:
2981 self._ApplyBuildRule(F, TAB_UNKNOWN_FILE)
2982 return RetVal
2983
2984 def _MatchBuildRuleOrder(self, FileList):
2985 Order_Dict = {}
2986 self.BuildOption
2987 for SingleFile in FileList:
2988 if self.BuildRuleOrder and SingleFile.Ext in self.BuildRuleOrder and SingleFile.Ext in self.BuildRules:
2989 key = SingleFile.Path.split(SingleFile.Ext)[0]
2990 if key in Order_Dict:
2991 Order_Dict[key].append(SingleFile.Ext)
2992 else:
2993 Order_Dict[key] = [SingleFile.Ext]
2994
2995 RemoveList = []
2996 for F in Order_Dict:
2997 if len(Order_Dict[F]) > 1:
2998 Order_Dict[F].sort(key=lambda i: self.BuildRuleOrder.index(i))
2999 for Ext in Order_Dict[F][1:]:
3000 RemoveList.append(F + Ext)
3001
3002 for item in RemoveList:
3003 FileList.remove(item)
3004
3005 return FileList
3006
3007 ## Return the list of unicode files
3008 @cached_property
3009 def UnicodeFileList(self):
3010 return self.FileTypes.get(TAB_UNICODE_FILE,[])
3011
3012 ## Return the list of vfr files
3013 @cached_property
3014 def VfrFileList(self):
3015 return self.FileTypes.get(TAB_VFR_FILE, [])
3016
3017 ## Return the list of Image Definition files
3018 @cached_property
3019 def IdfFileList(self):
3020 return self.FileTypes.get(TAB_IMAGE_FILE,[])
3021
3022 ## Return a list of files which can be built from binary
3023 #
3024 # "Build" binary files are just to copy them to build directory.
3025 #
3026 # @retval list The list of files which can be built later
3027 #
3028 @cached_property
3029 def BinaryFileList(self):
3030 RetVal = []
3031 for F in self.Module.Binaries:
3032 if F.Target not in [TAB_ARCH_COMMON, '*'] and F.Target != self.BuildTarget:
3033 continue
3034 RetVal.append(F)
3035 self._ApplyBuildRule(F, F.Type, BinaryFileList=RetVal)
3036 return RetVal
3037
3038 @cached_property
3039 def BuildRules(self):
3040 RetVal = {}
3041 BuildRuleDatabase = self.PlatformInfo.BuildRule
3042 for Type in BuildRuleDatabase.FileTypeList:
3043 #first try getting build rule by BuildRuleFamily
3044 RuleObject = BuildRuleDatabase[Type, self.BuildType, self.Arch, self.BuildRuleFamily]
3045 if not RuleObject:
3046 # build type is always module type, but ...
3047 if self.ModuleType != self.BuildType:
3048 RuleObject = BuildRuleDatabase[Type, self.ModuleType, self.Arch, self.BuildRuleFamily]
3049 #second try getting build rule by ToolChainFamily
3050 if not RuleObject:
3051 RuleObject = BuildRuleDatabase[Type, self.BuildType, self.Arch, self.ToolChainFamily]
3052 if not RuleObject:
3053 # build type is always module type, but ...
3054 if self.ModuleType != self.BuildType:
3055 RuleObject = BuildRuleDatabase[Type, self.ModuleType, self.Arch, self.ToolChainFamily]
3056 if not RuleObject:
3057 continue
3058 RuleObject = RuleObject.Instantiate(self.Macros)
3059 RetVal[Type] = RuleObject
3060 for Ext in RuleObject.SourceFileExtList:
3061 RetVal[Ext] = RuleObject
3062 return RetVal
3063
3064 def _ApplyBuildRule(self, File, FileType, BinaryFileList=None):
3065 if self._BuildTargets is None:
3066 self._IntroBuildTargetList = set()
3067 self._FinalBuildTargetList = set()
3068 self._BuildTargets = defaultdict(set)
3069 self._FileTypes = defaultdict(set)
3070
3071 if not BinaryFileList:
3072 BinaryFileList = self.BinaryFileList
3073
3074 SubDirectory = os.path.join(self.OutputDir, File.SubDir)
3075 if not os.path.exists(SubDirectory):
3076 CreateDirectory(SubDirectory)
3077 LastTarget = None
3078 RuleChain = set()
3079 SourceList = [File]
3080 Index = 0
3081 #
3082 # Make sure to get build rule order value
3083 #
3084 self.BuildOption
3085
3086 while Index < len(SourceList):
3087 Source = SourceList[Index]
3088 Index = Index + 1
3089
3090 if Source != File:
3091 CreateDirectory(Source.Dir)
3092
3093 if File.IsBinary and File == Source and File in BinaryFileList:
3094 # Skip all files that are not binary libraries
3095 if not self.IsLibrary:
3096 continue
3097 RuleObject = self.BuildRules[TAB_DEFAULT_BINARY_FILE]
3098 elif FileType in self.BuildRules:
3099 RuleObject = self.BuildRules[FileType]
3100 elif Source.Ext in self.BuildRules:
3101 RuleObject = self.BuildRules[Source.Ext]
3102 else:
3103 # stop at no more rules
3104 if LastTarget:
3105 self._FinalBuildTargetList.add(LastTarget)
3106 break
3107
3108 FileType = RuleObject.SourceFileType
3109 self._FileTypes[FileType].add(Source)
3110
3111 # stop at STATIC_LIBRARY for library
3112 if self.IsLibrary and FileType == TAB_STATIC_LIBRARY:
3113 if LastTarget:
3114 self._FinalBuildTargetList.add(LastTarget)
3115 break
3116
3117 Target = RuleObject.Apply(Source, self.BuildRuleOrder)
3118 if not Target:
3119 if LastTarget:
3120 self._FinalBuildTargetList.add(LastTarget)
3121 break
3122 elif not Target.Outputs:
3123 # Only do build for target with outputs
3124 self._FinalBuildTargetList.add(Target)
3125
3126 self._BuildTargets[FileType].add(Target)
3127
3128 if not Source.IsBinary and Source == File:
3129 self._IntroBuildTargetList.add(Target)
3130
3131 # to avoid cyclic rule
3132 if FileType in RuleChain:
3133 break
3134
3135 RuleChain.add(FileType)
3136 SourceList.extend(Target.Outputs)
3137 LastTarget = Target
3138 FileType = TAB_UNKNOWN_FILE
3139
3140 @cached_property
3141 def Targets(self):
3142 if self._BuildTargets is None:
3143 self._IntroBuildTargetList = set()
3144 self._FinalBuildTargetList = set()
3145 self._BuildTargets = defaultdict(set)
3146 self._FileTypes = defaultdict(set)
3147
3148 #TRICK: call SourceFileList property to apply build rule for source files
3149 self.SourceFileList
3150
3151 #TRICK: call _GetBinaryFileList to apply build rule for binary files
3152 self.BinaryFileList
3153
3154 return self._BuildTargets
3155
3156 @cached_property
3157 def IntroTargetList(self):
3158 self.Targets
3159 return self._IntroBuildTargetList
3160
3161 @cached_property
3162 def CodaTargetList(self):
3163 self.Targets
3164 return self._FinalBuildTargetList
3165
3166 @cached_property
3167 def FileTypes(self):
3168 self.Targets
3169 return self._FileTypes
3170
3171 ## Get the list of package object the module depends on
3172 #
3173 # @retval list The package object list
3174 #
3175 @cached_property
3176 def DependentPackageList(self):
3177 return self.Module.Packages
3178
3179 ## Return the list of auto-generated code file
3180 #
3181 # @retval list The list of auto-generated file
3182 #
3183 @cached_property
3184 def AutoGenFileList(self):
3185 AutoGenUniIdf = self.BuildType != 'UEFI_HII'
3186 UniStringBinBuffer = BytesIO()
3187 IdfGenBinBuffer = BytesIO()
3188 RetVal = {}
3189 AutoGenC = TemplateString()
3190 AutoGenH = TemplateString()
3191 StringH = TemplateString()
3192 StringIdf = TemplateString()
3193 GenC.CreateCode(self, AutoGenC, AutoGenH, StringH, AutoGenUniIdf, UniStringBinBuffer, StringIdf, AutoGenUniIdf, IdfGenBinBuffer)
3194 #
3195 # AutoGen.c is generated if there are library classes in inf, or there are object files
3196 #
3197 if str(AutoGenC) != "" and (len(self.Module.LibraryClasses) > 0
3198 or TAB_OBJECT_FILE in self.FileTypes):
3199 AutoFile = PathClass(gAutoGenCodeFileName, self.DebugDir)
3200 RetVal[AutoFile] = str(AutoGenC)
3201 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3202 if str(AutoGenH) != "":
3203 AutoFile = PathClass(gAutoGenHeaderFileName, self.DebugDir)
3204 RetVal[AutoFile] = str(AutoGenH)
3205 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3206 if str(StringH) != "":
3207 AutoFile = PathClass(gAutoGenStringFileName % {"module_name":self.Name}, self.DebugDir)
3208 RetVal[AutoFile] = str(StringH)
3209 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3210 if UniStringBinBuffer is not None and UniStringBinBuffer.getvalue() != "":
3211 AutoFile = PathClass(gAutoGenStringFormFileName % {"module_name":self.Name}, self.OutputDir)
3212 RetVal[AutoFile] = UniStringBinBuffer.getvalue()
3213 AutoFile.IsBinary = True
3214 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3215 if UniStringBinBuffer is not None:
3216 UniStringBinBuffer.close()
3217 if str(StringIdf) != "":
3218 AutoFile = PathClass(gAutoGenImageDefFileName % {"module_name":self.Name}, self.DebugDir)
3219 RetVal[AutoFile] = str(StringIdf)
3220 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3221 if IdfGenBinBuffer is not None and IdfGenBinBuffer.getvalue() != "":
3222 AutoFile = PathClass(gAutoGenIdfFileName % {"module_name":self.Name}, self.OutputDir)
3223 RetVal[AutoFile] = IdfGenBinBuffer.getvalue()
3224 AutoFile.IsBinary = True
3225 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3226 if IdfGenBinBuffer is not None:
3227 IdfGenBinBuffer.close()
3228 return RetVal
3229
3230 ## Return the list of library modules explicitly or implicityly used by this module
3231 @cached_property
3232 def DependentLibraryList(self):
3233 # only merge library classes and PCD for non-library module
3234 if self.IsLibrary:
3235 return []
3236 if self.AutoGenVersion < 0x00010005:
3237 return self.PlatformInfo.ResolveLibraryReference(self.Module)
3238 return self.PlatformInfo.ApplyLibraryInstance(self.Module)
3239
3240 ## Get the list of PCDs from current module
3241 #
3242 # @retval list The list of PCD
3243 #
3244 @cached_property
3245 def ModulePcdList(self):
3246 # apply PCD settings from platform
3247 RetVal = self.PlatformInfo.ApplyPcdSetting(self.Module, self.Module.Pcds)
3248 ExtendCopyDictionaryLists(self._PcdComments, self.Module.PcdComments)
3249 return RetVal
3250
3251 ## Get the list of PCDs from dependent libraries
3252 #
3253 # @retval list The list of PCD
3254 #
3255 @cached_property
3256 def LibraryPcdList(self):
3257 if self.IsLibrary:
3258 return []
3259 RetVal = []
3260 Pcds = set()
3261 # get PCDs from dependent libraries
3262 for Library in self.DependentLibraryList:
3263 PcdsInLibrary = OrderedDict()
3264 ExtendCopyDictionaryLists(self._PcdComments, Library.PcdComments)
3265 for Key in Library.Pcds:
3266 # skip duplicated PCDs
3267 if Key in self.Module.Pcds or Key in Pcds:
3268 continue
3269 Pcds.add(Key)
3270 PcdsInLibrary[Key] = copy.copy(Library.Pcds[Key])
3271 RetVal.extend(self.PlatformInfo.ApplyPcdSetting(self.Module, PcdsInLibrary, Library=Library))
3272 return RetVal
3273
3274 ## Get the GUID value mapping
3275 #
3276 # @retval dict The mapping between GUID cname and its value
3277 #
3278 @cached_property
3279 def GuidList(self):
3280 RetVal = OrderedDict(self.Module.Guids)
3281 for Library in self.DependentLibraryList:
3282 RetVal.update(Library.Guids)
3283 ExtendCopyDictionaryLists(self._GuidComments, Library.GuidComments)
3284 ExtendCopyDictionaryLists(self._GuidComments, self.Module.GuidComments)
3285 return RetVal
3286
3287 @cached_property
3288 def GetGuidsUsedByPcd(self):
3289 RetVal = OrderedDict(self.Module.GetGuidsUsedByPcd())
3290 for Library in self.DependentLibraryList:
3291 RetVal.update(Library.GetGuidsUsedByPcd())
3292 return RetVal
3293 ## Get the protocol value mapping
3294 #
3295 # @retval dict The mapping between protocol cname and its value
3296 #
3297 @cached_property
3298 def ProtocolList(self):
3299 RetVal = OrderedDict(self.Module.Protocols)
3300 for Library in self.DependentLibraryList:
3301 RetVal.update(Library.Protocols)
3302 ExtendCopyDictionaryLists(self._ProtocolComments, Library.ProtocolComments)
3303 ExtendCopyDictionaryLists(self._ProtocolComments, self.Module.ProtocolComments)
3304 return RetVal
3305
3306 ## Get the PPI value mapping
3307 #
3308 # @retval dict The mapping between PPI cname and its value
3309 #
3310 @cached_property
3311 def PpiList(self):
3312 RetVal = OrderedDict(self.Module.Ppis)
3313 for Library in self.DependentLibraryList:
3314 RetVal.update(Library.Ppis)
3315 ExtendCopyDictionaryLists(self._PpiComments, Library.PpiComments)
3316 ExtendCopyDictionaryLists(self._PpiComments, self.Module.PpiComments)
3317 return RetVal
3318
3319 ## Get the list of include search path
3320 #
3321 # @retval list The list path
3322 #
3323 @cached_property
3324 def IncludePathList(self):
3325 RetVal = []
3326 if self.AutoGenVersion < 0x00010005:
3327 for Inc in self.Module.Includes:
3328 if Inc not in RetVal:
3329 RetVal.append(Inc)
3330 # for Edk modules
3331 Inc = path.join(Inc, self.Arch.capitalize())
3332 if os.path.exists(Inc) and Inc not in RetVal:
3333 RetVal.append(Inc)
3334 # Edk module needs to put DEBUG_DIR at the end of search path and not to use SOURCE_DIR all the time
3335 RetVal.append(self.DebugDir)
3336 else:
3337 RetVal.append(self.MetaFile.Dir)
3338 RetVal.append(self.DebugDir)
3339
3340 for Package in self.Module.Packages:
3341 PackageDir = mws.join(self.WorkspaceDir, Package.MetaFile.Dir)
3342 if PackageDir not in RetVal:
3343 RetVal.append(PackageDir)
3344 IncludesList = Package.Includes
3345 if Package._PrivateIncludes:
3346 if not self.MetaFile.Path.startswith(PackageDir):
3347 IncludesList = list(set(Package.Includes).difference(set(Package._PrivateIncludes)))
3348 for Inc in IncludesList:
3349 if Inc not in RetVal:
3350 RetVal.append(str(Inc))
3351 return RetVal
3352
3353 @cached_property
3354 def IncludePathLength(self):
3355 return sum(len(inc)+1 for inc in self.IncludePathList)
3356
3357 ## Get HII EX PCDs which maybe used by VFR
3358 #
3359 # efivarstore used by VFR may relate with HII EX PCDs
3360 # Get the variable name and GUID from efivarstore and HII EX PCD
3361 # List the HII EX PCDs in As Built INF if both name and GUID match.
3362 #
3363 # @retval list HII EX PCDs
3364 #
3365 def _GetPcdsMaybeUsedByVfr(self):
3366 if not self.SourceFileList:
3367 return []
3368
3369 NameGuids = set()
3370 for SrcFile in self.SourceFileList:
3371 if SrcFile.Ext.lower() != '.vfr':
3372 continue
3373 Vfri = os.path.join(self.OutputDir, SrcFile.BaseName + '.i')
3374 if not os.path.exists(Vfri):
3375 continue
3376 VfriFile = open(Vfri, 'r')
3377 Content = VfriFile.read()
3378 VfriFile.close()
3379 Pos = Content.find('efivarstore')
3380 while Pos != -1:
3381 #
3382 # Make sure 'efivarstore' is the start of efivarstore statement
3383 # In case of the value of 'name' (name = efivarstore) is equal to 'efivarstore'
3384 #
3385 Index = Pos - 1
3386 while Index >= 0 and Content[Index] in ' \t\r\n':
3387 Index -= 1
3388 if Index >= 0 and Content[Index] != ';':
3389 Pos = Content.find('efivarstore', Pos + len('efivarstore'))
3390 continue
3391 #
3392 # 'efivarstore' must be followed by name and guid
3393 #
3394 Name = gEfiVarStoreNamePattern.search(Content, Pos)
3395 if not Name:
3396 break
3397 Guid = gEfiVarStoreGuidPattern.search(Content, Pos)
3398 if not Guid:
3399 break
3400 NameArray = ConvertStringToByteArray('L"' + Name.group(1) + '"')
3401 NameGuids.add((NameArray, GuidStructureStringToGuidString(Guid.group(1))))
3402 Pos = Content.find('efivarstore', Name.end())
3403 if not NameGuids:
3404 return []
3405 HiiExPcds = []
3406 for Pcd in self.PlatformInfo.Platform.Pcds.values():
3407 if Pcd.Type != TAB_PCDS_DYNAMIC_EX_HII:
3408 continue
3409 for SkuInfo in Pcd.SkuInfoList.values():
3410 Value = GuidValue(SkuInfo.VariableGuid, self.PlatformInfo.PackageList, self.MetaFile.Path)
3411 if not Value:
3412 continue
3413 Name = ConvertStringToByteArray(SkuInfo.VariableName)
3414 Guid = GuidStructureStringToGuidString(Value)
3415 if (Name, Guid) in NameGuids and Pcd not in HiiExPcds:
3416 HiiExPcds.append(Pcd)
3417 break
3418
3419 return HiiExPcds
3420
3421 def _GenOffsetBin(self):
3422 VfrUniBaseName = {}
3423 for SourceFile in self.Module.Sources:
3424 if SourceFile.Type.upper() == ".VFR" :
3425 #
3426 # search the .map file to find the offset of vfr binary in the PE32+/TE file.
3427 #
3428 VfrUniBaseName[SourceFile.BaseName] = (SourceFile.BaseName + "Bin")
3429 elif SourceFile.Type.upper() == ".UNI" :
3430 #
3431 # search the .map file to find the offset of Uni strings binary in the PE32+/TE file.
3432 #
3433 VfrUniBaseName["UniOffsetName"] = (self.Name + "Strings")
3434
3435 if not VfrUniBaseName:
3436 return None
3437 MapFileName = os.path.join(self.OutputDir, self.Name + ".map")
3438 EfiFileName = os.path.join(self.OutputDir, self.Name + ".efi")
3439 VfrUniOffsetList = GetVariableOffset(MapFileName, EfiFileName, VfrUniBaseName.values())
3440 if not VfrUniOffsetList:
3441 return None
3442
3443 OutputName = '%sOffset.bin' % self.Name
3444 UniVfrOffsetFileName = os.path.join( self.OutputDir, OutputName)
3445
3446 try:
3447 fInputfile = open(UniVfrOffsetFileName, "wb+", 0)
3448 except:
3449 EdkLogger.error("build", FILE_OPEN_FAILURE, "File open failed for %s" % UniVfrOffsetFileName, None)
3450
3451 # Use a instance of BytesIO to cache data
3452 fStringIO = BytesIO('')
3453
3454 for Item in VfrUniOffsetList:
3455 if (Item[0].find("Strings") != -1):
3456 #
3457 # UNI offset in image.
3458 # GUID + Offset
3459 # { 0x8913c5e0, 0x33f6, 0x4d86, { 0x9b, 0xf1, 0x43, 0xef, 0x89, 0xfc, 0x6, 0x66 } }
3460 #
3461 UniGuid = [0xe0, 0xc5, 0x13, 0x89, 0xf6, 0x33, 0x86, 0x4d, 0x9b, 0xf1, 0x43, 0xef, 0x89, 0xfc, 0x6, 0x66]
3462 UniGuid = [chr(ItemGuid) for ItemGuid in UniGuid]
3463 fStringIO.write(''.join(UniGuid))
3464 UniValue = pack ('Q', int (Item[1], 16))
3465 fStringIO.write (UniValue)
3466 else:
3467 #
3468 # VFR binary offset in image.
3469 # GUID + Offset
3470 # { 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2 } };
3471 #
3472 VfrGuid = [0xb4, 0x7c, 0xbc, 0xd0, 0x47, 0x6a, 0x5f, 0x49, 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2]
3473 VfrGuid = [chr(ItemGuid) for ItemGuid in VfrGuid]
3474 fStringIO.write(''.join(VfrGuid))
3475 VfrValue = pack ('Q', int (Item[1], 16))
3476 fStringIO.write (VfrValue)
3477 #
3478 # write data into file.
3479 #
3480 try :
3481 fInputfile.write (fStringIO.getvalue())
3482 except:
3483 EdkLogger.error("build", FILE_WRITE_FAILURE, "Write data to file %s failed, please check whether the "
3484 "file been locked or using by other applications." %UniVfrOffsetFileName, None)
3485
3486 fStringIO.close ()
3487 fInputfile.close ()
3488 return OutputName
3489
3490 ## Create AsBuilt INF file the module
3491 #
3492 def CreateAsBuiltInf(self, IsOnlyCopy = False):
3493 self.OutputFile = set()
3494 if IsOnlyCopy and GlobalData.gBinCacheDest:
3495 self.CopyModuleToCache()
3496 return
3497
3498 if self.IsAsBuiltInfCreated:
3499 return
3500
3501 # Skip the following code for EDK I inf
3502 if self.AutoGenVersion < 0x00010005:
3503 return
3504
3505 # Skip the following code for libraries
3506 if self.IsLibrary:
3507 return
3508
3509 # Skip the following code for modules with no source files
3510 if not self.SourceFileList:
3511 return
3512
3513 # Skip the following code for modules without any binary files
3514 if self.BinaryFileList:
3515 return
3516
3517 ### TODO: How to handles mixed source and binary modules
3518
3519 # Find all DynamicEx and PatchableInModule PCDs used by this module and dependent libraries
3520 # Also find all packages that the DynamicEx PCDs depend on
3521 Pcds = []
3522 PatchablePcds = []
3523 Packages = []
3524 PcdCheckList = []
3525 PcdTokenSpaceList = []
3526 for Pcd in self.ModulePcdList + self.LibraryPcdList:
3527 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE:
3528 PatchablePcds.append(Pcd)
3529 PcdCheckList.append((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, TAB_PCDS_PATCHABLE_IN_MODULE))
3530 elif Pcd.Type in PCD_DYNAMIC_EX_TYPE_SET:
3531 if Pcd not in Pcds:
3532 Pcds.append(Pcd)
3533 PcdCheckList.append((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC_EX))
3534 PcdCheckList.append((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC))
3535 PcdTokenSpaceList.append(Pcd.TokenSpaceGuidCName)
3536 GuidList = OrderedDict(self.GuidList)
3537 for TokenSpace in self.GetGuidsUsedByPcd:
3538 # If token space is not referred by patch PCD or Ex PCD, remove the GUID from GUID list
3539 # The GUIDs in GUIDs section should really be the GUIDs in source INF or referred by Ex an patch PCDs
3540 if TokenSpace not in PcdTokenSpaceList and TokenSpace in GuidList:
3541 GuidList.pop(TokenSpace)
3542 CheckList = (GuidList, self.PpiList, self.ProtocolList, PcdCheckList)
3543 for Package in self.DerivedPackageList:
3544 if Package in Packages:
3545 continue
3546 BeChecked = (Package.Guids, Package.Ppis, Package.Protocols, Package.Pcds)
3547 Found = False
3548 for Index in range(len(BeChecked)):
3549 for Item in CheckList[Index]:
3550 if Item in BeChecked[Index]:
3551 Packages.append(Package)
3552 Found = True
3553 break
3554 if Found:
3555 break
3556
3557 VfrPcds = self._GetPcdsMaybeUsedByVfr()
3558 for Pkg in self.PlatformInfo.PackageList:
3559 if Pkg in Packages:
3560 continue
3561 for VfrPcd in VfrPcds:
3562 if ((VfrPcd.TokenCName, VfrPcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC_EX) in Pkg.Pcds or
3563 (VfrPcd.TokenCName, VfrPcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC) in Pkg.Pcds):
3564 Packages.append(Pkg)
3565 break
3566
3567 ModuleType = SUP_MODULE_DXE_DRIVER if self.ModuleType == SUP_MODULE_UEFI_DRIVER and self.DepexGenerated else self.ModuleType
3568 DriverType = self.PcdIsDriver if self.PcdIsDriver else ''
3569 Guid = self.Guid
3570 MDefs = self.Module.Defines
3571
3572 AsBuiltInfDict = {
3573 'module_name' : self.Name,
3574 'module_guid' : Guid,
3575 'module_module_type' : ModuleType,
3576 'module_version_string' : [MDefs['VERSION_STRING']] if 'VERSION_STRING' in MDefs else [],
3577 'pcd_is_driver_string' : [],
3578 'module_uefi_specification_version' : [],
3579 'module_pi_specification_version' : [],
3580 'module_entry_point' : self.Module.ModuleEntryPointList,
3581 'module_unload_image' : self.Module.ModuleUnloadImageList,
3582 'module_constructor' : self.Module.ConstructorList,
3583 'module_destructor' : self.Module.DestructorList,
3584 'module_shadow' : [MDefs['SHADOW']] if 'SHADOW' in MDefs else [],
3585 'module_pci_vendor_id' : [MDefs['PCI_VENDOR_ID']] if 'PCI_VENDOR_ID' in MDefs else [],
3586 'module_pci_device_id' : [MDefs['PCI_DEVICE_ID']] if 'PCI_DEVICE_ID' in MDefs else [],
3587 'module_pci_class_code' : [MDefs['PCI_CLASS_CODE']] if 'PCI_CLASS_CODE' in MDefs else [],
3588 'module_pci_revision' : [MDefs['PCI_REVISION']] if 'PCI_REVISION' in MDefs else [],
3589 'module_build_number' : [MDefs['BUILD_NUMBER']] if 'BUILD_NUMBER' in MDefs else [],
3590 'module_spec' : [MDefs['SPEC']] if 'SPEC' in MDefs else [],
3591 'module_uefi_hii_resource_section' : [MDefs['UEFI_HII_RESOURCE_SECTION']] if 'UEFI_HII_RESOURCE_SECTION' in MDefs else [],
3592 'module_uni_file' : [MDefs['MODULE_UNI_FILE']] if 'MODULE_UNI_FILE' in MDefs else [],
3593 'module_arch' : self.Arch,
3594 'package_item' : [Package.MetaFile.File.replace('\\', '/') for Package in Packages],
3595 'binary_item' : [],
3596 'patchablepcd_item' : [],
3597 'pcd_item' : [],
3598 'protocol_item' : [],
3599 'ppi_item' : [],
3600 'guid_item' : [],
3601 'flags_item' : [],
3602 'libraryclasses_item' : []
3603 }
3604
3605 if 'MODULE_UNI_FILE' in MDefs:
3606 UNIFile = os.path.join(self.MetaFile.Dir, MDefs['MODULE_UNI_FILE'])
3607 if os.path.isfile(UNIFile):
3608 shutil.copy2(UNIFile, self.OutputDir)
3609
3610 if self.AutoGenVersion > int(gInfSpecVersion, 0):
3611 AsBuiltInfDict['module_inf_version'] = '0x%08x' % self.AutoGenVersion
3612 else:
3613 AsBuiltInfDict['module_inf_version'] = gInfSpecVersion
3614
3615 if DriverType:
3616 AsBuiltInfDict['pcd_is_driver_string'].append(DriverType)
3617
3618 if 'UEFI_SPECIFICATION_VERSION' in self.Specification:
3619 AsBuiltInfDict['module_uefi_specification_version'].append(self.Specification['UEFI_SPECIFICATION_VERSION'])
3620 if 'PI_SPECIFICATION_VERSION' in self.Specification:
3621 AsBuiltInfDict['module_pi_specification_version'].append(self.Specification['PI_SPECIFICATION_VERSION'])
3622
3623 OutputDir = self.OutputDir.replace('\\', '/').strip('/')
3624 DebugDir = self.DebugDir.replace('\\', '/').strip('/')
3625 for Item in self.CodaTargetList:
3626 File = Item.Target.Path.replace('\\', '/').strip('/').replace(DebugDir, '').replace(OutputDir, '').strip('/')
3627 self.OutputFile.add(File)
3628 if os.path.isabs(File):
3629 File = File.replace('\\', '/').strip('/').replace(OutputDir, '').strip('/')
3630 if Item.Target.Ext.lower() == '.aml':
3631 AsBuiltInfDict['binary_item'].append('ASL|' + File)
3632 elif Item.Target.Ext.lower() == '.acpi':
3633 AsBuiltInfDict['binary_item'].append('ACPI|' + File)
3634 elif Item.Target.Ext.lower() == '.efi':
3635 AsBuiltInfDict['binary_item'].append('PE32|' + self.Name + '.efi')
3636 else:
3637 AsBuiltInfDict['binary_item'].append('BIN|' + File)
3638 if self.DepexGenerated:
3639 self.OutputFile.add(self.Name + '.depex')
3640 if self.ModuleType in [SUP_MODULE_PEIM]:
3641 AsBuiltInfDict['binary_item'].append('PEI_DEPEX|' + self.Name + '.depex')
3642 elif self.ModuleType in [SUP_MODULE_DXE_DRIVER, SUP_MODULE_DXE_RUNTIME_DRIVER, SUP_MODULE_DXE_SAL_DRIVER, SUP_MODULE_UEFI_DRIVER]:
3643 AsBuiltInfDict['binary_item'].append('DXE_DEPEX|' + self.Name + '.depex')
3644 elif self.ModuleType in [SUP_MODULE_DXE_SMM_DRIVER]:
3645 AsBuiltInfDict['binary_item'].append('SMM_DEPEX|' + self.Name + '.depex')
3646
3647 Bin = self._GenOffsetBin()
3648 if Bin:
3649 AsBuiltInfDict['binary_item'].append('BIN|%s' % Bin)
3650 self.OutputFile.add(Bin)
3651
3652 for Root, Dirs, Files in os.walk(OutputDir):
3653 for File in Files:
3654 if File.lower().endswith('.pdb'):
3655 AsBuiltInfDict['binary_item'].append('DISPOSABLE|' + File)
3656 self.OutputFile.add(File)
3657 HeaderComments = self.Module.HeaderComments
3658 StartPos = 0
3659 for Index in range(len(HeaderComments)):
3660 if HeaderComments[Index].find('@BinaryHeader') != -1:
3661 HeaderComments[Index] = HeaderComments[Index].replace('@BinaryHeader', '@file')
3662 StartPos = Index
3663 break
3664 AsBuiltInfDict['header_comments'] = '\n'.join(HeaderComments[StartPos:]).replace(':#', '://')
3665 AsBuiltInfDict['tail_comments'] = '\n'.join(self.Module.TailComments)
3666
3667 GenList = [
3668 (self.ProtocolList, self._ProtocolComments, 'protocol_item'),
3669 (self.PpiList, self._PpiComments, 'ppi_item'),
3670 (GuidList, self._GuidComments, 'guid_item')
3671 ]
3672 for Item in GenList:
3673 for CName in Item[0]:
3674 Comments = '\n '.join(Item[1][CName]) if CName in Item[1] else ''
3675 Entry = Comments + '\n ' + CName if Comments else CName
3676 AsBuiltInfDict[Item[2]].append(Entry)
3677 PatchList = parsePcdInfoFromMapFile(
3678 os.path.join(self.OutputDir, self.Name + '.map'),
3679 os.path.join(self.OutputDir, self.Name + '.efi')
3680 )
3681 if PatchList:
3682 for Pcd in PatchablePcds:
3683 TokenCName = Pcd.TokenCName
3684 for PcdItem in GlobalData.MixedPcd:
3685 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
3686 TokenCName = PcdItem[0]
3687 break
3688 for PatchPcd in PatchList:
3689 if TokenCName == PatchPcd[0]:
3690 break
3691 else:
3692 continue
3693 PcdValue = ''
3694 if Pcd.DatumType == 'BOOLEAN':
3695 BoolValue = Pcd.DefaultValue.upper()
3696 if BoolValue == 'TRUE':
3697 Pcd.DefaultValue = '1'
3698 elif BoolValue == 'FALSE':
3699 Pcd.DefaultValue = '0'
3700
3701 if Pcd.DatumType in TAB_PCD_NUMERIC_TYPES:
3702 HexFormat = '0x%02x'
3703 if Pcd.DatumType == TAB_UINT16:
3704 HexFormat = '0x%04x'
3705 elif Pcd.DatumType == TAB_UINT32:
3706 HexFormat = '0x%08x'
3707 elif Pcd.DatumType == TAB_UINT64:
3708 HexFormat = '0x%016x'
3709 PcdValue = HexFormat % int(Pcd.DefaultValue, 0)
3710 else:
3711 if Pcd.MaxDatumSize is None or Pcd.MaxDatumSize == '':
3712 EdkLogger.error("build", AUTOGEN_ERROR,
3713 "Unknown [MaxDatumSize] of PCD [%s.%s]" % (Pcd.TokenSpaceGuidCName, TokenCName)
3714 )
3715 ArraySize = int(Pcd.MaxDatumSize, 0)
3716 PcdValue = Pcd.DefaultValue
3717 if PcdValue[0] != '{':
3718 Unicode = False
3719 if PcdValue[0] == 'L':
3720 Unicode = True
3721 PcdValue = PcdValue.lstrip('L')
3722 PcdValue = eval(PcdValue)
3723 NewValue = '{'
3724 for Index in range(0, len(PcdValue)):
3725 if Unicode:
3726 CharVal = ord(PcdValue[Index])
3727 NewValue = NewValue + '0x%02x' % (CharVal & 0x00FF) + ', ' \
3728 + '0x%02x' % (CharVal >> 8) + ', '
3729 else:
3730 NewValue = NewValue + '0x%02x' % (ord(PcdValue[Index]) % 0x100) + ', '
3731 Padding = '0x00, '
3732 if Unicode:
3733 Padding = Padding * 2
3734 ArraySize = ArraySize / 2
3735 if ArraySize < (len(PcdValue) + 1):
3736 if Pcd.MaxSizeUserSet:
3737 EdkLogger.error("build", AUTOGEN_ERROR,
3738 "The maximum size of VOID* type PCD '%s.%s' is less than its actual size occupied." % (Pcd.TokenSpaceGuidCName, TokenCName)
3739 )
3740 else:
3741 ArraySize = len(PcdValue) + 1
3742 if ArraySize > len(PcdValue) + 1:
3743 NewValue = NewValue + Padding * (ArraySize - len(PcdValue) - 1)
3744 PcdValue = NewValue + Padding.strip().rstrip(',') + '}'
3745 elif len(PcdValue.split(',')) <= ArraySize:
3746 PcdValue = PcdValue.rstrip('}') + ', 0x00' * (ArraySize - len(PcdValue.split(',')))
3747 PcdValue += '}'
3748 else:
3749 if Pcd.MaxSizeUserSet:
3750 EdkLogger.error("build", AUTOGEN_ERROR,
3751 "The maximum size of VOID* type PCD '%s.%s' is less than its actual size occupied." % (Pcd.TokenSpaceGuidCName, TokenCName)
3752 )
3753 else:
3754 ArraySize = len(PcdValue) + 1
3755 PcdItem = '%s.%s|%s|0x%X' % \
3756 (Pcd.TokenSpaceGuidCName, TokenCName, PcdValue, PatchPcd[1])
3757 PcdComments = ''
3758 if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) in self._PcdComments:
3759 PcdComments = '\n '.join(self._PcdComments[Pcd.TokenSpaceGuidCName, Pcd.TokenCName])
3760 if PcdComments:
3761 PcdItem = PcdComments + '\n ' + PcdItem
3762 AsBuiltInfDict['patchablepcd_item'].append(PcdItem)
3763
3764 for Pcd in Pcds + VfrPcds:
3765 PcdCommentList = []
3766 HiiInfo = ''
3767 TokenCName = Pcd.TokenCName
3768 for PcdItem in GlobalData.MixedPcd:
3769 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
3770 TokenCName = PcdItem[0]
3771 break
3772 if Pcd.Type == TAB_PCDS_DYNAMIC_EX_HII:
3773 for SkuName in Pcd.SkuInfoList:
3774 SkuInfo = Pcd.SkuInfoList[SkuName]
3775 HiiInfo = '## %s|%s|%s' % (SkuInfo.VariableName, SkuInfo.VariableGuid, SkuInfo.VariableOffset)
3776 break
3777 if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) in self._PcdComments:
3778 PcdCommentList = self._PcdComments[Pcd.TokenSpaceGuidCName, Pcd.TokenCName][:]
3779 if HiiInfo:
3780 UsageIndex = -1
3781 UsageStr = ''
3782 for Index, Comment in enumerate(PcdCommentList):
3783 for Usage in UsageList:
3784 if Comment.find(Usage) != -1:
3785 UsageStr = Usage
3786 UsageIndex = Index
3787 break
3788 if UsageIndex != -1:
3789 PcdCommentList[UsageIndex] = '## %s %s %s' % (UsageStr, HiiInfo, PcdCommentList[UsageIndex].replace(UsageStr, ''))
3790 else:
3791 PcdCommentList.append('## UNDEFINED ' + HiiInfo)
3792 PcdComments = '\n '.join(PcdCommentList)
3793 PcdEntry = Pcd.TokenSpaceGuidCName + '.' + TokenCName
3794 if PcdComments:
3795 PcdEntry = PcdComments + '\n ' + PcdEntry
3796 AsBuiltInfDict['pcd_item'].append(PcdEntry)
3797 for Item in self.BuildOption:
3798 if 'FLAGS' in self.BuildOption[Item]:
3799 AsBuiltInfDict['flags_item'].append('%s:%s_%s_%s_%s_FLAGS = %s' % (self.ToolChainFamily, self.BuildTarget, self.ToolChain, self.Arch, Item, self.BuildOption[Item]['FLAGS'].strip()))
3800
3801 # Generated LibraryClasses section in comments.
3802 for Library in self.LibraryAutoGenList:
3803 AsBuiltInfDict['libraryclasses_item'].append(Library.MetaFile.File.replace('\\', '/'))
3804
3805 # Generated UserExtensions TianoCore section.
3806 # All tianocore user extensions are copied.
3807 UserExtStr = ''
3808 for TianoCore in self._GetTianoCoreUserExtensionList():
3809 UserExtStr += '\n'.join(TianoCore)
3810 ExtensionFile = os.path.join(self.MetaFile.Dir, TianoCore[1])
3811 if os.path.isfile(ExtensionFile):
3812 shutil.copy2(ExtensionFile, self.OutputDir)
3813 AsBuiltInfDict['userextension_tianocore_item'] = UserExtStr
3814
3815 # Generated depex expression section in comments.
3816 DepexExpresion = self._GetDepexExpresionString()
3817 AsBuiltInfDict['depexsection_item'] = DepexExpresion if DepexExpresion else ''
3818
3819 AsBuiltInf = TemplateString()
3820 AsBuiltInf.Append(gAsBuiltInfHeaderString.Replace(AsBuiltInfDict))
3821
3822 SaveFileOnChange(os.path.join(self.OutputDir, self.Name + '.inf'), str(AsBuiltInf), False)
3823
3824 self.IsAsBuiltInfCreated = True
3825 if GlobalData.gBinCacheDest:
3826 self.CopyModuleToCache()
3827
3828 def CopyModuleToCache(self):
3829 FileDir = path.join(GlobalData.gBinCacheDest, self.Arch, self.SourceDir, self.MetaFile.BaseName)
3830 CreateDirectory (FileDir)
3831 HashFile = path.join(self.BuildDir, self.Name + '.hash')
3832 ModuleFile = path.join(self.OutputDir, self.Name + '.inf')
3833 if os.path.exists(HashFile):
3834 shutil.copy2(HashFile, FileDir)
3835 if os.path.exists(ModuleFile):
3836 shutil.copy2(ModuleFile, FileDir)
3837 if not self.OutputFile:
3838 Ma = self.BuildDatabase[PathClass(ModuleFile), self.Arch, self.BuildTarget, self.ToolChain]
3839 self.OutputFile = Ma.Binaries
3840 if self.OutputFile:
3841 for File in self.OutputFile:
3842 File = str(File)
3843 if not os.path.isabs(File):
3844 File = os.path.join(self.OutputDir, File)
3845 if os.path.exists(File):
3846 shutil.copy2(File, FileDir)
3847
3848 def AttemptModuleCacheCopy(self):
3849 if self.IsBinaryModule:
3850 return False
3851 FileDir = path.join(GlobalData.gBinCacheSource, self.Arch, self.SourceDir, self.MetaFile.BaseName)
3852 HashFile = path.join(FileDir, self.Name + '.hash')
3853 if os.path.exists(HashFile):
3854 f = open(HashFile, 'r')
3855 CacheHash = f.read()
3856 f.close()
3857 if GlobalData.gModuleHash[self.Arch][self.Name]:
3858 if CacheHash == GlobalData.gModuleHash[self.Arch][self.Name]:
3859 for root, dir, files in os.walk(FileDir):
3860 for f in files:
3861 if self.Name + '.hash' in f:
3862 shutil.copy2(HashFile, self.BuildDir)
3863 else:
3864 File = path.join(root, f)
3865 shutil.copy2(File, self.OutputDir)
3866 if self.Name == "PcdPeim" or self.Name == "PcdDxe":
3867 CreatePcdDatabaseCode(self, TemplateString(), TemplateString())
3868 return True
3869 return False
3870
3871 ## Create makefile for the module and its dependent libraries
3872 #
3873 # @param CreateLibraryMakeFile Flag indicating if or not the makefiles of
3874 # dependent libraries will be created
3875 #
3876 @cached_class_function
3877 def CreateMakeFile(self, CreateLibraryMakeFile=True, GenFfsList = []):
3878 # nest this function inside it's only caller.
3879 def CreateTimeStamp():
3880 FileSet = {self.MetaFile.Path}
3881
3882 for SourceFile in self.Module.Sources:
3883 FileSet.add (SourceFile.Path)
3884
3885 for Lib in self.DependentLibraryList:
3886 FileSet.add (Lib.MetaFile.Path)
3887
3888 for f in self.AutoGenDepSet:
3889 FileSet.add (f.Path)
3890
3891 if os.path.exists (self.TimeStampPath):
3892 os.remove (self.TimeStampPath)
3893 with open(self.TimeStampPath, 'w+') as file:
3894 for f in FileSet:
3895 print(f, file=file)
3896
3897 # Ignore generating makefile when it is a binary module
3898 if self.IsBinaryModule:
3899 return
3900
3901 self.GenFfsList = GenFfsList
3902 if not self.IsLibrary and CreateLibraryMakeFile:
3903 for LibraryAutoGen in self.LibraryAutoGenList:
3904 LibraryAutoGen.CreateMakeFile()
3905
3906 if self.CanSkip():
3907 return
3908
3909 if len(self.CustomMakefile) == 0:
3910 Makefile = GenMake.ModuleMakefile(self)
3911 else:
3912 Makefile = GenMake.CustomMakefile(self)
3913 if Makefile.Generate():
3914 EdkLogger.debug(EdkLogger.DEBUG_9, "Generated makefile for module %s [%s]" %
3915 (self.Name, self.Arch))
3916 else:
3917 EdkLogger.debug(EdkLogger.DEBUG_9, "Skipped the generation of makefile for module %s [%s]" %
3918 (self.Name, self.Arch))
3919
3920 CreateTimeStamp()
3921
3922 def CopyBinaryFiles(self):
3923 for File in self.Module.Binaries:
3924 SrcPath = File.Path
3925 DstPath = os.path.join(self.OutputDir, os.path.basename(SrcPath))
3926 CopyLongFilePath(SrcPath, DstPath)
3927 ## Create autogen code for the module and its dependent libraries
3928 #
3929 # @param CreateLibraryCodeFile Flag indicating if or not the code of
3930 # dependent libraries will be created
3931 #
3932 def CreateCodeFile(self, CreateLibraryCodeFile=True):
3933 if self.IsCodeFileCreated:
3934 return
3935
3936 # Need to generate PcdDatabase even PcdDriver is binarymodule
3937 if self.IsBinaryModule and self.PcdIsDriver != '':
3938 CreatePcdDatabaseCode(self, TemplateString(), TemplateString())
3939 return
3940 if self.IsBinaryModule:
3941 if self.IsLibrary:
3942 self.CopyBinaryFiles()
3943 return
3944
3945 if not self.IsLibrary and CreateLibraryCodeFile:
3946 for LibraryAutoGen in self.LibraryAutoGenList:
3947 LibraryAutoGen.CreateCodeFile()
3948
3949 if self.CanSkip():
3950 return
3951
3952 AutoGenList = []
3953 IgoredAutoGenList = []
3954
3955 for File in self.AutoGenFileList:
3956 if GenC.Generate(File.Path, self.AutoGenFileList[File], File.IsBinary):
3957 #Ignore Edk AutoGen.c
3958 if self.AutoGenVersion < 0x00010005 and File.Name == 'AutoGen.c':
3959 continue
3960
3961 AutoGenList.append(str(File))
3962 else:
3963 IgoredAutoGenList.append(str(File))
3964
3965 # Skip the following code for EDK I inf
3966 if self.AutoGenVersion < 0x00010005:
3967 return
3968
3969 for ModuleType in self.DepexList:
3970 # Ignore empty [depex] section or [depex] section for SUP_MODULE_USER_DEFINED module
3971 if len(self.DepexList[ModuleType]) == 0 or ModuleType == SUP_MODULE_USER_DEFINED:
3972 continue
3973
3974 Dpx = GenDepex.DependencyExpression(self.DepexList[ModuleType], ModuleType, True)
3975 DpxFile = gAutoGenDepexFileName % {"module_name" : self.Name}
3976
3977 if len(Dpx.PostfixNotation) != 0:
3978 self.DepexGenerated = True
3979
3980 if Dpx.Generate(path.join(self.OutputDir, DpxFile)):
3981 AutoGenList.append(str(DpxFile))
3982 else:
3983 IgoredAutoGenList.append(str(DpxFile))
3984
3985 if IgoredAutoGenList == []:
3986 EdkLogger.debug(EdkLogger.DEBUG_9, "Generated [%s] files for module %s [%s]" %
3987 (" ".join(AutoGenList), self.Name, self.Arch))
3988 elif AutoGenList == []:
3989 EdkLogger.debug(EdkLogger.DEBUG_9, "Skipped the generation of [%s] files for module %s [%s]" %
3990 (" ".join(IgoredAutoGenList), self.Name, self.Arch))
3991 else:
3992 EdkLogger.debug(EdkLogger.DEBUG_9, "Generated [%s] (skipped %s) files for module %s [%s]" %
3993 (" ".join(AutoGenList), " ".join(IgoredAutoGenList), self.Name, self.Arch))
3994
3995 self.IsCodeFileCreated = True
3996 return AutoGenList
3997
3998 ## Summarize the ModuleAutoGen objects of all libraries used by this module
3999 @cached_property
4000 def LibraryAutoGenList(self):
4001 RetVal = []
4002 for Library in self.DependentLibraryList:
4003 La = ModuleAutoGen(
4004 self.Workspace,
4005 Library.MetaFile,
4006 self.BuildTarget,
4007 self.ToolChain,
4008 self.Arch,
4009 self.PlatformInfo.MetaFile
4010 )
4011 if La not in RetVal:
4012 RetVal.append(La)
4013 for Lib in La.CodaTargetList:
4014 self._ApplyBuildRule(Lib.Target, TAB_UNKNOWN_FILE)
4015 return RetVal
4016
4017 def GenModuleHash(self):
4018 if self.Arch not in GlobalData.gModuleHash:
4019 GlobalData.gModuleHash[self.Arch] = {}
4020 m = hashlib.md5()
4021 # Add Platform level hash
4022 m.update(GlobalData.gPlatformHash)
4023 # Add Package level hash
4024 if self.DependentPackageList:
4025 for Pkg in sorted(self.DependentPackageList, key=lambda x: x.PackageName):
4026 if Pkg.PackageName in GlobalData.gPackageHash[self.Arch]:
4027 m.update(GlobalData.gPackageHash[self.Arch][Pkg.PackageName])
4028
4029 # Add Library hash
4030 if self.LibraryAutoGenList:
4031 for Lib in sorted(self.LibraryAutoGenList, key=lambda x: x.Name):
4032 if Lib.Name not in GlobalData.gModuleHash[self.Arch]:
4033 Lib.GenModuleHash()
4034 m.update(GlobalData.gModuleHash[self.Arch][Lib.Name])
4035
4036 # Add Module self
4037 f = open(str(self.MetaFile), 'r')
4038 Content = f.read()
4039 f.close()
4040 m.update(Content)
4041 # Add Module's source files
4042 if self.SourceFileList:
4043 for File in sorted(self.SourceFileList, key=lambda x: str(x)):
4044 f = open(str(File), 'r')
4045 Content = f.read()
4046 f.close()
4047 m.update(Content)
4048
4049 ModuleHashFile = path.join(self.BuildDir, self.Name + ".hash")
4050 if self.Name not in GlobalData.gModuleHash[self.Arch]:
4051 GlobalData.gModuleHash[self.Arch][self.Name] = m.hexdigest()
4052 if GlobalData.gBinCacheSource:
4053 if self.AttemptModuleCacheCopy():
4054 return False
4055 return SaveFileOnChange(ModuleHashFile, m.hexdigest(), True)
4056
4057 ## Decide whether we can skip the ModuleAutoGen process
4058 def CanSkipbyHash(self):
4059 if GlobalData.gUseHashCache:
4060 return not self.GenModuleHash()
4061 return False
4062
4063 ## Decide whether we can skip the ModuleAutoGen process
4064 # If any source file is newer than the module than we cannot skip
4065 #
4066 def CanSkip(self):
4067 if self.MakeFileDir in GlobalData.gSikpAutoGenCache:
4068 return True
4069 if not os.path.exists(self.TimeStampPath):
4070 return False
4071 #last creation time of the module
4072 DstTimeStamp = os.stat(self.TimeStampPath)[8]
4073
4074 SrcTimeStamp = self.Workspace._SrcTimeStamp
4075 if SrcTimeStamp > DstTimeStamp:
4076 return False
4077
4078 with open(self.TimeStampPath,'r') as f:
4079 for source in f:
4080 source = source.rstrip('\n')
4081 if not os.path.exists(source):
4082 return False
4083 if source not in ModuleAutoGen.TimeDict :
4084 ModuleAutoGen.TimeDict[source] = os.stat(source)[8]
4085 if ModuleAutoGen.TimeDict[source] > DstTimeStamp:
4086 return False
4087 GlobalData.gSikpAutoGenCache.add(self.MakeFileDir)
4088 return True
4089
4090 @cached_property
4091 def TimeStampPath(self):
4092 return os.path.join(self.MakeFileDir, 'AutoGenTimeStamp')