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