]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/AutoGen/WorkspaceAutoGen.py
fde48b4b2788f2c7240aa27a9cd854acd8a84904
[mirror_edk2.git] / BaseTools / Source / Python / AutoGen / WorkspaceAutoGen.py
1 ## @file
2 # Create makefile for MS nmake and GNU make
3 #
4 # Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
5 # SPDX-License-Identifier: BSD-2-Clause-Patent
6 #
7
8 ## Import Modules
9 #
10 from __future__ import print_function
11 from __future__ import absolute_import
12 import os.path as path
13 import hashlib
14 from collections import defaultdict
15 from GenFds.FdfParser import FdfParser
16 from Workspace.WorkspaceCommon import GetModuleLibInstances
17 from AutoGen import GenMake
18 from AutoGen.AutoGen import AutoGen
19 from AutoGen.PlatformAutoGen import PlatformAutoGen
20 from AutoGen.BuildEngine import gDefaultBuildRuleFile
21 from Common.ToolDefClassObject import gDefaultToolsDefFile
22 from Common.StringUtils import NormPath
23 from Common.BuildToolError import *
24 from Common.DataType import *
25 from Common.Misc import *
26
27 ## Regular expression for splitting Dependency Expression string into tokens
28 gDepexTokenPattern = re.compile("(\(|\)|\w+| \S+\.inf)")
29
30 ## Regular expression for match: PCD(xxxx.yyy)
31 gPCDAsGuidPattern = re.compile(r"^PCD\(.+\..+\)$")
32
33 ## Workspace AutoGen class
34 #
35 # This class is used mainly to control the whole platform build for different
36 # architecture. This class will generate top level makefile.
37 #
38 class WorkspaceAutoGen(AutoGen):
39 # call super().__init__ then call the worker function with different parameter count
40 def __init__(self, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs):
41 if not hasattr(self, "_Init"):
42 self._InitWorker(Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs)
43 self._Init = True
44
45 ## Initialize WorkspaceAutoGen
46 #
47 # @param WorkspaceDir Root directory of workspace
48 # @param ActivePlatform Meta-file of active platform
49 # @param Target Build target
50 # @param Toolchain Tool chain name
51 # @param ArchList List of architecture of current build
52 # @param MetaFileDb Database containing meta-files
53 # @param BuildConfig Configuration of build
54 # @param ToolDefinition Tool chain definitions
55 # @param FlashDefinitionFile File of flash definition
56 # @param Fds FD list to be generated
57 # @param Fvs FV list to be generated
58 # @param Caps Capsule list to be generated
59 # @param SkuId SKU id from command line
60 #
61 def _InitWorker(self, WorkspaceDir, ActivePlatform, Target, Toolchain, ArchList, MetaFileDb,
62 BuildConfig, ToolDefinition, FlashDefinitionFile='', Fds=None, Fvs=None, Caps=None, SkuId='', UniFlag=None,
63 Progress=None, BuildModule=None):
64 self.BuildDatabase = MetaFileDb
65 self.MetaFile = ActivePlatform
66 self.WorkspaceDir = WorkspaceDir
67 self.Platform = self.BuildDatabase[self.MetaFile, TAB_ARCH_COMMON, Target, Toolchain]
68 GlobalData.gActivePlatform = self.Platform
69 self.BuildTarget = Target
70 self.ToolChain = Toolchain
71 self.ArchList = ArchList
72 self.SkuId = SkuId
73 self.UniFlag = UniFlag
74
75 self.TargetTxt = BuildConfig
76 self.ToolDef = ToolDefinition
77 self.FdfFile = FlashDefinitionFile
78 self.FdTargetList = Fds if Fds else []
79 self.FvTargetList = Fvs if Fvs else []
80 self.CapTargetList = Caps if Caps else []
81 self.AutoGenObjectList = []
82 self._GuidDict = {}
83
84 # there's many relative directory operations, so ...
85 os.chdir(self.WorkspaceDir)
86
87 self.MergeArch()
88 self.ValidateBuildTarget()
89
90 EdkLogger.info("")
91 if self.ArchList:
92 EdkLogger.info('%-16s = %s' % ("Architecture(s)", ' '.join(self.ArchList)))
93 EdkLogger.info('%-16s = %s' % ("Build target", self.BuildTarget))
94 EdkLogger.info('%-16s = %s' % ("Toolchain", self.ToolChain))
95
96 EdkLogger.info('\n%-24s = %s' % ("Active Platform", self.Platform))
97 if BuildModule:
98 EdkLogger.info('%-24s = %s' % ("Active Module", BuildModule))
99
100 if self.FdfFile:
101 EdkLogger.info('%-24s = %s' % ("Flash Image Definition", self.FdfFile))
102
103 EdkLogger.verbose("\nFLASH_DEFINITION = %s" % self.FdfFile)
104
105 if Progress:
106 Progress.Start("\nProcessing meta-data")
107 #
108 # Mark now build in AutoGen Phase
109 #
110 GlobalData.gAutoGenPhase = True
111 self.ProcessModuleFromPdf()
112 self.ProcessPcdType()
113 self.ProcessMixedPcd()
114 self.VerifyPcdsFromFDF()
115 self.CollectAllPcds()
116 for Pa in self.AutoGenObjectList:
117 Pa.FillData_LibConstPcd()
118 self.GeneratePkgLevelHash()
119 #
120 # Check PCDs token value conflict in each DEC file.
121 #
122 self._CheckAllPcdsTokenValueConflict()
123 #
124 # Check PCD type and definition between DSC and DEC
125 #
126 self._CheckPcdDefineAndType()
127
128 self.CreateBuildOptionsFile()
129 self.CreatePcdTokenNumberFile()
130 self.CreateModuleHashInfo()
131
132 #
133 # Merge Arch
134 #
135 def MergeArch(self):
136 if not self.ArchList:
137 ArchList = set(self.Platform.SupArchList)
138 else:
139 ArchList = set(self.ArchList) & set(self.Platform.SupArchList)
140 if not ArchList:
141 EdkLogger.error("build", PARAMETER_INVALID,
142 ExtraData = "Invalid ARCH specified. [Valid ARCH: %s]" % (" ".join(self.Platform.SupArchList)))
143 elif self.ArchList and len(ArchList) != len(self.ArchList):
144 SkippedArchList = set(self.ArchList).symmetric_difference(set(self.Platform.SupArchList))
145 EdkLogger.verbose("\nArch [%s] is ignored because the platform supports [%s] only!"
146 % (" ".join(SkippedArchList), " ".join(self.Platform.SupArchList)))
147 self.ArchList = tuple(ArchList)
148
149 # Validate build target
150 def ValidateBuildTarget(self):
151 if self.BuildTarget not in self.Platform.BuildTargets:
152 EdkLogger.error("build", PARAMETER_INVALID,
153 ExtraData="Build target [%s] is not supported by the platform. [Valid target: %s]"
154 % (self.BuildTarget, " ".join(self.Platform.BuildTargets)))
155 @cached_property
156 def FdfProfile(self):
157 if not self.FdfFile:
158 self.FdfFile = self.Platform.FlashDefinition
159
160 FdfProfile = None
161 if self.FdfFile:
162 Fdf = FdfParser(self.FdfFile.Path)
163 Fdf.ParseFile()
164 GlobalData.gFdfParser = Fdf
165 if Fdf.CurrentFdName and Fdf.CurrentFdName in Fdf.Profile.FdDict:
166 FdDict = Fdf.Profile.FdDict[Fdf.CurrentFdName]
167 for FdRegion in FdDict.RegionList:
168 if str(FdRegion.RegionType) is 'FILE' and self.Platform.VpdToolGuid in str(FdRegion.RegionDataList):
169 if int(FdRegion.Offset) % 8 != 0:
170 EdkLogger.error("build", FORMAT_INVALID, 'The VPD Base Address %s must be 8-byte aligned.' % (FdRegion.Offset))
171 FdfProfile = Fdf.Profile
172 else:
173 if self.FdTargetList:
174 EdkLogger.info("No flash definition file found. FD [%s] will be ignored." % " ".join(self.FdTargetList))
175 self.FdTargetList = []
176 if self.FvTargetList:
177 EdkLogger.info("No flash definition file found. FV [%s] will be ignored." % " ".join(self.FvTargetList))
178 self.FvTargetList = []
179 if self.CapTargetList:
180 EdkLogger.info("No flash definition file found. Capsule [%s] will be ignored." % " ".join(self.CapTargetList))
181 self.CapTargetList = []
182
183 return FdfProfile
184
185 def ProcessModuleFromPdf(self):
186
187 if self.FdfProfile:
188 for fvname in self.FvTargetList:
189 if fvname.upper() not in self.FdfProfile.FvDict:
190 EdkLogger.error("build", OPTION_VALUE_INVALID,
191 "No such an FV in FDF file: %s" % fvname)
192
193 # In DSC file may use FILE_GUID to override the module, then in the Platform.Modules use FILE_GUIDmodule.inf as key,
194 # but the path (self.MetaFile.Path) is the real path
195 for key in self.FdfProfile.InfDict:
196 if key == 'ArchTBD':
197 MetaFile_cache = defaultdict(set)
198 for Arch in self.ArchList:
199 Current_Platform_cache = self.BuildDatabase[self.MetaFile, Arch, self.BuildTarget, self.ToolChain]
200 for Pkey in Current_Platform_cache.Modules:
201 MetaFile_cache[Arch].add(Current_Platform_cache.Modules[Pkey].MetaFile)
202 for Inf in self.FdfProfile.InfDict[key]:
203 ModuleFile = PathClass(NormPath(Inf), GlobalData.gWorkspace, Arch)
204 for Arch in self.ArchList:
205 if ModuleFile in MetaFile_cache[Arch]:
206 break
207 else:
208 ModuleData = self.BuildDatabase[ModuleFile, Arch, self.BuildTarget, self.ToolChain]
209 if not ModuleData.IsBinaryModule:
210 EdkLogger.error('build', PARSER_ERROR, "Module %s NOT found in DSC file; Is it really a binary module?" % ModuleFile)
211
212 else:
213 for Arch in self.ArchList:
214 if Arch == key:
215 Platform = self.BuildDatabase[self.MetaFile, Arch, self.BuildTarget, self.ToolChain]
216 MetaFileList = set()
217 for Pkey in Platform.Modules:
218 MetaFileList.add(Platform.Modules[Pkey].MetaFile)
219 for Inf in self.FdfProfile.InfDict[key]:
220 ModuleFile = PathClass(NormPath(Inf), GlobalData.gWorkspace, Arch)
221 if ModuleFile in MetaFileList:
222 continue
223 ModuleData = self.BuildDatabase[ModuleFile, Arch, self.BuildTarget, self.ToolChain]
224 if not ModuleData.IsBinaryModule:
225 EdkLogger.error('build', PARSER_ERROR, "Module %s NOT found in DSC file; Is it really a binary module?" % ModuleFile)
226
227
228
229 # parse FDF file to get PCDs in it, if any
230 def VerifyPcdsFromFDF(self):
231
232 if self.FdfProfile:
233 PcdSet = self.FdfProfile.PcdDict
234 self.VerifyPcdDeclearation(PcdSet)
235
236 def ProcessPcdType(self):
237 for Arch in self.ArchList:
238 Platform = self.BuildDatabase[self.MetaFile, Arch, self.BuildTarget, self.ToolChain]
239 Platform.Pcds
240 # generate the SourcePcdDict and BinaryPcdDict
241 Libs = []
242 for BuildData in list(self.BuildDatabase._CACHE_.values()):
243 if BuildData.Arch != Arch:
244 continue
245 if BuildData.MetaFile.Ext == '.inf' and str(BuildData) in Platform.Modules :
246 Libs.extend(GetModuleLibInstances(BuildData, Platform,
247 self.BuildDatabase,
248 Arch,
249 self.BuildTarget,
250 self.ToolChain,
251 self.Platform.MetaFile,
252 EdkLogger
253 ))
254 for BuildData in list(self.BuildDatabase._CACHE_.values()):
255 if BuildData.Arch != Arch:
256 continue
257 if BuildData.MetaFile.Ext == '.inf':
258 for key in BuildData.Pcds:
259 if BuildData.Pcds[key].Pending:
260 if key in Platform.Pcds:
261 PcdInPlatform = Platform.Pcds[key]
262 if PcdInPlatform.Type:
263 BuildData.Pcds[key].Type = PcdInPlatform.Type
264 BuildData.Pcds[key].Pending = False
265
266 if BuildData.MetaFile in Platform.Modules:
267 PlatformModule = Platform.Modules[str(BuildData.MetaFile)]
268 if key in PlatformModule.Pcds:
269 PcdInPlatform = PlatformModule.Pcds[key]
270 if PcdInPlatform.Type:
271 BuildData.Pcds[key].Type = PcdInPlatform.Type
272 BuildData.Pcds[key].Pending = False
273 else:
274 #Pcd used in Library, Pcd Type from reference module if Pcd Type is Pending
275 if BuildData.Pcds[key].Pending:
276 if bool(BuildData.LibraryClass):
277 if BuildData in set(Libs):
278 ReferenceModules = BuildData.ReferenceModules
279 for ReferenceModule in ReferenceModules:
280 if ReferenceModule.MetaFile in Platform.Modules:
281 RefPlatformModule = Platform.Modules[str(ReferenceModule.MetaFile)]
282 if key in RefPlatformModule.Pcds:
283 PcdInReferenceModule = RefPlatformModule.Pcds[key]
284 if PcdInReferenceModule.Type:
285 BuildData.Pcds[key].Type = PcdInReferenceModule.Type
286 BuildData.Pcds[key].Pending = False
287 break
288
289 def ProcessMixedPcd(self):
290 for Arch in self.ArchList:
291 SourcePcdDict = {TAB_PCDS_DYNAMIC_EX:set(), TAB_PCDS_PATCHABLE_IN_MODULE:set(),TAB_PCDS_DYNAMIC:set(),TAB_PCDS_FIXED_AT_BUILD:set()}
292 BinaryPcdDict = {TAB_PCDS_DYNAMIC_EX:set(), TAB_PCDS_PATCHABLE_IN_MODULE:set()}
293 SourcePcdDict_Keys = SourcePcdDict.keys()
294 BinaryPcdDict_Keys = BinaryPcdDict.keys()
295
296 # generate the SourcePcdDict and BinaryPcdDict
297
298 for BuildData in list(self.BuildDatabase._CACHE_.values()):
299 if BuildData.Arch != Arch:
300 continue
301 if BuildData.MetaFile.Ext == '.inf':
302 for key in BuildData.Pcds:
303 if TAB_PCDS_DYNAMIC_EX in BuildData.Pcds[key].Type:
304 if BuildData.IsBinaryModule:
305 BinaryPcdDict[TAB_PCDS_DYNAMIC_EX].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
306 else:
307 SourcePcdDict[TAB_PCDS_DYNAMIC_EX].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
308
309 elif TAB_PCDS_PATCHABLE_IN_MODULE in BuildData.Pcds[key].Type:
310 if BuildData.MetaFile.Ext == '.inf':
311 if BuildData.IsBinaryModule:
312 BinaryPcdDict[TAB_PCDS_PATCHABLE_IN_MODULE].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
313 else:
314 SourcePcdDict[TAB_PCDS_PATCHABLE_IN_MODULE].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
315
316 elif TAB_PCDS_DYNAMIC in BuildData.Pcds[key].Type:
317 SourcePcdDict[TAB_PCDS_DYNAMIC].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
318 elif TAB_PCDS_FIXED_AT_BUILD in BuildData.Pcds[key].Type:
319 SourcePcdDict[TAB_PCDS_FIXED_AT_BUILD].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
320
321 #
322 # A PCD can only use one type for all source modules
323 #
324 for i in SourcePcdDict_Keys:
325 for j in SourcePcdDict_Keys:
326 if i != j:
327 Intersections = SourcePcdDict[i].intersection(SourcePcdDict[j])
328 if len(Intersections) > 0:
329 EdkLogger.error(
330 'build',
331 FORMAT_INVALID,
332 "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),
333 ExtraData='\n\t'.join(str(P[1]+'.'+P[0]) for P in Intersections)
334 )
335
336 #
337 # intersection the BinaryPCD for Mixed PCD
338 #
339 for i in BinaryPcdDict_Keys:
340 for j in BinaryPcdDict_Keys:
341 if i != j:
342 Intersections = BinaryPcdDict[i].intersection(BinaryPcdDict[j])
343 for item in Intersections:
344 NewPcd1 = (item[0] + '_' + i, item[1])
345 NewPcd2 = (item[0] + '_' + j, item[1])
346 if item not in GlobalData.MixedPcd:
347 GlobalData.MixedPcd[item] = [NewPcd1, NewPcd2]
348 else:
349 if NewPcd1 not in GlobalData.MixedPcd[item]:
350 GlobalData.MixedPcd[item].append(NewPcd1)
351 if NewPcd2 not in GlobalData.MixedPcd[item]:
352 GlobalData.MixedPcd[item].append(NewPcd2)
353
354 #
355 # intersection the SourcePCD and BinaryPCD for Mixed PCD
356 #
357 for i in SourcePcdDict_Keys:
358 for j in BinaryPcdDict_Keys:
359 if i != j:
360 Intersections = SourcePcdDict[i].intersection(BinaryPcdDict[j])
361 for item in Intersections:
362 NewPcd1 = (item[0] + '_' + i, item[1])
363 NewPcd2 = (item[0] + '_' + j, item[1])
364 if item not in GlobalData.MixedPcd:
365 GlobalData.MixedPcd[item] = [NewPcd1, NewPcd2]
366 else:
367 if NewPcd1 not in GlobalData.MixedPcd[item]:
368 GlobalData.MixedPcd[item].append(NewPcd1)
369 if NewPcd2 not in GlobalData.MixedPcd[item]:
370 GlobalData.MixedPcd[item].append(NewPcd2)
371
372 BuildData = self.BuildDatabase[self.MetaFile, Arch, self.BuildTarget, self.ToolChain]
373 for key in BuildData.Pcds:
374 for SinglePcd in GlobalData.MixedPcd:
375 if (BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName) == SinglePcd:
376 for item in GlobalData.MixedPcd[SinglePcd]:
377 Pcd_Type = item[0].split('_')[-1]
378 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 \
379 (Pcd_Type == TAB_PCDS_DYNAMIC and BuildData.Pcds[key].Type in PCD_DYNAMIC_TYPE_SET):
380 Value = BuildData.Pcds[key]
381 Value.TokenCName = BuildData.Pcds[key].TokenCName + '_' + Pcd_Type
382 if len(key) == 2:
383 newkey = (Value.TokenCName, key[1])
384 elif len(key) == 3:
385 newkey = (Value.TokenCName, key[1], key[2])
386 del BuildData.Pcds[key]
387 BuildData.Pcds[newkey] = Value
388 break
389 break
390
391 if self.FdfProfile:
392 PcdSet = self.FdfProfile.PcdDict
393 # handle the mixed pcd in FDF file
394 for key in PcdSet:
395 if key in GlobalData.MixedPcd:
396 Value = PcdSet[key]
397 del PcdSet[key]
398 for item in GlobalData.MixedPcd[key]:
399 PcdSet[item] = Value
400
401 #Collect package set information from INF of FDF
402 @cached_property
403 def PkgSet(self):
404 if not self.FdfFile:
405 self.FdfFile = self.Platform.FlashDefinition
406
407 if self.FdfFile:
408 ModuleList = self.FdfProfile.InfList
409 else:
410 ModuleList = []
411 Pkgs = {}
412 for Arch in self.ArchList:
413 Platform = self.BuildDatabase[self.MetaFile, Arch, self.BuildTarget, self.ToolChain]
414 PkgSet = set()
415 for mb in [self.BuildDatabase[m, Arch, self.BuildTarget, self.ToolChain] for m in Platform.Modules]:
416 PkgSet.update(mb.Packages)
417 for Inf in ModuleList:
418 ModuleFile = PathClass(NormPath(Inf), GlobalData.gWorkspace, Arch)
419 if ModuleFile in Platform.Modules:
420 continue
421 ModuleData = self.BuildDatabase[ModuleFile, Arch, self.BuildTarget, self.ToolChain]
422 PkgSet.update(ModuleData.Packages)
423 PkgSet.update(Platform.Packages)
424 Pkgs[Arch] = list(PkgSet)
425 return Pkgs
426
427 def VerifyPcdDeclearation(self,PcdSet):
428 for Arch in self.ArchList:
429 Platform = self.BuildDatabase[self.MetaFile, Arch, self.BuildTarget, self.ToolChain]
430 Pkgs = self.PkgSet[Arch]
431 DecPcds = set()
432 DecPcdsKey = set()
433 for Pkg in Pkgs:
434 for Pcd in Pkg.Pcds:
435 DecPcds.add((Pcd[0], Pcd[1]))
436 DecPcdsKey.add((Pcd[0], Pcd[1], Pcd[2]))
437
438 Platform.SkuName = self.SkuId
439 for Name, Guid,Fileds in PcdSet:
440 if (Name, Guid) not in DecPcds:
441 EdkLogger.error(
442 'build',
443 PARSER_ERROR,
444 "PCD (%s.%s) used in FDF is not declared in DEC files." % (Guid, Name),
445 File = self.FdfProfile.PcdFileLineDict[Name, Guid, Fileds][0],
446 Line = self.FdfProfile.PcdFileLineDict[Name, Guid, Fileds][1]
447 )
448 else:
449 # Check whether Dynamic or DynamicEx PCD used in FDF file. If used, build break and give a error message.
450 if (Name, Guid, TAB_PCDS_FIXED_AT_BUILD) in DecPcdsKey \
451 or (Name, Guid, TAB_PCDS_PATCHABLE_IN_MODULE) in DecPcdsKey \
452 or (Name, Guid, TAB_PCDS_FEATURE_FLAG) in DecPcdsKey:
453 continue
454 elif (Name, Guid, TAB_PCDS_DYNAMIC) in DecPcdsKey or (Name, Guid, TAB_PCDS_DYNAMIC_EX) in DecPcdsKey:
455 EdkLogger.error(
456 'build',
457 PARSER_ERROR,
458 "Using Dynamic or DynamicEx type of PCD [%s.%s] in FDF file is not allowed." % (Guid, Name),
459 File = self.FdfProfile.PcdFileLineDict[Name, Guid, Fileds][0],
460 Line = self.FdfProfile.PcdFileLineDict[Name, Guid, Fileds][1]
461 )
462 def CollectAllPcds(self):
463
464 for Arch in self.ArchList:
465 Pa = PlatformAutoGen(self, self.MetaFile, self.BuildTarget, self.ToolChain, Arch)
466 #
467 # Explicitly collect platform's dynamic PCDs
468 #
469 Pa.CollectPlatformDynamicPcds()
470 Pa.CollectFixedAtBuildPcds()
471 self.AutoGenObjectList.append(Pa)
472 # We need to calculate the PcdTokenNumber after all Arch Pcds are collected.
473 for Arch in self.ArchList:
474 #Pcd TokenNumber
475 Pa = PlatformAutoGen(self, self.MetaFile, self.BuildTarget, self.ToolChain, Arch)
476 self.UpdateModuleDataPipe(Arch, {"PCD_TNUM":Pa.PcdTokenNumber})
477
478 def UpdateModuleDataPipe(self,arch, attr_dict):
479 for (Target, Toolchain, Arch, MetaFile) in AutoGen.Cache():
480 if Arch != arch:
481 continue
482 try:
483 AutoGen.Cache()[(Target, Toolchain, Arch, MetaFile)].DataPipe.DataContainer = attr_dict
484 except Exception:
485 pass
486 #
487 # Generate Package level hash value
488 #
489 def GeneratePkgLevelHash(self):
490 for Arch in self.ArchList:
491 GlobalData.gPackageHash = {}
492 if GlobalData.gUseHashCache:
493 for Pkg in self.PkgSet[Arch]:
494 self._GenPkgLevelHash(Pkg)
495
496
497 def CreateBuildOptionsFile(self):
498 #
499 # Create BuildOptions Macro & PCD metafile, also add the Active Platform and FDF file.
500 #
501 content = 'gCommandLineDefines: '
502 content += str(GlobalData.gCommandLineDefines)
503 content += TAB_LINE_BREAK
504 content += 'BuildOptionPcd: '
505 content += str(GlobalData.BuildOptionPcd)
506 content += TAB_LINE_BREAK
507 content += 'Active Platform: '
508 content += str(self.Platform)
509 content += TAB_LINE_BREAK
510 if self.FdfFile:
511 content += 'Flash Image Definition: '
512 content += str(self.FdfFile)
513 content += TAB_LINE_BREAK
514 SaveFileOnChange(os.path.join(self.BuildDir, 'BuildOptions'), content, False)
515
516 def CreatePcdTokenNumberFile(self):
517 #
518 # Create PcdToken Number file for Dynamic/DynamicEx Pcd.
519 #
520 PcdTokenNumber = 'PcdTokenNumber: '
521 Pa = self.AutoGenObjectList[0]
522 if Pa.PcdTokenNumber:
523 if Pa.DynamicPcdList:
524 for Pcd in Pa.DynamicPcdList:
525 PcdTokenNumber += TAB_LINE_BREAK
526 PcdTokenNumber += str((Pcd.TokenCName, Pcd.TokenSpaceGuidCName))
527 PcdTokenNumber += ' : '
528 PcdTokenNumber += str(Pa.PcdTokenNumber[Pcd.TokenCName, Pcd.TokenSpaceGuidCName])
529 SaveFileOnChange(os.path.join(self.BuildDir, 'PcdTokenNumber'), PcdTokenNumber, False)
530
531 def CreateModuleHashInfo(self):
532 #
533 # Get set of workspace metafiles
534 #
535 AllWorkSpaceMetaFiles = self._GetMetaFiles(self.BuildTarget, self.ToolChain)
536
537 #
538 # Retrieve latest modified time of all metafiles
539 #
540 SrcTimeStamp = 0
541 for f in AllWorkSpaceMetaFiles:
542 if os.stat(f)[8] > SrcTimeStamp:
543 SrcTimeStamp = os.stat(f)[8]
544 self._SrcTimeStamp = SrcTimeStamp
545
546 if GlobalData.gUseHashCache:
547 m = hashlib.md5()
548 for files in AllWorkSpaceMetaFiles:
549 if files.endswith('.dec'):
550 continue
551 f = open(files, 'rb')
552 Content = f.read()
553 f.close()
554 m.update(Content)
555 SaveFileOnChange(os.path.join(self.BuildDir, 'AutoGen.hash'), m.hexdigest(), False)
556 GlobalData.gPlatformHash = m.hexdigest()
557
558 #
559 # Write metafile list to build directory
560 #
561 AutoGenFilePath = os.path.join(self.BuildDir, 'AutoGen')
562 if os.path.exists (AutoGenFilePath):
563 os.remove(AutoGenFilePath)
564 if not os.path.exists(self.BuildDir):
565 os.makedirs(self.BuildDir)
566 with open(os.path.join(self.BuildDir, 'AutoGen'), 'w+') as file:
567 for f in AllWorkSpaceMetaFiles:
568 print(f, file=file)
569 return True
570
571 def _GenPkgLevelHash(self, Pkg):
572 if Pkg.PackageName in GlobalData.gPackageHash:
573 return
574
575 PkgDir = os.path.join(self.BuildDir, Pkg.Arch, Pkg.PackageName)
576 CreateDirectory(PkgDir)
577 HashFile = os.path.join(PkgDir, Pkg.PackageName + '.hash')
578 m = hashlib.md5()
579 # Get .dec file's hash value
580 f = open(Pkg.MetaFile.Path, 'rb')
581 Content = f.read()
582 f.close()
583 m.update(Content)
584 # Get include files hash value
585 if Pkg.Includes:
586 for inc in sorted(Pkg.Includes, key=lambda x: str(x)):
587 for Root, Dirs, Files in os.walk(str(inc)):
588 for File in sorted(Files):
589 File_Path = os.path.join(Root, File)
590 f = open(File_Path, 'rb')
591 Content = f.read()
592 f.close()
593 m.update(Content)
594 SaveFileOnChange(HashFile, m.hexdigest(), False)
595 GlobalData.gPackageHash[Pkg.PackageName] = m.hexdigest()
596
597 def _GetMetaFiles(self, Target, Toolchain):
598 AllWorkSpaceMetaFiles = set()
599 #
600 # add fdf
601 #
602 if self.FdfFile:
603 AllWorkSpaceMetaFiles.add (self.FdfFile.Path)
604 for f in GlobalData.gFdfParser.GetAllIncludedFile():
605 AllWorkSpaceMetaFiles.add (f.FileName)
606 #
607 # add dsc
608 #
609 AllWorkSpaceMetaFiles.add(self.MetaFile.Path)
610
611 #
612 # add build_rule.txt & tools_def.txt
613 #
614 AllWorkSpaceMetaFiles.add(os.path.join(GlobalData.gConfDirectory, gDefaultBuildRuleFile))
615 AllWorkSpaceMetaFiles.add(os.path.join(GlobalData.gConfDirectory, gDefaultToolsDefFile))
616
617 # add BuildOption metafile
618 #
619 AllWorkSpaceMetaFiles.add(os.path.join(self.BuildDir, 'BuildOptions'))
620
621 # add PcdToken Number file for Dynamic/DynamicEx Pcd
622 #
623 AllWorkSpaceMetaFiles.add(os.path.join(self.BuildDir, 'PcdTokenNumber'))
624
625 for Pa in self.AutoGenObjectList:
626 AllWorkSpaceMetaFiles.add(Pa.ToolDefinitionFile)
627
628 for Arch in self.ArchList:
629 #
630 # add dec
631 #
632 for Package in PlatformAutoGen(self, self.MetaFile, Target, Toolchain, Arch).PackageList:
633 AllWorkSpaceMetaFiles.add(Package.MetaFile.Path)
634
635 #
636 # add included dsc
637 #
638 for filePath in self.BuildDatabase[self.MetaFile, Arch, Target, Toolchain]._RawData.IncludedFiles:
639 AllWorkSpaceMetaFiles.add(filePath.Path)
640
641 return AllWorkSpaceMetaFiles
642
643 def _CheckPcdDefineAndType(self):
644 PcdTypeSet = {TAB_PCDS_FIXED_AT_BUILD,
645 TAB_PCDS_PATCHABLE_IN_MODULE,
646 TAB_PCDS_FEATURE_FLAG,
647 TAB_PCDS_DYNAMIC,
648 TAB_PCDS_DYNAMIC_EX}
649
650 # This dict store PCDs which are not used by any modules with specified arches
651 UnusedPcd = OrderedDict()
652 for Pa in self.AutoGenObjectList:
653 # Key of DSC's Pcds dictionary is PcdCName, TokenSpaceGuid
654 for Pcd in Pa.Platform.Pcds:
655 PcdType = Pa.Platform.Pcds[Pcd].Type
656
657 # If no PCD type, this PCD comes from FDF
658 if not PcdType:
659 continue
660
661 # Try to remove Hii and Vpd suffix
662 if PcdType.startswith(TAB_PCDS_DYNAMIC_EX):
663 PcdType = TAB_PCDS_DYNAMIC_EX
664 elif PcdType.startswith(TAB_PCDS_DYNAMIC):
665 PcdType = TAB_PCDS_DYNAMIC
666
667 for Package in Pa.PackageList:
668 # Key of DEC's Pcds dictionary is PcdCName, TokenSpaceGuid, PcdType
669 if (Pcd[0], Pcd[1], PcdType) in Package.Pcds:
670 break
671 for Type in PcdTypeSet:
672 if (Pcd[0], Pcd[1], Type) in Package.Pcds:
673 EdkLogger.error(
674 'build',
675 FORMAT_INVALID,
676 "Type [%s] of PCD [%s.%s] in DSC file doesn't match the type [%s] defined in DEC file." \
677 % (Pa.Platform.Pcds[Pcd].Type, Pcd[1], Pcd[0], Type),
678 ExtraData=None
679 )
680 return
681 else:
682 UnusedPcd.setdefault(Pcd, []).append(Pa.Arch)
683
684 for Pcd in UnusedPcd:
685 EdkLogger.warn(
686 'build',
687 "The PCD was not specified by any INF module in the platform for the given architecture.\n"
688 "\tPCD: [%s.%s]\n\tPlatform: [%s]\n\tArch: %s"
689 % (Pcd[1], Pcd[0], os.path.basename(str(self.MetaFile)), str(UnusedPcd[Pcd])),
690 ExtraData=None
691 )
692
693 def __repr__(self):
694 return "%s [%s]" % (self.MetaFile, ", ".join(self.ArchList))
695
696 ## Return the directory to store FV files
697 @cached_property
698 def FvDir(self):
699 return path.join(self.BuildDir, TAB_FV_DIRECTORY)
700
701 ## Return the directory to store all intermediate and final files built
702 @cached_property
703 def BuildDir(self):
704 return self.AutoGenObjectList[0].BuildDir
705
706 ## Return the build output directory platform specifies
707 @cached_property
708 def OutputDir(self):
709 return self.Platform.OutputDirectory
710
711 ## Return platform name
712 @cached_property
713 def Name(self):
714 return self.Platform.PlatformName
715
716 ## Return meta-file GUID
717 @cached_property
718 def Guid(self):
719 return self.Platform.Guid
720
721 ## Return platform version
722 @cached_property
723 def Version(self):
724 return self.Platform.Version
725
726 ## Return paths of tools
727 @cached_property
728 def ToolDefinition(self):
729 return self.AutoGenObjectList[0].ToolDefinition
730
731 ## Return directory of platform makefile
732 #
733 # @retval string Makefile directory
734 #
735 @cached_property
736 def MakeFileDir(self):
737 return self.BuildDir
738
739 ## Return build command string
740 #
741 # @retval string Build command string
742 #
743 @cached_property
744 def BuildCommand(self):
745 # BuildCommand should be all the same. So just get one from platform AutoGen
746 return self.AutoGenObjectList[0].BuildCommand
747
748 ## Check the PCDs token value conflict in each DEC file.
749 #
750 # Will cause build break and raise error message while two PCDs conflict.
751 #
752 # @return None
753 #
754 def _CheckAllPcdsTokenValueConflict(self):
755 for Pa in self.AutoGenObjectList:
756 for Package in Pa.PackageList:
757 PcdList = list(Package.Pcds.values())
758 PcdList.sort(key=lambda x: int(x.TokenValue, 0))
759 Count = 0
760 while (Count < len(PcdList) - 1) :
761 Item = PcdList[Count]
762 ItemNext = PcdList[Count + 1]
763 #
764 # Make sure in the same token space the TokenValue should be unique
765 #
766 if (int(Item.TokenValue, 0) == int(ItemNext.TokenValue, 0)):
767 SameTokenValuePcdList = []
768 SameTokenValuePcdList.append(Item)
769 SameTokenValuePcdList.append(ItemNext)
770 RemainPcdListLength = len(PcdList) - Count - 2
771 for ValueSameCount in range(RemainPcdListLength):
772 if int(PcdList[len(PcdList) - RemainPcdListLength + ValueSameCount].TokenValue, 0) == int(Item.TokenValue, 0):
773 SameTokenValuePcdList.append(PcdList[len(PcdList) - RemainPcdListLength + ValueSameCount])
774 else:
775 break;
776 #
777 # Sort same token value PCD list with TokenGuid and TokenCName
778 #
779 SameTokenValuePcdList.sort(key=lambda x: "%s.%s" % (x.TokenSpaceGuidCName, x.TokenCName))
780 SameTokenValuePcdListCount = 0
781 while (SameTokenValuePcdListCount < len(SameTokenValuePcdList) - 1):
782 Flag = False
783 TemListItem = SameTokenValuePcdList[SameTokenValuePcdListCount]
784 TemListItemNext = SameTokenValuePcdList[SameTokenValuePcdListCount + 1]
785
786 if (TemListItem.TokenSpaceGuidCName == TemListItemNext.TokenSpaceGuidCName) and (TemListItem.TokenCName != TemListItemNext.TokenCName):
787 for PcdItem in GlobalData.MixedPcd:
788 if (TemListItem.TokenCName, TemListItem.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem] or \
789 (TemListItemNext.TokenCName, TemListItemNext.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
790 Flag = True
791 if not Flag:
792 EdkLogger.error(
793 'build',
794 FORMAT_INVALID,
795 "The TokenValue [%s] of PCD [%s.%s] is conflict with: [%s.%s] in %s"\
796 % (TemListItem.TokenValue, TemListItem.TokenSpaceGuidCName, TemListItem.TokenCName, TemListItemNext.TokenSpaceGuidCName, TemListItemNext.TokenCName, Package),
797 ExtraData=None
798 )
799 SameTokenValuePcdListCount += 1
800 Count += SameTokenValuePcdListCount
801 Count += 1
802
803 PcdList = list(Package.Pcds.values())
804 PcdList.sort(key=lambda x: "%s.%s" % (x.TokenSpaceGuidCName, x.TokenCName))
805 Count = 0
806 while (Count < len(PcdList) - 1) :
807 Item = PcdList[Count]
808 ItemNext = PcdList[Count + 1]
809 #
810 # Check PCDs with same TokenSpaceGuidCName.TokenCName have same token value as well.
811 #
812 if (Item.TokenSpaceGuidCName == ItemNext.TokenSpaceGuidCName) and (Item.TokenCName == ItemNext.TokenCName) and (int(Item.TokenValue, 0) != int(ItemNext.TokenValue, 0)):
813 EdkLogger.error(
814 'build',
815 FORMAT_INVALID,
816 "The TokenValue [%s] of PCD [%s.%s] in %s defined in two places should be same as well."\
817 % (Item.TokenValue, Item.TokenSpaceGuidCName, Item.TokenCName, Package),
818 ExtraData=None
819 )
820 Count += 1
821 ## Generate fds command
822 @property
823 def GenFdsCommand(self):
824 return (GenMake.TopLevelMakefile(self)._TEMPLATE_.Replace(GenMake.TopLevelMakefile(self)._TemplateDict)).strip()
825
826 @property
827 def GenFdsCommandDict(self):
828 FdsCommandDict = {}
829 LogLevel = EdkLogger.GetLevel()
830 if LogLevel == EdkLogger.VERBOSE:
831 FdsCommandDict["verbose"] = True
832 elif LogLevel <= EdkLogger.DEBUG_9:
833 FdsCommandDict["debug"] = LogLevel - 1
834 elif LogLevel == EdkLogger.QUIET:
835 FdsCommandDict["quiet"] = True
836
837 FdsCommandDict["GenfdsMultiThread"] = GlobalData.gEnableGenfdsMultiThread
838 if GlobalData.gIgnoreSource:
839 FdsCommandDict["IgnoreSources"] = True
840
841 FdsCommandDict["OptionPcd"] = []
842 for pcd in GlobalData.BuildOptionPcd:
843 if pcd[2]:
844 pcdname = '.'.join(pcd[0:3])
845 else:
846 pcdname = '.'.join(pcd[0:2])
847 if pcd[3].startswith('{'):
848 FdsCommandDict["OptionPcd"].append(pcdname + '=' + 'H' + '"' + pcd[3] + '"')
849 else:
850 FdsCommandDict["OptionPcd"].append(pcdname + '=' + pcd[3])
851
852 MacroList = []
853 # macros passed to GenFds
854 MacroDict = {}
855 MacroDict.update(GlobalData.gGlobalDefines)
856 MacroDict.update(GlobalData.gCommandLineDefines)
857 for MacroName in MacroDict:
858 if MacroDict[MacroName] != "":
859 MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\')))
860 else:
861 MacroList.append('"%s"' % MacroName)
862 FdsCommandDict["macro"] = MacroList
863
864 FdsCommandDict["fdf_file"] = [self.FdfFile]
865 FdsCommandDict["build_target"] = self.BuildTarget
866 FdsCommandDict["toolchain_tag"] = self.ToolChain
867 FdsCommandDict["active_platform"] = str(self)
868
869 FdsCommandDict["conf_directory"] = GlobalData.gConfDirectory
870 FdsCommandDict["build_architecture_list"] = ','.join(self.ArchList)
871 FdsCommandDict["platform_build_directory"] = self.BuildDir
872
873 FdsCommandDict["fd"] = self.FdTargetList
874 FdsCommandDict["fv"] = self.FvTargetList
875 FdsCommandDict["cap"] = self.CapTargetList
876 return FdsCommandDict
877
878 ## Create makefile for the platform and modules in it
879 #
880 # @param CreateDepsMakeFile Flag indicating if the makefile for
881 # modules will be created as well
882 #
883 def CreateMakeFile(self, CreateDepsMakeFile=False):
884 if not CreateDepsMakeFile:
885 return
886 for Pa in self.AutoGenObjectList:
887 Pa.CreateMakeFile(CreateDepsMakeFile)
888
889 ## Create autogen code for platform and modules
890 #
891 # Since there's no autogen code for platform, this method will do nothing
892 # if CreateModuleCodeFile is set to False.
893 #
894 # @param CreateDepsCodeFile Flag indicating if creating module's
895 # autogen code file or not
896 #
897 def CreateCodeFile(self, CreateDepsCodeFile=False):
898 if not CreateDepsCodeFile:
899 return
900 for Pa in self.AutoGenObjectList:
901 Pa.CreateCodeFile(CreateDepsCodeFile)
902
903 ## Create AsBuilt INF file the platform
904 #
905 def CreateAsBuiltInf(self):
906 return
907