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