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