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