]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/AutoGen/AutoGen.py
BaseTool/Build: Add --disable-include-path-check.
[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 list(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:[SkuObj for SkuObj in PcdNvStoreDfBuffer[0].SkuInfoList.values() ]}
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 FixedVoidTypePcds = {}
2896 if item in self.FixedVoidTypePcds:
2897 FixedVoidTypePcds = self.FixedVoidTypePcds
2898 elif M in self.PlatformInfo.LibraryAutoGenList:
2899 Index = self.PlatformInfo.LibraryAutoGenList.index(M)
2900 FixedVoidTypePcds = self.PlatformInfo.LibraryAutoGenList[Index].FixedVoidTypePcds
2901 if item not in FixedVoidTypePcds:
2902 EdkLogger.error("build", FORMAT_INVALID, "{} used in [Depex] section should be used as FixedAtBuild type and VOID* datum type in the module.".format(item))
2903 else:
2904 Value = FixedVoidTypePcds[item]
2905 if len(Value.split(',')) != 16:
2906 EdkLogger.error("build", FORMAT_INVALID,
2907 "{} used in [Depex] section should be used as FixedAtBuild type and VOID* datum type and 16 bytes in the module.".format(item))
2908 NewList.append(Value)
2909 DepexList.extend(NewList)
2910 if DepexList[-1] == 'END': # no need of a END at this time
2911 DepexList.pop()
2912 DepexList.append(')')
2913 Inherited = True
2914 if Inherited:
2915 EdkLogger.verbose("DEPEX[%s] (+%s) = %s" % (self.Name, M.BaseName, DepexList))
2916 if 'BEFORE' in DepexList or 'AFTER' in DepexList:
2917 break
2918 if len(DepexList) > 0:
2919 EdkLogger.verbose('')
2920 return {self.ModuleType:DepexList}
2921
2922 ## Merge dependency expression
2923 #
2924 # @retval list The token list of the dependency expression after parsed
2925 #
2926 @cached_property
2927 def DepexExpressionDict(self):
2928 if self.DxsFile or self.IsLibrary or TAB_DEPENDENCY_EXPRESSION_FILE in self.FileTypes:
2929 return {}
2930
2931 DepexExpressionString = ''
2932 #
2933 # Append depex from dependent libraries, if not "BEFORE", "AFTER" expresion
2934 #
2935 for M in [self.Module] + self.DependentLibraryList:
2936 Inherited = False
2937 for D in M.DepexExpression[self.Arch, self.ModuleType]:
2938 if DepexExpressionString != '':
2939 DepexExpressionString += ' AND '
2940 DepexExpressionString += '('
2941 DepexExpressionString += D
2942 DepexExpressionString = DepexExpressionString.rstrip('END').strip()
2943 DepexExpressionString += ')'
2944 Inherited = True
2945 if Inherited:
2946 EdkLogger.verbose("DEPEX[%s] (+%s) = %s" % (self.Name, M.BaseName, DepexExpressionString))
2947 if 'BEFORE' in DepexExpressionString or 'AFTER' in DepexExpressionString:
2948 break
2949 if len(DepexExpressionString) > 0:
2950 EdkLogger.verbose('')
2951
2952 return {self.ModuleType:DepexExpressionString}
2953
2954 # Get the tiano core user extension, it is contain dependent library.
2955 # @retval: a list contain tiano core userextension.
2956 #
2957 def _GetTianoCoreUserExtensionList(self):
2958 TianoCoreUserExtentionList = []
2959 for M in [self.Module] + self.DependentLibraryList:
2960 Filename = M.MetaFile.Path
2961 InfObj = InfSectionParser.InfSectionParser(Filename)
2962 TianoCoreUserExtenList = InfObj.GetUserExtensionTianoCore()
2963 for TianoCoreUserExtent in TianoCoreUserExtenList:
2964 for Section in TianoCoreUserExtent:
2965 ItemList = Section.split(TAB_SPLIT)
2966 Arch = self.Arch
2967 if len(ItemList) == 4:
2968 Arch = ItemList[3]
2969 if Arch.upper() == TAB_ARCH_COMMON or Arch.upper() == self.Arch.upper():
2970 TianoCoreList = []
2971 TianoCoreList.extend([TAB_SECTION_START + Section + TAB_SECTION_END])
2972 TianoCoreList.extend(TianoCoreUserExtent[Section][:])
2973 TianoCoreList.append('\n')
2974 TianoCoreUserExtentionList.append(TianoCoreList)
2975
2976 return TianoCoreUserExtentionList
2977
2978 ## Return the list of specification version required for the module
2979 #
2980 # @retval list The list of specification defined in module file
2981 #
2982 @cached_property
2983 def Specification(self):
2984 return self.Module.Specification
2985
2986 ## Tool option for the module build
2987 #
2988 # @param PlatformInfo The object of PlatformBuildInfo
2989 # @retval dict The dict containing valid options
2990 #
2991 @cached_property
2992 def BuildOption(self):
2993 RetVal, self.BuildRuleOrder = self.PlatformInfo.ApplyBuildOption(self.Module)
2994 if self.BuildRuleOrder:
2995 self.BuildRuleOrder = ['.%s' % Ext for Ext in self.BuildRuleOrder.split()]
2996 return RetVal
2997
2998 ## Get include path list from tool option for the module build
2999 #
3000 # @retval list The include path list
3001 #
3002 @cached_property
3003 def BuildOptionIncPathList(self):
3004 #
3005 # Regular expression for finding Include Directories, the difference between MSFT and INTEL/GCC/RVCT
3006 # is the former use /I , the Latter used -I to specify include directories
3007 #
3008 if self.PlatformInfo.ToolChainFamily in (TAB_COMPILER_MSFT):
3009 BuildOptIncludeRegEx = gBuildOptIncludePatternMsft
3010 elif self.PlatformInfo.ToolChainFamily in ('INTEL', 'GCC', 'RVCT'):
3011 BuildOptIncludeRegEx = gBuildOptIncludePatternOther
3012 else:
3013 #
3014 # New ToolChainFamily, don't known whether there is option to specify include directories
3015 #
3016 return []
3017
3018 RetVal = []
3019 for Tool in ('CC', 'PP', 'VFRPP', 'ASLPP', 'ASLCC', 'APP', 'ASM'):
3020 try:
3021 FlagOption = self.BuildOption[Tool]['FLAGS']
3022 except KeyError:
3023 FlagOption = ''
3024
3025 if self.ToolChainFamily != 'RVCT':
3026 IncPathList = [NormPath(Path, self.Macros) for Path in BuildOptIncludeRegEx.findall(FlagOption)]
3027 else:
3028 #
3029 # RVCT may specify a list of directory seperated by commas
3030 #
3031 IncPathList = []
3032 for Path in BuildOptIncludeRegEx.findall(FlagOption):
3033 PathList = GetSplitList(Path, TAB_COMMA_SPLIT)
3034 IncPathList.extend(NormPath(PathEntry, self.Macros) for PathEntry in PathList)
3035
3036 #
3037 # EDK II modules must not reference header files outside of the packages they depend on or
3038 # within the module's directory tree. Report error if violation.
3039 #
3040 if GlobalData.gDisableIncludePathCheck == False:
3041 for Path in IncPathList:
3042 if (Path not in self.IncludePathList) and (CommonPath([Path, self.MetaFile.Dir]) != self.MetaFile.Dir):
3043 ErrMsg = "The include directory for the EDK II module in this line is invalid %s specified in %s FLAGS '%s'" % (Path, Tool, FlagOption)
3044 EdkLogger.error("build",
3045 PARAMETER_INVALID,
3046 ExtraData=ErrMsg,
3047 File=str(self.MetaFile))
3048 RetVal += IncPathList
3049 return RetVal
3050
3051 ## Return a list of files which can be built from source
3052 #
3053 # What kind of files can be built is determined by build rules in
3054 # $(CONF_DIRECTORY)/build_rule.txt and toolchain family.
3055 #
3056 @cached_property
3057 def SourceFileList(self):
3058 RetVal = []
3059 ToolChainTagSet = {"", TAB_STAR, self.ToolChain}
3060 ToolChainFamilySet = {"", TAB_STAR, self.ToolChainFamily, self.BuildRuleFamily}
3061 for F in self.Module.Sources:
3062 # match tool chain
3063 if F.TagName not in ToolChainTagSet:
3064 EdkLogger.debug(EdkLogger.DEBUG_9, "The toolchain [%s] for processing file [%s] is found, "
3065 "but [%s] is currently used" % (F.TagName, str(F), self.ToolChain))
3066 continue
3067 # match tool chain family or build rule family
3068 if F.ToolChainFamily not in ToolChainFamilySet:
3069 EdkLogger.debug(
3070 EdkLogger.DEBUG_0,
3071 "The file [%s] must be built by tools of [%s], " \
3072 "but current toolchain family is [%s], buildrule family is [%s]" \
3073 % (str(F), F.ToolChainFamily, self.ToolChainFamily, self.BuildRuleFamily))
3074 continue
3075
3076 # add the file path into search path list for file including
3077 if F.Dir not in self.IncludePathList:
3078 self.IncludePathList.insert(0, F.Dir)
3079 RetVal.append(F)
3080
3081 self._MatchBuildRuleOrder(RetVal)
3082
3083 for F in RetVal:
3084 self._ApplyBuildRule(F, TAB_UNKNOWN_FILE)
3085 return RetVal
3086
3087 def _MatchBuildRuleOrder(self, FileList):
3088 Order_Dict = {}
3089 self.BuildOption
3090 for SingleFile in FileList:
3091 if self.BuildRuleOrder and SingleFile.Ext in self.BuildRuleOrder and SingleFile.Ext in self.BuildRules:
3092 key = SingleFile.Path.rsplit(SingleFile.Ext,1)[0]
3093 if key in Order_Dict:
3094 Order_Dict[key].append(SingleFile.Ext)
3095 else:
3096 Order_Dict[key] = [SingleFile.Ext]
3097
3098 RemoveList = []
3099 for F in Order_Dict:
3100 if len(Order_Dict[F]) > 1:
3101 Order_Dict[F].sort(key=lambda i: self.BuildRuleOrder.index(i))
3102 for Ext in Order_Dict[F][1:]:
3103 RemoveList.append(F + Ext)
3104
3105 for item in RemoveList:
3106 FileList.remove(item)
3107
3108 return FileList
3109
3110 ## Return the list of unicode files
3111 @cached_property
3112 def UnicodeFileList(self):
3113 return self.FileTypes.get(TAB_UNICODE_FILE,[])
3114
3115 ## Return the list of vfr files
3116 @cached_property
3117 def VfrFileList(self):
3118 return self.FileTypes.get(TAB_VFR_FILE, [])
3119
3120 ## Return the list of Image Definition files
3121 @cached_property
3122 def IdfFileList(self):
3123 return self.FileTypes.get(TAB_IMAGE_FILE,[])
3124
3125 ## Return a list of files which can be built from binary
3126 #
3127 # "Build" binary files are just to copy them to build directory.
3128 #
3129 # @retval list The list of files which can be built later
3130 #
3131 @cached_property
3132 def BinaryFileList(self):
3133 RetVal = []
3134 for F in self.Module.Binaries:
3135 if F.Target not in [TAB_ARCH_COMMON, TAB_STAR] and F.Target != self.BuildTarget:
3136 continue
3137 RetVal.append(F)
3138 self._ApplyBuildRule(F, F.Type, BinaryFileList=RetVal)
3139 return RetVal
3140
3141 @cached_property
3142 def BuildRules(self):
3143 RetVal = {}
3144 BuildRuleDatabase = self.PlatformInfo.BuildRule
3145 for Type in BuildRuleDatabase.FileTypeList:
3146 #first try getting build rule by BuildRuleFamily
3147 RuleObject = BuildRuleDatabase[Type, self.BuildType, self.Arch, self.BuildRuleFamily]
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.BuildRuleFamily]
3152 #second try getting build rule by ToolChainFamily
3153 if not RuleObject:
3154 RuleObject = BuildRuleDatabase[Type, self.BuildType, self.Arch, self.ToolChainFamily]
3155 if not RuleObject:
3156 # build type is always module type, but ...
3157 if self.ModuleType != self.BuildType:
3158 RuleObject = BuildRuleDatabase[Type, self.ModuleType, self.Arch, self.ToolChainFamily]
3159 if not RuleObject:
3160 continue
3161 RuleObject = RuleObject.Instantiate(self.Macros)
3162 RetVal[Type] = RuleObject
3163 for Ext in RuleObject.SourceFileExtList:
3164 RetVal[Ext] = RuleObject
3165 return RetVal
3166
3167 def _ApplyBuildRule(self, File, FileType, BinaryFileList=None):
3168 if self._BuildTargets is None:
3169 self._IntroBuildTargetList = set()
3170 self._FinalBuildTargetList = set()
3171 self._BuildTargets = defaultdict(set)
3172 self._FileTypes = defaultdict(set)
3173
3174 if not BinaryFileList:
3175 BinaryFileList = self.BinaryFileList
3176
3177 SubDirectory = os.path.join(self.OutputDir, File.SubDir)
3178 if not os.path.exists(SubDirectory):
3179 CreateDirectory(SubDirectory)
3180 LastTarget = None
3181 RuleChain = set()
3182 SourceList = [File]
3183 Index = 0
3184 #
3185 # Make sure to get build rule order value
3186 #
3187 self.BuildOption
3188
3189 while Index < len(SourceList):
3190 Source = SourceList[Index]
3191 Index = Index + 1
3192
3193 if Source != File:
3194 CreateDirectory(Source.Dir)
3195
3196 if File.IsBinary and File == Source and File in BinaryFileList:
3197 # Skip all files that are not binary libraries
3198 if not self.IsLibrary:
3199 continue
3200 RuleObject = self.BuildRules[TAB_DEFAULT_BINARY_FILE]
3201 elif FileType in self.BuildRules:
3202 RuleObject = self.BuildRules[FileType]
3203 elif Source.Ext in self.BuildRules:
3204 RuleObject = self.BuildRules[Source.Ext]
3205 else:
3206 # stop at no more rules
3207 if LastTarget:
3208 self._FinalBuildTargetList.add(LastTarget)
3209 break
3210
3211 FileType = RuleObject.SourceFileType
3212 self._FileTypes[FileType].add(Source)
3213
3214 # stop at STATIC_LIBRARY for library
3215 if self.IsLibrary and FileType == TAB_STATIC_LIBRARY:
3216 if LastTarget:
3217 self._FinalBuildTargetList.add(LastTarget)
3218 break
3219
3220 Target = RuleObject.Apply(Source, self.BuildRuleOrder)
3221 if not Target:
3222 if LastTarget:
3223 self._FinalBuildTargetList.add(LastTarget)
3224 break
3225 elif not Target.Outputs:
3226 # Only do build for target with outputs
3227 self._FinalBuildTargetList.add(Target)
3228
3229 self._BuildTargets[FileType].add(Target)
3230
3231 if not Source.IsBinary and Source == File:
3232 self._IntroBuildTargetList.add(Target)
3233
3234 # to avoid cyclic rule
3235 if FileType in RuleChain:
3236 break
3237
3238 RuleChain.add(FileType)
3239 SourceList.extend(Target.Outputs)
3240 LastTarget = Target
3241 FileType = TAB_UNKNOWN_FILE
3242
3243 @cached_property
3244 def Targets(self):
3245 if self._BuildTargets is None:
3246 self._IntroBuildTargetList = set()
3247 self._FinalBuildTargetList = set()
3248 self._BuildTargets = defaultdict(set)
3249 self._FileTypes = defaultdict(set)
3250
3251 #TRICK: call SourceFileList property to apply build rule for source files
3252 self.SourceFileList
3253
3254 #TRICK: call _GetBinaryFileList to apply build rule for binary files
3255 self.BinaryFileList
3256
3257 return self._BuildTargets
3258
3259 @cached_property
3260 def IntroTargetList(self):
3261 self.Targets
3262 return self._IntroBuildTargetList
3263
3264 @cached_property
3265 def CodaTargetList(self):
3266 self.Targets
3267 return self._FinalBuildTargetList
3268
3269 @cached_property
3270 def FileTypes(self):
3271 self.Targets
3272 return self._FileTypes
3273
3274 ## Get the list of package object the module depends on
3275 #
3276 # @retval list The package object list
3277 #
3278 @cached_property
3279 def DependentPackageList(self):
3280 return self.Module.Packages
3281
3282 ## Return the list of auto-generated code file
3283 #
3284 # @retval list The list of auto-generated file
3285 #
3286 @cached_property
3287 def AutoGenFileList(self):
3288 AutoGenUniIdf = self.BuildType != 'UEFI_HII'
3289 UniStringBinBuffer = BytesIO()
3290 IdfGenBinBuffer = BytesIO()
3291 RetVal = {}
3292 AutoGenC = TemplateString()
3293 AutoGenH = TemplateString()
3294 StringH = TemplateString()
3295 StringIdf = TemplateString()
3296 GenC.CreateCode(self, AutoGenC, AutoGenH, StringH, AutoGenUniIdf, UniStringBinBuffer, StringIdf, AutoGenUniIdf, IdfGenBinBuffer)
3297 #
3298 # AutoGen.c is generated if there are library classes in inf, or there are object files
3299 #
3300 if str(AutoGenC) != "" and (len(self.Module.LibraryClasses) > 0
3301 or TAB_OBJECT_FILE in self.FileTypes):
3302 AutoFile = PathClass(gAutoGenCodeFileName, self.DebugDir)
3303 RetVal[AutoFile] = str(AutoGenC)
3304 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3305 if str(AutoGenH) != "":
3306 AutoFile = PathClass(gAutoGenHeaderFileName, self.DebugDir)
3307 RetVal[AutoFile] = str(AutoGenH)
3308 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3309 if str(StringH) != "":
3310 AutoFile = PathClass(gAutoGenStringFileName % {"module_name":self.Name}, self.DebugDir)
3311 RetVal[AutoFile] = str(StringH)
3312 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3313 if UniStringBinBuffer is not None and UniStringBinBuffer.getvalue() != b"":
3314 AutoFile = PathClass(gAutoGenStringFormFileName % {"module_name":self.Name}, self.OutputDir)
3315 RetVal[AutoFile] = UniStringBinBuffer.getvalue()
3316 AutoFile.IsBinary = True
3317 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3318 if UniStringBinBuffer is not None:
3319 UniStringBinBuffer.close()
3320 if str(StringIdf) != "":
3321 AutoFile = PathClass(gAutoGenImageDefFileName % {"module_name":self.Name}, self.DebugDir)
3322 RetVal[AutoFile] = str(StringIdf)
3323 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3324 if IdfGenBinBuffer is not None and IdfGenBinBuffer.getvalue() != b"":
3325 AutoFile = PathClass(gAutoGenIdfFileName % {"module_name":self.Name}, self.OutputDir)
3326 RetVal[AutoFile] = IdfGenBinBuffer.getvalue()
3327 AutoFile.IsBinary = True
3328 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3329 if IdfGenBinBuffer is not None:
3330 IdfGenBinBuffer.close()
3331 return RetVal
3332
3333 ## Return the list of library modules explicitly or implicitly used by this module
3334 @cached_property
3335 def DependentLibraryList(self):
3336 # only merge library classes and PCD for non-library module
3337 if self.IsLibrary:
3338 return []
3339 return self.PlatformInfo.ApplyLibraryInstance(self.Module)
3340
3341 ## Get the list of PCDs from current module
3342 #
3343 # @retval list The list of PCD
3344 #
3345 @cached_property
3346 def ModulePcdList(self):
3347 # apply PCD settings from platform
3348 RetVal = self.PlatformInfo.ApplyPcdSetting(self.Module, self.Module.Pcds)
3349 ExtendCopyDictionaryLists(self._PcdComments, self.Module.PcdComments)
3350 return RetVal
3351
3352 ## Get the list of PCDs from dependent libraries
3353 #
3354 # @retval list The list of PCD
3355 #
3356 @cached_property
3357 def LibraryPcdList(self):
3358 if self.IsLibrary:
3359 return []
3360 RetVal = []
3361 Pcds = set()
3362 # get PCDs from dependent libraries
3363 for Library in self.DependentLibraryList:
3364 PcdsInLibrary = OrderedDict()
3365 ExtendCopyDictionaryLists(self._PcdComments, Library.PcdComments)
3366 for Key in Library.Pcds:
3367 # skip duplicated PCDs
3368 if Key in self.Module.Pcds or Key in Pcds:
3369 continue
3370 Pcds.add(Key)
3371 PcdsInLibrary[Key] = copy.copy(Library.Pcds[Key])
3372 RetVal.extend(self.PlatformInfo.ApplyPcdSetting(self.Module, PcdsInLibrary, Library=Library))
3373 return RetVal
3374
3375 ## Get the GUID value mapping
3376 #
3377 # @retval dict The mapping between GUID cname and its value
3378 #
3379 @cached_property
3380 def GuidList(self):
3381 RetVal = OrderedDict(self.Module.Guids)
3382 for Library in self.DependentLibraryList:
3383 RetVal.update(Library.Guids)
3384 ExtendCopyDictionaryLists(self._GuidComments, Library.GuidComments)
3385 ExtendCopyDictionaryLists(self._GuidComments, self.Module.GuidComments)
3386 return RetVal
3387
3388 @cached_property
3389 def GetGuidsUsedByPcd(self):
3390 RetVal = OrderedDict(self.Module.GetGuidsUsedByPcd())
3391 for Library in self.DependentLibraryList:
3392 RetVal.update(Library.GetGuidsUsedByPcd())
3393 return RetVal
3394 ## Get the protocol value mapping
3395 #
3396 # @retval dict The mapping between protocol cname and its value
3397 #
3398 @cached_property
3399 def ProtocolList(self):
3400 RetVal = OrderedDict(self.Module.Protocols)
3401 for Library in self.DependentLibraryList:
3402 RetVal.update(Library.Protocols)
3403 ExtendCopyDictionaryLists(self._ProtocolComments, Library.ProtocolComments)
3404 ExtendCopyDictionaryLists(self._ProtocolComments, self.Module.ProtocolComments)
3405 return RetVal
3406
3407 ## Get the PPI value mapping
3408 #
3409 # @retval dict The mapping between PPI cname and its value
3410 #
3411 @cached_property
3412 def PpiList(self):
3413 RetVal = OrderedDict(self.Module.Ppis)
3414 for Library in self.DependentLibraryList:
3415 RetVal.update(Library.Ppis)
3416 ExtendCopyDictionaryLists(self._PpiComments, Library.PpiComments)
3417 ExtendCopyDictionaryLists(self._PpiComments, self.Module.PpiComments)
3418 return RetVal
3419
3420 ## Get the list of include search path
3421 #
3422 # @retval list The list path
3423 #
3424 @cached_property
3425 def IncludePathList(self):
3426 RetVal = []
3427 RetVal.append(self.MetaFile.Dir)
3428 RetVal.append(self.DebugDir)
3429
3430 for Package in self.Module.Packages:
3431 PackageDir = mws.join(self.WorkspaceDir, Package.MetaFile.Dir)
3432 if PackageDir not in RetVal:
3433 RetVal.append(PackageDir)
3434 IncludesList = Package.Includes
3435 if Package._PrivateIncludes:
3436 if not self.MetaFile.Path.startswith(PackageDir):
3437 IncludesList = list(set(Package.Includes).difference(set(Package._PrivateIncludes)))
3438 for Inc in IncludesList:
3439 if Inc not in RetVal:
3440 RetVal.append(str(Inc))
3441 return RetVal
3442
3443 @cached_property
3444 def IncludePathLength(self):
3445 return sum(len(inc)+1 for inc in self.IncludePathList)
3446
3447 ## Get HII EX PCDs which maybe used by VFR
3448 #
3449 # efivarstore used by VFR may relate with HII EX PCDs
3450 # Get the variable name and GUID from efivarstore and HII EX PCD
3451 # List the HII EX PCDs in As Built INF if both name and GUID match.
3452 #
3453 # @retval list HII EX PCDs
3454 #
3455 def _GetPcdsMaybeUsedByVfr(self):
3456 if not self.SourceFileList:
3457 return []
3458
3459 NameGuids = set()
3460 for SrcFile in self.SourceFileList:
3461 if SrcFile.Ext.lower() != '.vfr':
3462 continue
3463 Vfri = os.path.join(self.OutputDir, SrcFile.BaseName + '.i')
3464 if not os.path.exists(Vfri):
3465 continue
3466 VfriFile = open(Vfri, 'r')
3467 Content = VfriFile.read()
3468 VfriFile.close()
3469 Pos = Content.find('efivarstore')
3470 while Pos != -1:
3471 #
3472 # Make sure 'efivarstore' is the start of efivarstore statement
3473 # In case of the value of 'name' (name = efivarstore) is equal to 'efivarstore'
3474 #
3475 Index = Pos - 1
3476 while Index >= 0 and Content[Index] in ' \t\r\n':
3477 Index -= 1
3478 if Index >= 0 and Content[Index] != ';':
3479 Pos = Content.find('efivarstore', Pos + len('efivarstore'))
3480 continue
3481 #
3482 # 'efivarstore' must be followed by name and guid
3483 #
3484 Name = gEfiVarStoreNamePattern.search(Content, Pos)
3485 if not Name:
3486 break
3487 Guid = gEfiVarStoreGuidPattern.search(Content, Pos)
3488 if not Guid:
3489 break
3490 NameArray = _ConvertStringToByteArray('L"' + Name.group(1) + '"')
3491 NameGuids.add((NameArray, GuidStructureStringToGuidString(Guid.group(1))))
3492 Pos = Content.find('efivarstore', Name.end())
3493 if not NameGuids:
3494 return []
3495 HiiExPcds = []
3496 for Pcd in self.PlatformInfo.Platform.Pcds.values():
3497 if Pcd.Type != TAB_PCDS_DYNAMIC_EX_HII:
3498 continue
3499 for SkuInfo in Pcd.SkuInfoList.values():
3500 Value = GuidValue(SkuInfo.VariableGuid, self.PlatformInfo.PackageList, self.MetaFile.Path)
3501 if not Value:
3502 continue
3503 Name = _ConvertStringToByteArray(SkuInfo.VariableName)
3504 Guid = GuidStructureStringToGuidString(Value)
3505 if (Name, Guid) in NameGuids and Pcd not in HiiExPcds:
3506 HiiExPcds.append(Pcd)
3507 break
3508
3509 return HiiExPcds
3510
3511 def _GenOffsetBin(self):
3512 VfrUniBaseName = {}
3513 for SourceFile in self.Module.Sources:
3514 if SourceFile.Type.upper() == ".VFR" :
3515 #
3516 # search the .map file to find the offset of vfr binary in the PE32+/TE file.
3517 #
3518 VfrUniBaseName[SourceFile.BaseName] = (SourceFile.BaseName + "Bin")
3519 elif SourceFile.Type.upper() == ".UNI" :
3520 #
3521 # search the .map file to find the offset of Uni strings binary in the PE32+/TE file.
3522 #
3523 VfrUniBaseName["UniOffsetName"] = (self.Name + "Strings")
3524
3525 if not VfrUniBaseName:
3526 return None
3527 MapFileName = os.path.join(self.OutputDir, self.Name + ".map")
3528 EfiFileName = os.path.join(self.OutputDir, self.Name + ".efi")
3529 VfrUniOffsetList = GetVariableOffset(MapFileName, EfiFileName, list(VfrUniBaseName.values()))
3530 if not VfrUniOffsetList:
3531 return None
3532
3533 OutputName = '%sOffset.bin' % self.Name
3534 UniVfrOffsetFileName = os.path.join( self.OutputDir, OutputName)
3535
3536 try:
3537 fInputfile = open(UniVfrOffsetFileName, "wb+", 0)
3538 except:
3539 EdkLogger.error("build", FILE_OPEN_FAILURE, "File open failed for %s" % UniVfrOffsetFileName, None)
3540
3541 # Use a instance of BytesIO to cache data
3542 fStringIO = BytesIO()
3543
3544 for Item in VfrUniOffsetList:
3545 if (Item[0].find("Strings") != -1):
3546 #
3547 # UNI offset in image.
3548 # GUID + Offset
3549 # { 0x8913c5e0, 0x33f6, 0x4d86, { 0x9b, 0xf1, 0x43, 0xef, 0x89, 0xfc, 0x6, 0x66 } }
3550 #
3551 UniGuid = b'\xe0\xc5\x13\x89\xf63\x86M\x9b\xf1C\xef\x89\xfc\x06f'
3552 fStringIO.write(UniGuid)
3553 UniValue = pack ('Q', int (Item[1], 16))
3554 fStringIO.write (UniValue)
3555 else:
3556 #
3557 # VFR binary offset in image.
3558 # GUID + Offset
3559 # { 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2 } };
3560 #
3561 VfrGuid = b'\xb4|\xbc\xd0Gj_I\xaa\x11q\x07F\xda\x06\xa2'
3562 fStringIO.write(VfrGuid)
3563 VfrValue = pack ('Q', int (Item[1], 16))
3564 fStringIO.write (VfrValue)
3565 #
3566 # write data into file.
3567 #
3568 try :
3569 fInputfile.write (fStringIO.getvalue())
3570 except:
3571 EdkLogger.error("build", FILE_WRITE_FAILURE, "Write data to file %s failed, please check whether the "
3572 "file been locked or using by other applications." %UniVfrOffsetFileName, None)
3573
3574 fStringIO.close ()
3575 fInputfile.close ()
3576 return OutputName
3577
3578 ## Create AsBuilt INF file the module
3579 #
3580 def CreateAsBuiltInf(self, IsOnlyCopy = False):
3581 self.OutputFile = set()
3582 if IsOnlyCopy and GlobalData.gBinCacheDest:
3583 self.CopyModuleToCache()
3584 return
3585
3586 if self.IsAsBuiltInfCreated:
3587 return
3588
3589 # Skip the following code for libraries
3590 if self.IsLibrary:
3591 return
3592
3593 # Skip the following code for modules with no source files
3594 if not self.SourceFileList:
3595 return
3596
3597 # Skip the following code for modules without any binary files
3598 if self.BinaryFileList:
3599 return
3600
3601 ### TODO: How to handles mixed source and binary modules
3602
3603 # Find all DynamicEx and PatchableInModule PCDs used by this module and dependent libraries
3604 # Also find all packages that the DynamicEx PCDs depend on
3605 Pcds = []
3606 PatchablePcds = []
3607 Packages = []
3608 PcdCheckList = []
3609 PcdTokenSpaceList = []
3610 for Pcd in self.ModulePcdList + self.LibraryPcdList:
3611 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE:
3612 PatchablePcds.append(Pcd)
3613 PcdCheckList.append((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, TAB_PCDS_PATCHABLE_IN_MODULE))
3614 elif Pcd.Type in PCD_DYNAMIC_EX_TYPE_SET:
3615 if Pcd not in Pcds:
3616 Pcds.append(Pcd)
3617 PcdCheckList.append((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC_EX))
3618 PcdCheckList.append((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC))
3619 PcdTokenSpaceList.append(Pcd.TokenSpaceGuidCName)
3620 GuidList = OrderedDict(self.GuidList)
3621 for TokenSpace in self.GetGuidsUsedByPcd:
3622 # If token space is not referred by patch PCD or Ex PCD, remove the GUID from GUID list
3623 # The GUIDs in GUIDs section should really be the GUIDs in source INF or referred by Ex an patch PCDs
3624 if TokenSpace not in PcdTokenSpaceList and TokenSpace in GuidList:
3625 GuidList.pop(TokenSpace)
3626 CheckList = (GuidList, self.PpiList, self.ProtocolList, PcdCheckList)
3627 for Package in self.DerivedPackageList:
3628 if Package in Packages:
3629 continue
3630 BeChecked = (Package.Guids, Package.Ppis, Package.Protocols, Package.Pcds)
3631 Found = False
3632 for Index in range(len(BeChecked)):
3633 for Item in CheckList[Index]:
3634 if Item in BeChecked[Index]:
3635 Packages.append(Package)
3636 Found = True
3637 break
3638 if Found:
3639 break
3640
3641 VfrPcds = self._GetPcdsMaybeUsedByVfr()
3642 for Pkg in self.PlatformInfo.PackageList:
3643 if Pkg in Packages:
3644 continue
3645 for VfrPcd in VfrPcds:
3646 if ((VfrPcd.TokenCName, VfrPcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC_EX) in Pkg.Pcds or
3647 (VfrPcd.TokenCName, VfrPcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC) in Pkg.Pcds):
3648 Packages.append(Pkg)
3649 break
3650
3651 ModuleType = SUP_MODULE_DXE_DRIVER if self.ModuleType == SUP_MODULE_UEFI_DRIVER and self.DepexGenerated else self.ModuleType
3652 DriverType = self.PcdIsDriver if self.PcdIsDriver else ''
3653 Guid = self.Guid
3654 MDefs = self.Module.Defines
3655
3656 AsBuiltInfDict = {
3657 'module_name' : self.Name,
3658 'module_guid' : Guid,
3659 'module_module_type' : ModuleType,
3660 'module_version_string' : [MDefs['VERSION_STRING']] if 'VERSION_STRING' in MDefs else [],
3661 'pcd_is_driver_string' : [],
3662 'module_uefi_specification_version' : [],
3663 'module_pi_specification_version' : [],
3664 'module_entry_point' : self.Module.ModuleEntryPointList,
3665 'module_unload_image' : self.Module.ModuleUnloadImageList,
3666 'module_constructor' : self.Module.ConstructorList,
3667 'module_destructor' : self.Module.DestructorList,
3668 'module_shadow' : [MDefs['SHADOW']] if 'SHADOW' in MDefs else [],
3669 'module_pci_vendor_id' : [MDefs['PCI_VENDOR_ID']] if 'PCI_VENDOR_ID' in MDefs else [],
3670 'module_pci_device_id' : [MDefs['PCI_DEVICE_ID']] if 'PCI_DEVICE_ID' in MDefs else [],
3671 'module_pci_class_code' : [MDefs['PCI_CLASS_CODE']] if 'PCI_CLASS_CODE' in MDefs else [],
3672 'module_pci_revision' : [MDefs['PCI_REVISION']] if 'PCI_REVISION' in MDefs else [],
3673 'module_build_number' : [MDefs['BUILD_NUMBER']] if 'BUILD_NUMBER' in MDefs else [],
3674 'module_spec' : [MDefs['SPEC']] if 'SPEC' in MDefs else [],
3675 'module_uefi_hii_resource_section' : [MDefs['UEFI_HII_RESOURCE_SECTION']] if 'UEFI_HII_RESOURCE_SECTION' in MDefs else [],
3676 'module_uni_file' : [MDefs['MODULE_UNI_FILE']] if 'MODULE_UNI_FILE' in MDefs else [],
3677 'module_arch' : self.Arch,
3678 'package_item' : [Package.MetaFile.File.replace('\\', '/') for Package in Packages],
3679 'binary_item' : [],
3680 'patchablepcd_item' : [],
3681 'pcd_item' : [],
3682 'protocol_item' : [],
3683 'ppi_item' : [],
3684 'guid_item' : [],
3685 'flags_item' : [],
3686 'libraryclasses_item' : []
3687 }
3688
3689 if 'MODULE_UNI_FILE' in MDefs:
3690 UNIFile = os.path.join(self.MetaFile.Dir, MDefs['MODULE_UNI_FILE'])
3691 if os.path.isfile(UNIFile):
3692 shutil.copy2(UNIFile, self.OutputDir)
3693
3694 if self.AutoGenVersion > int(gInfSpecVersion, 0):
3695 AsBuiltInfDict['module_inf_version'] = '0x%08x' % self.AutoGenVersion
3696 else:
3697 AsBuiltInfDict['module_inf_version'] = gInfSpecVersion
3698
3699 if DriverType:
3700 AsBuiltInfDict['pcd_is_driver_string'].append(DriverType)
3701
3702 if 'UEFI_SPECIFICATION_VERSION' in self.Specification:
3703 AsBuiltInfDict['module_uefi_specification_version'].append(self.Specification['UEFI_SPECIFICATION_VERSION'])
3704 if 'PI_SPECIFICATION_VERSION' in self.Specification:
3705 AsBuiltInfDict['module_pi_specification_version'].append(self.Specification['PI_SPECIFICATION_VERSION'])
3706
3707 OutputDir = self.OutputDir.replace('\\', '/').strip('/')
3708 DebugDir = self.DebugDir.replace('\\', '/').strip('/')
3709 for Item in self.CodaTargetList:
3710 File = Item.Target.Path.replace('\\', '/').strip('/').replace(DebugDir, '').replace(OutputDir, '').strip('/')
3711 self.OutputFile.add(File)
3712 if os.path.isabs(File):
3713 File = File.replace('\\', '/').strip('/').replace(OutputDir, '').strip('/')
3714 if Item.Target.Ext.lower() == '.aml':
3715 AsBuiltInfDict['binary_item'].append('ASL|' + File)
3716 elif Item.Target.Ext.lower() == '.acpi':
3717 AsBuiltInfDict['binary_item'].append('ACPI|' + File)
3718 elif Item.Target.Ext.lower() == '.efi':
3719 AsBuiltInfDict['binary_item'].append('PE32|' + self.Name + '.efi')
3720 else:
3721 AsBuiltInfDict['binary_item'].append('BIN|' + File)
3722 if not self.DepexGenerated:
3723 DepexFile = os.path.join(self.OutputDir, self.Name + '.depex')
3724 if os.path.exists(DepexFile):
3725 self.DepexGenerated = True
3726 if self.DepexGenerated:
3727 self.OutputFile.add(self.Name + '.depex')
3728 if self.ModuleType in [SUP_MODULE_PEIM]:
3729 AsBuiltInfDict['binary_item'].append('PEI_DEPEX|' + self.Name + '.depex')
3730 elif self.ModuleType in [SUP_MODULE_DXE_DRIVER, SUP_MODULE_DXE_RUNTIME_DRIVER, SUP_MODULE_DXE_SAL_DRIVER, SUP_MODULE_UEFI_DRIVER]:
3731 AsBuiltInfDict['binary_item'].append('DXE_DEPEX|' + self.Name + '.depex')
3732 elif self.ModuleType in [SUP_MODULE_DXE_SMM_DRIVER]:
3733 AsBuiltInfDict['binary_item'].append('SMM_DEPEX|' + self.Name + '.depex')
3734
3735 Bin = self._GenOffsetBin()
3736 if Bin:
3737 AsBuiltInfDict['binary_item'].append('BIN|%s' % Bin)
3738 self.OutputFile.add(Bin)
3739
3740 for Root, Dirs, Files in os.walk(OutputDir):
3741 for File in Files:
3742 if File.lower().endswith('.pdb'):
3743 AsBuiltInfDict['binary_item'].append('DISPOSABLE|' + File)
3744 self.OutputFile.add(File)
3745 HeaderComments = self.Module.HeaderComments
3746 StartPos = 0
3747 for Index in range(len(HeaderComments)):
3748 if HeaderComments[Index].find('@BinaryHeader') != -1:
3749 HeaderComments[Index] = HeaderComments[Index].replace('@BinaryHeader', '@file')
3750 StartPos = Index
3751 break
3752 AsBuiltInfDict['header_comments'] = '\n'.join(HeaderComments[StartPos:]).replace(':#', '://')
3753 AsBuiltInfDict['tail_comments'] = '\n'.join(self.Module.TailComments)
3754
3755 GenList = [
3756 (self.ProtocolList, self._ProtocolComments, 'protocol_item'),
3757 (self.PpiList, self._PpiComments, 'ppi_item'),
3758 (GuidList, self._GuidComments, 'guid_item')
3759 ]
3760 for Item in GenList:
3761 for CName in Item[0]:
3762 Comments = '\n '.join(Item[1][CName]) if CName in Item[1] else ''
3763 Entry = Comments + '\n ' + CName if Comments else CName
3764 AsBuiltInfDict[Item[2]].append(Entry)
3765 PatchList = parsePcdInfoFromMapFile(
3766 os.path.join(self.OutputDir, self.Name + '.map'),
3767 os.path.join(self.OutputDir, self.Name + '.efi')
3768 )
3769 if PatchList:
3770 for Pcd in PatchablePcds:
3771 TokenCName = Pcd.TokenCName
3772 for PcdItem in GlobalData.MixedPcd:
3773 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
3774 TokenCName = PcdItem[0]
3775 break
3776 for PatchPcd in PatchList:
3777 if TokenCName == PatchPcd[0]:
3778 break
3779 else:
3780 continue
3781 PcdValue = ''
3782 if Pcd.DatumType == 'BOOLEAN':
3783 BoolValue = Pcd.DefaultValue.upper()
3784 if BoolValue == 'TRUE':
3785 Pcd.DefaultValue = '1'
3786 elif BoolValue == 'FALSE':
3787 Pcd.DefaultValue = '0'
3788
3789 if Pcd.DatumType in TAB_PCD_NUMERIC_TYPES:
3790 HexFormat = '0x%02x'
3791 if Pcd.DatumType == TAB_UINT16:
3792 HexFormat = '0x%04x'
3793 elif Pcd.DatumType == TAB_UINT32:
3794 HexFormat = '0x%08x'
3795 elif Pcd.DatumType == TAB_UINT64:
3796 HexFormat = '0x%016x'
3797 PcdValue = HexFormat % int(Pcd.DefaultValue, 0)
3798 else:
3799 if Pcd.MaxDatumSize is None or Pcd.MaxDatumSize == '':
3800 EdkLogger.error("build", AUTOGEN_ERROR,
3801 "Unknown [MaxDatumSize] of PCD [%s.%s]" % (Pcd.TokenSpaceGuidCName, TokenCName)
3802 )
3803 ArraySize = int(Pcd.MaxDatumSize, 0)
3804 PcdValue = Pcd.DefaultValue
3805 if PcdValue[0] != '{':
3806 Unicode = False
3807 if PcdValue[0] == 'L':
3808 Unicode = True
3809 PcdValue = PcdValue.lstrip('L')
3810 PcdValue = eval(PcdValue)
3811 NewValue = '{'
3812 for Index in range(0, len(PcdValue)):
3813 if Unicode:
3814 CharVal = ord(PcdValue[Index])
3815 NewValue = NewValue + '0x%02x' % (CharVal & 0x00FF) + ', ' \
3816 + '0x%02x' % (CharVal >> 8) + ', '
3817 else:
3818 NewValue = NewValue + '0x%02x' % (ord(PcdValue[Index]) % 0x100) + ', '
3819 Padding = '0x00, '
3820 if Unicode:
3821 Padding = Padding * 2
3822 ArraySize = ArraySize // 2
3823 if ArraySize < (len(PcdValue) + 1):
3824 if Pcd.MaxSizeUserSet:
3825 EdkLogger.error("build", AUTOGEN_ERROR,
3826 "The maximum size of VOID* type PCD '%s.%s' is less than its actual size occupied." % (Pcd.TokenSpaceGuidCName, TokenCName)
3827 )
3828 else:
3829 ArraySize = len(PcdValue) + 1
3830 if ArraySize > len(PcdValue) + 1:
3831 NewValue = NewValue + Padding * (ArraySize - len(PcdValue) - 1)
3832 PcdValue = NewValue + Padding.strip().rstrip(',') + '}'
3833 elif len(PcdValue.split(',')) <= ArraySize:
3834 PcdValue = PcdValue.rstrip('}') + ', 0x00' * (ArraySize - len(PcdValue.split(',')))
3835 PcdValue += '}'
3836 else:
3837 if Pcd.MaxSizeUserSet:
3838 EdkLogger.error("build", AUTOGEN_ERROR,
3839 "The maximum size of VOID* type PCD '%s.%s' is less than its actual size occupied." % (Pcd.TokenSpaceGuidCName, TokenCName)
3840 )
3841 else:
3842 ArraySize = len(PcdValue) + 1
3843 PcdItem = '%s.%s|%s|0x%X' % \
3844 (Pcd.TokenSpaceGuidCName, TokenCName, PcdValue, PatchPcd[1])
3845 PcdComments = ''
3846 if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) in self._PcdComments:
3847 PcdComments = '\n '.join(self._PcdComments[Pcd.TokenSpaceGuidCName, Pcd.TokenCName])
3848 if PcdComments:
3849 PcdItem = PcdComments + '\n ' + PcdItem
3850 AsBuiltInfDict['patchablepcd_item'].append(PcdItem)
3851
3852 for Pcd in Pcds + VfrPcds:
3853 PcdCommentList = []
3854 HiiInfo = ''
3855 TokenCName = Pcd.TokenCName
3856 for PcdItem in GlobalData.MixedPcd:
3857 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
3858 TokenCName = PcdItem[0]
3859 break
3860 if Pcd.Type == TAB_PCDS_DYNAMIC_EX_HII:
3861 for SkuName in Pcd.SkuInfoList:
3862 SkuInfo = Pcd.SkuInfoList[SkuName]
3863 HiiInfo = '## %s|%s|%s' % (SkuInfo.VariableName, SkuInfo.VariableGuid, SkuInfo.VariableOffset)
3864 break
3865 if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) in self._PcdComments:
3866 PcdCommentList = self._PcdComments[Pcd.TokenSpaceGuidCName, Pcd.TokenCName][:]
3867 if HiiInfo:
3868 UsageIndex = -1
3869 UsageStr = ''
3870 for Index, Comment in enumerate(PcdCommentList):
3871 for Usage in UsageList:
3872 if Comment.find(Usage) != -1:
3873 UsageStr = Usage
3874 UsageIndex = Index
3875 break
3876 if UsageIndex != -1:
3877 PcdCommentList[UsageIndex] = '## %s %s %s' % (UsageStr, HiiInfo, PcdCommentList[UsageIndex].replace(UsageStr, ''))
3878 else:
3879 PcdCommentList.append('## UNDEFINED ' + HiiInfo)
3880 PcdComments = '\n '.join(PcdCommentList)
3881 PcdEntry = Pcd.TokenSpaceGuidCName + '.' + TokenCName
3882 if PcdComments:
3883 PcdEntry = PcdComments + '\n ' + PcdEntry
3884 AsBuiltInfDict['pcd_item'].append(PcdEntry)
3885 for Item in self.BuildOption:
3886 if 'FLAGS' in self.BuildOption[Item]:
3887 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()))
3888
3889 # Generated LibraryClasses section in comments.
3890 for Library in self.LibraryAutoGenList:
3891 AsBuiltInfDict['libraryclasses_item'].append(Library.MetaFile.File.replace('\\', '/'))
3892
3893 # Generated UserExtensions TianoCore section.
3894 # All tianocore user extensions are copied.
3895 UserExtStr = ''
3896 for TianoCore in self._GetTianoCoreUserExtensionList():
3897 UserExtStr += '\n'.join(TianoCore)
3898 ExtensionFile = os.path.join(self.MetaFile.Dir, TianoCore[1])
3899 if os.path.isfile(ExtensionFile):
3900 shutil.copy2(ExtensionFile, self.OutputDir)
3901 AsBuiltInfDict['userextension_tianocore_item'] = UserExtStr
3902
3903 # Generated depex expression section in comments.
3904 DepexExpression = self._GetDepexExpresionString()
3905 AsBuiltInfDict['depexsection_item'] = DepexExpression if DepexExpression else ''
3906
3907 AsBuiltInf = TemplateString()
3908 AsBuiltInf.Append(gAsBuiltInfHeaderString.Replace(AsBuiltInfDict))
3909
3910 SaveFileOnChange(os.path.join(self.OutputDir, self.Name + '.inf'), str(AsBuiltInf), False)
3911
3912 self.IsAsBuiltInfCreated = True
3913 if GlobalData.gBinCacheDest:
3914 self.CopyModuleToCache()
3915
3916 def CopyModuleToCache(self):
3917 FileDir = path.join(GlobalData.gBinCacheDest, self.Arch, self.SourceDir, self.MetaFile.BaseName)
3918 CreateDirectory (FileDir)
3919 HashFile = path.join(self.BuildDir, self.Name + '.hash')
3920 ModuleFile = path.join(self.OutputDir, self.Name + '.inf')
3921 if os.path.exists(HashFile):
3922 shutil.copy2(HashFile, FileDir)
3923 if os.path.exists(ModuleFile):
3924 shutil.copy2(ModuleFile, FileDir)
3925 if not self.OutputFile:
3926 Ma = self.BuildDatabase[PathClass(ModuleFile), self.Arch, self.BuildTarget, self.ToolChain]
3927 self.OutputFile = Ma.Binaries
3928 if self.OutputFile:
3929 for File in self.OutputFile:
3930 File = str(File)
3931 if not os.path.isabs(File):
3932 File = os.path.join(self.OutputDir, File)
3933 if os.path.exists(File):
3934 shutil.copy2(File, FileDir)
3935
3936 def AttemptModuleCacheCopy(self):
3937 if self.IsBinaryModule:
3938 return False
3939 FileDir = path.join(GlobalData.gBinCacheSource, self.Arch, self.SourceDir, self.MetaFile.BaseName)
3940 HashFile = path.join(FileDir, self.Name + '.hash')
3941 if os.path.exists(HashFile):
3942 f = open(HashFile, 'r')
3943 CacheHash = f.read()
3944 f.close()
3945 if GlobalData.gModuleHash[self.Arch][self.Name]:
3946 if CacheHash == GlobalData.gModuleHash[self.Arch][self.Name]:
3947 for root, dir, files in os.walk(FileDir):
3948 for f in files:
3949 if self.Name + '.hash' in f:
3950 shutil.copy2(HashFile, self.BuildDir)
3951 else:
3952 File = path.join(root, f)
3953 shutil.copy2(File, self.OutputDir)
3954 if self.Name == "PcdPeim" or self.Name == "PcdDxe":
3955 CreatePcdDatabaseCode(self, TemplateString(), TemplateString())
3956 return True
3957 return False
3958
3959 ## Create makefile for the module and its dependent libraries
3960 #
3961 # @param CreateLibraryMakeFile Flag indicating if or not the makefiles of
3962 # dependent libraries will be created
3963 #
3964 @cached_class_function
3965 def CreateMakeFile(self, CreateLibraryMakeFile=True, GenFfsList = []):
3966 # nest this function inside it's only caller.
3967 def CreateTimeStamp():
3968 FileSet = {self.MetaFile.Path}
3969
3970 for SourceFile in self.Module.Sources:
3971 FileSet.add (SourceFile.Path)
3972
3973 for Lib in self.DependentLibraryList:
3974 FileSet.add (Lib.MetaFile.Path)
3975
3976 for f in self.AutoGenDepSet:
3977 FileSet.add (f.Path)
3978
3979 if os.path.exists (self.TimeStampPath):
3980 os.remove (self.TimeStampPath)
3981 with open(self.TimeStampPath, 'w+') as file:
3982 for f in FileSet:
3983 print(f, file=file)
3984
3985 # Ignore generating makefile when it is a binary module
3986 if self.IsBinaryModule:
3987 return
3988
3989 self.GenFfsList = GenFfsList
3990 if not self.IsLibrary and CreateLibraryMakeFile:
3991 for LibraryAutoGen in self.LibraryAutoGenList:
3992 LibraryAutoGen.CreateMakeFile()
3993
3994 if self.CanSkip():
3995 return
3996
3997 if len(self.CustomMakefile) == 0:
3998 Makefile = GenMake.ModuleMakefile(self)
3999 else:
4000 Makefile = GenMake.CustomMakefile(self)
4001 if Makefile.Generate():
4002 EdkLogger.debug(EdkLogger.DEBUG_9, "Generated makefile for module %s [%s]" %
4003 (self.Name, self.Arch))
4004 else:
4005 EdkLogger.debug(EdkLogger.DEBUG_9, "Skipped the generation of makefile for module %s [%s]" %
4006 (self.Name, self.Arch))
4007
4008 CreateTimeStamp()
4009
4010 def CopyBinaryFiles(self):
4011 for File in self.Module.Binaries:
4012 SrcPath = File.Path
4013 DstPath = os.path.join(self.OutputDir, os.path.basename(SrcPath))
4014 CopyLongFilePath(SrcPath, DstPath)
4015 ## Create autogen code for the module and its dependent libraries
4016 #
4017 # @param CreateLibraryCodeFile Flag indicating if or not the code of
4018 # dependent libraries will be created
4019 #
4020 def CreateCodeFile(self, CreateLibraryCodeFile=True):
4021 if self.IsCodeFileCreated:
4022 return
4023
4024 # Need to generate PcdDatabase even PcdDriver is binarymodule
4025 if self.IsBinaryModule and self.PcdIsDriver != '':
4026 CreatePcdDatabaseCode(self, TemplateString(), TemplateString())
4027 return
4028 if self.IsBinaryModule:
4029 if self.IsLibrary:
4030 self.CopyBinaryFiles()
4031 return
4032
4033 if not self.IsLibrary and CreateLibraryCodeFile:
4034 for LibraryAutoGen in self.LibraryAutoGenList:
4035 LibraryAutoGen.CreateCodeFile()
4036
4037 if self.CanSkip():
4038 return
4039
4040 AutoGenList = []
4041 IgoredAutoGenList = []
4042
4043 for File in self.AutoGenFileList:
4044 if GenC.Generate(File.Path, self.AutoGenFileList[File], File.IsBinary):
4045 AutoGenList.append(str(File))
4046 else:
4047 IgoredAutoGenList.append(str(File))
4048
4049
4050 for ModuleType in self.DepexList:
4051 # Ignore empty [depex] section or [depex] section for SUP_MODULE_USER_DEFINED module
4052 if len(self.DepexList[ModuleType]) == 0 or ModuleType == SUP_MODULE_USER_DEFINED:
4053 continue
4054
4055 Dpx = GenDepex.DependencyExpression(self.DepexList[ModuleType], ModuleType, True)
4056 DpxFile = gAutoGenDepexFileName % {"module_name" : self.Name}
4057
4058 if len(Dpx.PostfixNotation) != 0:
4059 self.DepexGenerated = True
4060
4061 if Dpx.Generate(path.join(self.OutputDir, DpxFile)):
4062 AutoGenList.append(str(DpxFile))
4063 else:
4064 IgoredAutoGenList.append(str(DpxFile))
4065
4066 if IgoredAutoGenList == []:
4067 EdkLogger.debug(EdkLogger.DEBUG_9, "Generated [%s] files for module %s [%s]" %
4068 (" ".join(AutoGenList), self.Name, self.Arch))
4069 elif AutoGenList == []:
4070 EdkLogger.debug(EdkLogger.DEBUG_9, "Skipped the generation of [%s] files for module %s [%s]" %
4071 (" ".join(IgoredAutoGenList), self.Name, self.Arch))
4072 else:
4073 EdkLogger.debug(EdkLogger.DEBUG_9, "Generated [%s] (skipped %s) files for module %s [%s]" %
4074 (" ".join(AutoGenList), " ".join(IgoredAutoGenList), self.Name, self.Arch))
4075
4076 self.IsCodeFileCreated = True
4077 return AutoGenList
4078
4079 ## Summarize the ModuleAutoGen objects of all libraries used by this module
4080 @cached_property
4081 def LibraryAutoGenList(self):
4082 RetVal = []
4083 for Library in self.DependentLibraryList:
4084 La = ModuleAutoGen(
4085 self.Workspace,
4086 Library.MetaFile,
4087 self.BuildTarget,
4088 self.ToolChain,
4089 self.Arch,
4090 self.PlatformInfo.MetaFile
4091 )
4092 if La not in RetVal:
4093 RetVal.append(La)
4094 for Lib in La.CodaTargetList:
4095 self._ApplyBuildRule(Lib.Target, TAB_UNKNOWN_FILE)
4096 return RetVal
4097
4098 def GenModuleHash(self):
4099 if self.Arch not in GlobalData.gModuleHash:
4100 GlobalData.gModuleHash[self.Arch] = {}
4101 m = hashlib.md5()
4102 # Add Platform level hash
4103 m.update(GlobalData.gPlatformHash.encode('utf-8'))
4104 # Add Package level hash
4105 if self.DependentPackageList:
4106 for Pkg in sorted(self.DependentPackageList, key=lambda x: x.PackageName):
4107 if Pkg.PackageName in GlobalData.gPackageHash[self.Arch]:
4108 m.update(GlobalData.gPackageHash[self.Arch][Pkg.PackageName].encode('utf-8'))
4109
4110 # Add Library hash
4111 if self.LibraryAutoGenList:
4112 for Lib in sorted(self.LibraryAutoGenList, key=lambda x: x.Name):
4113 if Lib.Name not in GlobalData.gModuleHash[self.Arch]:
4114 Lib.GenModuleHash()
4115 m.update(GlobalData.gModuleHash[self.Arch][Lib.Name].encode('utf-8'))
4116
4117 # Add Module self
4118 f = open(str(self.MetaFile), 'rb')
4119 Content = f.read()
4120 f.close()
4121 m.update(Content)
4122 # Add Module's source files
4123 if self.SourceFileList:
4124 for File in sorted(self.SourceFileList, key=lambda x: str(x)):
4125 f = open(str(File), 'rb')
4126 Content = f.read()
4127 f.close()
4128 m.update(Content)
4129
4130 ModuleHashFile = path.join(self.BuildDir, self.Name + ".hash")
4131 if self.Name not in GlobalData.gModuleHash[self.Arch]:
4132 GlobalData.gModuleHash[self.Arch][self.Name] = m.hexdigest()
4133 if GlobalData.gBinCacheSource:
4134 if self.AttemptModuleCacheCopy():
4135 return False
4136 return SaveFileOnChange(ModuleHashFile, m.hexdigest(), False)
4137
4138 ## Decide whether we can skip the ModuleAutoGen process
4139 def CanSkipbyHash(self):
4140 if GlobalData.gUseHashCache:
4141 return not self.GenModuleHash()
4142 return False
4143
4144 ## Decide whether we can skip the ModuleAutoGen process
4145 # If any source file is newer than the module than we cannot skip
4146 #
4147 def CanSkip(self):
4148 if self.MakeFileDir in GlobalData.gSikpAutoGenCache:
4149 return True
4150 if not os.path.exists(self.TimeStampPath):
4151 return False
4152 #last creation time of the module
4153 DstTimeStamp = os.stat(self.TimeStampPath)[8]
4154
4155 SrcTimeStamp = self.Workspace._SrcTimeStamp
4156 if SrcTimeStamp > DstTimeStamp:
4157 return False
4158
4159 with open(self.TimeStampPath,'r') as f:
4160 for source in f:
4161 source = source.rstrip('\n')
4162 if not os.path.exists(source):
4163 return False
4164 if source not in ModuleAutoGen.TimeDict :
4165 ModuleAutoGen.TimeDict[source] = os.stat(source)[8]
4166 if ModuleAutoGen.TimeDict[source] > DstTimeStamp:
4167 return False
4168 GlobalData.gSikpAutoGenCache.add(self.MakeFileDir)
4169 return True
4170
4171 @cached_property
4172 def TimeStampPath(self):
4173 return os.path.join(self.MakeFileDir, 'AutoGenTimeStamp')