]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/AutoGen/AutoGen.py
BaseTools: Refactor PlatformAutoGen
[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._BuildDir = None
282 self._FvDir = None
283 self._MakeFileDir = None
284 self._BuildCommand = None
285 self._GuidDict = {}
286
287 # there's many relative directory operations, so ...
288 os.chdir(self.WorkspaceDir)
289
290 #
291 # Merge Arch
292 #
293 if not self.ArchList:
294 ArchList = set(self.Platform.SupArchList)
295 else:
296 ArchList = set(self.ArchList) & set(self.Platform.SupArchList)
297 if not ArchList:
298 EdkLogger.error("build", PARAMETER_INVALID,
299 ExtraData = "Invalid ARCH specified. [Valid ARCH: %s]" % (" ".join(self.Platform.SupArchList)))
300 elif self.ArchList and len(ArchList) != len(self.ArchList):
301 SkippedArchList = set(self.ArchList).symmetric_difference(set(self.Platform.SupArchList))
302 EdkLogger.verbose("\nArch [%s] is ignored because the platform supports [%s] only!"
303 % (" ".join(SkippedArchList), " ".join(self.Platform.SupArchList)))
304 self.ArchList = tuple(ArchList)
305
306 # Validate build target
307 if self.BuildTarget not in self.Platform.BuildTargets:
308 EdkLogger.error("build", PARAMETER_INVALID,
309 ExtraData="Build target [%s] is not supported by the platform. [Valid target: %s]"
310 % (self.BuildTarget, " ".join(self.Platform.BuildTargets)))
311
312
313 # parse FDF file to get PCDs in it, if any
314 if not self.FdfFile:
315 self.FdfFile = self.Platform.FlashDefinition
316
317 EdkLogger.info("")
318 if self.ArchList:
319 EdkLogger.info('%-16s = %s' % ("Architecture(s)", ' '.join(self.ArchList)))
320 EdkLogger.info('%-16s = %s' % ("Build target", self.BuildTarget))
321 EdkLogger.info('%-16s = %s' % ("Toolchain", self.ToolChain))
322
323 EdkLogger.info('\n%-24s = %s' % ("Active Platform", self.Platform))
324 if BuildModule:
325 EdkLogger.info('%-24s = %s' % ("Active Module", BuildModule))
326
327 if self.FdfFile:
328 EdkLogger.info('%-24s = %s' % ("Flash Image Definition", self.FdfFile))
329
330 EdkLogger.verbose("\nFLASH_DEFINITION = %s" % self.FdfFile)
331
332 if Progress:
333 Progress.Start("\nProcessing meta-data")
334
335 if self.FdfFile:
336 #
337 # Mark now build in AutoGen Phase
338 #
339 GlobalData.gAutoGenPhase = True
340 Fdf = FdfParser(self.FdfFile.Path)
341 Fdf.ParseFile()
342 GlobalData.gFdfParser = Fdf
343 GlobalData.gAutoGenPhase = False
344 PcdSet = Fdf.Profile.PcdDict
345 if Fdf.CurrentFdName and Fdf.CurrentFdName in Fdf.Profile.FdDict:
346 FdDict = Fdf.Profile.FdDict[Fdf.CurrentFdName]
347 for FdRegion in FdDict.RegionList:
348 if str(FdRegion.RegionType) is 'FILE' and self.Platform.VpdToolGuid in str(FdRegion.RegionDataList):
349 if int(FdRegion.Offset) % 8 != 0:
350 EdkLogger.error("build", FORMAT_INVALID, 'The VPD Base Address %s must be 8-byte aligned.' % (FdRegion.Offset))
351 ModuleList = Fdf.Profile.InfList
352 self.FdfProfile = Fdf.Profile
353 for fvname in self.FvTargetList:
354 if fvname.upper() not in self.FdfProfile.FvDict:
355 EdkLogger.error("build", OPTION_VALUE_INVALID,
356 "No such an FV in FDF file: %s" % fvname)
357
358 # In DSC file may use FILE_GUID to override the module, then in the Platform.Modules use FILE_GUIDmodule.inf as key,
359 # but the path (self.MetaFile.Path) is the real path
360 for key in self.FdfProfile.InfDict:
361 if key == 'ArchTBD':
362 MetaFile_cache = defaultdict(set)
363 for Arch in self.ArchList:
364 Current_Platform_cache = self.BuildDatabase[self.MetaFile, Arch, Target, Toolchain]
365 for Pkey in Current_Platform_cache.Modules:
366 MetaFile_cache[Arch].add(Current_Platform_cache.Modules[Pkey].MetaFile)
367 for Inf in self.FdfProfile.InfDict[key]:
368 ModuleFile = PathClass(NormPath(Inf), GlobalData.gWorkspace, Arch)
369 for Arch in self.ArchList:
370 if ModuleFile in MetaFile_cache[Arch]:
371 break
372 else:
373 ModuleData = self.BuildDatabase[ModuleFile, Arch, Target, Toolchain]
374 if not ModuleData.IsBinaryModule:
375 EdkLogger.error('build', PARSER_ERROR, "Module %s NOT found in DSC file; Is it really a binary module?" % ModuleFile)
376
377 else:
378 for Arch in self.ArchList:
379 if Arch == key:
380 Platform = self.BuildDatabase[self.MetaFile, Arch, Target, Toolchain]
381 MetaFileList = set()
382 for Pkey in Platform.Modules:
383 MetaFileList.add(Platform.Modules[Pkey].MetaFile)
384 for Inf in self.FdfProfile.InfDict[key]:
385 ModuleFile = PathClass(NormPath(Inf), GlobalData.gWorkspace, Arch)
386 if ModuleFile in MetaFileList:
387 continue
388 ModuleData = self.BuildDatabase[ModuleFile, Arch, Target, Toolchain]
389 if not ModuleData.IsBinaryModule:
390 EdkLogger.error('build', PARSER_ERROR, "Module %s NOT found in DSC file; Is it really a binary module?" % ModuleFile)
391
392 else:
393 PcdSet = {}
394 ModuleList = []
395 self.FdfProfile = None
396 if self.FdTargetList:
397 EdkLogger.info("No flash definition file found. FD [%s] will be ignored." % " ".join(self.FdTargetList))
398 self.FdTargetList = []
399 if self.FvTargetList:
400 EdkLogger.info("No flash definition file found. FV [%s] will be ignored." % " ".join(self.FvTargetList))
401 self.FvTargetList = []
402 if self.CapTargetList:
403 EdkLogger.info("No flash definition file found. Capsule [%s] will be ignored." % " ".join(self.CapTargetList))
404 self.CapTargetList = []
405
406 # apply SKU and inject PCDs from Flash Definition file
407 for Arch in self.ArchList:
408 Platform = self.BuildDatabase[self.MetaFile, Arch, Target, Toolchain]
409 PlatformPcds = Platform.Pcds
410 self._GuidDict = Platform._GuidDict
411 SourcePcdDict = {TAB_PCDS_DYNAMIC_EX:set(), TAB_PCDS_PATCHABLE_IN_MODULE:set(),TAB_PCDS_DYNAMIC:set(),TAB_PCDS_FIXED_AT_BUILD:set()}
412 BinaryPcdDict = {TAB_PCDS_DYNAMIC_EX:set(), TAB_PCDS_PATCHABLE_IN_MODULE:set()}
413 SourcePcdDict_Keys = SourcePcdDict.keys()
414 BinaryPcdDict_Keys = BinaryPcdDict.keys()
415
416 # generate the SourcePcdDict and BinaryPcdDict
417 PGen = PlatformAutoGen(self, self.MetaFile, Target, Toolchain, Arch)
418 for BuildData in PGen.BuildDatabase._CACHE_.values():
419 if BuildData.Arch != Arch:
420 continue
421 if BuildData.MetaFile.Ext == '.inf':
422 for key in BuildData.Pcds:
423 if BuildData.Pcds[key].Pending:
424 if key in Platform.Pcds:
425 PcdInPlatform = Platform.Pcds[key]
426 if PcdInPlatform.Type:
427 BuildData.Pcds[key].Type = PcdInPlatform.Type
428 BuildData.Pcds[key].Pending = False
429
430 if BuildData.MetaFile in Platform.Modules:
431 PlatformModule = Platform.Modules[str(BuildData.MetaFile)]
432 if key in PlatformModule.Pcds:
433 PcdInPlatform = PlatformModule.Pcds[key]
434 if PcdInPlatform.Type:
435 BuildData.Pcds[key].Type = PcdInPlatform.Type
436 BuildData.Pcds[key].Pending = False
437 else:
438 #Pcd used in Library, Pcd Type from reference module if Pcd Type is Pending
439 if BuildData.Pcds[key].Pending:
440 MGen = ModuleAutoGen(self, BuildData.MetaFile, Target, Toolchain, Arch, self.MetaFile)
441 if MGen and MGen.IsLibrary:
442 if MGen in PGen.LibraryAutoGenList:
443 ReferenceModules = MGen.ReferenceModules
444 for ReferenceModule in ReferenceModules:
445 if ReferenceModule.MetaFile in Platform.Modules:
446 RefPlatformModule = Platform.Modules[str(ReferenceModule.MetaFile)]
447 if key in RefPlatformModule.Pcds:
448 PcdInReferenceModule = RefPlatformModule.Pcds[key]
449 if PcdInReferenceModule.Type:
450 BuildData.Pcds[key].Type = PcdInReferenceModule.Type
451 BuildData.Pcds[key].Pending = False
452 break
453
454 if TAB_PCDS_DYNAMIC_EX in BuildData.Pcds[key].Type:
455 if BuildData.IsBinaryModule:
456 BinaryPcdDict[TAB_PCDS_DYNAMIC_EX].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
457 else:
458 SourcePcdDict[TAB_PCDS_DYNAMIC_EX].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
459
460 elif TAB_PCDS_PATCHABLE_IN_MODULE in BuildData.Pcds[key].Type:
461 if BuildData.MetaFile.Ext == '.inf':
462 if BuildData.IsBinaryModule:
463 BinaryPcdDict[TAB_PCDS_PATCHABLE_IN_MODULE].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
464 else:
465 SourcePcdDict[TAB_PCDS_PATCHABLE_IN_MODULE].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
466
467 elif TAB_PCDS_DYNAMIC in BuildData.Pcds[key].Type:
468 SourcePcdDict[TAB_PCDS_DYNAMIC].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
469 elif TAB_PCDS_FIXED_AT_BUILD in BuildData.Pcds[key].Type:
470 SourcePcdDict[TAB_PCDS_FIXED_AT_BUILD].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
471 else:
472 pass
473 #
474 # A PCD can only use one type for all source modules
475 #
476 for i in SourcePcdDict_Keys:
477 for j in SourcePcdDict_Keys:
478 if i != j:
479 Intersections = SourcePcdDict[i].intersection(SourcePcdDict[j])
480 if len(Intersections) > 0:
481 EdkLogger.error(
482 'build',
483 FORMAT_INVALID,
484 "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),
485 ExtraData='\n\t'.join(str(P[1]+'.'+P[0]) for P in Intersections)
486 )
487
488 #
489 # intersection the BinaryPCD for Mixed PCD
490 #
491 for i in BinaryPcdDict_Keys:
492 for j in BinaryPcdDict_Keys:
493 if i != j:
494 Intersections = BinaryPcdDict[i].intersection(BinaryPcdDict[j])
495 for item in Intersections:
496 NewPcd1 = (item[0] + '_' + i, item[1])
497 NewPcd2 = (item[0] + '_' + j, item[1])
498 if item not in GlobalData.MixedPcd:
499 GlobalData.MixedPcd[item] = [NewPcd1, NewPcd2]
500 else:
501 if NewPcd1 not in GlobalData.MixedPcd[item]:
502 GlobalData.MixedPcd[item].append(NewPcd1)
503 if NewPcd2 not in GlobalData.MixedPcd[item]:
504 GlobalData.MixedPcd[item].append(NewPcd2)
505
506 #
507 # intersection the SourcePCD and BinaryPCD for Mixed PCD
508 #
509 for i in SourcePcdDict_Keys:
510 for j in BinaryPcdDict_Keys:
511 if i != j:
512 Intersections = SourcePcdDict[i].intersection(BinaryPcdDict[j])
513 for item in Intersections:
514 NewPcd1 = (item[0] + '_' + i, item[1])
515 NewPcd2 = (item[0] + '_' + j, item[1])
516 if item not in GlobalData.MixedPcd:
517 GlobalData.MixedPcd[item] = [NewPcd1, NewPcd2]
518 else:
519 if NewPcd1 not in GlobalData.MixedPcd[item]:
520 GlobalData.MixedPcd[item].append(NewPcd1)
521 if NewPcd2 not in GlobalData.MixedPcd[item]:
522 GlobalData.MixedPcd[item].append(NewPcd2)
523
524 for BuildData in PGen.BuildDatabase._CACHE_.values():
525 if BuildData.Arch != Arch:
526 continue
527 for key in BuildData.Pcds:
528 for SinglePcd in GlobalData.MixedPcd:
529 if (BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName) == SinglePcd:
530 for item in GlobalData.MixedPcd[SinglePcd]:
531 Pcd_Type = item[0].split('_')[-1]
532 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 \
533 (Pcd_Type == TAB_PCDS_DYNAMIC and BuildData.Pcds[key].Type in PCD_DYNAMIC_TYPE_SET):
534 Value = BuildData.Pcds[key]
535 Value.TokenCName = BuildData.Pcds[key].TokenCName + '_' + Pcd_Type
536 if len(key) == 2:
537 newkey = (Value.TokenCName, key[1])
538 elif len(key) == 3:
539 newkey = (Value.TokenCName, key[1], key[2])
540 del BuildData.Pcds[key]
541 BuildData.Pcds[newkey] = Value
542 break
543 break
544
545 # handle the mixed pcd in FDF file
546 for key in PcdSet:
547 if key in GlobalData.MixedPcd:
548 Value = PcdSet[key]
549 del PcdSet[key]
550 for item in GlobalData.MixedPcd[key]:
551 PcdSet[item] = Value
552
553 #Collect package set information from INF of FDF
554 PkgSet = set()
555 for Inf in ModuleList:
556 ModuleFile = PathClass(NormPath(Inf), GlobalData.gWorkspace, Arch)
557 if ModuleFile in Platform.Modules:
558 continue
559 ModuleData = self.BuildDatabase[ModuleFile, Arch, Target, Toolchain]
560 PkgSet.update(ModuleData.Packages)
561 Pkgs = list(PkgSet) + list(PGen.PackageList)
562 DecPcds = set()
563 DecPcdsKey = set()
564 for Pkg in Pkgs:
565 for Pcd in Pkg.Pcds:
566 DecPcds.add((Pcd[0], Pcd[1]))
567 DecPcdsKey.add((Pcd[0], Pcd[1], Pcd[2]))
568
569 Platform.SkuName = self.SkuId
570 for Name, Guid,Fileds in PcdSet:
571 if (Name, Guid) not in DecPcds:
572 EdkLogger.error(
573 'build',
574 PARSER_ERROR,
575 "PCD (%s.%s) used in FDF is not declared in DEC files." % (Guid, Name),
576 File = self.FdfProfile.PcdFileLineDict[Name, Guid][0],
577 Line = self.FdfProfile.PcdFileLineDict[Name, Guid][1]
578 )
579 else:
580 # Check whether Dynamic or DynamicEx PCD used in FDF file. If used, build break and give a error message.
581 if (Name, Guid, TAB_PCDS_FIXED_AT_BUILD) in DecPcdsKey \
582 or (Name, Guid, TAB_PCDS_PATCHABLE_IN_MODULE) in DecPcdsKey \
583 or (Name, Guid, TAB_PCDS_FEATURE_FLAG) in DecPcdsKey:
584 continue
585 elif (Name, Guid, TAB_PCDS_DYNAMIC) in DecPcdsKey or (Name, Guid, TAB_PCDS_DYNAMIC_EX) in DecPcdsKey:
586 EdkLogger.error(
587 'build',
588 PARSER_ERROR,
589 "Using Dynamic or DynamicEx type of PCD [%s.%s] in FDF file is not allowed." % (Guid, Name),
590 File = self.FdfProfile.PcdFileLineDict[Name, Guid][0],
591 Line = self.FdfProfile.PcdFileLineDict[Name, Guid][1]
592 )
593
594 Pa = PlatformAutoGen(self, self.MetaFile, Target, Toolchain, Arch)
595 #
596 # Explicitly collect platform's dynamic PCDs
597 #
598 Pa.CollectPlatformDynamicPcds()
599 Pa.CollectFixedAtBuildPcds()
600 self.AutoGenObjectList.append(Pa)
601
602 #
603 # Generate Package level hash value
604 #
605 GlobalData.gPackageHash[Arch] = {}
606 if GlobalData.gUseHashCache:
607 for Pkg in Pkgs:
608 self._GenPkgLevelHash(Pkg)
609
610 #
611 # Check PCDs token value conflict in each DEC file.
612 #
613 self._CheckAllPcdsTokenValueConflict()
614
615 #
616 # Check PCD type and definition between DSC and DEC
617 #
618 self._CheckPcdDefineAndType()
619
620 #
621 # Create BuildOptions Macro & PCD metafile, also add the Active Platform and FDF file.
622 #
623 content = 'gCommandLineDefines: '
624 content += str(GlobalData.gCommandLineDefines)
625 content += os.linesep
626 content += 'BuildOptionPcd: '
627 content += str(GlobalData.BuildOptionPcd)
628 content += os.linesep
629 content += 'Active Platform: '
630 content += str(self.Platform)
631 content += os.linesep
632 if self.FdfFile:
633 content += 'Flash Image Definition: '
634 content += str(self.FdfFile)
635 content += os.linesep
636 SaveFileOnChange(os.path.join(self.BuildDir, 'BuildOptions'), content, False)
637
638 #
639 # Create PcdToken Number file for Dynamic/DynamicEx Pcd.
640 #
641 PcdTokenNumber = 'PcdTokenNumber: '
642 if Pa.PcdTokenNumber:
643 if Pa.DynamicPcdList:
644 for Pcd in Pa.DynamicPcdList:
645 PcdTokenNumber += os.linesep
646 PcdTokenNumber += str((Pcd.TokenCName, Pcd.TokenSpaceGuidCName))
647 PcdTokenNumber += ' : '
648 PcdTokenNumber += str(Pa.PcdTokenNumber[Pcd.TokenCName, Pcd.TokenSpaceGuidCName])
649 SaveFileOnChange(os.path.join(self.BuildDir, 'PcdTokenNumber'), PcdTokenNumber, False)
650
651 #
652 # Get set of workspace metafiles
653 #
654 AllWorkSpaceMetaFiles = self._GetMetaFiles(Target, Toolchain, Arch)
655
656 #
657 # Retrieve latest modified time of all metafiles
658 #
659 SrcTimeStamp = 0
660 for f in AllWorkSpaceMetaFiles:
661 if os.stat(f)[8] > SrcTimeStamp:
662 SrcTimeStamp = os.stat(f)[8]
663 self._SrcTimeStamp = SrcTimeStamp
664
665 if GlobalData.gUseHashCache:
666 m = hashlib.md5()
667 for files in AllWorkSpaceMetaFiles:
668 if files.endswith('.dec'):
669 continue
670 f = open(files, 'r')
671 Content = f.read()
672 f.close()
673 m.update(Content)
674 SaveFileOnChange(os.path.join(self.BuildDir, 'AutoGen.hash'), m.hexdigest(), True)
675 GlobalData.gPlatformHash = m.hexdigest()
676
677 #
678 # Write metafile list to build directory
679 #
680 AutoGenFilePath = os.path.join(self.BuildDir, 'AutoGen')
681 if os.path.exists (AutoGenFilePath):
682 os.remove(AutoGenFilePath)
683 if not os.path.exists(self.BuildDir):
684 os.makedirs(self.BuildDir)
685 with open(os.path.join(self.BuildDir, 'AutoGen'), 'w+') as file:
686 for f in AllWorkSpaceMetaFiles:
687 print(f, file=file)
688 return True
689
690 def _GenPkgLevelHash(self, Pkg):
691 if Pkg.PackageName in GlobalData.gPackageHash[Pkg.Arch]:
692 return
693
694 PkgDir = os.path.join(self.BuildDir, Pkg.Arch, Pkg.PackageName)
695 CreateDirectory(PkgDir)
696 HashFile = os.path.join(PkgDir, Pkg.PackageName + '.hash')
697 m = hashlib.md5()
698 # Get .dec file's hash value
699 f = open(Pkg.MetaFile.Path, 'r')
700 Content = f.read()
701 f.close()
702 m.update(Content)
703 # Get include files hash value
704 if Pkg.Includes:
705 for inc in sorted(Pkg.Includes, key=lambda x: str(x)):
706 for Root, Dirs, Files in os.walk(str(inc)):
707 for File in sorted(Files):
708 File_Path = os.path.join(Root, File)
709 f = open(File_Path, 'r')
710 Content = f.read()
711 f.close()
712 m.update(Content)
713 SaveFileOnChange(HashFile, m.hexdigest(), True)
714 GlobalData.gPackageHash[Pkg.Arch][Pkg.PackageName] = m.hexdigest()
715
716 def _GetMetaFiles(self, Target, Toolchain, Arch):
717 AllWorkSpaceMetaFiles = set()
718 #
719 # add fdf
720 #
721 if self.FdfFile:
722 AllWorkSpaceMetaFiles.add (self.FdfFile.Path)
723 for f in GlobalData.gFdfParser.GetAllIncludedFile():
724 AllWorkSpaceMetaFiles.add (f.FileName)
725 #
726 # add dsc
727 #
728 AllWorkSpaceMetaFiles.add(self.MetaFile.Path)
729
730 #
731 # add build_rule.txt & tools_def.txt
732 #
733 AllWorkSpaceMetaFiles.add(os.path.join(GlobalData.gConfDirectory, gDefaultBuildRuleFile))
734 AllWorkSpaceMetaFiles.add(os.path.join(GlobalData.gConfDirectory, gDefaultToolsDefFile))
735
736 # add BuildOption metafile
737 #
738 AllWorkSpaceMetaFiles.add(os.path.join(self.BuildDir, 'BuildOptions'))
739
740 # add PcdToken Number file for Dynamic/DynamicEx Pcd
741 #
742 AllWorkSpaceMetaFiles.add(os.path.join(self.BuildDir, 'PcdTokenNumber'))
743
744 for Arch in self.ArchList:
745 #
746 # add dec
747 #
748 for Package in PlatformAutoGen(self, self.MetaFile, Target, Toolchain, Arch).PackageList:
749 AllWorkSpaceMetaFiles.add(Package.MetaFile.Path)
750
751 #
752 # add included dsc
753 #
754 for filePath in self.BuildDatabase[self.MetaFile, Arch, Target, Toolchain]._RawData.IncludedFiles:
755 AllWorkSpaceMetaFiles.add(filePath.Path)
756
757 return AllWorkSpaceMetaFiles
758
759 def _CheckPcdDefineAndType(self):
760 PcdTypeSet = {TAB_PCDS_FIXED_AT_BUILD,
761 TAB_PCDS_PATCHABLE_IN_MODULE,
762 TAB_PCDS_FEATURE_FLAG,
763 TAB_PCDS_DYNAMIC,
764 TAB_PCDS_DYNAMIC_EX}
765
766 # This dict store PCDs which are not used by any modules with specified arches
767 UnusedPcd = OrderedDict()
768 for Pa in self.AutoGenObjectList:
769 # Key of DSC's Pcds dictionary is PcdCName, TokenSpaceGuid
770 for Pcd in Pa.Platform.Pcds:
771 PcdType = Pa.Platform.Pcds[Pcd].Type
772
773 # If no PCD type, this PCD comes from FDF
774 if not PcdType:
775 continue
776
777 # Try to remove Hii and Vpd suffix
778 if PcdType.startswith(TAB_PCDS_DYNAMIC_EX):
779 PcdType = TAB_PCDS_DYNAMIC_EX
780 elif PcdType.startswith(TAB_PCDS_DYNAMIC):
781 PcdType = TAB_PCDS_DYNAMIC
782
783 for Package in Pa.PackageList:
784 # Key of DEC's Pcds dictionary is PcdCName, TokenSpaceGuid, PcdType
785 if (Pcd[0], Pcd[1], PcdType) in Package.Pcds:
786 break
787 for Type in PcdTypeSet:
788 if (Pcd[0], Pcd[1], Type) in Package.Pcds:
789 EdkLogger.error(
790 'build',
791 FORMAT_INVALID,
792 "Type [%s] of PCD [%s.%s] in DSC file doesn't match the type [%s] defined in DEC file." \
793 % (Pa.Platform.Pcds[Pcd].Type, Pcd[1], Pcd[0], Type),
794 ExtraData=None
795 )
796 return
797 else:
798 UnusedPcd.setdefault(Pcd, []).append(Pa.Arch)
799
800 for Pcd in UnusedPcd:
801 EdkLogger.warn(
802 'build',
803 "The PCD was not specified by any INF module in the platform for the given architecture.\n"
804 "\tPCD: [%s.%s]\n\tPlatform: [%s]\n\tArch: %s"
805 % (Pcd[1], Pcd[0], os.path.basename(str(self.MetaFile)), str(UnusedPcd[Pcd])),
806 ExtraData=None
807 )
808
809 def __repr__(self):
810 return "%s [%s]" % (self.MetaFile, ", ".join(self.ArchList))
811
812 ## Return the directory to store FV files
813 def _GetFvDir(self):
814 if self._FvDir is None:
815 self._FvDir = path.join(self.BuildDir, TAB_FV_DIRECTORY)
816 return self._FvDir
817
818 ## Return the directory to store all intermediate and final files built
819 def _GetBuildDir(self):
820 if self._BuildDir is None:
821 return self.AutoGenObjectList[0].BuildDir
822
823 ## Return the build output directory platform specifies
824 def _GetOutputDir(self):
825 return self.Platform.OutputDirectory
826
827 ## Return platform name
828 def _GetName(self):
829 return self.Platform.PlatformName
830
831 ## Return meta-file GUID
832 def _GetGuid(self):
833 return self.Platform.Guid
834
835 ## Return platform version
836 def _GetVersion(self):
837 return self.Platform.Version
838
839 ## Return paths of tools
840 def _GetToolDefinition(self):
841 return self.AutoGenObjectList[0].ToolDefinition
842
843 ## Return directory of platform makefile
844 #
845 # @retval string Makefile directory
846 #
847 def _GetMakeFileDir(self):
848 if self._MakeFileDir is None:
849 self._MakeFileDir = self.BuildDir
850 return self._MakeFileDir
851
852 ## Return build command string
853 #
854 # @retval string Build command string
855 #
856 def _GetBuildCommand(self):
857 if self._BuildCommand is None:
858 # BuildCommand should be all the same. So just get one from platform AutoGen
859 self._BuildCommand = self.AutoGenObjectList[0].BuildCommand
860 return self._BuildCommand
861
862 ## Check the PCDs token value conflict in each DEC file.
863 #
864 # Will cause build break and raise error message while two PCDs conflict.
865 #
866 # @return None
867 #
868 def _CheckAllPcdsTokenValueConflict(self):
869 for Pa in self.AutoGenObjectList:
870 for Package in Pa.PackageList:
871 PcdList = Package.Pcds.values()
872 PcdList.sort(key=lambda x: int(x.TokenValue, 0))
873 Count = 0
874 while (Count < len(PcdList) - 1) :
875 Item = PcdList[Count]
876 ItemNext = PcdList[Count + 1]
877 #
878 # Make sure in the same token space the TokenValue should be unique
879 #
880 if (int(Item.TokenValue, 0) == int(ItemNext.TokenValue, 0)):
881 SameTokenValuePcdList = []
882 SameTokenValuePcdList.append(Item)
883 SameTokenValuePcdList.append(ItemNext)
884 RemainPcdListLength = len(PcdList) - Count - 2
885 for ValueSameCount in range(RemainPcdListLength):
886 if int(PcdList[len(PcdList) - RemainPcdListLength + ValueSameCount].TokenValue, 0) == int(Item.TokenValue, 0):
887 SameTokenValuePcdList.append(PcdList[len(PcdList) - RemainPcdListLength + ValueSameCount])
888 else:
889 break;
890 #
891 # Sort same token value PCD list with TokenGuid and TokenCName
892 #
893 SameTokenValuePcdList.sort(key=lambda x: "%s.%s" % (x.TokenSpaceGuidCName, x.TokenCName))
894 SameTokenValuePcdListCount = 0
895 while (SameTokenValuePcdListCount < len(SameTokenValuePcdList) - 1):
896 Flag = False
897 TemListItem = SameTokenValuePcdList[SameTokenValuePcdListCount]
898 TemListItemNext = SameTokenValuePcdList[SameTokenValuePcdListCount + 1]
899
900 if (TemListItem.TokenSpaceGuidCName == TemListItemNext.TokenSpaceGuidCName) and (TemListItem.TokenCName != TemListItemNext.TokenCName):
901 for PcdItem in GlobalData.MixedPcd:
902 if (TemListItem.TokenCName, TemListItem.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem] or \
903 (TemListItemNext.TokenCName, TemListItemNext.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
904 Flag = True
905 if not Flag:
906 EdkLogger.error(
907 'build',
908 FORMAT_INVALID,
909 "The TokenValue [%s] of PCD [%s.%s] is conflict with: [%s.%s] in %s"\
910 % (TemListItem.TokenValue, TemListItem.TokenSpaceGuidCName, TemListItem.TokenCName, TemListItemNext.TokenSpaceGuidCName, TemListItemNext.TokenCName, Package),
911 ExtraData=None
912 )
913 SameTokenValuePcdListCount += 1
914 Count += SameTokenValuePcdListCount
915 Count += 1
916
917 PcdList = Package.Pcds.values()
918 PcdList.sort(key=lambda x: "%s.%s" % (x.TokenSpaceGuidCName, x.TokenCName))
919 Count = 0
920 while (Count < len(PcdList) - 1) :
921 Item = PcdList[Count]
922 ItemNext = PcdList[Count + 1]
923 #
924 # Check PCDs with same TokenSpaceGuidCName.TokenCName have same token value as well.
925 #
926 if (Item.TokenSpaceGuidCName == ItemNext.TokenSpaceGuidCName) and (Item.TokenCName == ItemNext.TokenCName) and (int(Item.TokenValue, 0) != int(ItemNext.TokenValue, 0)):
927 EdkLogger.error(
928 'build',
929 FORMAT_INVALID,
930 "The TokenValue [%s] of PCD [%s.%s] in %s defined in two places should be same as well."\
931 % (Item.TokenValue, Item.TokenSpaceGuidCName, Item.TokenCName, Package),
932 ExtraData=None
933 )
934 Count += 1
935 ## Generate fds command
936 def _GenFdsCommand(self):
937 return (GenMake.TopLevelMakefile(self)._TEMPLATE_.Replace(GenMake.TopLevelMakefile(self)._TemplateDict)).strip()
938
939 ## Create makefile for the platform and modules in it
940 #
941 # @param CreateDepsMakeFile Flag indicating if the makefile for
942 # modules will be created as well
943 #
944 def CreateMakeFile(self, CreateDepsMakeFile=False):
945 if not CreateDepsMakeFile:
946 return
947 for Pa in self.AutoGenObjectList:
948 Pa.CreateMakeFile(True)
949
950 ## Create autogen code for platform and modules
951 #
952 # Since there's no autogen code for platform, this method will do nothing
953 # if CreateModuleCodeFile is set to False.
954 #
955 # @param CreateDepsCodeFile Flag indicating if creating module's
956 # autogen code file or not
957 #
958 def CreateCodeFile(self, CreateDepsCodeFile=False):
959 if not CreateDepsCodeFile:
960 return
961 for Pa in self.AutoGenObjectList:
962 Pa.CreateCodeFile(True)
963
964 ## Create AsBuilt INF file the platform
965 #
966 def CreateAsBuiltInf(self):
967 return
968
969 Name = property(_GetName)
970 Guid = property(_GetGuid)
971 Version = property(_GetVersion)
972 OutputDir = property(_GetOutputDir)
973
974 ToolDefinition = property(_GetToolDefinition) # toolcode : tool path
975
976 BuildDir = property(_GetBuildDir)
977 FvDir = property(_GetFvDir)
978 MakeFileDir = property(_GetMakeFileDir)
979 BuildCommand = property(_GetBuildCommand)
980 GenFdsCommand = property(_GenFdsCommand)
981
982 ## AutoGen class for platform
983 #
984 # PlatformAutoGen class will process the original information in platform
985 # file in order to generate makefile for platform.
986 #
987 class PlatformAutoGen(AutoGen):
988 # call super().__init__ then call the worker function with different parameter count
989 def __init__(self, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs):
990 if not hasattr(self, "_Init"):
991 super(PlatformAutoGen, self).__init__(self, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs)
992 self._InitWorker(Workspace, MetaFile, Target, Toolchain, Arch)
993 self._Init = True
994 #
995 # Used to store all PCDs for both PEI and DXE phase, in order to generate
996 # correct PCD database
997 #
998 _DynaPcdList_ = []
999 _NonDynaPcdList_ = []
1000 _PlatformPcds = {}
1001
1002 #
1003 # The priority list while override build option
1004 #
1005 PrioList = {"0x11111" : 16, # TARGET_TOOLCHAIN_ARCH_COMMANDTYPE_ATTRIBUTE (Highest)
1006 "0x01111" : 15, # ******_TOOLCHAIN_ARCH_COMMANDTYPE_ATTRIBUTE
1007 "0x10111" : 14, # TARGET_*********_ARCH_COMMANDTYPE_ATTRIBUTE
1008 "0x00111" : 13, # ******_*********_ARCH_COMMANDTYPE_ATTRIBUTE
1009 "0x11011" : 12, # TARGET_TOOLCHAIN_****_COMMANDTYPE_ATTRIBUTE
1010 "0x01011" : 11, # ******_TOOLCHAIN_****_COMMANDTYPE_ATTRIBUTE
1011 "0x10011" : 10, # TARGET_*********_****_COMMANDTYPE_ATTRIBUTE
1012 "0x00011" : 9, # ******_*********_****_COMMANDTYPE_ATTRIBUTE
1013 "0x11101" : 8, # TARGET_TOOLCHAIN_ARCH_***********_ATTRIBUTE
1014 "0x01101" : 7, # ******_TOOLCHAIN_ARCH_***********_ATTRIBUTE
1015 "0x10101" : 6, # TARGET_*********_ARCH_***********_ATTRIBUTE
1016 "0x00101" : 5, # ******_*********_ARCH_***********_ATTRIBUTE
1017 "0x11001" : 4, # TARGET_TOOLCHAIN_****_***********_ATTRIBUTE
1018 "0x01001" : 3, # ******_TOOLCHAIN_****_***********_ATTRIBUTE
1019 "0x10001" : 2, # TARGET_*********_****_***********_ATTRIBUTE
1020 "0x00001" : 1} # ******_*********_****_***********_ATTRIBUTE (Lowest)
1021
1022 ## Initialize PlatformAutoGen
1023 #
1024 #
1025 # @param Workspace WorkspaceAutoGen object
1026 # @param PlatformFile Platform file (DSC file)
1027 # @param Target Build target (DEBUG, RELEASE)
1028 # @param Toolchain Name of tool chain
1029 # @param Arch arch of the platform supports
1030 #
1031 def _InitWorker(self, Workspace, PlatformFile, Target, Toolchain, Arch):
1032 EdkLogger.debug(EdkLogger.DEBUG_9, "AutoGen platform [%s] [%s]" % (PlatformFile, Arch))
1033 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (PlatformFile, Arch, Toolchain, Target)
1034
1035 self.MetaFile = PlatformFile
1036 self.Workspace = Workspace
1037 self.WorkspaceDir = Workspace.WorkspaceDir
1038 self.ToolChain = Toolchain
1039 self.BuildTarget = Target
1040 self.Arch = Arch
1041 self.SourceDir = PlatformFile.SubDir
1042 self.SourceOverrideDir = None
1043 self.FdTargetList = self.Workspace.FdTargetList
1044 self.FvTargetList = self.Workspace.FvTargetList
1045 self.AllPcdList = []
1046 # get the original module/package/platform objects
1047 self.BuildDatabase = Workspace.BuildDatabase
1048 self.DscBuildDataObj = Workspace.Platform
1049
1050 # flag indicating if the makefile/C-code file has been created or not
1051 self.IsMakeFileCreated = False
1052
1053 self._DynamicPcdList = None # [(TokenCName1, TokenSpaceGuidCName1), (TokenCName2, TokenSpaceGuidCName2), ...]
1054 self._NonDynamicPcdList = None # [(TokenCName1, TokenSpaceGuidCName1), (TokenCName2, TokenSpaceGuidCName2), ...]
1055
1056 self._AsBuildInfList = []
1057 self._AsBuildModuleList = []
1058
1059 self.VariableInfo = None
1060
1061 if GlobalData.gFdfParser is not None:
1062 self._AsBuildInfList = GlobalData.gFdfParser.Profile.InfList
1063 for Inf in self._AsBuildInfList:
1064 InfClass = PathClass(NormPath(Inf), GlobalData.gWorkspace, self.Arch)
1065 M = self.BuildDatabase[InfClass, self.Arch, self.BuildTarget, self.ToolChain]
1066 if not M.IsBinaryModule:
1067 continue
1068 self._AsBuildModuleList.append(InfClass)
1069 # get library/modules for build
1070 self.LibraryBuildDirectoryList = []
1071 self.ModuleBuildDirectoryList = []
1072
1073 return True
1074
1075 @cached_class_function
1076 def __repr__(self):
1077 return "%s [%s]" % (self.MetaFile, self.Arch)
1078
1079 ## Create autogen code for platform and modules
1080 #
1081 # Since there's no autogen code for platform, this method will do nothing
1082 # if CreateModuleCodeFile is set to False.
1083 #
1084 # @param CreateModuleCodeFile Flag indicating if creating module's
1085 # autogen code file or not
1086 #
1087 @cached_class_function
1088 def CreateCodeFile(self, CreateModuleCodeFile=False):
1089 # only module has code to be greated, so do nothing if CreateModuleCodeFile is False
1090 if not CreateModuleCodeFile:
1091 return
1092
1093 for Ma in self.ModuleAutoGenList:
1094 Ma.CreateCodeFile(True)
1095
1096 ## Generate Fds Command
1097 @cached_property
1098 def GenFdsCommand(self):
1099 return self.Workspace.GenFdsCommand
1100
1101 ## Create makefile for the platform and mdoules in it
1102 #
1103 # @param CreateModuleMakeFile Flag indicating if the makefile for
1104 # modules will be created as well
1105 #
1106 def CreateMakeFile(self, CreateModuleMakeFile=False, FfsCommand = {}):
1107 if CreateModuleMakeFile:
1108 for ModuleFile in self.Platform.Modules:
1109 Ma = ModuleAutoGen(self.Workspace, ModuleFile, self.BuildTarget,
1110 self.ToolChain, self.Arch, self.MetaFile)
1111 if (ModuleFile.File, self.Arch) in FfsCommand:
1112 Ma.CreateMakeFile(True, FfsCommand[ModuleFile.File, self.Arch])
1113 else:
1114 Ma.CreateMakeFile(True)
1115 #Ma.CreateAsBuiltInf()
1116
1117 # no need to create makefile for the platform more than once
1118 if self.IsMakeFileCreated:
1119 return
1120
1121 # create library/module build dirs for platform
1122 Makefile = GenMake.PlatformMakefile(self)
1123 self.LibraryBuildDirectoryList = Makefile.GetLibraryBuildDirectoryList()
1124 self.ModuleBuildDirectoryList = Makefile.GetModuleBuildDirectoryList()
1125
1126 self.IsMakeFileCreated = True
1127
1128 ## Deal with Shared FixedAtBuild Pcds
1129 #
1130 def CollectFixedAtBuildPcds(self):
1131 for LibAuto in self.LibraryAutoGenList:
1132 FixedAtBuildPcds = {}
1133 ShareFixedAtBuildPcdsSameValue = {}
1134 for Module in LibAuto.ReferenceModules:
1135 for Pcd in set(Module.FixedAtBuildPcds + LibAuto.FixedAtBuildPcds):
1136 DefaultValue = Pcd.DefaultValue
1137 # Cover the case: DSC component override the Pcd value and the Pcd only used in one Lib
1138 if Pcd in Module.LibraryPcdList:
1139 Index = Module.LibraryPcdList.index(Pcd)
1140 DefaultValue = Module.LibraryPcdList[Index].DefaultValue
1141 key = ".".join((Pcd.TokenSpaceGuidCName, Pcd.TokenCName))
1142 if key not in FixedAtBuildPcds:
1143 ShareFixedAtBuildPcdsSameValue[key] = True
1144 FixedAtBuildPcds[key] = DefaultValue
1145 else:
1146 if FixedAtBuildPcds[key] != DefaultValue:
1147 ShareFixedAtBuildPcdsSameValue[key] = False
1148 for Pcd in LibAuto.FixedAtBuildPcds:
1149 key = ".".join((Pcd.TokenSpaceGuidCName, Pcd.TokenCName))
1150 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) not in self.NonDynamicPcdDict:
1151 continue
1152 else:
1153 DscPcd = self.NonDynamicPcdDict[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName)]
1154 if DscPcd.Type != TAB_PCDS_FIXED_AT_BUILD:
1155 continue
1156 if key in ShareFixedAtBuildPcdsSameValue and ShareFixedAtBuildPcdsSameValue[key]:
1157 LibAuto.ConstPcd[key] = FixedAtBuildPcds[key]
1158
1159 def CollectVariables(self, DynamicPcdSet):
1160 VpdRegionSize = 0
1161 VpdRegionBase = 0
1162 if self.Workspace.FdfFile:
1163 FdDict = self.Workspace.FdfProfile.FdDict[GlobalData.gFdfParser.CurrentFdName]
1164 for FdRegion in FdDict.RegionList:
1165 for item in FdRegion.RegionDataList:
1166 if self.Platform.VpdToolGuid.strip() and self.Platform.VpdToolGuid in item:
1167 VpdRegionSize = FdRegion.Size
1168 VpdRegionBase = FdRegion.Offset
1169 break
1170
1171 VariableInfo = VariableMgr(self.DscBuildDataObj._GetDefaultStores(), self.DscBuildDataObj._GetSkuIds())
1172 VariableInfo.SetVpdRegionMaxSize(VpdRegionSize)
1173 VariableInfo.SetVpdRegionOffset(VpdRegionBase)
1174 Index = 0
1175 for Pcd in DynamicPcdSet:
1176 pcdname = ".".join((Pcd.TokenSpaceGuidCName, Pcd.TokenCName))
1177 for SkuName in Pcd.SkuInfoList:
1178 Sku = Pcd.SkuInfoList[SkuName]
1179 SkuId = Sku.SkuId
1180 if SkuId is None or SkuId == '':
1181 continue
1182 if len(Sku.VariableName) > 0:
1183 VariableGuidStructure = Sku.VariableGuidValue
1184 VariableGuid = GuidStructureStringToGuidString(VariableGuidStructure)
1185 for StorageName in Sku.DefaultStoreDict:
1186 VariableInfo.append_variable(var_info(Index, pcdname, StorageName, SkuName, StringToArray(Sku.VariableName), VariableGuid, Sku.VariableOffset, Sku.VariableAttribute, Sku.HiiDefaultValue, Sku.DefaultStoreDict[StorageName], Pcd.DatumType))
1187 Index += 1
1188 return VariableInfo
1189
1190 def UpdateNVStoreMaxSize(self, OrgVpdFile):
1191 if self.VariableInfo:
1192 VpdMapFilePath = os.path.join(self.BuildDir, TAB_FV_DIRECTORY, "%s.map" % self.Platform.VpdToolGuid)
1193 PcdNvStoreDfBuffer = [item for item in self._DynamicPcdList if item.TokenCName == "PcdNvStoreDefaultValueBuffer" and item.TokenSpaceGuidCName == "gEfiMdeModulePkgTokenSpaceGuid"]
1194
1195 if PcdNvStoreDfBuffer:
1196 if os.path.exists(VpdMapFilePath):
1197 OrgVpdFile.Read(VpdMapFilePath)
1198 PcdItems = OrgVpdFile.GetOffset(PcdNvStoreDfBuffer[0])
1199 NvStoreOffset = PcdItems.values()[0].strip() if PcdItems else '0'
1200 else:
1201 EdkLogger.error("build", FILE_READ_FAILURE, "Can not find VPD map file %s to fix up VPD offset." % VpdMapFilePath)
1202
1203 NvStoreOffset = int(NvStoreOffset, 16) if NvStoreOffset.upper().startswith("0X") else int(NvStoreOffset)
1204 default_skuobj = PcdNvStoreDfBuffer[0].SkuInfoList.get(TAB_DEFAULT)
1205 maxsize = self.VariableInfo.VpdRegionSize - NvStoreOffset if self.VariableInfo.VpdRegionSize else len(default_skuobj.DefaultValue.split(","))
1206 var_data = self.VariableInfo.PatchNVStoreDefaultMaxSize(maxsize)
1207
1208 if var_data and default_skuobj:
1209 default_skuobj.DefaultValue = var_data
1210 PcdNvStoreDfBuffer[0].DefaultValue = var_data
1211 PcdNvStoreDfBuffer[0].SkuInfoList.clear()
1212 PcdNvStoreDfBuffer[0].SkuInfoList[TAB_DEFAULT] = default_skuobj
1213 PcdNvStoreDfBuffer[0].MaxDatumSize = str(len(default_skuobj.DefaultValue.split(",")))
1214
1215 return OrgVpdFile
1216
1217 ## Collect dynamic PCDs
1218 #
1219 # Gather dynamic PCDs list from each module and their settings from platform
1220 # This interface should be invoked explicitly when platform action is created.
1221 #
1222 def CollectPlatformDynamicPcds(self):
1223 for key in self.Platform.Pcds:
1224 for SinglePcd in GlobalData.MixedPcd:
1225 if (self.Platform.Pcds[key].TokenCName, self.Platform.Pcds[key].TokenSpaceGuidCName) == SinglePcd:
1226 for item in GlobalData.MixedPcd[SinglePcd]:
1227 Pcd_Type = item[0].split('_')[-1]
1228 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 \
1229 (Pcd_Type == TAB_PCDS_DYNAMIC and self.Platform.Pcds[key].Type in PCD_DYNAMIC_TYPE_SET):
1230 Value = self.Platform.Pcds[key]
1231 Value.TokenCName = self.Platform.Pcds[key].TokenCName + '_' + Pcd_Type
1232 if len(key) == 2:
1233 newkey = (Value.TokenCName, key[1])
1234 elif len(key) == 3:
1235 newkey = (Value.TokenCName, key[1], key[2])
1236 del self.Platform.Pcds[key]
1237 self.Platform.Pcds[newkey] = Value
1238 break
1239 break
1240
1241 # for gathering error information
1242 NoDatumTypePcdList = set()
1243 FdfModuleList = []
1244 for InfName in self._AsBuildInfList:
1245 InfName = mws.join(self.WorkspaceDir, InfName)
1246 FdfModuleList.append(os.path.normpath(InfName))
1247 for F in self.Platform.Modules.keys():
1248 M = ModuleAutoGen(self.Workspace, F, self.BuildTarget, self.ToolChain, self.Arch, self.MetaFile)
1249 #GuidValue.update(M.Guids)
1250
1251 self.Platform.Modules[F].M = M
1252
1253 for PcdFromModule in M.ModulePcdList + M.LibraryPcdList:
1254 # make sure that the "VOID*" kind of datum has MaxDatumSize set
1255 if PcdFromModule.DatumType == TAB_VOID and not PcdFromModule.MaxDatumSize:
1256 NoDatumTypePcdList.add("%s.%s [%s]" % (PcdFromModule.TokenSpaceGuidCName, PcdFromModule.TokenCName, F))
1257
1258 # Check the PCD from Binary INF or Source INF
1259 if M.IsBinaryModule == True:
1260 PcdFromModule.IsFromBinaryInf = True
1261
1262 # Check the PCD from DSC or not
1263 PcdFromModule.IsFromDsc = (PcdFromModule.TokenCName, PcdFromModule.TokenSpaceGuidCName) in self.Platform.Pcds
1264
1265 if PcdFromModule.Type in PCD_DYNAMIC_TYPE_SET or PcdFromModule.Type in PCD_DYNAMIC_EX_TYPE_SET:
1266 if F.Path not in FdfModuleList:
1267 # If one of the Source built modules listed in the DSC is not listed
1268 # in FDF modules, and the INF lists a PCD can only use the PcdsDynamic
1269 # access method (it is only listed in the DEC file that declares the
1270 # PCD as PcdsDynamic), then build tool will report warning message
1271 # notify the PI that they are attempting to build a module that must
1272 # be included in a flash image in order to be functional. These Dynamic
1273 # PCD will not be added into the Database unless it is used by other
1274 # modules that are included in the FDF file.
1275 if PcdFromModule.Type in PCD_DYNAMIC_TYPE_SET and \
1276 PcdFromModule.IsFromBinaryInf == False:
1277 # Print warning message to let the developer make a determine.
1278 continue
1279 # If one of the Source built modules listed in the DSC is not listed in
1280 # FDF modules, and the INF lists a PCD can only use the PcdsDynamicEx
1281 # access method (it is only listed in the DEC file that declares the
1282 # PCD as PcdsDynamicEx), then DO NOT break the build; DO NOT add the
1283 # PCD to the Platform's PCD Database.
1284 if PcdFromModule.Type in PCD_DYNAMIC_EX_TYPE_SET:
1285 continue
1286 #
1287 # If a dynamic PCD used by a PEM module/PEI module & DXE module,
1288 # it should be stored in Pcd PEI database, If a dynamic only
1289 # used by DXE module, it should be stored in DXE PCD database.
1290 # The default Phase is DXE
1291 #
1292 if M.ModuleType in SUP_MODULE_SET_PEI:
1293 PcdFromModule.Phase = "PEI"
1294 if PcdFromModule not in self._DynaPcdList_:
1295 self._DynaPcdList_.append(PcdFromModule)
1296 elif PcdFromModule.Phase == 'PEI':
1297 # overwrite any the same PCD existing, if Phase is PEI
1298 Index = self._DynaPcdList_.index(PcdFromModule)
1299 self._DynaPcdList_[Index] = PcdFromModule
1300 elif PcdFromModule not in self._NonDynaPcdList_:
1301 self._NonDynaPcdList_.append(PcdFromModule)
1302 elif PcdFromModule in self._NonDynaPcdList_ and PcdFromModule.IsFromBinaryInf == True:
1303 Index = self._NonDynaPcdList_.index(PcdFromModule)
1304 if self._NonDynaPcdList_[Index].IsFromBinaryInf == False:
1305 #The PCD from Binary INF will override the same one from source INF
1306 self._NonDynaPcdList_.remove (self._NonDynaPcdList_[Index])
1307 PcdFromModule.Pending = False
1308 self._NonDynaPcdList_.append (PcdFromModule)
1309 DscModuleSet = {os.path.normpath(ModuleInf.Path) for ModuleInf in self.Platform.Modules}
1310 # add the PCD from modules that listed in FDF but not in DSC to Database
1311 for InfName in FdfModuleList:
1312 if InfName not in DscModuleSet:
1313 InfClass = PathClass(InfName)
1314 M = self.BuildDatabase[InfClass, self.Arch, self.BuildTarget, self.ToolChain]
1315 # If a module INF in FDF but not in current arch's DSC module list, it must be module (either binary or source)
1316 # for different Arch. PCDs in source module for different Arch is already added before, so skip the source module here.
1317 # For binary module, if in current arch, we need to list the PCDs into database.
1318 if not M.IsBinaryModule:
1319 continue
1320 # Override the module PCD setting by platform setting
1321 ModulePcdList = self.ApplyPcdSetting(M, M.Pcds)
1322 for PcdFromModule in ModulePcdList:
1323 PcdFromModule.IsFromBinaryInf = True
1324 PcdFromModule.IsFromDsc = False
1325 # Only allow the DynamicEx and Patchable PCD in AsBuild INF
1326 if PcdFromModule.Type not in PCD_DYNAMIC_EX_TYPE_SET and PcdFromModule.Type not in TAB_PCDS_PATCHABLE_IN_MODULE:
1327 EdkLogger.error("build", AUTOGEN_ERROR, "PCD setting error",
1328 File=self.MetaFile,
1329 ExtraData="\n\tExisted %s PCD %s in:\n\t\t%s\n"
1330 % (PcdFromModule.Type, PcdFromModule.TokenCName, InfName))
1331 # make sure that the "VOID*" kind of datum has MaxDatumSize set
1332 if PcdFromModule.DatumType == TAB_VOID and not PcdFromModule.MaxDatumSize:
1333 NoDatumTypePcdList.add("%s.%s [%s]" % (PcdFromModule.TokenSpaceGuidCName, PcdFromModule.TokenCName, InfName))
1334 if M.ModuleType in SUP_MODULE_SET_PEI:
1335 PcdFromModule.Phase = "PEI"
1336 if PcdFromModule not in self._DynaPcdList_ and PcdFromModule.Type in PCD_DYNAMIC_EX_TYPE_SET:
1337 self._DynaPcdList_.append(PcdFromModule)
1338 elif PcdFromModule not in self._NonDynaPcdList_ and PcdFromModule.Type in TAB_PCDS_PATCHABLE_IN_MODULE:
1339 self._NonDynaPcdList_.append(PcdFromModule)
1340 if PcdFromModule in self._DynaPcdList_ and PcdFromModule.Phase == 'PEI' and PcdFromModule.Type in PCD_DYNAMIC_EX_TYPE_SET:
1341 # Overwrite the phase of any the same PCD existing, if Phase is PEI.
1342 # It is to solve the case that a dynamic PCD used by a PEM module/PEI
1343 # module & DXE module at a same time.
1344 # Overwrite the type of the PCDs in source INF by the type of AsBuild
1345 # INF file as DynamicEx.
1346 Index = self._DynaPcdList_.index(PcdFromModule)
1347 self._DynaPcdList_[Index].Phase = PcdFromModule.Phase
1348 self._DynaPcdList_[Index].Type = PcdFromModule.Type
1349 for PcdFromModule in self._NonDynaPcdList_:
1350 # If a PCD is not listed in the DSC file, but binary INF files used by
1351 # this platform all (that use this PCD) list the PCD in a [PatchPcds]
1352 # section, AND all source INF files used by this platform the build
1353 # that use the PCD list the PCD in either a [Pcds] or [PatchPcds]
1354 # section, then the tools must NOT add the PCD to the Platform's PCD
1355 # Database; the build must assign the access method for this PCD as
1356 # PcdsPatchableInModule.
1357 if PcdFromModule not in self._DynaPcdList_:
1358 continue
1359 Index = self._DynaPcdList_.index(PcdFromModule)
1360 if PcdFromModule.IsFromDsc == False and \
1361 PcdFromModule.Type in TAB_PCDS_PATCHABLE_IN_MODULE and \
1362 PcdFromModule.IsFromBinaryInf == True and \
1363 self._DynaPcdList_[Index].IsFromBinaryInf == False:
1364 Index = self._DynaPcdList_.index(PcdFromModule)
1365 self._DynaPcdList_.remove (self._DynaPcdList_[Index])
1366
1367 # print out error information and break the build, if error found
1368 if len(NoDatumTypePcdList) > 0:
1369 NoDatumTypePcdListString = "\n\t\t".join(NoDatumTypePcdList)
1370 EdkLogger.error("build", AUTOGEN_ERROR, "PCD setting error",
1371 File=self.MetaFile,
1372 ExtraData="\n\tPCD(s) without MaxDatumSize:\n\t\t%s\n"
1373 % NoDatumTypePcdListString)
1374 self._NonDynamicPcdList = self._NonDynaPcdList_
1375 self._DynamicPcdList = self._DynaPcdList_
1376 #
1377 # Sort dynamic PCD list to:
1378 # 1) If PCD's datum type is VOID* and value is unicode string which starts with L, the PCD item should
1379 # try to be put header of dynamicd List
1380 # 2) If PCD is HII type, the PCD item should be put after unicode type PCD
1381 #
1382 # The reason of sorting is make sure the unicode string is in double-byte alignment in string table.
1383 #
1384 UnicodePcdArray = set()
1385 HiiPcdArray = set()
1386 OtherPcdArray = set()
1387 VpdPcdDict = {}
1388 VpdFile = VpdInfoFile.VpdInfoFile()
1389 NeedProcessVpdMapFile = False
1390
1391 for pcd in self.Platform.Pcds:
1392 if pcd not in self._PlatformPcds:
1393 self._PlatformPcds[pcd] = self.Platform.Pcds[pcd]
1394
1395 for item in self._PlatformPcds:
1396 if self._PlatformPcds[item].DatumType and self._PlatformPcds[item].DatumType not in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64, TAB_VOID, "BOOLEAN"]:
1397 self._PlatformPcds[item].DatumType = TAB_VOID
1398
1399 if (self.Workspace.ArchList[-1] == self.Arch):
1400 for Pcd in self._DynamicPcdList:
1401 # just pick the a value to determine whether is unicode string type
1402 Sku = Pcd.SkuInfoList.values()[0]
1403 Sku.VpdOffset = Sku.VpdOffset.strip()
1404
1405 if Pcd.DatumType not in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64, TAB_VOID, "BOOLEAN"]:
1406 Pcd.DatumType = TAB_VOID
1407
1408 # if found PCD which datum value is unicode string the insert to left size of UnicodeIndex
1409 # if found HII type PCD then insert to right of UnicodeIndex
1410 if Pcd.Type in [TAB_PCDS_DYNAMIC_VPD, TAB_PCDS_DYNAMIC_EX_VPD]:
1411 VpdPcdDict[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName)] = Pcd
1412
1413 #Collect DynamicHii PCD values and assign it to DynamicExVpd PCD gEfiMdeModulePkgTokenSpaceGuid.PcdNvStoreDefaultValueBuffer
1414 PcdNvStoreDfBuffer = VpdPcdDict.get(("PcdNvStoreDefaultValueBuffer", "gEfiMdeModulePkgTokenSpaceGuid"))
1415 if PcdNvStoreDfBuffer:
1416 self.VariableInfo = self.CollectVariables(self._DynamicPcdList)
1417 vardump = self.VariableInfo.dump()
1418 if vardump:
1419 PcdNvStoreDfBuffer.DefaultValue = vardump
1420 for skuname in PcdNvStoreDfBuffer.SkuInfoList:
1421 PcdNvStoreDfBuffer.SkuInfoList[skuname].DefaultValue = vardump
1422 PcdNvStoreDfBuffer.MaxDatumSize = str(len(vardump.split(",")))
1423 else:
1424 #If the end user define [DefaultStores] and [XXX.Menufacturing] in DSC, but forget to configure PcdNvStoreDefaultValueBuffer to PcdsDynamicVpd
1425 if [Pcd for Pcd in self._DynamicPcdList if Pcd.UserDefinedDefaultStoresFlag]:
1426 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)
1427 PlatformPcds = sorted(self._PlatformPcds.keys())
1428 #
1429 # Add VPD type PCD into VpdFile and determine whether the VPD PCD need to be fixed up.
1430 #
1431 VpdSkuMap = {}
1432 for PcdKey in PlatformPcds:
1433 Pcd = self._PlatformPcds[PcdKey]
1434 if Pcd.Type in [TAB_PCDS_DYNAMIC_VPD, TAB_PCDS_DYNAMIC_EX_VPD] and \
1435 PcdKey in VpdPcdDict:
1436 Pcd = VpdPcdDict[PcdKey]
1437 SkuValueMap = {}
1438 DefaultSku = Pcd.SkuInfoList.get(TAB_DEFAULT)
1439 if DefaultSku:
1440 PcdValue = DefaultSku.DefaultValue
1441 if PcdValue not in SkuValueMap:
1442 SkuValueMap[PcdValue] = []
1443 VpdFile.Add(Pcd, TAB_DEFAULT, DefaultSku.VpdOffset)
1444 SkuValueMap[PcdValue].append(DefaultSku)
1445
1446 for (SkuName, Sku) in Pcd.SkuInfoList.items():
1447 Sku.VpdOffset = Sku.VpdOffset.strip()
1448 PcdValue = Sku.DefaultValue
1449 if PcdValue == "":
1450 PcdValue = Pcd.DefaultValue
1451 if Sku.VpdOffset != '*':
1452 if PcdValue.startswith("{"):
1453 Alignment = 8
1454 elif PcdValue.startswith("L"):
1455 Alignment = 2
1456 else:
1457 Alignment = 1
1458 try:
1459 VpdOffset = int(Sku.VpdOffset)
1460 except:
1461 try:
1462 VpdOffset = int(Sku.VpdOffset, 16)
1463 except:
1464 EdkLogger.error("build", FORMAT_INVALID, "Invalid offset value %s for PCD %s.%s." % (Sku.VpdOffset, Pcd.TokenSpaceGuidCName, Pcd.TokenCName))
1465 if VpdOffset % Alignment != 0:
1466 if PcdValue.startswith("{"):
1467 EdkLogger.warn("build", "The offset value of PCD %s.%s is not 8-byte aligned!" %(Pcd.TokenSpaceGuidCName, Pcd.TokenCName), File=self.MetaFile)
1468 else:
1469 EdkLogger.error("build", FORMAT_INVALID, 'The offset value of PCD %s.%s should be %s-byte aligned.' % (Pcd.TokenSpaceGuidCName, Pcd.TokenCName, Alignment))
1470 if PcdValue not in SkuValueMap:
1471 SkuValueMap[PcdValue] = []
1472 VpdFile.Add(Pcd, SkuName, Sku.VpdOffset)
1473 SkuValueMap[PcdValue].append(Sku)
1474 # if the offset of a VPD is *, then it need to be fixed up by third party tool.
1475 if not NeedProcessVpdMapFile and Sku.VpdOffset == "*":
1476 NeedProcessVpdMapFile = True
1477 if self.Platform.VpdToolGuid is None or self.Platform.VpdToolGuid == '':
1478 EdkLogger.error("Build", FILE_NOT_FOUND, \
1479 "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.")
1480
1481 VpdSkuMap[PcdKey] = SkuValueMap
1482 #
1483 # Fix the PCDs define in VPD PCD section that never referenced by module.
1484 # An example is PCD for signature usage.
1485 #
1486 for DscPcd in PlatformPcds:
1487 DscPcdEntry = self._PlatformPcds[DscPcd]
1488 if DscPcdEntry.Type in [TAB_PCDS_DYNAMIC_VPD, TAB_PCDS_DYNAMIC_EX_VPD]:
1489 if not (self.Platform.VpdToolGuid is None or self.Platform.VpdToolGuid == ''):
1490 FoundFlag = False
1491 for VpdPcd in VpdFile._VpdArray:
1492 # This PCD has been referenced by module
1493 if (VpdPcd.TokenSpaceGuidCName == DscPcdEntry.TokenSpaceGuidCName) and \
1494 (VpdPcd.TokenCName == DscPcdEntry.TokenCName):
1495 FoundFlag = True
1496
1497 # Not found, it should be signature
1498 if not FoundFlag :
1499 # just pick the a value to determine whether is unicode string type
1500 SkuValueMap = {}
1501 SkuObjList = DscPcdEntry.SkuInfoList.items()
1502 DefaultSku = DscPcdEntry.SkuInfoList.get(TAB_DEFAULT)
1503 if DefaultSku:
1504 defaultindex = SkuObjList.index((TAB_DEFAULT, DefaultSku))
1505 SkuObjList[0], SkuObjList[defaultindex] = SkuObjList[defaultindex], SkuObjList[0]
1506 for (SkuName, Sku) in SkuObjList:
1507 Sku.VpdOffset = Sku.VpdOffset.strip()
1508
1509 # Need to iterate DEC pcd information to get the value & datumtype
1510 for eachDec in self.PackageList:
1511 for DecPcd in eachDec.Pcds:
1512 DecPcdEntry = eachDec.Pcds[DecPcd]
1513 if (DecPcdEntry.TokenSpaceGuidCName == DscPcdEntry.TokenSpaceGuidCName) and \
1514 (DecPcdEntry.TokenCName == DscPcdEntry.TokenCName):
1515 # Print warning message to let the developer make a determine.
1516 EdkLogger.warn("build", "Unreferenced vpd pcd used!",
1517 File=self.MetaFile, \
1518 ExtraData = "PCD: %s.%s used in the DSC file %s is unreferenced." \
1519 %(DscPcdEntry.TokenSpaceGuidCName, DscPcdEntry.TokenCName, self.Platform.MetaFile.Path))
1520
1521 DscPcdEntry.DatumType = DecPcdEntry.DatumType
1522 DscPcdEntry.DefaultValue = DecPcdEntry.DefaultValue
1523 DscPcdEntry.TokenValue = DecPcdEntry.TokenValue
1524 DscPcdEntry.TokenSpaceGuidValue = eachDec.Guids[DecPcdEntry.TokenSpaceGuidCName]
1525 # Only fix the value while no value provided in DSC file.
1526 if not Sku.DefaultValue:
1527 DscPcdEntry.SkuInfoList[DscPcdEntry.SkuInfoList.keys()[0]].DefaultValue = DecPcdEntry.DefaultValue
1528
1529 if DscPcdEntry not in self._DynamicPcdList:
1530 self._DynamicPcdList.append(DscPcdEntry)
1531 Sku.VpdOffset = Sku.VpdOffset.strip()
1532 PcdValue = Sku.DefaultValue
1533 if PcdValue == "":
1534 PcdValue = DscPcdEntry.DefaultValue
1535 if Sku.VpdOffset != '*':
1536 if PcdValue.startswith("{"):
1537 Alignment = 8
1538 elif PcdValue.startswith("L"):
1539 Alignment = 2
1540 else:
1541 Alignment = 1
1542 try:
1543 VpdOffset = int(Sku.VpdOffset)
1544 except:
1545 try:
1546 VpdOffset = int(Sku.VpdOffset, 16)
1547 except:
1548 EdkLogger.error("build", FORMAT_INVALID, "Invalid offset value %s for PCD %s.%s." % (Sku.VpdOffset, DscPcdEntry.TokenSpaceGuidCName, DscPcdEntry.TokenCName))
1549 if VpdOffset % Alignment != 0:
1550 if PcdValue.startswith("{"):
1551 EdkLogger.warn("build", "The offset value of PCD %s.%s is not 8-byte aligned!" %(DscPcdEntry.TokenSpaceGuidCName, DscPcdEntry.TokenCName), File=self.MetaFile)
1552 else:
1553 EdkLogger.error("build", FORMAT_INVALID, 'The offset value of PCD %s.%s should be %s-byte aligned.' % (DscPcdEntry.TokenSpaceGuidCName, DscPcdEntry.TokenCName, Alignment))
1554 if PcdValue not in SkuValueMap:
1555 SkuValueMap[PcdValue] = []
1556 VpdFile.Add(DscPcdEntry, SkuName, Sku.VpdOffset)
1557 SkuValueMap[PcdValue].append(Sku)
1558 if not NeedProcessVpdMapFile and Sku.VpdOffset == "*":
1559 NeedProcessVpdMapFile = True
1560 if DscPcdEntry.DatumType == TAB_VOID and PcdValue.startswith("L"):
1561 UnicodePcdArray.add(DscPcdEntry)
1562 elif len(Sku.VariableName) > 0:
1563 HiiPcdArray.add(DscPcdEntry)
1564 else:
1565 OtherPcdArray.add(DscPcdEntry)
1566
1567 # if the offset of a VPD is *, then it need to be fixed up by third party tool.
1568 VpdSkuMap[DscPcd] = SkuValueMap
1569 if (self.Platform.FlashDefinition is None or self.Platform.FlashDefinition == '') and \
1570 VpdFile.GetCount() != 0:
1571 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE,
1572 "Fail to get FLASH_DEFINITION definition in DSC file %s which is required when DSC contains VPD PCD." % str(self.Platform.MetaFile))
1573
1574 if VpdFile.GetCount() != 0:
1575
1576 self.FixVpdOffset(VpdFile)
1577
1578 self.FixVpdOffset(self.UpdateNVStoreMaxSize(VpdFile))
1579
1580 # Process VPD map file generated by third party BPDG tool
1581 if NeedProcessVpdMapFile:
1582 VpdMapFilePath = os.path.join(self.BuildDir, TAB_FV_DIRECTORY, "%s.map" % self.Platform.VpdToolGuid)
1583 if os.path.exists(VpdMapFilePath):
1584 VpdFile.Read(VpdMapFilePath)
1585
1586 # Fixup "*" offset
1587 for pcd in VpdSkuMap:
1588 vpdinfo = VpdFile.GetVpdInfo(pcd)
1589 if vpdinfo is None:
1590 # just pick the a value to determine whether is unicode string type
1591 continue
1592 for pcdvalue in VpdSkuMap[pcd]:
1593 for sku in VpdSkuMap[pcd][pcdvalue]:
1594 for item in vpdinfo:
1595 if item[2] == pcdvalue:
1596 sku.VpdOffset = item[1]
1597 else:
1598 EdkLogger.error("build", FILE_READ_FAILURE, "Can not find VPD map file %s to fix up VPD offset." % VpdMapFilePath)
1599
1600 # Delete the DynamicPcdList At the last time enter into this function
1601 for Pcd in self._DynamicPcdList:
1602 # just pick the a value to determine whether is unicode string type
1603 Sku = Pcd.SkuInfoList.values()[0]
1604 Sku.VpdOffset = Sku.VpdOffset.strip()
1605
1606 if Pcd.DatumType not in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64, TAB_VOID, "BOOLEAN"]:
1607 Pcd.DatumType = TAB_VOID
1608
1609 PcdValue = Sku.DefaultValue
1610 if Pcd.DatumType == TAB_VOID and PcdValue.startswith("L"):
1611 # if found PCD which datum value is unicode string the insert to left size of UnicodeIndex
1612 UnicodePcdArray.add(Pcd)
1613 elif len(Sku.VariableName) > 0:
1614 # if found HII type PCD then insert to right of UnicodeIndex
1615 HiiPcdArray.add(Pcd)
1616 else:
1617 OtherPcdArray.add(Pcd)
1618 del self._DynamicPcdList[:]
1619 self._DynamicPcdList.extend(list(UnicodePcdArray))
1620 self._DynamicPcdList.extend(list(HiiPcdArray))
1621 self._DynamicPcdList.extend(list(OtherPcdArray))
1622 allskuset = [(SkuName, Sku.SkuId) for pcd in self._DynamicPcdList for (SkuName, Sku) in pcd.SkuInfoList.items()]
1623 for pcd in self._DynamicPcdList:
1624 if len(pcd.SkuInfoList) == 1:
1625 for (SkuName, SkuId) in allskuset:
1626 if type(SkuId) in (str, unicode) and eval(SkuId) == 0 or SkuId == 0:
1627 continue
1628 pcd.SkuInfoList[SkuName] = copy.deepcopy(pcd.SkuInfoList[TAB_DEFAULT])
1629 pcd.SkuInfoList[SkuName].SkuId = SkuId
1630 pcd.SkuInfoList[SkuName].SkuIdName = SkuName
1631 self.AllPcdList = self._NonDynamicPcdList + self._DynamicPcdList
1632
1633 def FixVpdOffset(self, VpdFile ):
1634 FvPath = os.path.join(self.BuildDir, TAB_FV_DIRECTORY)
1635 if not os.path.exists(FvPath):
1636 try:
1637 os.makedirs(FvPath)
1638 except:
1639 EdkLogger.error("build", FILE_WRITE_FAILURE, "Fail to create FV folder under %s" % self.BuildDir)
1640
1641 VpdFilePath = os.path.join(FvPath, "%s.txt" % self.Platform.VpdToolGuid)
1642
1643 if VpdFile.Write(VpdFilePath):
1644 # retrieve BPDG tool's path from tool_def.txt according to VPD_TOOL_GUID defined in DSC file.
1645 BPDGToolName = None
1646 for ToolDef in self.ToolDefinition.values():
1647 if TAB_GUID in ToolDef and ToolDef[TAB_GUID] == self.Platform.VpdToolGuid:
1648 if "PATH" not in ToolDef:
1649 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "PATH attribute was not provided for BPDG guid tool %s in tools_def.txt" % self.Platform.VpdToolGuid)
1650 BPDGToolName = ToolDef["PATH"]
1651 break
1652 # Call third party GUID BPDG tool.
1653 if BPDGToolName is not None:
1654 VpdInfoFile.CallExtenalBPDGTool(BPDGToolName, VpdFilePath)
1655 else:
1656 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.")
1657
1658 ## Return the platform build data object
1659 @cached_property
1660 def Platform(self):
1661 return self.BuildDatabase[self.MetaFile, self.Arch, self.BuildTarget, self.ToolChain]
1662
1663 ## Return platform name
1664 @cached_property
1665 def Name(self):
1666 return self.Platform.PlatformName
1667
1668 ## Return the meta file GUID
1669 @cached_property
1670 def Guid(self):
1671 return self.Platform.Guid
1672
1673 ## Return the platform version
1674 @cached_property
1675 def Version(self):
1676 return self.Platform.Version
1677
1678 ## Return the FDF file name
1679 @cached_property
1680 def FdfFile(self):
1681 if self.Workspace.FdfFile:
1682 RetVal= mws.join(self.WorkspaceDir, self.Workspace.FdfFile)
1683 else:
1684 RetVal = ''
1685 return RetVal
1686
1687 ## Return the build output directory platform specifies
1688 @cached_property
1689 def OutputDir(self):
1690 return self.Platform.OutputDirectory
1691
1692 ## Return the directory to store all intermediate and final files built
1693 @cached_property
1694 def BuildDir(self):
1695 if os.path.isabs(self.OutputDir):
1696 GlobalData.gBuildDirectory = RetVal = path.join(
1697 path.abspath(self.OutputDir),
1698 self.BuildTarget + "_" + self.ToolChain,
1699 )
1700 else:
1701 GlobalData.gBuildDirectory = RetVal = path.join(
1702 self.WorkspaceDir,
1703 self.OutputDir,
1704 self.BuildTarget + "_" + self.ToolChain,
1705 )
1706 return RetVal
1707
1708 ## Return directory of platform makefile
1709 #
1710 # @retval string Makefile directory
1711 #
1712 @cached_property
1713 def MakeFileDir(self):
1714 return path.join(self.BuildDir, self.Arch)
1715
1716 ## Return build command string
1717 #
1718 # @retval string Build command string
1719 #
1720 @cached_property
1721 def BuildCommand(self):
1722 RetVal = []
1723 if "MAKE" in self.ToolDefinition and "PATH" in self.ToolDefinition["MAKE"]:
1724 RetVal += SplitOption(self.ToolDefinition["MAKE"]["PATH"])
1725 if "FLAGS" in self.ToolDefinition["MAKE"]:
1726 NewOption = self.ToolDefinition["MAKE"]["FLAGS"].strip()
1727 if NewOption != '':
1728 RetVal += SplitOption(NewOption)
1729 if "MAKE" in self.EdkIIBuildOption:
1730 if "FLAGS" in self.EdkIIBuildOption["MAKE"]:
1731 Flags = self.EdkIIBuildOption["MAKE"]["FLAGS"]
1732 if Flags.startswith('='):
1733 RetVal = [RetVal[0]] + [Flags[1:]]
1734 else:
1735 RetVal.append(Flags)
1736 return RetVal
1737
1738 ## Get tool chain definition
1739 #
1740 # Get each tool defition for given tool chain from tools_def.txt and platform
1741 #
1742 @cached_property
1743 def ToolDefinition(self):
1744 ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDictionary
1745 if TAB_TOD_DEFINES_COMMAND_TYPE not in self.Workspace.ToolDef.ToolsDefTxtDatabase:
1746 EdkLogger.error('build', RESOURCE_NOT_AVAILABLE, "No tools found in configuration",
1747 ExtraData="[%s]" % self.MetaFile)
1748 RetVal = {}
1749 DllPathList = set()
1750 for Def in ToolDefinition:
1751 Target, Tag, Arch, Tool, Attr = Def.split("_")
1752 if Target != self.BuildTarget or Tag != self.ToolChain or Arch != self.Arch:
1753 continue
1754
1755 Value = ToolDefinition[Def]
1756 # don't record the DLL
1757 if Attr == "DLL":
1758 DllPathList.add(Value)
1759 continue
1760
1761 if Tool not in RetVal:
1762 RetVal[Tool] = {}
1763 RetVal[Tool][Attr] = Value
1764
1765 ToolsDef = ''
1766 if GlobalData.gOptions.SilentMode and "MAKE" in RetVal:
1767 if "FLAGS" not in RetVal["MAKE"]:
1768 RetVal["MAKE"]["FLAGS"] = ""
1769 RetVal["MAKE"]["FLAGS"] += " -s"
1770 MakeFlags = ''
1771 for Tool in RetVal:
1772 for Attr in RetVal[Tool]:
1773 Value = RetVal[Tool][Attr]
1774 if Tool in self._BuildOptionWithToolDef(RetVal) and Attr in self._BuildOptionWithToolDef(RetVal)[Tool]:
1775 # check if override is indicated
1776 if self._BuildOptionWithToolDef(RetVal)[Tool][Attr].startswith('='):
1777 Value = self._BuildOptionWithToolDef(RetVal)[Tool][Attr][1:]
1778 else:
1779 if Attr != 'PATH':
1780 Value += " " + self._BuildOptionWithToolDef(RetVal)[Tool][Attr]
1781 else:
1782 Value = self._BuildOptionWithToolDef(RetVal)[Tool][Attr]
1783
1784 if Attr == "PATH":
1785 # Don't put MAKE definition in the file
1786 if Tool != "MAKE":
1787 ToolsDef += "%s = %s\n" % (Tool, Value)
1788 elif Attr != "DLL":
1789 # Don't put MAKE definition in the file
1790 if Tool == "MAKE":
1791 if Attr == "FLAGS":
1792 MakeFlags = Value
1793 else:
1794 ToolsDef += "%s_%s = %s\n" % (Tool, Attr, Value)
1795 ToolsDef += "\n"
1796
1797 SaveFileOnChange(self.ToolDefinitionFile, ToolsDef)
1798 for DllPath in DllPathList:
1799 os.environ["PATH"] = DllPath + os.pathsep + os.environ["PATH"]
1800 os.environ["MAKE_FLAGS"] = MakeFlags
1801
1802 return RetVal
1803
1804 ## Return the paths of tools
1805 @cached_property
1806 def ToolDefinitionFile(self):
1807 return os.path.join(self.MakeFileDir, "TOOLS_DEF." + self.Arch)
1808
1809 ## Retrieve the toolchain family of given toolchain tag. Default to 'MSFT'.
1810 @cached_property
1811 def ToolChainFamily(self):
1812 ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDatabase
1813 if TAB_TOD_DEFINES_FAMILY not in ToolDefinition \
1814 or self.ToolChain not in ToolDefinition[TAB_TOD_DEFINES_FAMILY] \
1815 or not ToolDefinition[TAB_TOD_DEFINES_FAMILY][self.ToolChain]:
1816 EdkLogger.verbose("No tool chain family found in configuration for %s. Default to MSFT." \
1817 % self.ToolChain)
1818 RetVal = TAB_COMPILER_MSFT
1819 else:
1820 RetVal = ToolDefinition[TAB_TOD_DEFINES_FAMILY][self.ToolChain]
1821 return RetVal
1822
1823 @cached_property
1824 def BuildRuleFamily(self):
1825 ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDatabase
1826 if TAB_TOD_DEFINES_BUILDRULEFAMILY not in ToolDefinition \
1827 or self.ToolChain not in ToolDefinition[TAB_TOD_DEFINES_BUILDRULEFAMILY] \
1828 or not ToolDefinition[TAB_TOD_DEFINES_BUILDRULEFAMILY][self.ToolChain]:
1829 EdkLogger.verbose("No tool chain family found in configuration for %s. Default to MSFT." \
1830 % self.ToolChain)
1831 return TAB_COMPILER_MSFT
1832
1833 return ToolDefinition[TAB_TOD_DEFINES_BUILDRULEFAMILY][self.ToolChain]
1834
1835 ## Return the build options specific for all modules in this platform
1836 @cached_property
1837 def BuildOption(self):
1838 return self._ExpandBuildOption(self.Platform.BuildOptions)
1839
1840 def _BuildOptionWithToolDef(self, ToolDef):
1841 return self._ExpandBuildOption(self.Platform.BuildOptions, ToolDef=ToolDef)
1842
1843 ## Return the build options specific for EDK modules in this platform
1844 @cached_property
1845 def EdkBuildOption(self):
1846 return self._ExpandBuildOption(self.Platform.BuildOptions, EDK_NAME)
1847
1848 ## Return the build options specific for EDKII modules in this platform
1849 @cached_property
1850 def EdkIIBuildOption(self):
1851 return self._ExpandBuildOption(self.Platform.BuildOptions, EDKII_NAME)
1852
1853 ## Parse build_rule.txt in Conf Directory.
1854 #
1855 # @retval BuildRule object
1856 #
1857 @cached_property
1858 def BuildRule(self):
1859 BuildRuleFile = None
1860 if TAB_TAT_DEFINES_BUILD_RULE_CONF in self.Workspace.TargetTxt.TargetTxtDictionary:
1861 BuildRuleFile = self.Workspace.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_BUILD_RULE_CONF]
1862 if not BuildRuleFile:
1863 BuildRuleFile = gDefaultBuildRuleFile
1864 RetVal = BuildRule(BuildRuleFile)
1865 if RetVal._FileVersion == "":
1866 RetVal._FileVersion = AutoGenReqBuildRuleVerNum
1867 else:
1868 if RetVal._FileVersion < AutoGenReqBuildRuleVerNum :
1869 # If Build Rule's version is less than the version number required by the tools, halting the build.
1870 EdkLogger.error("build", AUTOGEN_ERROR,
1871 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])"\
1872 % (RetVal._FileVersion, AutoGenReqBuildRuleVerNum))
1873 return RetVal
1874
1875 ## Summarize the packages used by modules in this platform
1876 @cached_property
1877 def PackageList(self):
1878 RetVal = set()
1879 for La in self.LibraryAutoGenList:
1880 RetVal.update(La.DependentPackageList)
1881 for Ma in self.ModuleAutoGenList:
1882 RetVal.update(Ma.DependentPackageList)
1883 #Collect package set information from INF of FDF
1884 for ModuleFile in self._AsBuildModuleList:
1885 if ModuleFile in self.Platform.Modules:
1886 continue
1887 ModuleData = self.BuildDatabase[ModuleFile, self.Arch, self.BuildTarget, self.ToolChain]
1888 RetVal.update(ModuleData.Packages)
1889 return list(RetVal)
1890
1891 @cached_property
1892 def NonDynamicPcdDict(self):
1893 return {(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):Pcd for Pcd in self.NonDynamicPcdList}
1894
1895 ## Get list of non-dynamic PCDs
1896 @cached_property
1897 def NonDynamicPcdList(self):
1898 self.CollectPlatformDynamicPcds()
1899 return self._NonDynamicPcdList
1900
1901 ## Get list of dynamic PCDs
1902 @cached_property
1903 def DynamicPcdList(self):
1904 self.CollectPlatformDynamicPcds()
1905 return self._DynamicPcdList
1906
1907 ## Generate Token Number for all PCD
1908 @cached_property
1909 def PcdTokenNumber(self):
1910 RetVal = OrderedDict()
1911 TokenNumber = 1
1912 #
1913 # Make the Dynamic and DynamicEx PCD use within different TokenNumber area.
1914 # Such as:
1915 #
1916 # Dynamic PCD:
1917 # TokenNumber 0 ~ 10
1918 # DynamicEx PCD:
1919 # TokeNumber 11 ~ 20
1920 #
1921 for Pcd in self.DynamicPcdList:
1922 if Pcd.Phase == "PEI" and Pcd.Type in PCD_DYNAMIC_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 == "PEI" and Pcd.Type in PCD_DYNAMIC_EX_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_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.DynamicPcdList:
1940 if Pcd.Phase == "DXE" and Pcd.Type in PCD_DYNAMIC_EX_TYPE_SET:
1941 EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))
1942 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
1943 TokenNumber += 1
1944
1945 for Pcd in self.NonDynamicPcdList:
1946 RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
1947 TokenNumber += 1
1948 return RetVal
1949
1950 ## Summarize ModuleAutoGen objects of all modules to be built for this platform
1951 @cached_property
1952 def ModuleAutoGenList(self):
1953 RetVal = []
1954 for ModuleFile in self.Platform.Modules:
1955 Ma = ModuleAutoGen(
1956 self.Workspace,
1957 ModuleFile,
1958 self.BuildTarget,
1959 self.ToolChain,
1960 self.Arch,
1961 self.MetaFile
1962 )
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 ModuleFile in self.Platform.Modules:
1972 Ma = ModuleAutoGen(
1973 self.Workspace,
1974 ModuleFile,
1975 self.BuildTarget,
1976 self.ToolChain,
1977 self.Arch,
1978 self.MetaFile
1979 )
1980 for La in Ma.LibraryAutoGenList:
1981 if La not in RetVal:
1982 RetVal.append(La)
1983 if Ma not in La.ReferenceModules:
1984 La.ReferenceModules.append(Ma)
1985 return RetVal
1986
1987 ## Test if a module is supported by the platform
1988 #
1989 # An error will be raised directly if the module or its arch is not supported
1990 # by the platform or current configuration
1991 #
1992 def ValidModule(self, Module):
1993 return Module in self.Platform.Modules or Module in self.Platform.LibraryInstances \
1994 or Module in self._AsBuildModuleList
1995
1996 ## Resolve the library classes in a module to library instances
1997 #
1998 # This method will not only resolve library classes but also sort the library
1999 # instances according to the dependency-ship.
2000 #
2001 # @param Module The module from which the library classes will be resolved
2002 #
2003 # @retval library_list List of library instances sorted
2004 #
2005 def ApplyLibraryInstance(self, Module):
2006 # Cover the case that the binary INF file is list in the FDF file but not DSC file, return empty list directly
2007 if str(Module) not in self.Platform.Modules:
2008 return []
2009
2010 return GetModuleLibInstances(Module,
2011 self.Platform,
2012 self.BuildDatabase,
2013 self.Arch,
2014 self.BuildTarget,
2015 self.ToolChain,
2016 self.MetaFile,
2017 EdkLogger)
2018
2019 ## Override PCD setting (type, value, ...)
2020 #
2021 # @param ToPcd The PCD to be overrided
2022 # @param FromPcd The PCD overrideing from
2023 #
2024 def _OverridePcd(self, ToPcd, FromPcd, Module="", Msg="", Library=""):
2025 #
2026 # in case there's PCDs coming from FDF file, which have no type given.
2027 # at this point, ToPcd.Type has the type found from dependent
2028 # package
2029 #
2030 TokenCName = ToPcd.TokenCName
2031 for PcdItem in GlobalData.MixedPcd:
2032 if (ToPcd.TokenCName, ToPcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
2033 TokenCName = PcdItem[0]
2034 break
2035 if FromPcd is not None:
2036 if ToPcd.Pending and FromPcd.Type:
2037 ToPcd.Type = FromPcd.Type
2038 elif ToPcd.Type and FromPcd.Type\
2039 and ToPcd.Type != FromPcd.Type and ToPcd.Type in FromPcd.Type:
2040 if ToPcd.Type.strip() == TAB_PCDS_DYNAMIC_EX:
2041 ToPcd.Type = FromPcd.Type
2042 elif ToPcd.Type and FromPcd.Type \
2043 and ToPcd.Type != FromPcd.Type:
2044 if Library:
2045 Module = str(Module) + " 's library file (" + str(Library) + ")"
2046 EdkLogger.error("build", OPTION_CONFLICT, "Mismatched PCD type",
2047 ExtraData="%s.%s is used as [%s] in module %s, but as [%s] in %s."\
2048 % (ToPcd.TokenSpaceGuidCName, TokenCName,
2049 ToPcd.Type, Module, FromPcd.Type, Msg),
2050 File=self.MetaFile)
2051
2052 if FromPcd.MaxDatumSize:
2053 ToPcd.MaxDatumSize = FromPcd.MaxDatumSize
2054 ToPcd.MaxSizeUserSet = FromPcd.MaxDatumSize
2055 if FromPcd.DefaultValue:
2056 ToPcd.DefaultValue = FromPcd.DefaultValue
2057 if FromPcd.TokenValue:
2058 ToPcd.TokenValue = FromPcd.TokenValue
2059 if FromPcd.DatumType:
2060 ToPcd.DatumType = FromPcd.DatumType
2061 if FromPcd.SkuInfoList:
2062 ToPcd.SkuInfoList = FromPcd.SkuInfoList
2063 if FromPcd.UserDefinedDefaultStoresFlag:
2064 ToPcd.UserDefinedDefaultStoresFlag = FromPcd.UserDefinedDefaultStoresFlag
2065 # Add Flexible PCD format parse
2066 if ToPcd.DefaultValue:
2067 try:
2068 ToPcd.DefaultValue = ValueExpressionEx(ToPcd.DefaultValue, ToPcd.DatumType, self.Workspace._GuidDict)(True)
2069 except BadExpression as Value:
2070 EdkLogger.error('Parser', FORMAT_INVALID, 'PCD [%s.%s] Value "%s", %s' %(ToPcd.TokenSpaceGuidCName, ToPcd.TokenCName, ToPcd.DefaultValue, Value),
2071 File=self.MetaFile)
2072
2073 # check the validation of datum
2074 IsValid, Cause = CheckPcdDatum(ToPcd.DatumType, ToPcd.DefaultValue)
2075 if not IsValid:
2076 EdkLogger.error('build', FORMAT_INVALID, Cause, File=self.MetaFile,
2077 ExtraData="%s.%s" % (ToPcd.TokenSpaceGuidCName, TokenCName))
2078 ToPcd.validateranges = FromPcd.validateranges
2079 ToPcd.validlists = FromPcd.validlists
2080 ToPcd.expressions = FromPcd.expressions
2081
2082 if FromPcd is not None and ToPcd.DatumType == TAB_VOID and not ToPcd.MaxDatumSize:
2083 EdkLogger.debug(EdkLogger.DEBUG_9, "No MaxDatumSize specified for PCD %s.%s" \
2084 % (ToPcd.TokenSpaceGuidCName, TokenCName))
2085 Value = ToPcd.DefaultValue
2086 if not Value:
2087 ToPcd.MaxDatumSize = '1'
2088 elif Value[0] == 'L':
2089 ToPcd.MaxDatumSize = str((len(Value) - 2) * 2)
2090 elif Value[0] == '{':
2091 ToPcd.MaxDatumSize = str(len(Value.split(',')))
2092 else:
2093 ToPcd.MaxDatumSize = str(len(Value) - 1)
2094
2095 # apply default SKU for dynamic PCDS if specified one is not available
2096 if (ToPcd.Type in PCD_DYNAMIC_TYPE_SET or ToPcd.Type in PCD_DYNAMIC_EX_TYPE_SET) \
2097 and not ToPcd.SkuInfoList:
2098 if self.Platform.SkuName in self.Platform.SkuIds:
2099 SkuName = self.Platform.SkuName
2100 else:
2101 SkuName = TAB_DEFAULT
2102 ToPcd.SkuInfoList = {
2103 SkuName : SkuInfoClass(SkuName, self.Platform.SkuIds[SkuName][0], '', '', '', '', '', ToPcd.DefaultValue)
2104 }
2105
2106 ## Apply PCD setting defined platform to a module
2107 #
2108 # @param Module The module from which the PCD setting will be overrided
2109 #
2110 # @retval PCD_list The list PCDs with settings from platform
2111 #
2112 def ApplyPcdSetting(self, Module, Pcds, Library=""):
2113 # for each PCD in module
2114 for Name, Guid in Pcds:
2115 PcdInModule = Pcds[Name, Guid]
2116 # find out the PCD setting in platform
2117 if (Name, Guid) in self.Platform.Pcds:
2118 PcdInPlatform = self.Platform.Pcds[Name, Guid]
2119 else:
2120 PcdInPlatform = None
2121 # then override the settings if any
2122 self._OverridePcd(PcdInModule, PcdInPlatform, Module, Msg="DSC PCD sections", Library=Library)
2123 # resolve the VariableGuid value
2124 for SkuId in PcdInModule.SkuInfoList:
2125 Sku = PcdInModule.SkuInfoList[SkuId]
2126 if Sku.VariableGuid == '': continue
2127 Sku.VariableGuidValue = GuidValue(Sku.VariableGuid, self.PackageList, self.MetaFile.Path)
2128 if Sku.VariableGuidValue is None:
2129 PackageList = "\n\t".join(str(P) for P in self.PackageList)
2130 EdkLogger.error(
2131 'build',
2132 RESOURCE_NOT_AVAILABLE,
2133 "Value of GUID [%s] is not found in" % Sku.VariableGuid,
2134 ExtraData=PackageList + "\n\t(used with %s.%s from module %s)" \
2135 % (Guid, Name, str(Module)),
2136 File=self.MetaFile
2137 )
2138
2139 # override PCD settings with module specific setting
2140 if Module in self.Platform.Modules:
2141 PlatformModule = self.Platform.Modules[str(Module)]
2142 for Key in PlatformModule.Pcds:
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 == "*":
2218 PriorityValue &= 0x01111
2219 if ToolChain == "*":
2220 PriorityValue &= 0x10111
2221 if Arch == "*":
2222 PriorityValue &= 0x11011
2223 if CommandType == "*":
2224 PriorityValue &= 0x11101
2225 if Attr == "*":
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 == "*") and\
2261 (ToolChain == self.ToolChain or ToolChain == "*") and\
2262 (Arch == self.Arch or Arch == "*") 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 == "*" or Target2 == "*") and\
2284 (ToolChain1 == ToolChain2 or ToolChain1 == "*" or ToolChain2 == "*") and\
2285 (Arch1 == Arch2 or Arch1 == "*" or Arch2 == "*") and\
2286 (CommandType1 == CommandType2 or CommandType1 == "*" or CommandType2 == "*") and\
2287 (Attr1 == Attr2 or Attr1 == "*" or Attr2 == "*"):
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 == "*" or Target == self.BuildTarget:
2317 if Tag == "*" or Tag == self.ToolChain:
2318 if Arch == "*" 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 == "*" or Target == self.BuildTarget:
2352 if Tag == "*" or Tag == self.ToolChain:
2353 if Arch == "*" 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.Workspace.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.PlatformInfo.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 = {"", "*", self.ToolChain}
2979 ToolChainFamilySet = {"", "*", 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, '*'] 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 self.DepexGenerated:
3661 self.OutputFile.add(self.Name + '.depex')
3662 if self.ModuleType in [SUP_MODULE_PEIM]:
3663 AsBuiltInfDict['binary_item'].append('PEI_DEPEX|' + self.Name + '.depex')
3664 elif self.ModuleType in [SUP_MODULE_DXE_DRIVER, SUP_MODULE_DXE_RUNTIME_DRIVER, SUP_MODULE_DXE_SAL_DRIVER, SUP_MODULE_UEFI_DRIVER]:
3665 AsBuiltInfDict['binary_item'].append('DXE_DEPEX|' + self.Name + '.depex')
3666 elif self.ModuleType in [SUP_MODULE_DXE_SMM_DRIVER]:
3667 AsBuiltInfDict['binary_item'].append('SMM_DEPEX|' + self.Name + '.depex')
3668
3669 Bin = self._GenOffsetBin()
3670 if Bin:
3671 AsBuiltInfDict['binary_item'].append('BIN|%s' % Bin)
3672 self.OutputFile.add(Bin)
3673
3674 for Root, Dirs, Files in os.walk(OutputDir):
3675 for File in Files:
3676 if File.lower().endswith('.pdb'):
3677 AsBuiltInfDict['binary_item'].append('DISPOSABLE|' + File)
3678 self.OutputFile.add(File)
3679 HeaderComments = self.Module.HeaderComments
3680 StartPos = 0
3681 for Index in range(len(HeaderComments)):
3682 if HeaderComments[Index].find('@BinaryHeader') != -1:
3683 HeaderComments[Index] = HeaderComments[Index].replace('@BinaryHeader', '@file')
3684 StartPos = Index
3685 break
3686 AsBuiltInfDict['header_comments'] = '\n'.join(HeaderComments[StartPos:]).replace(':#', '://')
3687 AsBuiltInfDict['tail_comments'] = '\n'.join(self.Module.TailComments)
3688
3689 GenList = [
3690 (self.ProtocolList, self._ProtocolComments, 'protocol_item'),
3691 (self.PpiList, self._PpiComments, 'ppi_item'),
3692 (GuidList, self._GuidComments, 'guid_item')
3693 ]
3694 for Item in GenList:
3695 for CName in Item[0]:
3696 Comments = '\n '.join(Item[1][CName]) if CName in Item[1] else ''
3697 Entry = Comments + '\n ' + CName if Comments else CName
3698 AsBuiltInfDict[Item[2]].append(Entry)
3699 PatchList = parsePcdInfoFromMapFile(
3700 os.path.join(self.OutputDir, self.Name + '.map'),
3701 os.path.join(self.OutputDir, self.Name + '.efi')
3702 )
3703 if PatchList:
3704 for Pcd in PatchablePcds:
3705 TokenCName = Pcd.TokenCName
3706 for PcdItem in GlobalData.MixedPcd:
3707 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
3708 TokenCName = PcdItem[0]
3709 break
3710 for PatchPcd in PatchList:
3711 if TokenCName == PatchPcd[0]:
3712 break
3713 else:
3714 continue
3715 PcdValue = ''
3716 if Pcd.DatumType == 'BOOLEAN':
3717 BoolValue = Pcd.DefaultValue.upper()
3718 if BoolValue == 'TRUE':
3719 Pcd.DefaultValue = '1'
3720 elif BoolValue == 'FALSE':
3721 Pcd.DefaultValue = '0'
3722
3723 if Pcd.DatumType in TAB_PCD_NUMERIC_TYPES:
3724 HexFormat = '0x%02x'
3725 if Pcd.DatumType == TAB_UINT16:
3726 HexFormat = '0x%04x'
3727 elif Pcd.DatumType == TAB_UINT32:
3728 HexFormat = '0x%08x'
3729 elif Pcd.DatumType == TAB_UINT64:
3730 HexFormat = '0x%016x'
3731 PcdValue = HexFormat % int(Pcd.DefaultValue, 0)
3732 else:
3733 if Pcd.MaxDatumSize is None or Pcd.MaxDatumSize == '':
3734 EdkLogger.error("build", AUTOGEN_ERROR,
3735 "Unknown [MaxDatumSize] of PCD [%s.%s]" % (Pcd.TokenSpaceGuidCName, TokenCName)
3736 )
3737 ArraySize = int(Pcd.MaxDatumSize, 0)
3738 PcdValue = Pcd.DefaultValue
3739 if PcdValue[0] != '{':
3740 Unicode = False
3741 if PcdValue[0] == 'L':
3742 Unicode = True
3743 PcdValue = PcdValue.lstrip('L')
3744 PcdValue = eval(PcdValue)
3745 NewValue = '{'
3746 for Index in range(0, len(PcdValue)):
3747 if Unicode:
3748 CharVal = ord(PcdValue[Index])
3749 NewValue = NewValue + '0x%02x' % (CharVal & 0x00FF) + ', ' \
3750 + '0x%02x' % (CharVal >> 8) + ', '
3751 else:
3752 NewValue = NewValue + '0x%02x' % (ord(PcdValue[Index]) % 0x100) + ', '
3753 Padding = '0x00, '
3754 if Unicode:
3755 Padding = Padding * 2
3756 ArraySize = ArraySize / 2
3757 if ArraySize < (len(PcdValue) + 1):
3758 if Pcd.MaxSizeUserSet:
3759 EdkLogger.error("build", AUTOGEN_ERROR,
3760 "The maximum size of VOID* type PCD '%s.%s' is less than its actual size occupied." % (Pcd.TokenSpaceGuidCName, TokenCName)
3761 )
3762 else:
3763 ArraySize = len(PcdValue) + 1
3764 if ArraySize > len(PcdValue) + 1:
3765 NewValue = NewValue + Padding * (ArraySize - len(PcdValue) - 1)
3766 PcdValue = NewValue + Padding.strip().rstrip(',') + '}'
3767 elif len(PcdValue.split(',')) <= ArraySize:
3768 PcdValue = PcdValue.rstrip('}') + ', 0x00' * (ArraySize - len(PcdValue.split(',')))
3769 PcdValue += '}'
3770 else:
3771 if Pcd.MaxSizeUserSet:
3772 EdkLogger.error("build", AUTOGEN_ERROR,
3773 "The maximum size of VOID* type PCD '%s.%s' is less than its actual size occupied." % (Pcd.TokenSpaceGuidCName, TokenCName)
3774 )
3775 else:
3776 ArraySize = len(PcdValue) + 1
3777 PcdItem = '%s.%s|%s|0x%X' % \
3778 (Pcd.TokenSpaceGuidCName, TokenCName, PcdValue, PatchPcd[1])
3779 PcdComments = ''
3780 if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) in self._PcdComments:
3781 PcdComments = '\n '.join(self._PcdComments[Pcd.TokenSpaceGuidCName, Pcd.TokenCName])
3782 if PcdComments:
3783 PcdItem = PcdComments + '\n ' + PcdItem
3784 AsBuiltInfDict['patchablepcd_item'].append(PcdItem)
3785
3786 for Pcd in Pcds + VfrPcds:
3787 PcdCommentList = []
3788 HiiInfo = ''
3789 TokenCName = Pcd.TokenCName
3790 for PcdItem in GlobalData.MixedPcd:
3791 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
3792 TokenCName = PcdItem[0]
3793 break
3794 if Pcd.Type == TAB_PCDS_DYNAMIC_EX_HII:
3795 for SkuName in Pcd.SkuInfoList:
3796 SkuInfo = Pcd.SkuInfoList[SkuName]
3797 HiiInfo = '## %s|%s|%s' % (SkuInfo.VariableName, SkuInfo.VariableGuid, SkuInfo.VariableOffset)
3798 break
3799 if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) in self._PcdComments:
3800 PcdCommentList = self._PcdComments[Pcd.TokenSpaceGuidCName, Pcd.TokenCName][:]
3801 if HiiInfo:
3802 UsageIndex = -1
3803 UsageStr = ''
3804 for Index, Comment in enumerate(PcdCommentList):
3805 for Usage in UsageList:
3806 if Comment.find(Usage) != -1:
3807 UsageStr = Usage
3808 UsageIndex = Index
3809 break
3810 if UsageIndex != -1:
3811 PcdCommentList[UsageIndex] = '## %s %s %s' % (UsageStr, HiiInfo, PcdCommentList[UsageIndex].replace(UsageStr, ''))
3812 else:
3813 PcdCommentList.append('## UNDEFINED ' + HiiInfo)
3814 PcdComments = '\n '.join(PcdCommentList)
3815 PcdEntry = Pcd.TokenSpaceGuidCName + '.' + TokenCName
3816 if PcdComments:
3817 PcdEntry = PcdComments + '\n ' + PcdEntry
3818 AsBuiltInfDict['pcd_item'].append(PcdEntry)
3819 for Item in self.BuildOption:
3820 if 'FLAGS' in self.BuildOption[Item]:
3821 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()))
3822
3823 # Generated LibraryClasses section in comments.
3824 for Library in self.LibraryAutoGenList:
3825 AsBuiltInfDict['libraryclasses_item'].append(Library.MetaFile.File.replace('\\', '/'))
3826
3827 # Generated UserExtensions TianoCore section.
3828 # All tianocore user extensions are copied.
3829 UserExtStr = ''
3830 for TianoCore in self._GetTianoCoreUserExtensionList():
3831 UserExtStr += '\n'.join(TianoCore)
3832 ExtensionFile = os.path.join(self.MetaFile.Dir, TianoCore[1])
3833 if os.path.isfile(ExtensionFile):
3834 shutil.copy2(ExtensionFile, self.OutputDir)
3835 AsBuiltInfDict['userextension_tianocore_item'] = UserExtStr
3836
3837 # Generated depex expression section in comments.
3838 DepexExpresion = self._GetDepexExpresionString()
3839 AsBuiltInfDict['depexsection_item'] = DepexExpresion if DepexExpresion else ''
3840
3841 AsBuiltInf = TemplateString()
3842 AsBuiltInf.Append(gAsBuiltInfHeaderString.Replace(AsBuiltInfDict))
3843
3844 SaveFileOnChange(os.path.join(self.OutputDir, self.Name + '.inf'), str(AsBuiltInf), False)
3845
3846 self.IsAsBuiltInfCreated = True
3847 if GlobalData.gBinCacheDest:
3848 self.CopyModuleToCache()
3849
3850 def CopyModuleToCache(self):
3851 FileDir = path.join(GlobalData.gBinCacheDest, self.Arch, self.SourceDir, self.MetaFile.BaseName)
3852 CreateDirectory (FileDir)
3853 HashFile = path.join(self.BuildDir, self.Name + '.hash')
3854 ModuleFile = path.join(self.OutputDir, self.Name + '.inf')
3855 if os.path.exists(HashFile):
3856 shutil.copy2(HashFile, FileDir)
3857 if os.path.exists(ModuleFile):
3858 shutil.copy2(ModuleFile, FileDir)
3859 if not self.OutputFile:
3860 Ma = self.Workspace.BuildDatabase[PathClass(ModuleFile), self.Arch, self.BuildTarget, self.ToolChain]
3861 self.OutputFile = Ma.Binaries
3862 if self.OutputFile:
3863 for File in self.OutputFile:
3864 File = str(File)
3865 if not os.path.isabs(File):
3866 File = os.path.join(self.OutputDir, File)
3867 if os.path.exists(File):
3868 shutil.copy2(File, FileDir)
3869
3870 def AttemptModuleCacheCopy(self):
3871 if self.IsBinaryModule:
3872 return False
3873 FileDir = path.join(GlobalData.gBinCacheSource, self.Arch, self.SourceDir, self.MetaFile.BaseName)
3874 HashFile = path.join(FileDir, self.Name + '.hash')
3875 if os.path.exists(HashFile):
3876 f = open(HashFile, 'r')
3877 CacheHash = f.read()
3878 f.close()
3879 if GlobalData.gModuleHash[self.Arch][self.Name]:
3880 if CacheHash == GlobalData.gModuleHash[self.Arch][self.Name]:
3881 for root, dir, files in os.walk(FileDir):
3882 for f in files:
3883 if self.Name + '.hash' in f:
3884 shutil.copy2(HashFile, self.BuildDir)
3885 else:
3886 File = path.join(root, f)
3887 shutil.copy2(File, self.OutputDir)
3888 if self.Name == "PcdPeim" or self.Name == "PcdDxe":
3889 CreatePcdDatabaseCode(self, TemplateString(), TemplateString())
3890 return True
3891 return False
3892
3893 ## Create makefile for the module and its dependent libraries
3894 #
3895 # @param CreateLibraryMakeFile Flag indicating if or not the makefiles of
3896 # dependent libraries will be created
3897 #
3898 @cached_class_function
3899 def CreateMakeFile(self, CreateLibraryMakeFile=True, GenFfsList = []):
3900 # nest this function inside it's only caller.
3901 def CreateTimeStamp():
3902 FileSet = {self.MetaFile.Path}
3903
3904 for SourceFile in self.Module.Sources:
3905 FileSet.add (SourceFile.Path)
3906
3907 for Lib in self.DependentLibraryList:
3908 FileSet.add (Lib.MetaFile.Path)
3909
3910 for f in self.AutoGenDepSet:
3911 FileSet.add (f.Path)
3912
3913 if os.path.exists (self.TimeStampPath):
3914 os.remove (self.TimeStampPath)
3915 with open(self.TimeStampPath, 'w+') as file:
3916 for f in FileSet:
3917 print(f, file=file)
3918
3919 # Ignore generating makefile when it is a binary module
3920 if self.IsBinaryModule:
3921 return
3922
3923 self.GenFfsList = GenFfsList
3924 if not self.IsLibrary and CreateLibraryMakeFile:
3925 for LibraryAutoGen in self.LibraryAutoGenList:
3926 LibraryAutoGen.CreateMakeFile()
3927
3928 if self.CanSkip():
3929 return
3930
3931 if len(self.CustomMakefile) == 0:
3932 Makefile = GenMake.ModuleMakefile(self)
3933 else:
3934 Makefile = GenMake.CustomMakefile(self)
3935 if Makefile.Generate():
3936 EdkLogger.debug(EdkLogger.DEBUG_9, "Generated makefile for module %s [%s]" %
3937 (self.Name, self.Arch))
3938 else:
3939 EdkLogger.debug(EdkLogger.DEBUG_9, "Skipped the generation of makefile for module %s [%s]" %
3940 (self.Name, self.Arch))
3941
3942 CreateTimeStamp()
3943
3944 def CopyBinaryFiles(self):
3945 for File in self.Module.Binaries:
3946 SrcPath = File.Path
3947 DstPath = os.path.join(self.OutputDir, os.path.basename(SrcPath))
3948 CopyLongFilePath(SrcPath, DstPath)
3949 ## Create autogen code for the module and its dependent libraries
3950 #
3951 # @param CreateLibraryCodeFile Flag indicating if or not the code of
3952 # dependent libraries will be created
3953 #
3954 def CreateCodeFile(self, CreateLibraryCodeFile=True):
3955 if self.IsCodeFileCreated:
3956 return
3957
3958 # Need to generate PcdDatabase even PcdDriver is binarymodule
3959 if self.IsBinaryModule and self.PcdIsDriver != '':
3960 CreatePcdDatabaseCode(self, TemplateString(), TemplateString())
3961 return
3962 if self.IsBinaryModule:
3963 if self.IsLibrary:
3964 self.CopyBinaryFiles()
3965 return
3966
3967 if not self.IsLibrary and CreateLibraryCodeFile:
3968 for LibraryAutoGen in self.LibraryAutoGenList:
3969 LibraryAutoGen.CreateCodeFile()
3970
3971 if self.CanSkip():
3972 return
3973
3974 AutoGenList = []
3975 IgoredAutoGenList = []
3976
3977 for File in self.AutoGenFileList:
3978 if GenC.Generate(File.Path, self.AutoGenFileList[File], File.IsBinary):
3979 #Ignore Edk AutoGen.c
3980 if self.AutoGenVersion < 0x00010005 and File.Name == 'AutoGen.c':
3981 continue
3982
3983 AutoGenList.append(str(File))
3984 else:
3985 IgoredAutoGenList.append(str(File))
3986
3987 # Skip the following code for EDK I inf
3988 if self.AutoGenVersion < 0x00010005:
3989 return
3990
3991 for ModuleType in self.DepexList:
3992 # Ignore empty [depex] section or [depex] section for SUP_MODULE_USER_DEFINED module
3993 if len(self.DepexList[ModuleType]) == 0 or ModuleType == SUP_MODULE_USER_DEFINED:
3994 continue
3995
3996 Dpx = GenDepex.DependencyExpression(self.DepexList[ModuleType], ModuleType, True)
3997 DpxFile = gAutoGenDepexFileName % {"module_name" : self.Name}
3998
3999 if len(Dpx.PostfixNotation) != 0:
4000 self.DepexGenerated = True
4001
4002 if Dpx.Generate(path.join(self.OutputDir, DpxFile)):
4003 AutoGenList.append(str(DpxFile))
4004 else:
4005 IgoredAutoGenList.append(str(DpxFile))
4006
4007 if IgoredAutoGenList == []:
4008 EdkLogger.debug(EdkLogger.DEBUG_9, "Generated [%s] files for module %s [%s]" %
4009 (" ".join(AutoGenList), self.Name, self.Arch))
4010 elif AutoGenList == []:
4011 EdkLogger.debug(EdkLogger.DEBUG_9, "Skipped the generation of [%s] files for module %s [%s]" %
4012 (" ".join(IgoredAutoGenList), self.Name, self.Arch))
4013 else:
4014 EdkLogger.debug(EdkLogger.DEBUG_9, "Generated [%s] (skipped %s) files for module %s [%s]" %
4015 (" ".join(AutoGenList), " ".join(IgoredAutoGenList), self.Name, self.Arch))
4016
4017 self.IsCodeFileCreated = True
4018 return AutoGenList
4019
4020 ## Summarize the ModuleAutoGen objects of all libraries used by this module
4021 @cached_property
4022 def LibraryAutoGenList(self):
4023 RetVal = []
4024 for Library in self.DependentLibraryList:
4025 La = ModuleAutoGen(
4026 self.Workspace,
4027 Library.MetaFile,
4028 self.BuildTarget,
4029 self.ToolChain,
4030 self.Arch,
4031 self.PlatformInfo.MetaFile
4032 )
4033 if La not in RetVal:
4034 RetVal.append(La)
4035 for Lib in La.CodaTargetList:
4036 self._ApplyBuildRule(Lib.Target, TAB_UNKNOWN_FILE)
4037 return RetVal
4038
4039 def GenModuleHash(self):
4040 if self.Arch not in GlobalData.gModuleHash:
4041 GlobalData.gModuleHash[self.Arch] = {}
4042 m = hashlib.md5()
4043 # Add Platform level hash
4044 m.update(GlobalData.gPlatformHash)
4045 # Add Package level hash
4046 if self.DependentPackageList:
4047 for Pkg in sorted(self.DependentPackageList, key=lambda x: x.PackageName):
4048 if Pkg.PackageName in GlobalData.gPackageHash[self.Arch]:
4049 m.update(GlobalData.gPackageHash[self.Arch][Pkg.PackageName])
4050
4051 # Add Library hash
4052 if self.LibraryAutoGenList:
4053 for Lib in sorted(self.LibraryAutoGenList, key=lambda x: x.Name):
4054 if Lib.Name not in GlobalData.gModuleHash[self.Arch]:
4055 Lib.GenModuleHash()
4056 m.update(GlobalData.gModuleHash[self.Arch][Lib.Name])
4057
4058 # Add Module self
4059 f = open(str(self.MetaFile), 'r')
4060 Content = f.read()
4061 f.close()
4062 m.update(Content)
4063 # Add Module's source files
4064 if self.SourceFileList:
4065 for File in sorted(self.SourceFileList, key=lambda x: str(x)):
4066 f = open(str(File), 'r')
4067 Content = f.read()
4068 f.close()
4069 m.update(Content)
4070
4071 ModuleHashFile = path.join(self.BuildDir, self.Name + ".hash")
4072 if self.Name not in GlobalData.gModuleHash[self.Arch]:
4073 GlobalData.gModuleHash[self.Arch][self.Name] = m.hexdigest()
4074 if GlobalData.gBinCacheSource:
4075 if self.AttemptModuleCacheCopy():
4076 return False
4077 return SaveFileOnChange(ModuleHashFile, m.hexdigest(), True)
4078
4079 ## Decide whether we can skip the ModuleAutoGen process
4080 def CanSkipbyHash(self):
4081 if GlobalData.gUseHashCache:
4082 return not self.GenModuleHash()
4083 return False
4084
4085 ## Decide whether we can skip the ModuleAutoGen process
4086 # If any source file is newer than the module than we cannot skip
4087 #
4088 def CanSkip(self):
4089 if self.MakeFileDir in GlobalData.gSikpAutoGenCache:
4090 return True
4091 if not os.path.exists(self.TimeStampPath):
4092 return False
4093 #last creation time of the module
4094 DstTimeStamp = os.stat(self.TimeStampPath)[8]
4095
4096 SrcTimeStamp = self.Workspace._SrcTimeStamp
4097 if SrcTimeStamp > DstTimeStamp:
4098 return False
4099
4100 with open(self.TimeStampPath,'r') as f:
4101 for source in f:
4102 source = source.rstrip('\n')
4103 if not os.path.exists(source):
4104 return False
4105 if source not in ModuleAutoGen.TimeDict :
4106 ModuleAutoGen.TimeDict[source] = os.stat(source)[8]
4107 if ModuleAutoGen.TimeDict[source] > DstTimeStamp:
4108 return False
4109 GlobalData.gSikpAutoGenCache.add(self.MakeFileDir)
4110 return True
4111
4112 @cached_property
4113 def TimeStampPath(self):
4114 return os.path.join(self.MakeFileDir, 'AutoGenTimeStamp')