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