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