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