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