]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/AutoGen/AutoGen.py
BaseTools: Fix some build and report file issue
[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(sorted(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 list(BuildData.Pcds.keys()):
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 += "\n"
620 content += 'BuildOptionPcd: '
621 content += str(GlobalData.BuildOptionPcd)
622 content += "\n"
623 content += 'Active Platform: '
624 content += str(self.Platform)
625 content += "\n"
626 if self.FdfFile:
627 content += 'Flash Image Definition: '
628 content += str(self.FdfFile)
629 content += "\n"
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 += "\n"
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, 'rb')
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 sorted(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, 'rb')
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, 'rb')
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 = list(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 = list(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 = list(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 list(M.ModulePcdList) + list(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 = list(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 = list(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[list(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 = list(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 #python3.6 set is not ordered at all
1602 self._DynamicPcdList = sorted(self._DynamicPcdList, key=lambda x:(x.TokenSpaceGuidCName, x.TokenCName))
1603 self._NonDynamicPcdList = sorted(self._NonDynamicPcdList, key=lambda x: (x.TokenSpaceGuidCName, x.TokenCName))
1604 allskuset = [(SkuName, Sku.SkuId) for pcd in self._DynamicPcdList for (SkuName, Sku) in pcd.SkuInfoList.items()]
1605 for pcd in self._DynamicPcdList:
1606 if len(pcd.SkuInfoList) == 1:
1607 for (SkuName, SkuId) in allskuset:
1608 if isinstance(SkuId, str) and eval(SkuId) == 0 or SkuId == 0:
1609 continue
1610 pcd.SkuInfoList[SkuName] = copy.deepcopy(pcd.SkuInfoList[TAB_DEFAULT])
1611 pcd.SkuInfoList[SkuName].SkuId = SkuId
1612 pcd.SkuInfoList[SkuName].SkuIdName = SkuName
1613 self.AllPcdList = self._NonDynamicPcdList + self._DynamicPcdList
1614
1615 def FixVpdOffset(self, VpdFile ):
1616 FvPath = os.path.join(self.BuildDir, TAB_FV_DIRECTORY)
1617 if not os.path.exists(FvPath):
1618 try:
1619 os.makedirs(FvPath)
1620 except:
1621 EdkLogger.error("build", FILE_WRITE_FAILURE, "Fail to create FV folder under %s" % self.BuildDir)
1622
1623 VpdFilePath = os.path.join(FvPath, "%s.txt" % self.Platform.VpdToolGuid)
1624
1625 if VpdFile.Write(VpdFilePath):
1626 # retrieve BPDG tool's path from tool_def.txt according to VPD_TOOL_GUID defined in DSC file.
1627 BPDGToolName = None
1628 for ToolDef in self.ToolDefinition.values():
1629 if TAB_GUID in ToolDef and ToolDef[TAB_GUID] == self.Platform.VpdToolGuid:
1630 if "PATH" not in ToolDef:
1631 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "PATH attribute was not provided for BPDG guid tool %s in tools_def.txt" % self.Platform.VpdToolGuid)
1632 BPDGToolName = ToolDef["PATH"]
1633 break
1634 # Call third party GUID BPDG tool.
1635 if BPDGToolName is not None:
1636 VpdInfoFile.CallExtenalBPDGTool(BPDGToolName, VpdFilePath)
1637 else:
1638 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.")
1639
1640 ## Return the platform build data object
1641 @cached_property
1642 def Platform(self):
1643 return self.BuildDatabase[self.MetaFile, self.Arch, self.BuildTarget, self.ToolChain]
1644
1645 ## Return platform name
1646 @cached_property
1647 def Name(self):
1648 return self.Platform.PlatformName
1649
1650 ## Return the meta file GUID
1651 @cached_property
1652 def Guid(self):
1653 return self.Platform.Guid
1654
1655 ## Return the platform version
1656 @cached_property
1657 def Version(self):
1658 return self.Platform.Version
1659
1660 ## Return the FDF file name
1661 @cached_property
1662 def FdfFile(self):
1663 if self.Workspace.FdfFile:
1664 RetVal= mws.join(self.WorkspaceDir, self.Workspace.FdfFile)
1665 else:
1666 RetVal = ''
1667 return RetVal
1668
1669 ## Return the build output directory platform specifies
1670 @cached_property
1671 def OutputDir(self):
1672 return self.Platform.OutputDirectory
1673
1674 ## Return the directory to store all intermediate and final files built
1675 @cached_property
1676 def BuildDir(self):
1677 if os.path.isabs(self.OutputDir):
1678 GlobalData.gBuildDirectory = RetVal = path.join(
1679 path.abspath(self.OutputDir),
1680 self.BuildTarget + "_" + self.ToolChain,
1681 )
1682 else:
1683 GlobalData.gBuildDirectory = RetVal = path.join(
1684 self.WorkspaceDir,
1685 self.OutputDir,
1686 self.BuildTarget + "_" + self.ToolChain,
1687 )
1688 return RetVal
1689
1690 ## Return directory of platform makefile
1691 #
1692 # @retval string Makefile directory
1693 #
1694 @cached_property
1695 def MakeFileDir(self):
1696 return path.join(self.BuildDir, self.Arch)
1697
1698 ## Return build command string
1699 #
1700 # @retval string Build command string
1701 #
1702 @cached_property
1703 def BuildCommand(self):
1704 RetVal = []
1705 if "MAKE" in self.ToolDefinition and "PATH" in self.ToolDefinition["MAKE"]:
1706 RetVal += SplitOption(self.ToolDefinition["MAKE"]["PATH"])
1707 if "FLAGS" in self.ToolDefinition["MAKE"]:
1708 NewOption = self.ToolDefinition["MAKE"]["FLAGS"].strip()
1709 if NewOption != '':
1710 RetVal += SplitOption(NewOption)
1711 if "MAKE" in self.EdkIIBuildOption:
1712 if "FLAGS" in self.EdkIIBuildOption["MAKE"]:
1713 Flags = self.EdkIIBuildOption["MAKE"]["FLAGS"]
1714 if Flags.startswith('='):
1715 RetVal = [RetVal[0]] + [Flags[1:]]
1716 else:
1717 RetVal.append(Flags)
1718 return RetVal
1719
1720 ## Get tool chain definition
1721 #
1722 # Get each tool defition for given tool chain from tools_def.txt and platform
1723 #
1724 @cached_property
1725 def ToolDefinition(self):
1726 ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDictionary
1727 if TAB_TOD_DEFINES_COMMAND_TYPE not in self.Workspace.ToolDef.ToolsDefTxtDatabase:
1728 EdkLogger.error('build', RESOURCE_NOT_AVAILABLE, "No tools found in configuration",
1729 ExtraData="[%s]" % self.MetaFile)
1730 RetVal = {}
1731 DllPathList = set()
1732 for Def in ToolDefinition:
1733 Target, Tag, Arch, Tool, Attr = Def.split("_")
1734 if Target != self.BuildTarget or Tag != self.ToolChain or Arch != self.Arch:
1735 continue
1736
1737 Value = ToolDefinition[Def]
1738 # don't record the DLL
1739 if Attr == "DLL":
1740 DllPathList.add(Value)
1741 continue
1742
1743 if Tool not in RetVal:
1744 RetVal[Tool] = {}
1745 RetVal[Tool][Attr] = Value
1746
1747 ToolsDef = ''
1748 if GlobalData.gOptions.SilentMode and "MAKE" in RetVal:
1749 if "FLAGS" not in RetVal["MAKE"]:
1750 RetVal["MAKE"]["FLAGS"] = ""
1751 RetVal["MAKE"]["FLAGS"] += " -s"
1752 MakeFlags = ''
1753 for Tool in RetVal:
1754 for Attr in RetVal[Tool]:
1755 Value = RetVal[Tool][Attr]
1756 if Tool in self._BuildOptionWithToolDef(RetVal) and Attr in self._BuildOptionWithToolDef(RetVal)[Tool]:
1757 # check if override is indicated
1758 if self._BuildOptionWithToolDef(RetVal)[Tool][Attr].startswith('='):
1759 Value = self._BuildOptionWithToolDef(RetVal)[Tool][Attr][1:]
1760 else:
1761 if Attr != 'PATH':
1762 Value += " " + self._BuildOptionWithToolDef(RetVal)[Tool][Attr]
1763 else:
1764 Value = self._BuildOptionWithToolDef(RetVal)[Tool][Attr]
1765
1766 if Attr == "PATH":
1767 # Don't put MAKE definition in the file
1768 if Tool != "MAKE":
1769 ToolsDef += "%s = %s\n" % (Tool, Value)
1770 elif Attr != "DLL":
1771 # Don't put MAKE definition in the file
1772 if Tool == "MAKE":
1773 if Attr == "FLAGS":
1774 MakeFlags = Value
1775 else:
1776 ToolsDef += "%s_%s = %s\n" % (Tool, Attr, Value)
1777 ToolsDef += "\n"
1778
1779 SaveFileOnChange(self.ToolDefinitionFile, ToolsDef)
1780 for DllPath in DllPathList:
1781 os.environ["PATH"] = DllPath + os.pathsep + os.environ["PATH"]
1782 os.environ["MAKE_FLAGS"] = MakeFlags
1783
1784 return RetVal
1785
1786 ## Return the paths of tools
1787 @cached_property
1788 def ToolDefinitionFile(self):
1789 return os.path.join(self.MakeFileDir, "TOOLS_DEF." + self.Arch)
1790
1791 ## Retrieve the toolchain family of given toolchain tag. Default to 'MSFT'.
1792 @cached_property
1793 def ToolChainFamily(self):
1794 ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDatabase
1795 if TAB_TOD_DEFINES_FAMILY not in ToolDefinition \
1796 or self.ToolChain not in ToolDefinition[TAB_TOD_DEFINES_FAMILY] \
1797 or not ToolDefinition[TAB_TOD_DEFINES_FAMILY][self.ToolChain]:
1798 EdkLogger.verbose("No tool chain family found in configuration for %s. Default to MSFT." \
1799 % self.ToolChain)
1800 RetVal = TAB_COMPILER_MSFT
1801 else:
1802 RetVal = ToolDefinition[TAB_TOD_DEFINES_FAMILY][self.ToolChain]
1803 return RetVal
1804
1805 @cached_property
1806 def BuildRuleFamily(self):
1807 ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDatabase
1808 if TAB_TOD_DEFINES_BUILDRULEFAMILY not in ToolDefinition \
1809 or self.ToolChain not in ToolDefinition[TAB_TOD_DEFINES_BUILDRULEFAMILY] \
1810 or not ToolDefinition[TAB_TOD_DEFINES_BUILDRULEFAMILY][self.ToolChain]:
1811 EdkLogger.verbose("No tool chain family found in configuration for %s. Default to MSFT." \
1812 % self.ToolChain)
1813 return TAB_COMPILER_MSFT
1814
1815 return ToolDefinition[TAB_TOD_DEFINES_BUILDRULEFAMILY][self.ToolChain]
1816
1817 ## Return the build options specific for all modules in this platform
1818 @cached_property
1819 def BuildOption(self):
1820 return self._ExpandBuildOption(self.Platform.BuildOptions)
1821
1822 def _BuildOptionWithToolDef(self, ToolDef):
1823 return self._ExpandBuildOption(self.Platform.BuildOptions, ToolDef=ToolDef)
1824
1825 ## Return the build options specific for EDK modules in this platform
1826 @cached_property
1827 def EdkBuildOption(self):
1828 return self._ExpandBuildOption(self.Platform.BuildOptions, EDK_NAME)
1829
1830 ## Return the build options specific for EDKII modules in this platform
1831 @cached_property
1832 def EdkIIBuildOption(self):
1833 return self._ExpandBuildOption(self.Platform.BuildOptions, EDKII_NAME)
1834
1835 ## Parse build_rule.txt in Conf Directory.
1836 #
1837 # @retval BuildRule object
1838 #
1839 @cached_property
1840 def BuildRule(self):
1841 BuildRuleFile = None
1842 if TAB_TAT_DEFINES_BUILD_RULE_CONF in self.Workspace.TargetTxt.TargetTxtDictionary:
1843 BuildRuleFile = self.Workspace.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_BUILD_RULE_CONF]
1844 if not BuildRuleFile:
1845 BuildRuleFile = gDefaultBuildRuleFile
1846 RetVal = BuildRule(BuildRuleFile)
1847 if RetVal._FileVersion == "":
1848 RetVal._FileVersion = AutoGenReqBuildRuleVerNum
1849 else:
1850 if RetVal._FileVersion < AutoGenReqBuildRuleVerNum :
1851 # If Build Rule's version is less than the version number required by the tools, halting the build.
1852 EdkLogger.error("build", AUTOGEN_ERROR,
1853 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])"\
1854 % (RetVal._FileVersion, AutoGenReqBuildRuleVerNum))
1855 return RetVal
1856
1857 ## Summarize the packages used by modules in this platform
1858 @cached_property
1859 def PackageList(self):
1860 RetVal = set()
1861 for La in self.LibraryAutoGenList:
1862 RetVal.update(La.DependentPackageList)
1863 for Ma in self.ModuleAutoGenList:
1864 RetVal.update(Ma.DependentPackageList)
1865 #Collect package set information from INF of FDF
1866 for ModuleFile in self._AsBuildModuleList:
1867 if ModuleFile in self.Platform.Modules:
1868 continue
1869 ModuleData = self.BuildDatabase[ModuleFile, self.Arch, self.BuildTarget, self.ToolChain]
1870 RetVal.update(ModuleData.Packages)
1871 return list(RetVal)
1872
1873 @cached_property
1874 def NonDynamicPcdDict(self):
1875 return {(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):Pcd for Pcd in self.NonDynamicPcdList}
1876
1877 ## Get list of non-dynamic PCDs
1878 @cached_property
1879 def NonDynamicPcdList(self):
1880 self.CollectPlatformDynamicPcds()
1881 return self._NonDynamicPcdList
1882
1883 ## Get list of dynamic PCDs
1884 @cached_property
1885 def DynamicPcdList(self):
1886 self.CollectPlatformDynamicPcds()
1887 return self._DynamicPcdList
1888
1889 ## Generate Token Number for all PCD
1890 @cached_property
1891 def PcdTokenNumber(self):
1892 RetVal = OrderedDict()
1893 TokenNumber = 1
1894 #
1895 # Make the Dynamic and DynamicEx PCD use within different TokenNumber area.
1896 # Such as:
1897 #
1898 # Dynamic PCD:
1899 # TokenNumber 0 ~ 10
1900 # DynamicEx PCD:
1901 # TokeNumber 11 ~ 20
1902 #
1903 for Pcd in self.DynamicPcdList:
1904 if Pcd.Phase == "PEI" and Pcd.Type in PCD_DYNAMIC_TYPE_SET:
1905 EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))
1906 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
1907 TokenNumber += 1
1908
1909 for Pcd in self.DynamicPcdList:
1910 if Pcd.Phase == "PEI" and Pcd.Type in PCD_DYNAMIC_EX_TYPE_SET:
1911 EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))
1912 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
1913 TokenNumber += 1
1914
1915 for Pcd in self.DynamicPcdList:
1916 if Pcd.Phase == "DXE" and Pcd.Type in PCD_DYNAMIC_TYPE_SET:
1917 EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))
1918 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
1919 TokenNumber += 1
1920
1921 for Pcd in self.DynamicPcdList:
1922 if Pcd.Phase == "DXE" and Pcd.Type in PCD_DYNAMIC_EX_TYPE_SET:
1923 EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))
1924 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
1925 TokenNumber += 1
1926
1927 for Pcd in self.NonDynamicPcdList:
1928 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
1929 TokenNumber += 1
1930 return RetVal
1931
1932 @cached_property
1933 def _MaList(self):
1934 for ModuleFile in self.Platform.Modules:
1935 Ma = ModuleAutoGen(
1936 self.Workspace,
1937 ModuleFile,
1938 self.BuildTarget,
1939 self.ToolChain,
1940 self.Arch,
1941 self.MetaFile
1942 )
1943 self.Platform.Modules[ModuleFile].M = Ma
1944 return [x.M for x in self.Platform.Modules.values()]
1945
1946 ## Summarize ModuleAutoGen objects of all modules to be built for this platform
1947 @cached_property
1948 def ModuleAutoGenList(self):
1949 RetVal = []
1950 for Ma in self._MaList:
1951 if Ma not in RetVal:
1952 RetVal.append(Ma)
1953 return RetVal
1954
1955 ## Summarize ModuleAutoGen objects of all libraries to be built for this platform
1956 @cached_property
1957 def LibraryAutoGenList(self):
1958 RetVal = []
1959 for Ma in self._MaList:
1960 for La in Ma.LibraryAutoGenList:
1961 if La not in RetVal:
1962 RetVal.append(La)
1963 if Ma not in La.ReferenceModules:
1964 La.ReferenceModules.append(Ma)
1965 return RetVal
1966
1967 ## Test if a module is supported by the platform
1968 #
1969 # An error will be raised directly if the module or its arch is not supported
1970 # by the platform or current configuration
1971 #
1972 def ValidModule(self, Module):
1973 return Module in self.Platform.Modules or Module in self.Platform.LibraryInstances \
1974 or Module in self._AsBuildModuleList
1975
1976 ## Resolve the library classes in a module to library instances
1977 #
1978 # This method will not only resolve library classes but also sort the library
1979 # instances according to the dependency-ship.
1980 #
1981 # @param Module The module from which the library classes will be resolved
1982 #
1983 # @retval library_list List of library instances sorted
1984 #
1985 def ApplyLibraryInstance(self, Module):
1986 # Cover the case that the binary INF file is list in the FDF file but not DSC file, return empty list directly
1987 if str(Module) not in self.Platform.Modules:
1988 return []
1989
1990 return GetModuleLibInstances(Module,
1991 self.Platform,
1992 self.BuildDatabase,
1993 self.Arch,
1994 self.BuildTarget,
1995 self.ToolChain,
1996 self.MetaFile,
1997 EdkLogger)
1998
1999 ## Override PCD setting (type, value, ...)
2000 #
2001 # @param ToPcd The PCD to be overrided
2002 # @param FromPcd The PCD overrideing from
2003 #
2004 def _OverridePcd(self, ToPcd, FromPcd, Module="", Msg="", Library=""):
2005 #
2006 # in case there's PCDs coming from FDF file, which have no type given.
2007 # at this point, ToPcd.Type has the type found from dependent
2008 # package
2009 #
2010 TokenCName = ToPcd.TokenCName
2011 for PcdItem in GlobalData.MixedPcd:
2012 if (ToPcd.TokenCName, ToPcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
2013 TokenCName = PcdItem[0]
2014 break
2015 if FromPcd is not None:
2016 if ToPcd.Pending and FromPcd.Type:
2017 ToPcd.Type = FromPcd.Type
2018 elif ToPcd.Type and FromPcd.Type\
2019 and ToPcd.Type != FromPcd.Type and ToPcd.Type in FromPcd.Type:
2020 if ToPcd.Type.strip() == TAB_PCDS_DYNAMIC_EX:
2021 ToPcd.Type = FromPcd.Type
2022 elif ToPcd.Type and FromPcd.Type \
2023 and ToPcd.Type != FromPcd.Type:
2024 if Library:
2025 Module = str(Module) + " 's library file (" + str(Library) + ")"
2026 EdkLogger.error("build", OPTION_CONFLICT, "Mismatched PCD type",
2027 ExtraData="%s.%s is used as [%s] in module %s, but as [%s] in %s."\
2028 % (ToPcd.TokenSpaceGuidCName, TokenCName,
2029 ToPcd.Type, Module, FromPcd.Type, Msg),
2030 File=self.MetaFile)
2031
2032 if FromPcd.MaxDatumSize:
2033 ToPcd.MaxDatumSize = FromPcd.MaxDatumSize
2034 ToPcd.MaxSizeUserSet = FromPcd.MaxDatumSize
2035 if FromPcd.DefaultValue:
2036 ToPcd.DefaultValue = FromPcd.DefaultValue
2037 if FromPcd.TokenValue:
2038 ToPcd.TokenValue = FromPcd.TokenValue
2039 if FromPcd.DatumType:
2040 ToPcd.DatumType = FromPcd.DatumType
2041 if FromPcd.SkuInfoList:
2042 ToPcd.SkuInfoList = FromPcd.SkuInfoList
2043 if FromPcd.UserDefinedDefaultStoresFlag:
2044 ToPcd.UserDefinedDefaultStoresFlag = FromPcd.UserDefinedDefaultStoresFlag
2045 # Add Flexible PCD format parse
2046 if ToPcd.DefaultValue:
2047 try:
2048 ToPcd.DefaultValue = ValueExpressionEx(ToPcd.DefaultValue, ToPcd.DatumType, self.Workspace._GuidDict)(True)
2049 except BadExpression as Value:
2050 EdkLogger.error('Parser', FORMAT_INVALID, 'PCD [%s.%s] Value "%s", %s' %(ToPcd.TokenSpaceGuidCName, ToPcd.TokenCName, ToPcd.DefaultValue, Value),
2051 File=self.MetaFile)
2052
2053 # check the validation of datum
2054 IsValid, Cause = CheckPcdDatum(ToPcd.DatumType, ToPcd.DefaultValue)
2055 if not IsValid:
2056 EdkLogger.error('build', FORMAT_INVALID, Cause, File=self.MetaFile,
2057 ExtraData="%s.%s" % (ToPcd.TokenSpaceGuidCName, TokenCName))
2058 ToPcd.validateranges = FromPcd.validateranges
2059 ToPcd.validlists = FromPcd.validlists
2060 ToPcd.expressions = FromPcd.expressions
2061 ToPcd.CustomAttribute = FromPcd.CustomAttribute
2062
2063 if FromPcd is not None and ToPcd.DatumType == TAB_VOID and not ToPcd.MaxDatumSize:
2064 EdkLogger.debug(EdkLogger.DEBUG_9, "No MaxDatumSize specified for PCD %s.%s" \
2065 % (ToPcd.TokenSpaceGuidCName, TokenCName))
2066 Value = ToPcd.DefaultValue
2067 if not Value:
2068 ToPcd.MaxDatumSize = '1'
2069 elif Value[0] == 'L':
2070 ToPcd.MaxDatumSize = str((len(Value) - 2) * 2)
2071 elif Value[0] == '{':
2072 ToPcd.MaxDatumSize = str(len(Value.split(',')))
2073 else:
2074 ToPcd.MaxDatumSize = str(len(Value) - 1)
2075
2076 # apply default SKU for dynamic PCDS if specified one is not available
2077 if (ToPcd.Type in PCD_DYNAMIC_TYPE_SET or ToPcd.Type in PCD_DYNAMIC_EX_TYPE_SET) \
2078 and not ToPcd.SkuInfoList:
2079 if self.Platform.SkuName in self.Platform.SkuIds:
2080 SkuName = self.Platform.SkuName
2081 else:
2082 SkuName = TAB_DEFAULT
2083 ToPcd.SkuInfoList = {
2084 SkuName : SkuInfoClass(SkuName, self.Platform.SkuIds[SkuName][0], '', '', '', '', '', ToPcd.DefaultValue)
2085 }
2086
2087 ## Apply PCD setting defined platform to a module
2088 #
2089 # @param Module The module from which the PCD setting will be overrided
2090 #
2091 # @retval PCD_list The list PCDs with settings from platform
2092 #
2093 def ApplyPcdSetting(self, Module, Pcds, Library=""):
2094 # for each PCD in module
2095 for Name, Guid in Pcds:
2096 PcdInModule = Pcds[Name, Guid]
2097 # find out the PCD setting in platform
2098 if (Name, Guid) in self.Platform.Pcds:
2099 PcdInPlatform = self.Platform.Pcds[Name, Guid]
2100 else:
2101 PcdInPlatform = None
2102 # then override the settings if any
2103 self._OverridePcd(PcdInModule, PcdInPlatform, Module, Msg="DSC PCD sections", Library=Library)
2104 # resolve the VariableGuid value
2105 for SkuId in PcdInModule.SkuInfoList:
2106 Sku = PcdInModule.SkuInfoList[SkuId]
2107 if Sku.VariableGuid == '': continue
2108 Sku.VariableGuidValue = GuidValue(Sku.VariableGuid, self.PackageList, self.MetaFile.Path)
2109 if Sku.VariableGuidValue is None:
2110 PackageList = "\n\t".join(str(P) for P in self.PackageList)
2111 EdkLogger.error(
2112 'build',
2113 RESOURCE_NOT_AVAILABLE,
2114 "Value of GUID [%s] is not found in" % Sku.VariableGuid,
2115 ExtraData=PackageList + "\n\t(used with %s.%s from module %s)" \
2116 % (Guid, Name, str(Module)),
2117 File=self.MetaFile
2118 )
2119
2120 # override PCD settings with module specific setting
2121 if Module in self.Platform.Modules:
2122 PlatformModule = self.Platform.Modules[str(Module)]
2123 for Key in PlatformModule.Pcds:
2124 Flag = False
2125 if Key in Pcds:
2126 ToPcd = Pcds[Key]
2127 Flag = True
2128 elif Key in GlobalData.MixedPcd:
2129 for PcdItem in GlobalData.MixedPcd[Key]:
2130 if PcdItem in Pcds:
2131 ToPcd = Pcds[PcdItem]
2132 Flag = True
2133 break
2134 if Flag:
2135 self._OverridePcd(ToPcd, PlatformModule.Pcds[Key], Module, Msg="DSC Components Module scoped PCD section", Library=Library)
2136 # use PCD value to calculate the MaxDatumSize when it is not specified
2137 for Name, Guid in Pcds:
2138 Pcd = Pcds[Name, Guid]
2139 if Pcd.DatumType == TAB_VOID and not Pcd.MaxDatumSize:
2140 Pcd.MaxSizeUserSet = None
2141 Value = Pcd.DefaultValue
2142 if not Value:
2143 Pcd.MaxDatumSize = '1'
2144 elif Value[0] == 'L':
2145 Pcd.MaxDatumSize = str((len(Value) - 2) * 2)
2146 elif Value[0] == '{':
2147 Pcd.MaxDatumSize = str(len(Value.split(',')))
2148 else:
2149 Pcd.MaxDatumSize = str(len(Value) - 1)
2150 return list(Pcds.values())
2151
2152 ## Resolve library names to library modules
2153 #
2154 # (for Edk.x modules)
2155 #
2156 # @param Module The module from which the library names will be resolved
2157 #
2158 # @retval library_list The list of library modules
2159 #
2160 def ResolveLibraryReference(self, Module):
2161 EdkLogger.verbose("")
2162 EdkLogger.verbose("Library instances of module [%s] [%s]:" % (str(Module), self.Arch))
2163 LibraryConsumerList = [Module]
2164
2165 # "CompilerStub" is a must for Edk modules
2166 if Module.Libraries:
2167 Module.Libraries.append("CompilerStub")
2168 LibraryList = []
2169 while len(LibraryConsumerList) > 0:
2170 M = LibraryConsumerList.pop()
2171 for LibraryName in M.Libraries:
2172 Library = self.Platform.LibraryClasses[LibraryName, ':dummy:']
2173 if Library is None:
2174 for Key in self.Platform.LibraryClasses.data:
2175 if LibraryName.upper() == Key.upper():
2176 Library = self.Platform.LibraryClasses[Key, ':dummy:']
2177 break
2178 if Library is None:
2179 EdkLogger.warn("build", "Library [%s] is not found" % LibraryName, File=str(M),
2180 ExtraData="\t%s [%s]" % (str(Module), self.Arch))
2181 continue
2182
2183 if Library not in LibraryList:
2184 LibraryList.append(Library)
2185 LibraryConsumerList.append(Library)
2186 EdkLogger.verbose("\t" + LibraryName + " : " + str(Library) + ' ' + str(type(Library)))
2187 return LibraryList
2188
2189 ## Calculate the priority value of the build option
2190 #
2191 # @param Key Build option definition contain: TARGET_TOOLCHAIN_ARCH_COMMANDTYPE_ATTRIBUTE
2192 #
2193 # @retval Value Priority value based on the priority list.
2194 #
2195 def CalculatePriorityValue(self, Key):
2196 Target, ToolChain, Arch, CommandType, Attr = Key.split('_')
2197 PriorityValue = 0x11111
2198 if Target == "*":
2199 PriorityValue &= 0x01111
2200 if ToolChain == "*":
2201 PriorityValue &= 0x10111
2202 if Arch == "*":
2203 PriorityValue &= 0x11011
2204 if CommandType == "*":
2205 PriorityValue &= 0x11101
2206 if Attr == "*":
2207 PriorityValue &= 0x11110
2208
2209 return self.PrioList["0x%0.5x" % PriorityValue]
2210
2211
2212 ## Expand * in build option key
2213 #
2214 # @param Options Options to be expanded
2215 # @param ToolDef Use specified ToolDef instead of full version.
2216 # This is needed during initialization to prevent
2217 # infinite recursion betweeh BuildOptions,
2218 # ToolDefinition, and this function.
2219 #
2220 # @retval options Options expanded
2221 #
2222 def _ExpandBuildOption(self, Options, ModuleStyle=None, ToolDef=None):
2223 if not ToolDef:
2224 ToolDef = self.ToolDefinition
2225 BuildOptions = {}
2226 FamilyMatch = False
2227 FamilyIsNull = True
2228
2229 OverrideList = {}
2230 #
2231 # Construct a list contain the build options which need override.
2232 #
2233 for Key in Options:
2234 #
2235 # Key[0] -- tool family
2236 # Key[1] -- TARGET_TOOLCHAIN_ARCH_COMMANDTYPE_ATTRIBUTE
2237 #
2238 if (Key[0] == self.BuildRuleFamily and
2239 (ModuleStyle is None or len(Key) < 3 or (len(Key) > 2 and Key[2] == ModuleStyle))):
2240 Target, ToolChain, Arch, CommandType, Attr = Key[1].split('_')
2241 if (Target == self.BuildTarget or Target == "*") and\
2242 (ToolChain == self.ToolChain or ToolChain == "*") and\
2243 (Arch == self.Arch or Arch == "*") and\
2244 Options[Key].startswith("="):
2245
2246 if OverrideList.get(Key[1]) is not None:
2247 OverrideList.pop(Key[1])
2248 OverrideList[Key[1]] = Options[Key]
2249
2250 #
2251 # Use the highest priority value.
2252 #
2253 if (len(OverrideList) >= 2):
2254 KeyList = list(OverrideList.keys())
2255 for Index in range(len(KeyList)):
2256 NowKey = KeyList[Index]
2257 Target1, ToolChain1, Arch1, CommandType1, Attr1 = NowKey.split("_")
2258 for Index1 in range(len(KeyList) - Index - 1):
2259 NextKey = KeyList[Index1 + Index + 1]
2260 #
2261 # Compare two Key, if one is included by another, choose the higher priority one
2262 #
2263 Target2, ToolChain2, Arch2, CommandType2, Attr2 = NextKey.split("_")
2264 if (Target1 == Target2 or Target1 == "*" or Target2 == "*") and\
2265 (ToolChain1 == ToolChain2 or ToolChain1 == "*" or ToolChain2 == "*") and\
2266 (Arch1 == Arch2 or Arch1 == "*" or Arch2 == "*") and\
2267 (CommandType1 == CommandType2 or CommandType1 == "*" or CommandType2 == "*") and\
2268 (Attr1 == Attr2 or Attr1 == "*" or Attr2 == "*"):
2269
2270 if self.CalculatePriorityValue(NowKey) > self.CalculatePriorityValue(NextKey):
2271 if Options.get((self.BuildRuleFamily, NextKey)) is not None:
2272 Options.pop((self.BuildRuleFamily, NextKey))
2273 else:
2274 if Options.get((self.BuildRuleFamily, NowKey)) is not None:
2275 Options.pop((self.BuildRuleFamily, NowKey))
2276
2277 for Key in Options:
2278 if ModuleStyle is not None and len (Key) > 2:
2279 # Check Module style is EDK or EDKII.
2280 # Only append build option for the matched style module.
2281 if ModuleStyle == EDK_NAME and Key[2] != EDK_NAME:
2282 continue
2283 elif ModuleStyle == EDKII_NAME and Key[2] != EDKII_NAME:
2284 continue
2285 Family = Key[0]
2286 Target, Tag, Arch, Tool, Attr = Key[1].split("_")
2287 # if tool chain family doesn't match, skip it
2288 if Tool in ToolDef and Family != "":
2289 FamilyIsNull = False
2290 if ToolDef[Tool].get(TAB_TOD_DEFINES_BUILDRULEFAMILY, "") != "":
2291 if Family != ToolDef[Tool][TAB_TOD_DEFINES_BUILDRULEFAMILY]:
2292 continue
2293 elif Family != ToolDef[Tool][TAB_TOD_DEFINES_FAMILY]:
2294 continue
2295 FamilyMatch = True
2296 # expand any wildcard
2297 if Target == "*" or Target == self.BuildTarget:
2298 if Tag == "*" or Tag == self.ToolChain:
2299 if Arch == "*" or Arch == self.Arch:
2300 if Tool not in BuildOptions:
2301 BuildOptions[Tool] = {}
2302 if Attr != "FLAGS" or Attr not in BuildOptions[Tool] or Options[Key].startswith('='):
2303 BuildOptions[Tool][Attr] = Options[Key]
2304 else:
2305 # append options for the same tool except PATH
2306 if Attr != 'PATH':
2307 BuildOptions[Tool][Attr] += " " + Options[Key]
2308 else:
2309 BuildOptions[Tool][Attr] = Options[Key]
2310 # Build Option Family has been checked, which need't to be checked again for family.
2311 if FamilyMatch or FamilyIsNull:
2312 return BuildOptions
2313
2314 for Key in Options:
2315 if ModuleStyle is not None and len (Key) > 2:
2316 # Check Module style is EDK or EDKII.
2317 # Only append build option for the matched style module.
2318 if ModuleStyle == EDK_NAME and Key[2] != EDK_NAME:
2319 continue
2320 elif ModuleStyle == EDKII_NAME and Key[2] != EDKII_NAME:
2321 continue
2322 Family = Key[0]
2323 Target, Tag, Arch, Tool, Attr = Key[1].split("_")
2324 # if tool chain family doesn't match, skip it
2325 if Tool not in ToolDef or Family == "":
2326 continue
2327 # option has been added before
2328 if Family != ToolDef[Tool][TAB_TOD_DEFINES_FAMILY]:
2329 continue
2330
2331 # expand any wildcard
2332 if Target == "*" or Target == self.BuildTarget:
2333 if Tag == "*" or Tag == self.ToolChain:
2334 if Arch == "*" or Arch == self.Arch:
2335 if Tool not in BuildOptions:
2336 BuildOptions[Tool] = {}
2337 if Attr != "FLAGS" or Attr not in BuildOptions[Tool] or Options[Key].startswith('='):
2338 BuildOptions[Tool][Attr] = Options[Key]
2339 else:
2340 # append options for the same tool except PATH
2341 if Attr != 'PATH':
2342 BuildOptions[Tool][Attr] += " " + Options[Key]
2343 else:
2344 BuildOptions[Tool][Attr] = Options[Key]
2345 return BuildOptions
2346
2347 ## Append build options in platform to a module
2348 #
2349 # @param Module The module to which the build options will be appened
2350 #
2351 # @retval options The options appended with build options in platform
2352 #
2353 def ApplyBuildOption(self, Module):
2354 # Get the different options for the different style module
2355 if Module.AutoGenVersion < 0x00010005:
2356 PlatformOptions = self.EdkBuildOption
2357 ModuleTypeOptions = self.Platform.GetBuildOptionsByModuleType(EDK_NAME, Module.ModuleType)
2358 else:
2359 PlatformOptions = self.EdkIIBuildOption
2360 ModuleTypeOptions = self.Platform.GetBuildOptionsByModuleType(EDKII_NAME, Module.ModuleType)
2361 ModuleTypeOptions = self._ExpandBuildOption(ModuleTypeOptions)
2362 ModuleOptions = self._ExpandBuildOption(Module.BuildOptions)
2363 if Module in self.Platform.Modules:
2364 PlatformModule = self.Platform.Modules[str(Module)]
2365 PlatformModuleOptions = self._ExpandBuildOption(PlatformModule.BuildOptions)
2366 else:
2367 PlatformModuleOptions = {}
2368
2369 BuildRuleOrder = None
2370 for Options in [self.ToolDefinition, ModuleOptions, PlatformOptions, ModuleTypeOptions, PlatformModuleOptions]:
2371 for Tool in Options:
2372 for Attr in Options[Tool]:
2373 if Attr == TAB_TOD_DEFINES_BUILDRULEORDER:
2374 BuildRuleOrder = Options[Tool][Attr]
2375
2376 AllTools = set(list(ModuleOptions.keys()) + list(PlatformOptions.keys()) +
2377 list(PlatformModuleOptions.keys()) + list(ModuleTypeOptions.keys()) +
2378 list(self.ToolDefinition.keys()))
2379 BuildOptions = defaultdict(lambda: defaultdict(str))
2380 for Tool in sorted(AllTools):
2381 for Options in [self.ToolDefinition, ModuleOptions, PlatformOptions, ModuleTypeOptions, PlatformModuleOptions]:
2382 if Tool not in Options:
2383 continue
2384 for Attr in Options[Tool]:
2385 #
2386 # Do not generate it in Makefile
2387 #
2388 if Attr == TAB_TOD_DEFINES_BUILDRULEORDER:
2389 continue
2390 Value = Options[Tool][Attr]
2391 # check if override is indicated
2392 if Value.startswith('='):
2393 BuildOptions[Tool][Attr] = mws.handleWsMacro(Value[1:])
2394 else:
2395 if Attr != 'PATH':
2396 BuildOptions[Tool][Attr] += " " + mws.handleWsMacro(Value)
2397 else:
2398 BuildOptions[Tool][Attr] = mws.handleWsMacro(Value)
2399
2400 if Module.AutoGenVersion < 0x00010005 and self.Workspace.UniFlag is not None:
2401 #
2402 # Override UNI flag only for EDK module.
2403 #
2404 BuildOptions['BUILD']['FLAGS'] = self.Workspace.UniFlag
2405 return BuildOptions, BuildRuleOrder
2406
2407 #
2408 # extend lists contained in a dictionary with lists stored in another dictionary
2409 # if CopyToDict is not derived from DefaultDict(list) then this may raise exception
2410 #
2411 def ExtendCopyDictionaryLists(CopyToDict, CopyFromDict):
2412 for Key in CopyFromDict:
2413 CopyToDict[Key].extend(CopyFromDict[Key])
2414
2415 # Create a directory specified by a set of path elements and return the full path
2416 def _MakeDir(PathList):
2417 RetVal = path.join(*PathList)
2418 CreateDirectory(RetVal)
2419 return RetVal
2420
2421 ## ModuleAutoGen class
2422 #
2423 # This class encapsules the AutoGen behaviors for the build tools. In addition to
2424 # the generation of AutoGen.h and AutoGen.c, it will generate *.depex file according
2425 # to the [depex] section in module's inf file.
2426 #
2427 class ModuleAutoGen(AutoGen):
2428 # call super().__init__ then call the worker function with different parameter count
2429 def __init__(self, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs):
2430 if not hasattr(self, "_Init"):
2431 super().__init__(Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs)
2432 self._InitWorker(Workspace, MetaFile, Target, Toolchain, Arch, *args)
2433 self._Init = True
2434
2435 ## Cache the timestamps of metafiles of every module in a class attribute
2436 #
2437 TimeDict = {}
2438
2439 def __new__(cls, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs):
2440 # check if this module is employed by active platform
2441 if not PlatformAutoGen(Workspace, args[0], Target, Toolchain, Arch).ValidModule(MetaFile):
2442 EdkLogger.verbose("Module [%s] for [%s] is not employed by active platform\n" \
2443 % (MetaFile, Arch))
2444 return None
2445 return super().__new__(cls, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs)
2446
2447 ## Initialize ModuleAutoGen
2448 #
2449 # @param Workspace EdkIIWorkspaceBuild object
2450 # @param ModuleFile The path of module file
2451 # @param Target Build target (DEBUG, RELEASE)
2452 # @param Toolchain Name of tool chain
2453 # @param Arch The arch the module supports
2454 # @param PlatformFile Platform meta-file
2455 #
2456 def _InitWorker(self, Workspace, ModuleFile, Target, Toolchain, Arch, PlatformFile):
2457 EdkLogger.debug(EdkLogger.DEBUG_9, "AutoGen module [%s] [%s]" % (ModuleFile, Arch))
2458 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (ModuleFile, Arch, Toolchain, Target)
2459
2460 self.Workspace = Workspace
2461 self.WorkspaceDir = Workspace.WorkspaceDir
2462 self.MetaFile = ModuleFile
2463 self.PlatformInfo = PlatformAutoGen(Workspace, PlatformFile, Target, Toolchain, Arch)
2464
2465 self.SourceDir = self.MetaFile.SubDir
2466 self.SourceDir = mws.relpath(self.SourceDir, self.WorkspaceDir)
2467
2468 self.SourceOverrideDir = None
2469 # use overrided path defined in DSC file
2470 if self.MetaFile.Key in GlobalData.gOverrideDir:
2471 self.SourceOverrideDir = GlobalData.gOverrideDir[self.MetaFile.Key]
2472
2473 self.ToolChain = Toolchain
2474 self.BuildTarget = Target
2475 self.Arch = Arch
2476 self.ToolChainFamily = self.PlatformInfo.ToolChainFamily
2477 self.BuildRuleFamily = self.PlatformInfo.BuildRuleFamily
2478
2479 self.IsCodeFileCreated = False
2480 self.IsAsBuiltInfCreated = False
2481 self.DepexGenerated = False
2482
2483 self.BuildDatabase = self.Workspace.BuildDatabase
2484 self.BuildRuleOrder = None
2485 self.BuildTime = 0
2486
2487 self._PcdComments = OrderedListDict()
2488 self._GuidComments = OrderedListDict()
2489 self._ProtocolComments = OrderedListDict()
2490 self._PpiComments = OrderedListDict()
2491 self._BuildTargets = None
2492 self._IntroBuildTargetList = None
2493 self._FinalBuildTargetList = None
2494 self._FileTypes = None
2495
2496 self.AutoGenDepSet = set()
2497 self.ReferenceModules = []
2498 self.ConstPcd = {}
2499
2500
2501 def __repr__(self):
2502 return "%s [%s]" % (self.MetaFile, self.Arch)
2503
2504 # Get FixedAtBuild Pcds of this Module
2505 @cached_property
2506 def FixedAtBuildPcds(self):
2507 RetVal = []
2508 for Pcd in self.ModulePcdList:
2509 if Pcd.Type != TAB_PCDS_FIXED_AT_BUILD:
2510 continue
2511 if Pcd not in RetVal:
2512 RetVal.append(Pcd)
2513 return RetVal
2514
2515 @cached_property
2516 def FixedVoidTypePcds(self):
2517 RetVal = {}
2518 for Pcd in self.FixedAtBuildPcds:
2519 if Pcd.DatumType == TAB_VOID:
2520 if '{}.{}'.format(Pcd.TokenSpaceGuidCName, Pcd.TokenCName) not in RetVal:
2521 RetVal['{}.{}'.format(Pcd.TokenSpaceGuidCName, Pcd.TokenCName)] = Pcd.DefaultValue
2522 return RetVal
2523
2524 @property
2525 def UniqueBaseName(self):
2526 BaseName = self.Name
2527 for Module in self.PlatformInfo.ModuleAutoGenList:
2528 if Module.MetaFile == self.MetaFile:
2529 continue
2530 if Module.Name == self.Name:
2531 if uuid.UUID(Module.Guid) == uuid.UUID(self.Guid):
2532 EdkLogger.error("build", FILE_DUPLICATED, 'Modules have same BaseName and FILE_GUID:\n'
2533 ' %s\n %s' % (Module.MetaFile, self.MetaFile))
2534 BaseName = '%s_%s' % (self.Name, self.Guid)
2535 return BaseName
2536
2537 # Macros could be used in build_rule.txt (also Makefile)
2538 @cached_property
2539 def Macros(self):
2540 return OrderedDict((
2541 ("WORKSPACE" ,self.WorkspaceDir),
2542 ("MODULE_NAME" ,self.Name),
2543 ("MODULE_NAME_GUID" ,self.UniqueBaseName),
2544 ("MODULE_GUID" ,self.Guid),
2545 ("MODULE_VERSION" ,self.Version),
2546 ("MODULE_TYPE" ,self.ModuleType),
2547 ("MODULE_FILE" ,str(self.MetaFile)),
2548 ("MODULE_FILE_BASE_NAME" ,self.MetaFile.BaseName),
2549 ("MODULE_RELATIVE_DIR" ,self.SourceDir),
2550 ("MODULE_DIR" ,self.SourceDir),
2551 ("BASE_NAME" ,self.Name),
2552 ("ARCH" ,self.Arch),
2553 ("TOOLCHAIN" ,self.ToolChain),
2554 ("TOOLCHAIN_TAG" ,self.ToolChain),
2555 ("TOOL_CHAIN_TAG" ,self.ToolChain),
2556 ("TARGET" ,self.BuildTarget),
2557 ("BUILD_DIR" ,self.PlatformInfo.BuildDir),
2558 ("BIN_DIR" ,os.path.join(self.PlatformInfo.BuildDir, self.Arch)),
2559 ("LIB_DIR" ,os.path.join(self.PlatformInfo.BuildDir, self.Arch)),
2560 ("MODULE_BUILD_DIR" ,self.BuildDir),
2561 ("OUTPUT_DIR" ,self.OutputDir),
2562 ("DEBUG_DIR" ,self.DebugDir),
2563 ("DEST_DIR_OUTPUT" ,self.OutputDir),
2564 ("DEST_DIR_DEBUG" ,self.DebugDir),
2565 ("PLATFORM_NAME" ,self.PlatformInfo.Name),
2566 ("PLATFORM_GUID" ,self.PlatformInfo.Guid),
2567 ("PLATFORM_VERSION" ,self.PlatformInfo.Version),
2568 ("PLATFORM_RELATIVE_DIR" ,self.PlatformInfo.SourceDir),
2569 ("PLATFORM_DIR" ,mws.join(self.WorkspaceDir, self.PlatformInfo.SourceDir)),
2570 ("PLATFORM_OUTPUT_DIR" ,self.PlatformInfo.OutputDir),
2571 ("FFS_OUTPUT_DIR" ,self.FfsOutputDir)
2572 ))
2573
2574 ## Return the module build data object
2575 @cached_property
2576 def Module(self):
2577 return self.BuildDatabase[self.MetaFile, self.Arch, self.BuildTarget, self.ToolChain]
2578
2579 ## Return the module name
2580 @cached_property
2581 def Name(self):
2582 return self.Module.BaseName
2583
2584 ## Return the module DxsFile if exist
2585 @cached_property
2586 def DxsFile(self):
2587 return self.Module.DxsFile
2588
2589 ## Return the module meta-file GUID
2590 @cached_property
2591 def Guid(self):
2592 #
2593 # To build same module more than once, the module path with FILE_GUID overridden has
2594 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the realy path
2595 # in DSC. The overridden GUID can be retrieved from file name
2596 #
2597 if os.path.basename(self.MetaFile.File) != os.path.basename(self.MetaFile.Path):
2598 #
2599 # Length of GUID is 36
2600 #
2601 return os.path.basename(self.MetaFile.Path)[:36]
2602 return self.Module.Guid
2603
2604 ## Return the module version
2605 @cached_property
2606 def Version(self):
2607 return self.Module.Version
2608
2609 ## Return the module type
2610 @cached_property
2611 def ModuleType(self):
2612 return self.Module.ModuleType
2613
2614 ## Return the component type (for Edk.x style of module)
2615 @cached_property
2616 def ComponentType(self):
2617 return self.Module.ComponentType
2618
2619 ## Return the build type
2620 @cached_property
2621 def BuildType(self):
2622 return self.Module.BuildType
2623
2624 ## Return the PCD_IS_DRIVER setting
2625 @cached_property
2626 def PcdIsDriver(self):
2627 return self.Module.PcdIsDriver
2628
2629 ## Return the autogen version, i.e. module meta-file version
2630 @cached_property
2631 def AutoGenVersion(self):
2632 return self.Module.AutoGenVersion
2633
2634 ## Check if the module is library or not
2635 @cached_property
2636 def IsLibrary(self):
2637 return bool(self.Module.LibraryClass)
2638
2639 ## Check if the module is binary module or not
2640 @cached_property
2641 def IsBinaryModule(self):
2642 return self.Module.IsBinaryModule
2643
2644 ## Return the directory to store intermediate files of the module
2645 @cached_property
2646 def BuildDir(self):
2647 return _MakeDir((
2648 self.PlatformInfo.BuildDir,
2649 self.Arch,
2650 self.SourceDir,
2651 self.MetaFile.BaseName
2652 ))
2653
2654 ## Return the directory to store the intermediate object files of the mdoule
2655 @cached_property
2656 def OutputDir(self):
2657 return _MakeDir((self.BuildDir, "OUTPUT"))
2658
2659 ## Return the directory path to store ffs file
2660 @cached_property
2661 def FfsOutputDir(self):
2662 if GlobalData.gFdfParser:
2663 return path.join(self.PlatformInfo.BuildDir, TAB_FV_DIRECTORY, "Ffs", self.Guid + self.Name)
2664 return ''
2665
2666 ## Return the directory to store auto-gened source files of the mdoule
2667 @cached_property
2668 def DebugDir(self):
2669 return _MakeDir((self.BuildDir, "DEBUG"))
2670
2671 ## Return the path of custom file
2672 @cached_property
2673 def CustomMakefile(self):
2674 RetVal = {}
2675 for Type in self.Module.CustomMakefile:
2676 MakeType = gMakeTypeMap[Type] if Type in gMakeTypeMap else 'nmake'
2677 if self.SourceOverrideDir is not None:
2678 File = os.path.join(self.SourceOverrideDir, self.Module.CustomMakefile[Type])
2679 if not os.path.exists(File):
2680 File = os.path.join(self.SourceDir, self.Module.CustomMakefile[Type])
2681 else:
2682 File = os.path.join(self.SourceDir, self.Module.CustomMakefile[Type])
2683 RetVal[MakeType] = File
2684 return RetVal
2685
2686 ## Return the directory of the makefile
2687 #
2688 # @retval string The directory string of module's makefile
2689 #
2690 @cached_property
2691 def MakeFileDir(self):
2692 return self.BuildDir
2693
2694 ## Return build command string
2695 #
2696 # @retval string Build command string
2697 #
2698 @cached_property
2699 def BuildCommand(self):
2700 return self.PlatformInfo.BuildCommand
2701
2702 ## Get object list of all packages the module and its dependent libraries belong to
2703 #
2704 # @retval list The list of package object
2705 #
2706 @cached_property
2707 def DerivedPackageList(self):
2708 PackageList = []
2709 for M in [self.Module] + self.DependentLibraryList:
2710 for Package in M.Packages:
2711 if Package in PackageList:
2712 continue
2713 PackageList.append(Package)
2714 return PackageList
2715
2716 ## Get the depex string
2717 #
2718 # @return : a string contain all depex expresion.
2719 def _GetDepexExpresionString(self):
2720 DepexStr = ''
2721 DepexList = []
2722 ## DPX_SOURCE IN Define section.
2723 if self.Module.DxsFile:
2724 return DepexStr
2725 for M in [self.Module] + self.DependentLibraryList:
2726 Filename = M.MetaFile.Path
2727 InfObj = InfSectionParser.InfSectionParser(Filename)
2728 DepexExpresionList = InfObj.GetDepexExpresionList()
2729 for DepexExpresion in DepexExpresionList:
2730 for key in DepexExpresion:
2731 Arch, ModuleType = key
2732 DepexExpr = [x for x in DepexExpresion[key] if not str(x).startswith('#')]
2733 # the type of build module is USER_DEFINED.
2734 # All different DEPEX section tags would be copied into the As Built INF file
2735 # and there would be separate DEPEX section tags
2736 if self.ModuleType.upper() == SUP_MODULE_USER_DEFINED:
2737 if (Arch.upper() == self.Arch.upper()) and (ModuleType.upper() != TAB_ARCH_COMMON):
2738 DepexList.append({(Arch, ModuleType): DepexExpr})
2739 else:
2740 if Arch.upper() == TAB_ARCH_COMMON or \
2741 (Arch.upper() == self.Arch.upper() and \
2742 ModuleType.upper() in [TAB_ARCH_COMMON, self.ModuleType.upper()]):
2743 DepexList.append({(Arch, ModuleType): DepexExpr})
2744
2745 #the type of build module is USER_DEFINED.
2746 if self.ModuleType.upper() == SUP_MODULE_USER_DEFINED:
2747 for Depex in DepexList:
2748 for key in Depex:
2749 DepexStr += '[Depex.%s.%s]\n' % key
2750 DepexStr += '\n'.join('# '+ val for val in Depex[key])
2751 DepexStr += '\n\n'
2752 if not DepexStr:
2753 return '[Depex.%s]\n' % self.Arch
2754 return DepexStr
2755
2756 #the type of build module not is USER_DEFINED.
2757 Count = 0
2758 for Depex in DepexList:
2759 Count += 1
2760 if DepexStr != '':
2761 DepexStr += ' AND '
2762 DepexStr += '('
2763 for D in Depex.values():
2764 DepexStr += ' '.join(val for val in D)
2765 Index = DepexStr.find('END')
2766 if Index > -1 and Index == len(DepexStr) - 3:
2767 DepexStr = DepexStr[:-3]
2768 DepexStr = DepexStr.strip()
2769 DepexStr += ')'
2770 if Count == 1:
2771 DepexStr = DepexStr.lstrip('(').rstrip(')').strip()
2772 if not DepexStr:
2773 return '[Depex.%s]\n' % self.Arch
2774 return '[Depex.%s]\n# ' % self.Arch + DepexStr
2775
2776 ## Merge dependency expression
2777 #
2778 # @retval list The token list of the dependency expression after parsed
2779 #
2780 @cached_property
2781 def DepexList(self):
2782 if self.DxsFile or self.IsLibrary or TAB_DEPENDENCY_EXPRESSION_FILE in self.FileTypes:
2783 return {}
2784
2785 DepexList = []
2786 #
2787 # Append depex from dependent libraries, if not "BEFORE", "AFTER" expresion
2788 #
2789 for M in [self.Module] + self.DependentLibraryList:
2790 Inherited = False
2791 for D in M.Depex[self.Arch, self.ModuleType]:
2792 if DepexList != []:
2793 DepexList.append('AND')
2794 DepexList.append('(')
2795 #replace D with value if D is FixedAtBuild PCD
2796 NewList = []
2797 for item in D:
2798 if '.' not in item:
2799 NewList.append(item)
2800 else:
2801 if item not in self._FixedPcdVoidTypeDict:
2802 EdkLogger.error("build", FORMAT_INVALID, "{} used in [Depex] section should be used as FixedAtBuild type and VOID* datum type in the module.".format(item))
2803 else:
2804 Value = self._FixedPcdVoidTypeDict[item]
2805 if len(Value.split(',')) != 16:
2806 EdkLogger.error("build", FORMAT_INVALID,
2807 "{} used in [Depex] section should be used as FixedAtBuild type and VOID* datum type and 16 bytes in the module.".format(item))
2808 NewList.append(Value)
2809 DepexList.extend(NewList)
2810 if DepexList[-1] == 'END': # no need of a END at this time
2811 DepexList.pop()
2812 DepexList.append(')')
2813 Inherited = True
2814 if Inherited:
2815 EdkLogger.verbose("DEPEX[%s] (+%s) = %s" % (self.Name, M.BaseName, DepexList))
2816 if 'BEFORE' in DepexList or 'AFTER' in DepexList:
2817 break
2818 if len(DepexList) > 0:
2819 EdkLogger.verbose('')
2820 return {self.ModuleType:DepexList}
2821
2822 ## Merge dependency expression
2823 #
2824 # @retval list The token list of the dependency expression after parsed
2825 #
2826 @cached_property
2827 def DepexExpressionDict(self):
2828 if self.DxsFile or self.IsLibrary or TAB_DEPENDENCY_EXPRESSION_FILE in self.FileTypes:
2829 return {}
2830
2831 DepexExpressionString = ''
2832 #
2833 # Append depex from dependent libraries, if not "BEFORE", "AFTER" expresion
2834 #
2835 for M in [self.Module] + self.DependentLibraryList:
2836 Inherited = False
2837 for D in M.DepexExpression[self.Arch, self.ModuleType]:
2838 if DepexExpressionString != '':
2839 DepexExpressionString += ' AND '
2840 DepexExpressionString += '('
2841 DepexExpressionString += D
2842 DepexExpressionString = DepexExpressionString.rstrip('END').strip()
2843 DepexExpressionString += ')'
2844 Inherited = True
2845 if Inherited:
2846 EdkLogger.verbose("DEPEX[%s] (+%s) = %s" % (self.Name, M.BaseName, DepexExpressionString))
2847 if 'BEFORE' in DepexExpressionString or 'AFTER' in DepexExpressionString:
2848 break
2849 if len(DepexExpressionString) > 0:
2850 EdkLogger.verbose('')
2851
2852 return {self.ModuleType:DepexExpressionString}
2853
2854 # Get the tiano core user extension, it is contain dependent library.
2855 # @retval: a list contain tiano core userextension.
2856 #
2857 def _GetTianoCoreUserExtensionList(self):
2858 TianoCoreUserExtentionList = []
2859 for M in [self.Module] + self.DependentLibraryList:
2860 Filename = M.MetaFile.Path
2861 InfObj = InfSectionParser.InfSectionParser(Filename)
2862 TianoCoreUserExtenList = InfObj.GetUserExtensionTianoCore()
2863 for TianoCoreUserExtent in TianoCoreUserExtenList:
2864 for Section in TianoCoreUserExtent:
2865 ItemList = Section.split(TAB_SPLIT)
2866 Arch = self.Arch
2867 if len(ItemList) == 4:
2868 Arch = ItemList[3]
2869 if Arch.upper() == TAB_ARCH_COMMON or Arch.upper() == self.Arch.upper():
2870 TianoCoreList = []
2871 TianoCoreList.extend([TAB_SECTION_START + Section + TAB_SECTION_END])
2872 TianoCoreList.extend(TianoCoreUserExtent[Section][:])
2873 TianoCoreList.append('\n')
2874 TianoCoreUserExtentionList.append(TianoCoreList)
2875
2876 return TianoCoreUserExtentionList
2877
2878 ## Return the list of specification version required for the module
2879 #
2880 # @retval list The list of specification defined in module file
2881 #
2882 @cached_property
2883 def Specification(self):
2884 return self.Module.Specification
2885
2886 ## Tool option for the module build
2887 #
2888 # @param PlatformInfo The object of PlatformBuildInfo
2889 # @retval dict The dict containing valid options
2890 #
2891 @cached_property
2892 def BuildOption(self):
2893 RetVal, self.BuildRuleOrder = self.PlatformInfo.ApplyBuildOption(self.Module)
2894 if self.BuildRuleOrder:
2895 self.BuildRuleOrder = ['.%s' % Ext for Ext in self.BuildRuleOrder.split()]
2896 return RetVal
2897
2898 ## Get include path list from tool option for the module build
2899 #
2900 # @retval list The include path list
2901 #
2902 @cached_property
2903 def BuildOptionIncPathList(self):
2904 #
2905 # Regular expression for finding Include Directories, the difference between MSFT and INTEL/GCC/RVCT
2906 # is the former use /I , the Latter used -I to specify include directories
2907 #
2908 if self.PlatformInfo.ToolChainFamily in (TAB_COMPILER_MSFT):
2909 BuildOptIncludeRegEx = gBuildOptIncludePatternMsft
2910 elif self.PlatformInfo.ToolChainFamily in ('INTEL', 'GCC', 'RVCT'):
2911 BuildOptIncludeRegEx = gBuildOptIncludePatternOther
2912 else:
2913 #
2914 # New ToolChainFamily, don't known whether there is option to specify include directories
2915 #
2916 return []
2917
2918 RetVal = []
2919 for Tool in ('CC', 'PP', 'VFRPP', 'ASLPP', 'ASLCC', 'APP', 'ASM'):
2920 try:
2921 FlagOption = self.BuildOption[Tool]['FLAGS']
2922 except KeyError:
2923 FlagOption = ''
2924
2925 if self.ToolChainFamily != 'RVCT':
2926 IncPathList = [NormPath(Path, self.Macros) for Path in BuildOptIncludeRegEx.findall(FlagOption)]
2927 else:
2928 #
2929 # RVCT may specify a list of directory seperated by commas
2930 #
2931 IncPathList = []
2932 for Path in BuildOptIncludeRegEx.findall(FlagOption):
2933 PathList = GetSplitList(Path, TAB_COMMA_SPLIT)
2934 IncPathList.extend(NormPath(PathEntry, self.Macros) for PathEntry in PathList)
2935
2936 #
2937 # EDK II modules must not reference header files outside of the packages they depend on or
2938 # within the module's directory tree. Report error if violation.
2939 #
2940 if self.AutoGenVersion >= 0x00010005:
2941 for Path in IncPathList:
2942 if (Path not in self.IncludePathList) and (CommonPath([Path, self.MetaFile.Dir]) != self.MetaFile.Dir):
2943 ErrMsg = "The include directory for the EDK II module in this line is invalid %s specified in %s FLAGS '%s'" % (Path, Tool, FlagOption)
2944 EdkLogger.error("build",
2945 PARAMETER_INVALID,
2946 ExtraData=ErrMsg,
2947 File=str(self.MetaFile))
2948 RetVal += IncPathList
2949 return RetVal
2950
2951 ## Return a list of files which can be built from source
2952 #
2953 # What kind of files can be built is determined by build rules in
2954 # $(CONF_DIRECTORY)/build_rule.txt and toolchain family.
2955 #
2956 @cached_property
2957 def SourceFileList(self):
2958 RetVal = []
2959 ToolChainTagSet = {"", "*", self.ToolChain}
2960 ToolChainFamilySet = {"", "*", self.ToolChainFamily, self.BuildRuleFamily}
2961 for F in self.Module.Sources:
2962 # match tool chain
2963 if F.TagName not in ToolChainTagSet:
2964 EdkLogger.debug(EdkLogger.DEBUG_9, "The toolchain [%s] for processing file [%s] is found, "
2965 "but [%s] is currently used" % (F.TagName, str(F), self.ToolChain))
2966 continue
2967 # match tool chain family or build rule family
2968 if F.ToolChainFamily not in ToolChainFamilySet:
2969 EdkLogger.debug(
2970 EdkLogger.DEBUG_0,
2971 "The file [%s] must be built by tools of [%s], " \
2972 "but current toolchain family is [%s], buildrule family is [%s]" \
2973 % (str(F), F.ToolChainFamily, self.ToolChainFamily, self.BuildRuleFamily))
2974 continue
2975
2976 # add the file path into search path list for file including
2977 if F.Dir not in self.IncludePathList and self.AutoGenVersion >= 0x00010005:
2978 self.IncludePathList.insert(0, F.Dir)
2979 RetVal.append(F)
2980
2981 self._MatchBuildRuleOrder(RetVal)
2982
2983 for F in RetVal:
2984 self._ApplyBuildRule(F, TAB_UNKNOWN_FILE)
2985 return RetVal
2986
2987 def _MatchBuildRuleOrder(self, FileList):
2988 Order_Dict = {}
2989 self.BuildOption
2990 for SingleFile in FileList:
2991 if self.BuildRuleOrder and SingleFile.Ext in self.BuildRuleOrder and SingleFile.Ext in self.BuildRules:
2992 key = SingleFile.Path.split(SingleFile.Ext)[0]
2993 if key in Order_Dict:
2994 Order_Dict[key].append(SingleFile.Ext)
2995 else:
2996 Order_Dict[key] = [SingleFile.Ext]
2997
2998 RemoveList = []
2999 for F in Order_Dict:
3000 if len(Order_Dict[F]) > 1:
3001 Order_Dict[F].sort(key=lambda i: self.BuildRuleOrder.index(i))
3002 for Ext in Order_Dict[F][1:]:
3003 RemoveList.append(F + Ext)
3004
3005 for item in RemoveList:
3006 FileList.remove(item)
3007
3008 return FileList
3009
3010 ## Return the list of unicode files
3011 @cached_property
3012 def UnicodeFileList(self):
3013 return self.FileTypes.get(TAB_UNICODE_FILE,[])
3014
3015 ## Return the list of vfr files
3016 @cached_property
3017 def VfrFileList(self):
3018 return self.FileTypes.get(TAB_VFR_FILE, [])
3019
3020 ## Return the list of Image Definition files
3021 @cached_property
3022 def IdfFileList(self):
3023 return self.FileTypes.get(TAB_IMAGE_FILE,[])
3024
3025 ## Return a list of files which can be built from binary
3026 #
3027 # "Build" binary files are just to copy them to build directory.
3028 #
3029 # @retval list The list of files which can be built later
3030 #
3031 @cached_property
3032 def BinaryFileList(self):
3033 RetVal = []
3034 for F in self.Module.Binaries:
3035 if F.Target not in [TAB_ARCH_COMMON, '*'] and F.Target != self.BuildTarget:
3036 continue
3037 RetVal.append(F)
3038 self._ApplyBuildRule(F, F.Type, BinaryFileList=RetVal)
3039 return RetVal
3040
3041 @cached_property
3042 def BuildRules(self):
3043 RetVal = {}
3044 BuildRuleDatabase = self.PlatformInfo.BuildRule
3045 for Type in BuildRuleDatabase.FileTypeList:
3046 #first try getting build rule by BuildRuleFamily
3047 RuleObject = BuildRuleDatabase[Type, self.BuildType, self.Arch, self.BuildRuleFamily]
3048 if not RuleObject:
3049 # build type is always module type, but ...
3050 if self.ModuleType != self.BuildType:
3051 RuleObject = BuildRuleDatabase[Type, self.ModuleType, self.Arch, self.BuildRuleFamily]
3052 #second try getting build rule by ToolChainFamily
3053 if not RuleObject:
3054 RuleObject = BuildRuleDatabase[Type, self.BuildType, self.Arch, self.ToolChainFamily]
3055 if not RuleObject:
3056 # build type is always module type, but ...
3057 if self.ModuleType != self.BuildType:
3058 RuleObject = BuildRuleDatabase[Type, self.ModuleType, self.Arch, self.ToolChainFamily]
3059 if not RuleObject:
3060 continue
3061 RuleObject = RuleObject.Instantiate(self.Macros)
3062 RetVal[Type] = RuleObject
3063 for Ext in RuleObject.SourceFileExtList:
3064 RetVal[Ext] = RuleObject
3065 return RetVal
3066
3067 def _ApplyBuildRule(self, File, FileType, BinaryFileList=None):
3068 if self._BuildTargets is None:
3069 self._IntroBuildTargetList = set()
3070 self._FinalBuildTargetList = set()
3071 self._BuildTargets = defaultdict(set)
3072 self._FileTypes = defaultdict(set)
3073
3074 if not BinaryFileList:
3075 BinaryFileList = self.BinaryFileList
3076
3077 SubDirectory = os.path.join(self.OutputDir, File.SubDir)
3078 if not os.path.exists(SubDirectory):
3079 CreateDirectory(SubDirectory)
3080 LastTarget = None
3081 RuleChain = set()
3082 SourceList = [File]
3083 Index = 0
3084 #
3085 # Make sure to get build rule order value
3086 #
3087 self.BuildOption
3088
3089 while Index < len(SourceList):
3090 Source = SourceList[Index]
3091 Index = Index + 1
3092
3093 if Source != File:
3094 CreateDirectory(Source.Dir)
3095
3096 if File.IsBinary and File == Source and File in BinaryFileList:
3097 # Skip all files that are not binary libraries
3098 if not self.IsLibrary:
3099 continue
3100 RuleObject = self.BuildRules[TAB_DEFAULT_BINARY_FILE]
3101 elif FileType in self.BuildRules:
3102 RuleObject = self.BuildRules[FileType]
3103 elif Source.Ext in self.BuildRules:
3104 RuleObject = self.BuildRules[Source.Ext]
3105 else:
3106 # stop at no more rules
3107 if LastTarget:
3108 self._FinalBuildTargetList.add(LastTarget)
3109 break
3110
3111 FileType = RuleObject.SourceFileType
3112 self._FileTypes[FileType].add(Source)
3113
3114 # stop at STATIC_LIBRARY for library
3115 if self.IsLibrary and FileType == TAB_STATIC_LIBRARY:
3116 if LastTarget:
3117 self._FinalBuildTargetList.add(LastTarget)
3118 break
3119
3120 Target = RuleObject.Apply(Source, self.BuildRuleOrder)
3121 if not Target:
3122 if LastTarget:
3123 self._FinalBuildTargetList.add(LastTarget)
3124 break
3125 elif not Target.Outputs:
3126 # Only do build for target with outputs
3127 self._FinalBuildTargetList.add(Target)
3128
3129 self._BuildTargets[FileType].add(Target)
3130
3131 if not Source.IsBinary and Source == File:
3132 self._IntroBuildTargetList.add(Target)
3133
3134 # to avoid cyclic rule
3135 if FileType in RuleChain:
3136 break
3137
3138 RuleChain.add(FileType)
3139 SourceList.extend(Target.Outputs)
3140 LastTarget = Target
3141 FileType = TAB_UNKNOWN_FILE
3142
3143 @cached_property
3144 def Targets(self):
3145 if self._BuildTargets is None:
3146 self._IntroBuildTargetList = set()
3147 self._FinalBuildTargetList = set()
3148 self._BuildTargets = defaultdict(set)
3149 self._FileTypes = defaultdict(set)
3150
3151 #TRICK: call SourceFileList property to apply build rule for source files
3152 self.SourceFileList
3153
3154 #TRICK: call _GetBinaryFileList to apply build rule for binary files
3155 self.BinaryFileList
3156
3157 return self._BuildTargets
3158
3159 @cached_property
3160 def IntroTargetList(self):
3161 self.Targets
3162 return sorted(self._IntroBuildTargetList, key=lambda x: str(x.Target))
3163
3164 @cached_property
3165 def CodaTargetList(self):
3166 self.Targets
3167 return sorted(self._FinalBuildTargetList, key=lambda x: str(x.Target))
3168
3169 @cached_property
3170 def FileTypes(self):
3171 self.Targets
3172 return self._FileTypes
3173
3174 ## Get the list of package object the module depends on
3175 #
3176 # @retval list The package object list
3177 #
3178 @cached_property
3179 def DependentPackageList(self):
3180 return self.Module.Packages
3181
3182 ## Return the list of auto-generated code file
3183 #
3184 # @retval list The list of auto-generated file
3185 #
3186 @cached_property
3187 def AutoGenFileList(self):
3188 AutoGenUniIdf = self.BuildType != 'UEFI_HII'
3189 UniStringBinBuffer = BytesIO()
3190 IdfGenBinBuffer = BytesIO()
3191 RetVal = {}
3192 AutoGenC = TemplateString()
3193 AutoGenH = TemplateString()
3194 StringH = TemplateString()
3195 StringIdf = TemplateString()
3196 GenC.CreateCode(self, AutoGenC, AutoGenH, StringH, AutoGenUniIdf, UniStringBinBuffer, StringIdf, AutoGenUniIdf, IdfGenBinBuffer)
3197 #
3198 # AutoGen.c is generated if there are library classes in inf, or there are object files
3199 #
3200 if str(AutoGenC) != "" and (len(self.Module.LibraryClasses) > 0
3201 or TAB_OBJECT_FILE in self.FileTypes):
3202 AutoFile = PathClass(gAutoGenCodeFileName, self.DebugDir)
3203 RetVal[AutoFile] = str(AutoGenC)
3204 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3205 if str(AutoGenH) != "":
3206 AutoFile = PathClass(gAutoGenHeaderFileName, self.DebugDir)
3207 RetVal[AutoFile] = str(AutoGenH)
3208 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3209 if str(StringH) != "":
3210 AutoFile = PathClass(gAutoGenStringFileName % {"module_name":self.Name}, self.DebugDir)
3211 RetVal[AutoFile] = str(StringH)
3212 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3213 if UniStringBinBuffer is not None and UniStringBinBuffer.getvalue() != b"":
3214 AutoFile = PathClass(gAutoGenStringFormFileName % {"module_name":self.Name}, self.OutputDir)
3215 RetVal[AutoFile] = UniStringBinBuffer.getvalue()
3216 AutoFile.IsBinary = True
3217 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3218 if UniStringBinBuffer is not None:
3219 UniStringBinBuffer.close()
3220 if str(StringIdf) != "":
3221 AutoFile = PathClass(gAutoGenImageDefFileName % {"module_name":self.Name}, self.DebugDir)
3222 RetVal[AutoFile] = str(StringIdf)
3223 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3224 if IdfGenBinBuffer is not None and IdfGenBinBuffer.getvalue() != b"":
3225 AutoFile = PathClass(gAutoGenIdfFileName % {"module_name":self.Name}, self.OutputDir)
3226 RetVal[AutoFile] = IdfGenBinBuffer.getvalue()
3227 AutoFile.IsBinary = True
3228 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3229 if IdfGenBinBuffer is not None:
3230 IdfGenBinBuffer.close()
3231 return RetVal
3232
3233 ## Return the list of library modules explicitly or implicityly used by this module
3234 @cached_property
3235 def DependentLibraryList(self):
3236 # only merge library classes and PCD for non-library module
3237 if self.IsLibrary:
3238 return []
3239 if self.AutoGenVersion < 0x00010005:
3240 return self.PlatformInfo.ResolveLibraryReference(self.Module)
3241 return self.PlatformInfo.ApplyLibraryInstance(self.Module)
3242
3243 ## Get the list of PCDs from current module
3244 #
3245 # @retval list The list of PCD
3246 #
3247 @cached_property
3248 def ModulePcdList(self):
3249 # apply PCD settings from platform
3250 RetVal = self.PlatformInfo.ApplyPcdSetting(self.Module, self.Module.Pcds)
3251 ExtendCopyDictionaryLists(self._PcdComments, self.Module.PcdComments)
3252 return RetVal
3253
3254 ## Get the list of PCDs from dependent libraries
3255 #
3256 # @retval list The list of PCD
3257 #
3258 @cached_property
3259 def LibraryPcdList(self):
3260 if self.IsLibrary:
3261 return []
3262 RetVal = []
3263 Pcds = set()
3264 # get PCDs from dependent libraries
3265 for Library in self.DependentLibraryList:
3266 PcdsInLibrary = OrderedDict()
3267 ExtendCopyDictionaryLists(self._PcdComments, Library.PcdComments)
3268 for Key in Library.Pcds:
3269 # skip duplicated PCDs
3270 if Key in self.Module.Pcds or Key in Pcds:
3271 continue
3272 Pcds.add(Key)
3273 PcdsInLibrary[Key] = copy.copy(Library.Pcds[Key])
3274 RetVal.extend(self.PlatformInfo.ApplyPcdSetting(self.Module, PcdsInLibrary, Library=Library))
3275 return RetVal
3276
3277 ## Get the GUID value mapping
3278 #
3279 # @retval dict The mapping between GUID cname and its value
3280 #
3281 @cached_property
3282 def GuidList(self):
3283 RetVal = OrderedDict(self.Module.Guids)
3284 for Library in self.DependentLibraryList:
3285 RetVal.update(Library.Guids)
3286 ExtendCopyDictionaryLists(self._GuidComments, Library.GuidComments)
3287 ExtendCopyDictionaryLists(self._GuidComments, self.Module.GuidComments)
3288 return RetVal
3289
3290 @cached_property
3291 def GetGuidsUsedByPcd(self):
3292 RetVal = OrderedDict(self.Module.GetGuidsUsedByPcd())
3293 for Library in self.DependentLibraryList:
3294 RetVal.update(Library.GetGuidsUsedByPcd())
3295 return RetVal
3296 ## Get the protocol value mapping
3297 #
3298 # @retval dict The mapping between protocol cname and its value
3299 #
3300 @cached_property
3301 def ProtocolList(self):
3302 RetVal = OrderedDict(self.Module.Protocols)
3303 for Library in self.DependentLibraryList:
3304 RetVal.update(Library.Protocols)
3305 ExtendCopyDictionaryLists(self._ProtocolComments, Library.ProtocolComments)
3306 ExtendCopyDictionaryLists(self._ProtocolComments, self.Module.ProtocolComments)
3307 return RetVal
3308
3309 ## Get the PPI value mapping
3310 #
3311 # @retval dict The mapping between PPI cname and its value
3312 #
3313 @cached_property
3314 def PpiList(self):
3315 RetVal = OrderedDict(self.Module.Ppis)
3316 for Library in self.DependentLibraryList:
3317 RetVal.update(Library.Ppis)
3318 ExtendCopyDictionaryLists(self._PpiComments, Library.PpiComments)
3319 ExtendCopyDictionaryLists(self._PpiComments, self.Module.PpiComments)
3320 return RetVal
3321
3322 ## Get the list of include search path
3323 #
3324 # @retval list The list path
3325 #
3326 @cached_property
3327 def IncludePathList(self):
3328 RetVal = []
3329 if self.AutoGenVersion < 0x00010005:
3330 for Inc in self.Module.Includes:
3331 if Inc not in RetVal:
3332 RetVal.append(Inc)
3333 # for Edk modules
3334 Inc = path.join(Inc, self.Arch.capitalize())
3335 if os.path.exists(Inc) and Inc not in RetVal:
3336 RetVal.append(Inc)
3337 # Edk module needs to put DEBUG_DIR at the end of search path and not to use SOURCE_DIR all the time
3338 RetVal.append(self.DebugDir)
3339 else:
3340 RetVal.append(self.MetaFile.Dir)
3341 RetVal.append(self.DebugDir)
3342
3343 for Package in self.Module.Packages:
3344 PackageDir = mws.join(self.WorkspaceDir, Package.MetaFile.Dir)
3345 if PackageDir not in RetVal:
3346 RetVal.append(PackageDir)
3347 IncludesList = Package.Includes
3348 if Package._PrivateIncludes:
3349 if not self.MetaFile.Path.startswith(PackageDir):
3350 IncludesList = list(set(Package.Includes).difference(set(Package._PrivateIncludes)))
3351 for Inc in IncludesList:
3352 if Inc not in RetVal:
3353 RetVal.append(str(Inc))
3354 return RetVal
3355
3356 @cached_property
3357 def IncludePathLength(self):
3358 return sum(len(inc)+1 for inc in self.IncludePathList)
3359
3360 ## Get HII EX PCDs which maybe used by VFR
3361 #
3362 # efivarstore used by VFR may relate with HII EX PCDs
3363 # Get the variable name and GUID from efivarstore and HII EX PCD
3364 # List the HII EX PCDs in As Built INF if both name and GUID match.
3365 #
3366 # @retval list HII EX PCDs
3367 #
3368 def _GetPcdsMaybeUsedByVfr(self):
3369 if not self.SourceFileList:
3370 return []
3371
3372 NameGuids = set()
3373 for SrcFile in self.SourceFileList:
3374 if SrcFile.Ext.lower() != '.vfr':
3375 continue
3376 Vfri = os.path.join(self.OutputDir, SrcFile.BaseName + '.i')
3377 if not os.path.exists(Vfri):
3378 continue
3379 VfriFile = open(Vfri, 'r')
3380 Content = VfriFile.read()
3381 VfriFile.close()
3382 Pos = Content.find('efivarstore')
3383 while Pos != -1:
3384 #
3385 # Make sure 'efivarstore' is the start of efivarstore statement
3386 # In case of the value of 'name' (name = efivarstore) is equal to 'efivarstore'
3387 #
3388 Index = Pos - 1
3389 while Index >= 0 and Content[Index] in ' \t\r\n':
3390 Index -= 1
3391 if Index >= 0 and Content[Index] != ';':
3392 Pos = Content.find('efivarstore', Pos + len('efivarstore'))
3393 continue
3394 #
3395 # 'efivarstore' must be followed by name and guid
3396 #
3397 Name = gEfiVarStoreNamePattern.search(Content, Pos)
3398 if not Name:
3399 break
3400 Guid = gEfiVarStoreGuidPattern.search(Content, Pos)
3401 if not Guid:
3402 break
3403 NameArray = ConvertStringToByteArray('L"' + Name.group(1) + '"')
3404 NameGuids.add((NameArray, GuidStructureStringToGuidString(Guid.group(1))))
3405 Pos = Content.find('efivarstore', Name.end())
3406 if not NameGuids:
3407 return []
3408 HiiExPcds = []
3409 for Pcd in self.PlatformInfo.Platform.Pcds.values():
3410 if Pcd.Type != TAB_PCDS_DYNAMIC_EX_HII:
3411 continue
3412 for SkuInfo in Pcd.SkuInfoList.values():
3413 Value = GuidValue(SkuInfo.VariableGuid, self.PlatformInfo.PackageList, self.MetaFile.Path)
3414 if not Value:
3415 continue
3416 Name = ConvertStringToByteArray(SkuInfo.VariableName)
3417 Guid = GuidStructureStringToGuidString(Value)
3418 if (Name, Guid) in NameGuids and Pcd not in HiiExPcds:
3419 HiiExPcds.append(Pcd)
3420 break
3421
3422 return HiiExPcds
3423
3424 def _GenOffsetBin(self):
3425 VfrUniBaseName = {}
3426 for SourceFile in self.Module.Sources:
3427 if SourceFile.Type.upper() == ".VFR" :
3428 #
3429 # search the .map file to find the offset of vfr binary in the PE32+/TE file.
3430 #
3431 VfrUniBaseName[SourceFile.BaseName] = (SourceFile.BaseName + "Bin")
3432 elif SourceFile.Type.upper() == ".UNI" :
3433 #
3434 # search the .map file to find the offset of Uni strings binary in the PE32+/TE file.
3435 #
3436 VfrUniBaseName["UniOffsetName"] = (self.Name + "Strings")
3437
3438 if not VfrUniBaseName:
3439 return None
3440 MapFileName = os.path.join(self.OutputDir, self.Name + ".map")
3441 EfiFileName = os.path.join(self.OutputDir, self.Name + ".efi")
3442 VfrUniOffsetList = GetVariableOffset(MapFileName, EfiFileName, list(VfrUniBaseName.values()))
3443 if not VfrUniOffsetList:
3444 return None
3445
3446 OutputName = '%sOffset.bin' % self.Name
3447 UniVfrOffsetFileName = os.path.join( self.OutputDir, OutputName)
3448
3449 try:
3450 fInputfile = open(UniVfrOffsetFileName, "wb+", 0)
3451 except:
3452 EdkLogger.error("build", FILE_OPEN_FAILURE, "File open failed for %s" % UniVfrOffsetFileName, None)
3453
3454 # Use a instance of BytesIO to cache data
3455 fStringIO = BytesIO()
3456
3457 for Item in VfrUniOffsetList:
3458 if (Item[0].find("Strings") != -1):
3459 #
3460 # UNI offset in image.
3461 # GUID + Offset
3462 # { 0x8913c5e0, 0x33f6, 0x4d86, { 0x9b, 0xf1, 0x43, 0xef, 0x89, 0xfc, 0x6, 0x66 } }
3463 #
3464 UniGuid = [0xe0, 0xc5, 0x13, 0x89, 0xf6, 0x33, 0x86, 0x4d, 0x9b, 0xf1, 0x43, 0xef, 0x89, 0xfc, 0x6, 0x66]
3465 fStringIO.write(bytes(UniGuid))
3466 UniValue = pack ('Q', int (Item[1], 16))
3467 fStringIO.write (UniValue)
3468 else:
3469 #
3470 # VFR binary offset in image.
3471 # GUID + Offset
3472 # { 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2 } };
3473 #
3474 VfrGuid = [0xb4, 0x7c, 0xbc, 0xd0, 0x47, 0x6a, 0x5f, 0x49, 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2]
3475 fStringIO.write(bytes(VfrGuid))
3476 VfrValue = pack ('Q', int (Item[1], 16))
3477 fStringIO.write (VfrValue)
3478 #
3479 # write data into file.
3480 #
3481 try :
3482 fInputfile.write (fStringIO.getvalue())
3483 except:
3484 EdkLogger.error("build", FILE_WRITE_FAILURE, "Write data to file %s failed, please check whether the "
3485 "file been locked or using by other applications." %UniVfrOffsetFileName, None)
3486
3487 fStringIO.close ()
3488 fInputfile.close ()
3489 return OutputName
3490
3491 ## Create AsBuilt INF file the module
3492 #
3493 def CreateAsBuiltInf(self, IsOnlyCopy = False):
3494 self.OutputFile = set()
3495 if IsOnlyCopy and GlobalData.gBinCacheDest:
3496 self.CopyModuleToCache()
3497 return
3498
3499 if self.IsAsBuiltInfCreated:
3500 return
3501
3502 # Skip the following code for EDK I inf
3503 if self.AutoGenVersion < 0x00010005:
3504 return
3505
3506 # Skip the following code for libraries
3507 if self.IsLibrary:
3508 return
3509
3510 # Skip the following code for modules with no source files
3511 if not self.SourceFileList:
3512 return
3513
3514 # Skip the following code for modules without any binary files
3515 if self.BinaryFileList:
3516 return
3517
3518 ### TODO: How to handles mixed source and binary modules
3519
3520 # Find all DynamicEx and PatchableInModule PCDs used by this module and dependent libraries
3521 # Also find all packages that the DynamicEx PCDs depend on
3522 Pcds = []
3523 PatchablePcds = []
3524 Packages = []
3525 PcdCheckList = []
3526 PcdTokenSpaceList = []
3527 for Pcd in list(self.ModulePcdList) + list(self.LibraryPcdList):
3528 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE:
3529 PatchablePcds.append(Pcd)
3530 PcdCheckList.append((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, TAB_PCDS_PATCHABLE_IN_MODULE))
3531 elif Pcd.Type in PCD_DYNAMIC_EX_TYPE_SET:
3532 if Pcd not in Pcds:
3533 Pcds.append(Pcd)
3534 PcdCheckList.append((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC_EX))
3535 PcdCheckList.append((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC))
3536 PcdTokenSpaceList.append(Pcd.TokenSpaceGuidCName)
3537 GuidList = OrderedDict(self.GuidList)
3538 for TokenSpace in self.GetGuidsUsedByPcd:
3539 # If token space is not referred by patch PCD or Ex PCD, remove the GUID from GUID list
3540 # The GUIDs in GUIDs section should really be the GUIDs in source INF or referred by Ex an patch PCDs
3541 if TokenSpace not in PcdTokenSpaceList and TokenSpace in GuidList:
3542 GuidList.pop(TokenSpace)
3543 CheckList = (GuidList, self.PpiList, self.ProtocolList, PcdCheckList)
3544 for Package in self.DerivedPackageList:
3545 if Package in Packages:
3546 continue
3547 BeChecked = (Package.Guids, Package.Ppis, Package.Protocols, Package.Pcds)
3548 Found = False
3549 for Index in range(len(BeChecked)):
3550 for Item in CheckList[Index]:
3551 if Item in BeChecked[Index]:
3552 Packages.append(Package)
3553 Found = True
3554 break
3555 if Found:
3556 break
3557
3558 VfrPcds = self._GetPcdsMaybeUsedByVfr()
3559 for Pkg in self.PlatformInfo.PackageList:
3560 if Pkg in Packages:
3561 continue
3562 for VfrPcd in VfrPcds:
3563 if ((VfrPcd.TokenCName, VfrPcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC_EX) in Pkg.Pcds or
3564 (VfrPcd.TokenCName, VfrPcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC) in Pkg.Pcds):
3565 Packages.append(Pkg)
3566 break
3567
3568 ModuleType = SUP_MODULE_DXE_DRIVER if self.ModuleType == SUP_MODULE_UEFI_DRIVER and self.DepexGenerated else self.ModuleType
3569 DriverType = self.PcdIsDriver if self.PcdIsDriver else ''
3570 Guid = self.Guid
3571 MDefs = self.Module.Defines
3572
3573 AsBuiltInfDict = {
3574 'module_name' : self.Name,
3575 'module_guid' : Guid,
3576 'module_module_type' : ModuleType,
3577 'module_version_string' : [MDefs['VERSION_STRING']] if 'VERSION_STRING' in MDefs else [],
3578 'pcd_is_driver_string' : [],
3579 'module_uefi_specification_version' : [],
3580 'module_pi_specification_version' : [],
3581 'module_entry_point' : self.Module.ModuleEntryPointList,
3582 'module_unload_image' : self.Module.ModuleUnloadImageList,
3583 'module_constructor' : self.Module.ConstructorList,
3584 'module_destructor' : self.Module.DestructorList,
3585 'module_shadow' : [MDefs['SHADOW']] if 'SHADOW' in MDefs else [],
3586 'module_pci_vendor_id' : [MDefs['PCI_VENDOR_ID']] if 'PCI_VENDOR_ID' in MDefs else [],
3587 'module_pci_device_id' : [MDefs['PCI_DEVICE_ID']] if 'PCI_DEVICE_ID' in MDefs else [],
3588 'module_pci_class_code' : [MDefs['PCI_CLASS_CODE']] if 'PCI_CLASS_CODE' in MDefs else [],
3589 'module_pci_revision' : [MDefs['PCI_REVISION']] if 'PCI_REVISION' in MDefs else [],
3590 'module_build_number' : [MDefs['BUILD_NUMBER']] if 'BUILD_NUMBER' in MDefs else [],
3591 'module_spec' : [MDefs['SPEC']] if 'SPEC' in MDefs else [],
3592 'module_uefi_hii_resource_section' : [MDefs['UEFI_HII_RESOURCE_SECTION']] if 'UEFI_HII_RESOURCE_SECTION' in MDefs else [],
3593 'module_uni_file' : [MDefs['MODULE_UNI_FILE']] if 'MODULE_UNI_FILE' in MDefs else [],
3594 'module_arch' : self.Arch,
3595 'package_item' : [Package.MetaFile.File.replace('\\', '/') for Package in Packages],
3596 'binary_item' : [],
3597 'patchablepcd_item' : [],
3598 'pcd_item' : [],
3599 'protocol_item' : [],
3600 'ppi_item' : [],
3601 'guid_item' : [],
3602 'flags_item' : [],
3603 'libraryclasses_item' : []
3604 }
3605
3606 if 'MODULE_UNI_FILE' in MDefs:
3607 UNIFile = os.path.join(self.MetaFile.Dir, MDefs['MODULE_UNI_FILE'])
3608 if os.path.isfile(UNIFile):
3609 shutil.copy2(UNIFile, self.OutputDir)
3610
3611 if self.AutoGenVersion > int(gInfSpecVersion, 0):
3612 AsBuiltInfDict['module_inf_version'] = '0x%08x' % self.AutoGenVersion
3613 else:
3614 AsBuiltInfDict['module_inf_version'] = gInfSpecVersion
3615
3616 if DriverType:
3617 AsBuiltInfDict['pcd_is_driver_string'].append(DriverType)
3618
3619 if 'UEFI_SPECIFICATION_VERSION' in self.Specification:
3620 AsBuiltInfDict['module_uefi_specification_version'].append(self.Specification['UEFI_SPECIFICATION_VERSION'])
3621 if 'PI_SPECIFICATION_VERSION' in self.Specification:
3622 AsBuiltInfDict['module_pi_specification_version'].append(self.Specification['PI_SPECIFICATION_VERSION'])
3623
3624 OutputDir = self.OutputDir.replace('\\', '/').strip('/')
3625 DebugDir = self.DebugDir.replace('\\', '/').strip('/')
3626 for Item in self.CodaTargetList:
3627 File = Item.Target.Path.replace('\\', '/').strip('/').replace(DebugDir, '').replace(OutputDir, '').strip('/')
3628 self.OutputFile.add(File)
3629 if os.path.isabs(File):
3630 File = File.replace('\\', '/').strip('/').replace(OutputDir, '').strip('/')
3631 if Item.Target.Ext.lower() == '.aml':
3632 AsBuiltInfDict['binary_item'].append('ASL|' + File)
3633 elif Item.Target.Ext.lower() == '.acpi':
3634 AsBuiltInfDict['binary_item'].append('ACPI|' + File)
3635 elif Item.Target.Ext.lower() == '.efi':
3636 AsBuiltInfDict['binary_item'].append('PE32|' + self.Name + '.efi')
3637 else:
3638 AsBuiltInfDict['binary_item'].append('BIN|' + File)
3639 if self.DepexGenerated:
3640 self.OutputFile.add(self.Name + '.depex')
3641 if self.ModuleType in [SUP_MODULE_PEIM]:
3642 AsBuiltInfDict['binary_item'].append('PEI_DEPEX|' + self.Name + '.depex')
3643 elif self.ModuleType in [SUP_MODULE_DXE_DRIVER, SUP_MODULE_DXE_RUNTIME_DRIVER, SUP_MODULE_DXE_SAL_DRIVER, SUP_MODULE_UEFI_DRIVER]:
3644 AsBuiltInfDict['binary_item'].append('DXE_DEPEX|' + self.Name + '.depex')
3645 elif self.ModuleType in [SUP_MODULE_DXE_SMM_DRIVER]:
3646 AsBuiltInfDict['binary_item'].append('SMM_DEPEX|' + self.Name + '.depex')
3647
3648 Bin = self._GenOffsetBin()
3649 if Bin:
3650 AsBuiltInfDict['binary_item'].append('BIN|%s' % Bin)
3651 self.OutputFile.add(Bin)
3652
3653 for Root, Dirs, Files in os.walk(OutputDir):
3654 for File in Files:
3655 if File.lower().endswith('.pdb'):
3656 AsBuiltInfDict['binary_item'].append('DISPOSABLE|' + File)
3657 self.OutputFile.add(File)
3658 HeaderComments = self.Module.HeaderComments
3659 StartPos = 0
3660 for Index in range(len(HeaderComments)):
3661 if HeaderComments[Index].find('@BinaryHeader') != -1:
3662 HeaderComments[Index] = HeaderComments[Index].replace('@BinaryHeader', '@file')
3663 StartPos = Index
3664 break
3665 AsBuiltInfDict['header_comments'] = '\n'.join(HeaderComments[StartPos:]).replace(':#', '://')
3666 AsBuiltInfDict['tail_comments'] = '\n'.join(self.Module.TailComments)
3667
3668 GenList = [
3669 (self.ProtocolList, self._ProtocolComments, 'protocol_item'),
3670 (self.PpiList, self._PpiComments, 'ppi_item'),
3671 (GuidList, self._GuidComments, 'guid_item')
3672 ]
3673 for Item in GenList:
3674 for CName in Item[0]:
3675 Comments = '\n '.join(Item[1][CName]) if CName in Item[1] else ''
3676 Entry = Comments + '\n ' + CName if Comments else CName
3677 AsBuiltInfDict[Item[2]].append(Entry)
3678 PatchList = parsePcdInfoFromMapFile(
3679 os.path.join(self.OutputDir, self.Name + '.map'),
3680 os.path.join(self.OutputDir, self.Name + '.efi')
3681 )
3682 if PatchList:
3683 for Pcd in PatchablePcds:
3684 TokenCName = Pcd.TokenCName
3685 for PcdItem in GlobalData.MixedPcd:
3686 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
3687 TokenCName = PcdItem[0]
3688 break
3689 for PatchPcd in PatchList:
3690 if TokenCName == PatchPcd[0]:
3691 break
3692 else:
3693 continue
3694 PcdValue = ''
3695 if Pcd.DatumType == 'BOOLEAN':
3696 BoolValue = Pcd.DefaultValue.upper()
3697 if BoolValue == 'TRUE':
3698 Pcd.DefaultValue = '1'
3699 elif BoolValue == 'FALSE':
3700 Pcd.DefaultValue = '0'
3701
3702 if Pcd.DatumType in TAB_PCD_NUMERIC_TYPES:
3703 HexFormat = '0x%02x'
3704 if Pcd.DatumType == TAB_UINT16:
3705 HexFormat = '0x%04x'
3706 elif Pcd.DatumType == TAB_UINT32:
3707 HexFormat = '0x%08x'
3708 elif Pcd.DatumType == TAB_UINT64:
3709 HexFormat = '0x%016x'
3710 PcdValue = HexFormat % int(Pcd.DefaultValue, 0)
3711 else:
3712 if Pcd.MaxDatumSize is None or Pcd.MaxDatumSize == '':
3713 EdkLogger.error("build", AUTOGEN_ERROR,
3714 "Unknown [MaxDatumSize] of PCD [%s.%s]" % (Pcd.TokenSpaceGuidCName, TokenCName)
3715 )
3716 ArraySize = int(Pcd.MaxDatumSize, 0)
3717 PcdValue = Pcd.DefaultValue
3718 if PcdValue[0] != '{':
3719 Unicode = False
3720 if PcdValue[0] == 'L':
3721 Unicode = True
3722 PcdValue = PcdValue.lstrip('L')
3723 PcdValue = eval(PcdValue)
3724 NewValue = '{'
3725 for Index in range(0, len(PcdValue)):
3726 if Unicode:
3727 CharVal = ord(PcdValue[Index])
3728 NewValue = NewValue + '0x%02x' % (CharVal & 0x00FF) + ', ' \
3729 + '0x%02x' % (CharVal >> 8) + ', '
3730 else:
3731 NewValue = NewValue + '0x%02x' % (ord(PcdValue[Index]) % 0x100) + ', '
3732 Padding = '0x00, '
3733 if Unicode:
3734 Padding = Padding * 2
3735 ArraySize = ArraySize // 2
3736 if ArraySize < (len(PcdValue) + 1):
3737 if Pcd.MaxSizeUserSet:
3738 EdkLogger.error("build", AUTOGEN_ERROR,
3739 "The maximum size of VOID* type PCD '%s.%s' is less than its actual size occupied." % (Pcd.TokenSpaceGuidCName, TokenCName)
3740 )
3741 else:
3742 ArraySize = len(PcdValue) + 1
3743 if ArraySize > len(PcdValue) + 1:
3744 NewValue = NewValue + Padding * (ArraySize - len(PcdValue) - 1)
3745 PcdValue = NewValue + Padding.strip().rstrip(',') + '}'
3746 elif len(PcdValue.split(',')) <= ArraySize:
3747 PcdValue = PcdValue.rstrip('}') + ', 0x00' * (ArraySize - len(PcdValue.split(',')))
3748 PcdValue += '}'
3749 else:
3750 if Pcd.MaxSizeUserSet:
3751 EdkLogger.error("build", AUTOGEN_ERROR,
3752 "The maximum size of VOID* type PCD '%s.%s' is less than its actual size occupied." % (Pcd.TokenSpaceGuidCName, TokenCName)
3753 )
3754 else:
3755 ArraySize = len(PcdValue) + 1
3756 PcdItem = '%s.%s|%s|0x%X' % \
3757 (Pcd.TokenSpaceGuidCName, TokenCName, PcdValue, PatchPcd[1])
3758 PcdComments = ''
3759 if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) in self._PcdComments:
3760 PcdComments = '\n '.join(self._PcdComments[Pcd.TokenSpaceGuidCName, Pcd.TokenCName])
3761 if PcdComments:
3762 PcdItem = PcdComments + '\n ' + PcdItem
3763 AsBuiltInfDict['patchablepcd_item'].append(PcdItem)
3764
3765 for Pcd in Pcds + VfrPcds:
3766 PcdCommentList = []
3767 HiiInfo = ''
3768 TokenCName = Pcd.TokenCName
3769 for PcdItem in GlobalData.MixedPcd:
3770 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
3771 TokenCName = PcdItem[0]
3772 break
3773 if Pcd.Type == TAB_PCDS_DYNAMIC_EX_HII:
3774 for SkuName in Pcd.SkuInfoList:
3775 SkuInfo = Pcd.SkuInfoList[SkuName]
3776 HiiInfo = '## %s|%s|%s' % (SkuInfo.VariableName, SkuInfo.VariableGuid, SkuInfo.VariableOffset)
3777 break
3778 if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) in self._PcdComments:
3779 PcdCommentList = self._PcdComments[Pcd.TokenSpaceGuidCName, Pcd.TokenCName][:]
3780 if HiiInfo:
3781 UsageIndex = -1
3782 UsageStr = ''
3783 for Index, Comment in enumerate(PcdCommentList):
3784 for Usage in UsageList:
3785 if Comment.find(Usage) != -1:
3786 UsageStr = Usage
3787 UsageIndex = Index
3788 break
3789 if UsageIndex != -1:
3790 PcdCommentList[UsageIndex] = '## %s %s %s' % (UsageStr, HiiInfo, PcdCommentList[UsageIndex].replace(UsageStr, ''))
3791 else:
3792 PcdCommentList.append('## UNDEFINED ' + HiiInfo)
3793 PcdComments = '\n '.join(PcdCommentList)
3794 PcdEntry = Pcd.TokenSpaceGuidCName + '.' + TokenCName
3795 if PcdComments:
3796 PcdEntry = PcdComments + '\n ' + PcdEntry
3797 AsBuiltInfDict['pcd_item'].append(PcdEntry)
3798 for Item in self.BuildOption:
3799 if 'FLAGS' in self.BuildOption[Item]:
3800 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()))
3801
3802 # Generated LibraryClasses section in comments.
3803 for Library in self.LibraryAutoGenList:
3804 AsBuiltInfDict['libraryclasses_item'].append(Library.MetaFile.File.replace('\\', '/'))
3805
3806 # Generated UserExtensions TianoCore section.
3807 # All tianocore user extensions are copied.
3808 UserExtStr = ''
3809 for TianoCore in self._GetTianoCoreUserExtensionList():
3810 UserExtStr += '\n'.join(TianoCore)
3811 ExtensionFile = os.path.join(self.MetaFile.Dir, TianoCore[1])
3812 if os.path.isfile(ExtensionFile):
3813 shutil.copy2(ExtensionFile, self.OutputDir)
3814 AsBuiltInfDict['userextension_tianocore_item'] = UserExtStr
3815
3816 # Generated depex expression section in comments.
3817 DepexExpresion = self._GetDepexExpresionString()
3818 AsBuiltInfDict['depexsection_item'] = DepexExpresion if DepexExpresion else ''
3819
3820 AsBuiltInf = TemplateString()
3821 AsBuiltInf.Append(gAsBuiltInfHeaderString.Replace(AsBuiltInfDict))
3822
3823 SaveFileOnChange(os.path.join(self.OutputDir, self.Name + '.inf'), str(AsBuiltInf), False)
3824
3825 self.IsAsBuiltInfCreated = True
3826 if GlobalData.gBinCacheDest:
3827 self.CopyModuleToCache()
3828
3829 def CopyModuleToCache(self):
3830 FileDir = path.join(GlobalData.gBinCacheDest, self.Arch, self.SourceDir, self.MetaFile.BaseName)
3831 CreateDirectory (FileDir)
3832 HashFile = path.join(self.BuildDir, self.Name + '.hash')
3833 ModuleFile = path.join(self.OutputDir, self.Name + '.inf')
3834 if os.path.exists(HashFile):
3835 shutil.copy2(HashFile, FileDir)
3836 if os.path.exists(ModuleFile):
3837 shutil.copy2(ModuleFile, FileDir)
3838 if not self.OutputFile:
3839 Ma = self.BuildDatabase[PathClass(ModuleFile), self.Arch, self.BuildTarget, self.ToolChain]
3840 self.OutputFile = Ma.Binaries
3841 if self.OutputFile:
3842 for File in self.OutputFile:
3843 File = str(File)
3844 if not os.path.isabs(File):
3845 File = os.path.join(self.OutputDir, File)
3846 if os.path.exists(File):
3847 shutil.copy2(File, FileDir)
3848
3849 def AttemptModuleCacheCopy(self):
3850 if self.IsBinaryModule:
3851 return False
3852 FileDir = path.join(GlobalData.gBinCacheSource, self.Arch, self.SourceDir, self.MetaFile.BaseName)
3853 HashFile = path.join(FileDir, self.Name + '.hash')
3854 if os.path.exists(HashFile):
3855 f = open(HashFile, 'r')
3856 CacheHash = f.read()
3857 f.close()
3858 if GlobalData.gModuleHash[self.Arch][self.Name]:
3859 if CacheHash == GlobalData.gModuleHash[self.Arch][self.Name]:
3860 for root, dir, files in os.walk(FileDir):
3861 for f in files:
3862 if self.Name + '.hash' in f:
3863 shutil.copy2(HashFile, self.BuildDir)
3864 else:
3865 File = path.join(root, f)
3866 shutil.copy2(File, self.OutputDir)
3867 if self.Name == "PcdPeim" or self.Name == "PcdDxe":
3868 CreatePcdDatabaseCode(self, TemplateString(), TemplateString())
3869 return True
3870 return False
3871
3872 ## Create makefile for the module and its dependent libraries
3873 #
3874 # @param CreateLibraryMakeFile Flag indicating if or not the makefiles of
3875 # dependent libraries will be created
3876 #
3877 @cached_class_function
3878 def CreateMakeFile(self, CreateLibraryMakeFile=True, GenFfsList = []):
3879 # nest this function inside it's only caller.
3880 def CreateTimeStamp():
3881 FileSet = {self.MetaFile.Path}
3882
3883 for SourceFile in self.Module.Sources:
3884 FileSet.add (SourceFile.Path)
3885
3886 for Lib in self.DependentLibraryList:
3887 FileSet.add (Lib.MetaFile.Path)
3888
3889 for f in self.AutoGenDepSet:
3890 FileSet.add (f.Path)
3891
3892 if os.path.exists (self.TimeStampPath):
3893 os.remove (self.TimeStampPath)
3894 with open(self.TimeStampPath, 'w+') as file:
3895 for f in sorted(FileSet):
3896 print(f, file=file)
3897
3898 # Ignore generating makefile when it is a binary module
3899 if self.IsBinaryModule:
3900 return
3901
3902 self.GenFfsList = GenFfsList
3903 if not self.IsLibrary and CreateLibraryMakeFile:
3904 for LibraryAutoGen in self.LibraryAutoGenList:
3905 LibraryAutoGen.CreateMakeFile()
3906
3907 if self.CanSkip():
3908 return
3909
3910 if len(self.CustomMakefile) == 0:
3911 Makefile = GenMake.ModuleMakefile(self)
3912 else:
3913 Makefile = GenMake.CustomMakefile(self)
3914 if Makefile.Generate():
3915 EdkLogger.debug(EdkLogger.DEBUG_9, "Generated makefile for module %s [%s]" %
3916 (self.Name, self.Arch))
3917 else:
3918 EdkLogger.debug(EdkLogger.DEBUG_9, "Skipped the generation of makefile for module %s [%s]" %
3919 (self.Name, self.Arch))
3920
3921 CreateTimeStamp()
3922
3923 def CopyBinaryFiles(self):
3924 for File in self.Module.Binaries:
3925 SrcPath = File.Path
3926 DstPath = os.path.join(self.OutputDir, os.path.basename(SrcPath))
3927 CopyLongFilePath(SrcPath, DstPath)
3928 ## Create autogen code for the module and its dependent libraries
3929 #
3930 # @param CreateLibraryCodeFile Flag indicating if or not the code of
3931 # dependent libraries will be created
3932 #
3933 def CreateCodeFile(self, CreateLibraryCodeFile=True):
3934 if self.IsCodeFileCreated:
3935 return
3936
3937 # Need to generate PcdDatabase even PcdDriver is binarymodule
3938 if self.IsBinaryModule and self.PcdIsDriver != '':
3939 CreatePcdDatabaseCode(self, TemplateString(), TemplateString())
3940 return
3941 if self.IsBinaryModule:
3942 if self.IsLibrary:
3943 self.CopyBinaryFiles()
3944 return
3945
3946 if not self.IsLibrary and CreateLibraryCodeFile:
3947 for LibraryAutoGen in self.LibraryAutoGenList:
3948 LibraryAutoGen.CreateCodeFile()
3949
3950 if self.CanSkip():
3951 return
3952
3953 AutoGenList = []
3954 IgoredAutoGenList = []
3955
3956 for File in self.AutoGenFileList:
3957 if GenC.Generate(File.Path, self.AutoGenFileList[File], File.IsBinary):
3958 #Ignore Edk AutoGen.c
3959 if self.AutoGenVersion < 0x00010005 and File.Name == 'AutoGen.c':
3960 continue
3961
3962 AutoGenList.append(str(File))
3963 else:
3964 IgoredAutoGenList.append(str(File))
3965
3966 # Skip the following code for EDK I inf
3967 if self.AutoGenVersion < 0x00010005:
3968 return
3969
3970 for ModuleType in self.DepexList:
3971 # Ignore empty [depex] section or [depex] section for SUP_MODULE_USER_DEFINED module
3972 if len(self.DepexList[ModuleType]) == 0 or ModuleType == SUP_MODULE_USER_DEFINED:
3973 continue
3974
3975 Dpx = GenDepex.DependencyExpression(self.DepexList[ModuleType], ModuleType, True)
3976 DpxFile = gAutoGenDepexFileName % {"module_name" : self.Name}
3977
3978 if len(Dpx.PostfixNotation) != 0:
3979 self.DepexGenerated = True
3980
3981 if Dpx.Generate(path.join(self.OutputDir, DpxFile)):
3982 AutoGenList.append(str(DpxFile))
3983 else:
3984 IgoredAutoGenList.append(str(DpxFile))
3985
3986 if IgoredAutoGenList == []:
3987 EdkLogger.debug(EdkLogger.DEBUG_9, "Generated [%s] files for module %s [%s]" %
3988 (" ".join(AutoGenList), self.Name, self.Arch))
3989 elif AutoGenList == []:
3990 EdkLogger.debug(EdkLogger.DEBUG_9, "Skipped the generation of [%s] files for module %s [%s]" %
3991 (" ".join(IgoredAutoGenList), self.Name, self.Arch))
3992 else:
3993 EdkLogger.debug(EdkLogger.DEBUG_9, "Generated [%s] (skipped %s) files for module %s [%s]" %
3994 (" ".join(AutoGenList), " ".join(IgoredAutoGenList), self.Name, self.Arch))
3995
3996 self.IsCodeFileCreated = True
3997 return AutoGenList
3998
3999 ## Summarize the ModuleAutoGen objects of all libraries used by this module
4000 @cached_property
4001 def LibraryAutoGenList(self):
4002 RetVal = []
4003 for Library in self.DependentLibraryList:
4004 La = ModuleAutoGen(
4005 self.Workspace,
4006 Library.MetaFile,
4007 self.BuildTarget,
4008 self.ToolChain,
4009 self.Arch,
4010 self.PlatformInfo.MetaFile
4011 )
4012 if La not in RetVal:
4013 RetVal.append(La)
4014 for Lib in La.CodaTargetList:
4015 self._ApplyBuildRule(Lib.Target, TAB_UNKNOWN_FILE)
4016 return RetVal
4017
4018 def GenModuleHash(self):
4019 if self.Arch not in GlobalData.gModuleHash:
4020 GlobalData.gModuleHash[self.Arch] = {}
4021 m = hashlib.md5()
4022 # Add Platform level hash
4023 m.update(GlobalData.gPlatformHash.encode('utf-8'))
4024 # Add Package level hash
4025 if self.DependentPackageList:
4026 for Pkg in sorted(self.DependentPackageList, key=lambda x: x.PackageName):
4027 if Pkg.PackageName in GlobalData.gPackageHash[self.Arch]:
4028 m.update(GlobalData.gPackageHash[self.Arch][Pkg.PackageName].encode('utf-8'))
4029
4030 # Add Library hash
4031 if self.LibraryAutoGenList:
4032 for Lib in sorted(self.LibraryAutoGenList, key=lambda x: x.Name):
4033 if Lib.Name not in GlobalData.gModuleHash[self.Arch]:
4034 Lib.GenModuleHash()
4035 m.update(GlobalData.gModuleHash[self.Arch][Lib.Name].encode('utf-8'))
4036
4037 # Add Module self
4038 f = open(str(self.MetaFile), 'rb')
4039 Content = f.read()
4040 f.close()
4041 m.update(Content)
4042 # Add Module's source files
4043 if self.SourceFileList:
4044 for File in sorted(self.SourceFileList, key=lambda x: str(x)):
4045 f = open(str(File), 'rb')
4046 Content = f.read()
4047 f.close()
4048 m.update(Content)
4049
4050 ModuleHashFile = path.join(self.BuildDir, self.Name + ".hash")
4051 if self.Name not in GlobalData.gModuleHash[self.Arch]:
4052 GlobalData.gModuleHash[self.Arch][self.Name] = m.hexdigest()
4053 if GlobalData.gBinCacheSource:
4054 if self.AttemptModuleCacheCopy():
4055 return False
4056 return SaveFileOnChange(ModuleHashFile, m.hexdigest(), True)
4057
4058 ## Decide whether we can skip the ModuleAutoGen process
4059 def CanSkipbyHash(self):
4060 if GlobalData.gUseHashCache:
4061 return not self.GenModuleHash()
4062 return False
4063
4064 ## Decide whether we can skip the ModuleAutoGen process
4065 # If any source file is newer than the module than we cannot skip
4066 #
4067 def CanSkip(self):
4068 if self.MakeFileDir in GlobalData.gSikpAutoGenCache:
4069 return True
4070 if not os.path.exists(self.TimeStampPath):
4071 return False
4072 #last creation time of the module
4073 DstTimeStamp = os.stat(self.TimeStampPath)[8]
4074
4075 SrcTimeStamp = self.Workspace._SrcTimeStamp
4076 if SrcTimeStamp > DstTimeStamp:
4077 return False
4078
4079 with open(self.TimeStampPath,'r') as f:
4080 for source in f:
4081 source = source.rstrip('\n')
4082 if not os.path.exists(source):
4083 return False
4084 if source not in ModuleAutoGen.TimeDict :
4085 ModuleAutoGen.TimeDict[source] = os.stat(source)[8]
4086 if ModuleAutoGen.TimeDict[source] > DstTimeStamp:
4087 return False
4088 GlobalData.gSikpAutoGenCache.add(self.MakeFileDir)
4089 return True
4090
4091 @cached_property
4092 def TimeStampPath(self):
4093 return os.path.join(self.MakeFileDir, 'AutoGenTimeStamp')