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