]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/Workspace/DecBuildData.py
BaseTools: Improve build performance of structure PCD value generation
[mirror_edk2.git] / BaseTools / Source / Python / Workspace / DecBuildData.py
CommitLineData
ae7b6df8
LG
1## @file\r
2# This file is used to create a database used by build tool\r
3#\r
e0db09cd 4# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>\r
ae7b6df8
LG
5# (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
6# This program and the accompanying materials\r
7# are licensed and made available under the terms and conditions of the BSD License\r
8# which accompanies this distribution. The full text of the license may be found at\r
9# http://opensource.org/licenses/bsd-license.php\r
10#\r
11# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13#\r
14from Common.String import *\r
15from Common.DataType import *\r
16from Common.Misc import *\r
17from types import *\r
18\r
19from Workspace.BuildClassObject import PackageBuildClassObject, StructurePcd, PcdClassObject\r
20\r
21## Platform build information from DEC file\r
22#\r
23# This class is used to retrieve information stored in database and convert them\r
24# into PackageBuildClassObject form for easier use for AutoGen.\r
25#\r
26class DecBuildData(PackageBuildClassObject):\r
27 # dict used to convert PCD type in database to string used by build tool\r
28 _PCD_TYPE_STRING_ = {\r
29 MODEL_PCD_FIXED_AT_BUILD : "FixedAtBuild",\r
30 MODEL_PCD_PATCHABLE_IN_MODULE : "PatchableInModule",\r
31 MODEL_PCD_FEATURE_FLAG : "FeatureFlag",\r
32 MODEL_PCD_DYNAMIC : "Dynamic",\r
33 MODEL_PCD_DYNAMIC_DEFAULT : "Dynamic",\r
34 MODEL_PCD_DYNAMIC_HII : "DynamicHii",\r
35 MODEL_PCD_DYNAMIC_VPD : "DynamicVpd",\r
36 MODEL_PCD_DYNAMIC_EX : "DynamicEx",\r
37 MODEL_PCD_DYNAMIC_EX_DEFAULT : "DynamicEx",\r
38 MODEL_PCD_DYNAMIC_EX_HII : "DynamicExHii",\r
39 MODEL_PCD_DYNAMIC_EX_VPD : "DynamicExVpd",\r
40 }\r
41\r
42 # dict used to convert part of [Defines] to members of DecBuildData directly\r
43 _PROPERTY_ = {\r
44 #\r
45 # Required Fields\r
46 #\r
47 TAB_DEC_DEFINES_PACKAGE_NAME : "_PackageName",\r
48 TAB_DEC_DEFINES_PACKAGE_GUID : "_Guid",\r
49 TAB_DEC_DEFINES_PACKAGE_VERSION : "_Version",\r
50 TAB_DEC_DEFINES_PKG_UNI_FILE : "_PkgUniFile",\r
51 }\r
52\r
53\r
54 ## Constructor of DecBuildData\r
55 #\r
56 # Initialize object of DecBuildData\r
57 #\r
58 # @param FilePath The path of package description file\r
59 # @param RawData The raw data of DEC file\r
60 # @param BuildDataBase Database used to retrieve module information\r
61 # @param Arch The target architecture\r
62 # @param Platform (not used for DecBuildData)\r
63 # @param Macros Macros used for replacement in DSC file\r
64 #\r
65 def __init__(self, File, RawData, BuildDataBase, Arch='COMMON', Target=None, Toolchain=None):\r
66 self.MetaFile = File\r
67 self._PackageDir = File.Dir\r
68 self._RawData = RawData\r
69 self._Bdb = BuildDataBase\r
70 self._Arch = Arch\r
71 self._Target = Target\r
72 self._Toolchain = Toolchain\r
73 self._Clear()\r
74\r
75 ## XXX[key] = value\r
76 def __setitem__(self, key, value):\r
77 self.__dict__[self._PROPERTY_[key]] = value\r
78\r
79 ## value = XXX[key]\r
80 def __getitem__(self, key):\r
81 return self.__dict__[self._PROPERTY_[key]]\r
82\r
83 ## "in" test support\r
84 def __contains__(self, key):\r
85 return key in self._PROPERTY_\r
86\r
87 ## Set all internal used members of DecBuildData to None\r
88 def _Clear(self):\r
89 self._Header = None\r
90 self._PackageName = None\r
91 self._Guid = None\r
92 self._Version = None\r
93 self._PkgUniFile = None\r
94 self._Protocols = None\r
95 self._Ppis = None\r
96 self._Guids = None\r
97 self._Includes = None\r
0a57a978 98 self._CommonIncludes = None\r
ae7b6df8
LG
99 self._LibraryClasses = None\r
100 self._Pcds = None\r
101 self.__Macros = None\r
102 self._PrivateProtocols = None\r
103 self._PrivatePpis = None\r
104 self._PrivateGuids = None\r
105 self._PrivateIncludes = None\r
106\r
107 ## Get current effective macros\r
108 def _GetMacros(self):\r
109 if self.__Macros == None:\r
110 self.__Macros = {}\r
111 self.__Macros.update(GlobalData.gGlobalDefines)\r
112 return self.__Macros\r
113\r
114 ## Get architecture\r
115 def _GetArch(self):\r
116 return self._Arch\r
117\r
118 ## Set architecture\r
119 #\r
120 # Changing the default ARCH to another may affect all other information\r
121 # because all information in a platform may be ARCH-related. That's\r
122 # why we need to clear all internal used members, in order to cause all\r
123 # information to be re-retrieved.\r
124 #\r
125 # @param Value The value of ARCH\r
126 #\r
127 def _SetArch(self, Value):\r
128 if self._Arch == Value:\r
129 return\r
130 self._Arch = Value\r
131 self._Clear()\r
132\r
133 ## Retrieve all information in [Defines] section\r
134 #\r
135 # (Retriving all [Defines] information in one-shot is just to save time.)\r
136 #\r
137 def _GetHeaderInfo(self):\r
138 RecordList = self._RawData[MODEL_META_DATA_HEADER, self._Arch]\r
139 for Record in RecordList:\r
140 Name = Record[1]\r
141 if Name in self:\r
142 self[Name] = Record[2]\r
143 self._Header = 'DUMMY'\r
144\r
145 ## Retrieve package name\r
146 def _GetPackageName(self):\r
147 if self._PackageName == None:\r
148 if self._Header == None:\r
149 self._GetHeaderInfo()\r
150 if self._PackageName == None:\r
151 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "No PACKAGE_NAME", File=self.MetaFile)\r
152 return self._PackageName\r
153\r
154 ## Retrieve file guid\r
155 def _GetFileGuid(self):\r
156 if self._Guid == None:\r
157 if self._Header == None:\r
158 self._GetHeaderInfo()\r
159 if self._Guid == None:\r
160 EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "No PACKAGE_GUID", File=self.MetaFile)\r
161 return self._Guid\r
162\r
163 ## Retrieve package version\r
164 def _GetVersion(self):\r
165 if self._Version == None:\r
166 if self._Header == None:\r
167 self._GetHeaderInfo()\r
168 if self._Version == None:\r
169 self._Version = ''\r
170 return self._Version\r
171\r
172 ## Retrieve protocol definitions (name/value pairs)\r
173 def _GetProtocol(self):\r
174 if self._Protocols == None:\r
175 #\r
176 # tdict is a special kind of dict, used for selecting correct\r
177 # protocol defition for given ARCH\r
178 #\r
179 ProtocolDict = tdict(True)\r
180 PrivateProtocolDict = tdict(True)\r
181 NameList = []\r
182 PrivateNameList = []\r
183 PublicNameList = []\r
184 # find out all protocol definitions for specific and 'common' arch\r
185 RecordList = self._RawData[MODEL_EFI_PROTOCOL, self._Arch]\r
186 for Name, Guid, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList:\r
187 if PrivateFlag == 'PRIVATE':\r
188 if Name not in PrivateNameList:\r
189 PrivateNameList.append(Name)\r
190 PrivateProtocolDict[Arch, Name] = Guid\r
191 if Name in PublicNameList:\r
192 EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo)\r
193 else:\r
194 if Name not in PublicNameList:\r
195 PublicNameList.append(Name)\r
196 if Name in PrivateNameList:\r
197 EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo)\r
198 if Name not in NameList:\r
199 NameList.append(Name)\r
200 ProtocolDict[Arch, Name] = Guid\r
201 # use sdict to keep the order\r
202 self._Protocols = sdict()\r
203 self._PrivateProtocols = sdict()\r
204 for Name in NameList:\r
205 #\r
206 # limit the ARCH to self._Arch, if no self._Arch found, tdict\r
207 # will automatically turn to 'common' ARCH for trying\r
208 #\r
209 self._Protocols[Name] = ProtocolDict[self._Arch, Name]\r
210 for Name in PrivateNameList:\r
211 self._PrivateProtocols[Name] = PrivateProtocolDict[self._Arch, Name]\r
212 return self._Protocols\r
213\r
214 ## Retrieve PPI definitions (name/value pairs)\r
215 def _GetPpi(self):\r
216 if self._Ppis == None:\r
217 #\r
218 # tdict is a special kind of dict, used for selecting correct\r
219 # PPI defition for given ARCH\r
220 #\r
221 PpiDict = tdict(True)\r
222 PrivatePpiDict = tdict(True)\r
223 NameList = []\r
224 PrivateNameList = []\r
225 PublicNameList = []\r
226 # find out all PPI definitions for specific arch and 'common' arch\r
227 RecordList = self._RawData[MODEL_EFI_PPI, self._Arch]\r
228 for Name, Guid, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList:\r
229 if PrivateFlag == 'PRIVATE':\r
230 if Name not in PrivateNameList:\r
231 PrivateNameList.append(Name)\r
232 PrivatePpiDict[Arch, Name] = Guid\r
233 if Name in PublicNameList:\r
234 EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo)\r
235 else:\r
236 if Name not in PublicNameList:\r
237 PublicNameList.append(Name)\r
238 if Name in PrivateNameList:\r
239 EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo)\r
240 if Name not in NameList:\r
241 NameList.append(Name)\r
242 PpiDict[Arch, Name] = Guid\r
243 # use sdict to keep the order\r
244 self._Ppis = sdict()\r
245 self._PrivatePpis = sdict()\r
246 for Name in NameList:\r
247 #\r
248 # limit the ARCH to self._Arch, if no self._Arch found, tdict\r
249 # will automatically turn to 'common' ARCH for trying\r
250 #\r
251 self._Ppis[Name] = PpiDict[self._Arch, Name]\r
252 for Name in PrivateNameList:\r
253 self._PrivatePpis[Name] = PrivatePpiDict[self._Arch, Name]\r
254 return self._Ppis\r
255\r
256 ## Retrieve GUID definitions (name/value pairs)\r
257 def _GetGuid(self):\r
258 if self._Guids == None:\r
259 #\r
260 # tdict is a special kind of dict, used for selecting correct\r
261 # GUID defition for given ARCH\r
262 #\r
263 GuidDict = tdict(True)\r
264 PrivateGuidDict = tdict(True)\r
265 NameList = []\r
266 PrivateNameList = []\r
267 PublicNameList = []\r
268 # find out all protocol definitions for specific and 'common' arch\r
269 RecordList = self._RawData[MODEL_EFI_GUID, self._Arch]\r
270 for Name, Guid, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList:\r
271 if PrivateFlag == 'PRIVATE':\r
272 if Name not in PrivateNameList:\r
273 PrivateNameList.append(Name)\r
274 PrivateGuidDict[Arch, Name] = Guid\r
275 if Name in PublicNameList:\r
276 EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo)\r
277 else:\r
278 if Name not in PublicNameList:\r
279 PublicNameList.append(Name)\r
280 if Name in PrivateNameList:\r
281 EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo)\r
282 if Name not in NameList:\r
283 NameList.append(Name)\r
284 GuidDict[Arch, Name] = Guid\r
285 # use sdict to keep the order\r
286 self._Guids = sdict()\r
287 self._PrivateGuids = sdict()\r
288 for Name in NameList:\r
289 #\r
290 # limit the ARCH to self._Arch, if no self._Arch found, tdict\r
291 # will automatically turn to 'common' ARCH for trying\r
292 #\r
293 self._Guids[Name] = GuidDict[self._Arch, Name]\r
294 for Name in PrivateNameList:\r
295 self._PrivateGuids[Name] = PrivateGuidDict[self._Arch, Name]\r
296 return self._Guids\r
297\r
298 ## Retrieve public include paths declared in this package\r
299 def _GetInclude(self):\r
0a57a978
FB
300 if self._Includes == None or self._CommonIncludes is None:\r
301 self._CommonIncludes = []\r
ae7b6df8
LG
302 self._Includes = []\r
303 self._PrivateIncludes = []\r
304 PublicInclues = []\r
305 RecordList = self._RawData[MODEL_EFI_INCLUDE, self._Arch]\r
306 Macros = self._Macros\r
307 Macros["EDK_SOURCE"] = GlobalData.gEcpSource\r
308 for Record in RecordList:\r
309 File = PathClass(NormPath(Record[0], Macros), self._PackageDir, Arch=self._Arch)\r
310 LineNo = Record[-1]\r
311 # validate the path\r
312 ErrorCode, ErrorInfo = File.Validate()\r
313 if ErrorCode != 0:\r
314 EdkLogger.error('build', ErrorCode, ExtraData=ErrorInfo, File=self.MetaFile, Line=LineNo)\r
315\r
316 # avoid duplicate include path\r
317 if File not in self._Includes:\r
318 self._Includes.append(File)\r
319 if Record[4] == 'PRIVATE':\r
320 if File not in self._PrivateIncludes:\r
321 self._PrivateIncludes.append(File)\r
322 if File in PublicInclues:\r
323 EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % File, File=self.MetaFile, Line=LineNo)\r
324 else:\r
325 if File not in PublicInclues:\r
326 PublicInclues.append(File)\r
327 if File in self._PrivateIncludes:\r
328 EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % File, File=self.MetaFile, Line=LineNo)\r
0a57a978
FB
329 if Record[3] == "COMMON":\r
330 self._CommonIncludes.append(File)\r
ae7b6df8
LG
331 return self._Includes\r
332\r
333 ## Retrieve library class declarations (not used in build at present)\r
334 def _GetLibraryClass(self):\r
335 if self._LibraryClasses == None:\r
336 #\r
337 # tdict is a special kind of dict, used for selecting correct\r
338 # library class declaration for given ARCH\r
339 #\r
340 LibraryClassDict = tdict(True)\r
341 LibraryClassSet = set()\r
342 RecordList = self._RawData[MODEL_EFI_LIBRARY_CLASS, self._Arch]\r
343 Macros = self._Macros\r
344 for LibraryClass, File, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList:\r
345 File = PathClass(NormPath(File, Macros), self._PackageDir, Arch=self._Arch)\r
346 # check the file validation\r
347 ErrorCode, ErrorInfo = File.Validate()\r
348 if ErrorCode != 0:\r
349 EdkLogger.error('build', ErrorCode, ExtraData=ErrorInfo, File=self.MetaFile, Line=LineNo)\r
350 LibraryClassSet.add(LibraryClass)\r
351 LibraryClassDict[Arch, LibraryClass] = File\r
352 self._LibraryClasses = sdict()\r
353 for LibraryClass in LibraryClassSet:\r
354 self._LibraryClasses[LibraryClass] = LibraryClassDict[self._Arch, LibraryClass]\r
355 return self._LibraryClasses\r
356\r
357 ## Retrieve PCD declarations\r
358 def _GetPcds(self):\r
359 if self._Pcds == None:\r
360 self._Pcds = sdict()\r
361 self._Pcds.update(self._GetPcd(MODEL_PCD_FIXED_AT_BUILD))\r
362 self._Pcds.update(self._GetPcd(MODEL_PCD_PATCHABLE_IN_MODULE))\r
363 self._Pcds.update(self._GetPcd(MODEL_PCD_FEATURE_FLAG))\r
364 self._Pcds.update(self._GetPcd(MODEL_PCD_DYNAMIC))\r
365 self._Pcds.update(self._GetPcd(MODEL_PCD_DYNAMIC_EX))\r
366 return self._Pcds\r
367\r
368\r
369 def ProcessStructurePcd(self, StructurePcdRawDataSet):\r
370 s_pcd_set = dict()\r
371 for s_pcd,LineNo in StructurePcdRawDataSet:\r
372 if s_pcd.TokenSpaceGuidCName not in s_pcd_set:\r
373 s_pcd_set[s_pcd.TokenSpaceGuidCName] = []\r
374 s_pcd_set[s_pcd.TokenSpaceGuidCName].append((s_pcd,LineNo))\r
375\r
376 str_pcd_set = []\r
377 for pcdname in s_pcd_set:\r
378 dep_pkgs = []\r
379 struct_pcd = StructurePcd()\r
380 for item,LineNo in s_pcd_set[pcdname]:\r
381 if "<HeaderFiles>" in item.TokenCName:\r
81add864 382 struct_pcd.StructuredPcdIncludeFile.append(item.DefaultValue)\r
ae7b6df8
LG
383 elif "<Packages>" in item.TokenCName:\r
384 dep_pkgs.append(item.DefaultValue)\r
385 elif item.DatumType == item.TokenCName:\r
386 struct_pcd.copy(item)\r
387 struct_pcd.TokenValue = struct_pcd.TokenValue.strip("{").strip()\r
388 struct_pcd.TokenSpaceGuidCName, struct_pcd.TokenCName = pcdname.split(".")\r
6a103440
FB
389 struct_pcd.PcdDefineLineNo = LineNo\r
390 struct_pcd.PkgPath = self.MetaFile.File\r
06140766 391 struct_pcd.SetDecDefaultValue(item.DefaultValue)\r
ae7b6df8
LG
392 else:\r
393 struct_pcd.AddDefaultValue(item.TokenCName, item.DefaultValue,self.MetaFile.File,LineNo)\r
394\r
395 struct_pcd.PackageDecs = dep_pkgs\r
8aa4db4b
FB
396 if not struct_pcd.StructuredPcdIncludeFile:\r
397 EdkLogger.error("build", PCD_STRUCTURE_PCD_ERROR, "The structure Pcd %s.%s header file is not found in %s line %s \n" % (struct_pcd.TokenSpaceGuidCName, struct_pcd.TokenCName,self.MetaFile.File,LineNo ))\r
ae7b6df8
LG
398\r
399 str_pcd_set.append(struct_pcd)\r
400\r
401 return str_pcd_set\r
402\r
403 ## Retrieve PCD declarations for given type\r
404 def _GetPcd(self, Type):\r
405 Pcds = sdict()\r
406 #\r
407 # tdict is a special kind of dict, used for selecting correct\r
408 # PCD declaration for given ARCH\r
409 #\r
410 PcdDict = tdict(True, 3)\r
411 # for summarizing PCD\r
e651d06c 412 PcdSet = []\r
ae7b6df8
LG
413 # find out all PCDs of the 'type'\r
414\r
415 StrPcdSet = []\r
416 RecordList = self._RawData[Type, self._Arch]\r
417 for TokenSpaceGuid, PcdCName, Setting, Arch, PrivateFlag, Dummy1, Dummy2 in RecordList:\r
418 PcdDict[Arch, PcdCName, TokenSpaceGuid] = (Setting,Dummy2)\r
e651d06c
LG
419 if not (PcdCName, TokenSpaceGuid) in PcdSet:\r
420 PcdSet.append((PcdCName, TokenSpaceGuid))\r
ae7b6df8
LG
421\r
422 for PcdCName, TokenSpaceGuid in PcdSet:\r
423 #\r
424 # limit the ARCH to self._Arch, if no self._Arch found, tdict\r
425 # will automatically turn to 'common' ARCH and try again\r
426 #\r
427 Setting,LineNo = PcdDict[self._Arch, PcdCName, TokenSpaceGuid]\r
428 if Setting == None:\r
429 continue\r
430\r
431 DefaultValue, DatumType, TokenNumber = AnalyzePcdData(Setting)\r
432 validateranges, validlists, expressions = self._RawData.GetValidExpression(TokenSpaceGuid, PcdCName)\r
433 PcdObj = PcdClassObject(\r
434 PcdCName,\r
435 TokenSpaceGuid,\r
436 self._PCD_TYPE_STRING_[Type],\r
437 DatumType,\r
438 DefaultValue,\r
439 TokenNumber,\r
440 '',\r
441 {},\r
442 False,\r
443 None,\r
444 list(validateranges),\r
445 list(validlists),\r
446 list(expressions)\r
447 )\r
448 if "." in TokenSpaceGuid:\r
449 StrPcdSet.append((PcdObj,LineNo))\r
450 else:\r
451 Pcds[PcdCName, TokenSpaceGuid, self._PCD_TYPE_STRING_[Type]] = PcdObj\r
452\r
453 StructurePcds = self.ProcessStructurePcd(StrPcdSet)\r
454 for pcd in StructurePcds:\r
455 Pcds[pcd.TokenCName, pcd.TokenSpaceGuidCName, self._PCD_TYPE_STRING_[Type]] = pcd\r
456\r
457 return Pcds\r
0a57a978
FB
458 @property\r
459 def CommonIncludes(self):\r
460 if self._CommonIncludes is None:\r
461 self.Includes\r
462 return self._CommonIncludes\r
ae7b6df8
LG
463\r
464\r
465 _Macros = property(_GetMacros)\r
466 Arch = property(_GetArch, _SetArch)\r
467 PackageName = property(_GetPackageName)\r
468 Guid = property(_GetFileGuid)\r
469 Version = property(_GetVersion)\r
470\r
471 Protocols = property(_GetProtocol)\r
472 Ppis = property(_GetPpi)\r
473 Guids = property(_GetGuid)\r
474 Includes = property(_GetInclude)\r
475 LibraryClasses = property(_GetLibraryClass)\r
476 Pcds = property(_GetPcds)\r