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