2 # This file is used to create a database used by build tool
4 # Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
5 # (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
6 # This program and the accompanying materials
7 # are licensed and made available under the terms and conditions of the BSD License
8 # which accompanies this distribution. The full text of the license may be found at
9 # http://opensource.org/licenses/bsd-license.php
11 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 from Common
.StringUtils
import *
15 from Common
.DataType
import *
16 from Common
.Misc
import *
18 from collections
import OrderedDict
19 from CommonDataClass
.DataClass
import *
20 from Workspace
.BuildClassObject
import PackageBuildClassObject
, StructurePcd
, PcdClassObject
21 from Common
.GlobalData
import gGlobalDefines
22 from re
import compile
24 ## Platform build information from DEC file
26 # This class is used to retrieve information stored in database and convert them
27 # into PackageBuildClassObject form for easier use for AutoGen.
29 class DecBuildData(PackageBuildClassObject
):
30 # dict used to convert PCD type in database to string used by build tool
32 MODEL_PCD_FIXED_AT_BUILD
: TAB_PCDS_FIXED_AT_BUILD
,
33 MODEL_PCD_PATCHABLE_IN_MODULE
: TAB_PCDS_PATCHABLE_IN_MODULE
,
34 MODEL_PCD_FEATURE_FLAG
: TAB_PCDS_FEATURE_FLAG
,
35 MODEL_PCD_DYNAMIC
: TAB_PCDS_DYNAMIC
,
36 MODEL_PCD_DYNAMIC_DEFAULT
: TAB_PCDS_DYNAMIC
,
37 MODEL_PCD_DYNAMIC_HII
: TAB_PCDS_DYNAMIC_HII
,
38 MODEL_PCD_DYNAMIC_VPD
: TAB_PCDS_DYNAMIC_VPD
,
39 MODEL_PCD_DYNAMIC_EX
: TAB_PCDS_DYNAMIC_EX
,
40 MODEL_PCD_DYNAMIC_EX_DEFAULT
: TAB_PCDS_DYNAMIC_EX
,
41 MODEL_PCD_DYNAMIC_EX_HII
: TAB_PCDS_DYNAMIC_EX_HII
,
42 MODEL_PCD_DYNAMIC_EX_VPD
: TAB_PCDS_DYNAMIC_EX_VPD
,
45 # dict used to convert part of [Defines] to members of DecBuildData directly
50 TAB_DEC_DEFINES_PACKAGE_NAME
: "_PackageName",
51 TAB_DEC_DEFINES_PACKAGE_GUID
: "_Guid",
52 TAB_DEC_DEFINES_PACKAGE_VERSION
: "_Version",
53 TAB_DEC_DEFINES_PKG_UNI_FILE
: "_PkgUniFile",
57 ## Constructor of DecBuildData
59 # Initialize object of DecBuildData
61 # @param FilePath The path of package description file
62 # @param RawData The raw data of DEC file
63 # @param BuildDataBase Database used to retrieve module information
64 # @param Arch The target architecture
65 # @param Platform (not used for DecBuildData)
66 # @param Macros Macros used for replacement in DSC file
68 def __init__(self
, File
, RawData
, BuildDataBase
, Arch
=TAB_ARCH_COMMON
, Target
=None, Toolchain
=None):
70 self
._PackageDir
= File
.Dir
71 self
._RawData
= RawData
72 self
._Bdb
= BuildDataBase
75 self
._Toolchain
= Toolchain
79 def __setitem__(self
, key
, value
):
80 self
.__dict
__[self
._PROPERTY
_[key
]] = value
83 def __getitem__(self
, key
):
84 return self
.__dict
__[self
._PROPERTY
_[key
]]
87 def __contains__(self
, key
):
88 return key
in self
._PROPERTY
_
90 ## Set all internal used members of DecBuildData to None
93 self
._PackageName
= None
96 self
._PkgUniFile
= None
97 self
._Protocols
= None
100 self
._Includes
= None
101 self
._CommonIncludes
= None
102 self
._LibraryClasses
= None
104 self
._MacroDict
= None
105 self
._PrivateProtocols
= None
106 self
._PrivatePpis
= None
107 self
._PrivateGuids
= None
108 self
._PrivateIncludes
= None
110 ## Get current effective macros
113 if self
._MacroDict
is None:
114 self
._MacroDict
= dict(gGlobalDefines
)
115 return self
._MacroDict
122 ## Retrieve all information in [Defines] section
124 # (Retrieving all [Defines] information in one-shot is just to save time.)
126 def _GetHeaderInfo(self
):
127 RecordList
= self
._RawData
[MODEL_META_DATA_HEADER
, self
._Arch
]
128 for Record
in RecordList
:
131 self
[Name
] = Record
[2]
132 self
._Header
= 'DUMMY'
134 ## Retrieve package name
136 def PackageName(self
):
137 if self
._PackageName
is None:
138 if self
._Header
is None:
139 self
._GetHeaderInfo
()
140 if self
._PackageName
is None:
141 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "No PACKAGE_NAME", File
=self
.MetaFile
)
142 return self
._PackageName
144 ## Retrieve file guid
146 def PackageName(self
):
147 if self
._Guid
is None:
148 if self
._Header
is None:
149 self
._GetHeaderInfo
()
150 if self
._Guid
is None:
151 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "No PACKAGE_GUID", File
=self
.MetaFile
)
154 ## Retrieve package version
157 if self
._Version
is None:
158 if self
._Header
is None:
159 self
._GetHeaderInfo
()
160 if self
._Version
is None:
164 ## Retrieve protocol definitions (name/value pairs)
167 if self
._Protocols
is None:
169 # tdict is a special kind of dict, used for selecting correct
170 # protocol definition for given ARCH
172 ProtocolDict
= tdict(True)
173 PrivateProtocolDict
= tdict(True)
177 # find out all protocol definitions for specific and 'common' arch
178 RecordList
= self
._RawData
[MODEL_EFI_PROTOCOL
, self
._Arch
]
179 for Name
, Guid
, Dummy
, Arch
, PrivateFlag
, ID
, LineNo
in RecordList
:
180 if PrivateFlag
== 'PRIVATE':
181 if Name
not in PrivateNameList
:
182 PrivateNameList
.append(Name
)
183 PrivateProtocolDict
[Arch
, Name
] = Guid
184 if Name
in PublicNameList
:
185 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
)
187 if Name
not in PublicNameList
:
188 PublicNameList
.append(Name
)
189 if Name
in PrivateNameList
:
190 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
)
191 if Name
not in NameList
:
192 NameList
.append(Name
)
193 ProtocolDict
[Arch
, Name
] = Guid
194 # use OrderedDict to keep the order
195 self
._Protocols
= OrderedDict()
196 self
._PrivateProtocols
= OrderedDict()
197 for Name
in NameList
:
199 # limit the ARCH to self._Arch, if no self._Arch found, tdict
200 # will automatically turn to 'common' ARCH for trying
202 self
._Protocols
[Name
] = ProtocolDict
[self
._Arch
, Name
]
203 for Name
in PrivateNameList
:
204 self
._PrivateProtocols
[Name
] = PrivateProtocolDict
[self
._Arch
, Name
]
205 return self
._Protocols
207 ## Retrieve PPI definitions (name/value pairs)
210 if self
._Ppis
is None:
212 # tdict is a special kind of dict, used for selecting correct
213 # PPI definition for given ARCH
215 PpiDict
= tdict(True)
216 PrivatePpiDict
= tdict(True)
220 # find out all PPI definitions for specific arch and 'common' arch
221 RecordList
= self
._RawData
[MODEL_EFI_PPI
, self
._Arch
]
222 for Name
, Guid
, Dummy
, Arch
, PrivateFlag
, ID
, LineNo
in RecordList
:
223 if PrivateFlag
== 'PRIVATE':
224 if Name
not in PrivateNameList
:
225 PrivateNameList
.append(Name
)
226 PrivatePpiDict
[Arch
, Name
] = Guid
227 if Name
in PublicNameList
:
228 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
)
230 if Name
not in PublicNameList
:
231 PublicNameList
.append(Name
)
232 if Name
in PrivateNameList
:
233 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
)
234 if Name
not in NameList
:
235 NameList
.append(Name
)
236 PpiDict
[Arch
, Name
] = Guid
237 # use OrderedDict to keep the order
238 self
._Ppis
= OrderedDict()
239 self
._PrivatePpis
= OrderedDict()
240 for Name
in NameList
:
242 # limit the ARCH to self._Arch, if no self._Arch found, tdict
243 # will automatically turn to 'common' ARCH for trying
245 self
._Ppis
[Name
] = PpiDict
[self
._Arch
, Name
]
246 for Name
in PrivateNameList
:
247 self
._PrivatePpis
[Name
] = PrivatePpiDict
[self
._Arch
, Name
]
250 ## Retrieve GUID definitions (name/value pairs)
253 if self
._Guids
is None:
255 # tdict is a special kind of dict, used for selecting correct
256 # GUID definition for given ARCH
258 GuidDict
= tdict(True)
259 PrivateGuidDict
= tdict(True)
263 # find out all protocol definitions for specific and 'common' arch
264 RecordList
= self
._RawData
[MODEL_EFI_GUID
, self
._Arch
]
265 for Name
, Guid
, Dummy
, Arch
, PrivateFlag
, ID
, LineNo
in RecordList
:
266 if PrivateFlag
== 'PRIVATE':
267 if Name
not in PrivateNameList
:
268 PrivateNameList
.append(Name
)
269 PrivateGuidDict
[Arch
, Name
] = Guid
270 if Name
in PublicNameList
:
271 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
)
273 if Name
not in PublicNameList
:
274 PublicNameList
.append(Name
)
275 if Name
in PrivateNameList
:
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
)
277 if Name
not in NameList
:
278 NameList
.append(Name
)
279 GuidDict
[Arch
, Name
] = Guid
280 # use OrderedDict to keep the order
281 self
._Guids
= OrderedDict()
282 self
._PrivateGuids
= OrderedDict()
283 for Name
in NameList
:
285 # limit the ARCH to self._Arch, if no self._Arch found, tdict
286 # will automatically turn to 'common' ARCH for trying
288 self
._Guids
[Name
] = GuidDict
[self
._Arch
, Name
]
289 for Name
in PrivateNameList
:
290 self
._PrivateGuids
[Name
] = PrivateGuidDict
[self
._Arch
, Name
]
293 ## Retrieve public include paths declared in this package
296 if self
._Includes
is None or self
._CommonIncludes
is None:
297 self
._CommonIncludes
= []
299 self
._PrivateIncludes
= []
301 RecordList
= self
._RawData
[MODEL_EFI_INCLUDE
, self
._Arch
]
302 Macros
= self
._Macros
303 for Record
in RecordList
:
304 File
= PathClass(NormPath(Record
[0], Macros
), self
._PackageDir
, Arch
=self
._Arch
)
307 ErrorCode
, ErrorInfo
= File
.Validate()
309 EdkLogger
.error('build', ErrorCode
, ExtraData
=ErrorInfo
, File
=self
.MetaFile
, Line
=LineNo
)
311 # avoid duplicate include path
312 if File
not in self
._Includes
:
313 self
._Includes
.append(File
)
314 if Record
[4] == 'PRIVATE':
315 if File
not in self
._PrivateIncludes
:
316 self
._PrivateIncludes
.append(File
)
317 if File
in PublicInclues
:
318 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
)
320 if File
not in PublicInclues
:
321 PublicInclues
.append(File
)
322 if File
in self
._PrivateIncludes
:
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
)
324 if Record
[3] == TAB_COMMON
:
325 self
._CommonIncludes
.append(File
)
326 return self
._Includes
328 ## Retrieve library class declarations (not used in build at present)
330 def LibraryClasses(self
):
331 if self
._LibraryClasses
is None:
333 # tdict is a special kind of dict, used for selecting correct
334 # library class declaration for given ARCH
336 LibraryClassDict
= tdict(True)
337 LibraryClassSet
= set()
338 RecordList
= self
._RawData
[MODEL_EFI_LIBRARY_CLASS
, self
._Arch
]
339 Macros
= self
._Macros
340 for LibraryClass
, File
, Dummy
, Arch
, PrivateFlag
, ID
, LineNo
in RecordList
:
341 File
= PathClass(NormPath(File
, Macros
), self
._PackageDir
, Arch
=self
._Arch
)
342 # check the file validation
343 ErrorCode
, ErrorInfo
= File
.Validate()
345 EdkLogger
.error('build', ErrorCode
, ExtraData
=ErrorInfo
, File
=self
.MetaFile
, Line
=LineNo
)
346 LibraryClassSet
.add(LibraryClass
)
347 LibraryClassDict
[Arch
, LibraryClass
] = File
348 self
._LibraryClasses
= OrderedDict()
349 for LibraryClass
in LibraryClassSet
:
350 self
._LibraryClasses
[LibraryClass
] = LibraryClassDict
[self
._Arch
, LibraryClass
]
351 return self
._LibraryClasses
353 ## Retrieve PCD declarations
356 if self
._Pcds
is None:
357 self
._Pcds
= OrderedDict()
358 self
._Pcds
.update(self
._GetPcd
(MODEL_PCD_FIXED_AT_BUILD
))
359 self
._Pcds
.update(self
._GetPcd
(MODEL_PCD_PATCHABLE_IN_MODULE
))
360 self
._Pcds
.update(self
._GetPcd
(MODEL_PCD_FEATURE_FLAG
))
361 self
._Pcds
.update(self
._GetPcd
(MODEL_PCD_DYNAMIC
))
362 self
._Pcds
.update(self
._GetPcd
(MODEL_PCD_DYNAMIC_EX
))
365 def ParsePcdName(self
,TokenCName
):
366 TokenCName
= TokenCName
.strip()
367 if TokenCName
.startswith("["):
368 if "." in TokenCName
:
369 Demesionattr
= TokenCName
[:TokenCName
.index(".")]
370 Fields
= TokenCName
[TokenCName
.index(".")+1:]
372 Demesionattr
= TokenCName
378 return Demesionattr
,Fields
380 def ProcessStructurePcd(self
, StructurePcdRawDataSet
):
381 s_pcd_set
= OrderedDict()
382 for s_pcd
, LineNo
in StructurePcdRawDataSet
:
383 if s_pcd
.TokenSpaceGuidCName
not in s_pcd_set
:
384 s_pcd_set
[s_pcd
.TokenSpaceGuidCName
] = []
385 s_pcd_set
[s_pcd
.TokenSpaceGuidCName
].append((s_pcd
, LineNo
))
388 for pcdname
in s_pcd_set
:
390 struct_pcd
= StructurePcd()
391 for item
, LineNo
in s_pcd_set
[pcdname
]:
392 if not item
.TokenCName
:
394 if "<HeaderFiles>" in item
.TokenCName
:
395 struct_pcd
.StructuredPcdIncludeFile
.append(item
.DefaultValue
)
396 elif "<Packages>" in item
.TokenCName
:
397 dep_pkgs
.append(item
.DefaultValue
)
398 elif item
.DatumType
== item
.TokenCName
:
399 struct_pcd
.copy(item
)
400 struct_pcd
.TokenValue
= struct_pcd
.TokenValue
.strip("{").strip()
401 struct_pcd
.TokenSpaceGuidCName
, struct_pcd
.TokenCName
= pcdname
.split(".")
402 struct_pcd
.PcdDefineLineNo
= LineNo
403 struct_pcd
.PkgPath
= self
.MetaFile
.File
404 struct_pcd
.SetDecDefaultValue(item
.DefaultValue
)
406 DemesionAttr
, Fields
= self
.ParsePcdName(item
.TokenCName
)
407 struct_pcd
.AddDefaultValue(Fields
, item
.DefaultValue
, self
.MetaFile
.File
, LineNo
,DemesionAttr
)
409 struct_pcd
.PackageDecs
= dep_pkgs
410 str_pcd_set
.append(struct_pcd
)
413 ## Retrieve PCD declarations for given type
414 def _GetPcd(self
, Type
):
417 # tdict is a special kind of dict, used for selecting correct
418 # PCD declaration for given ARCH
420 PcdDict
= tdict(True, 3)
421 # for summarizing PCD
423 # find out all PCDs of the 'type'
426 RecordList
= self
._RawData
[Type
, self
._Arch
]
427 for TokenSpaceGuid
, PcdCName
, Setting
, Arch
, PrivateFlag
, Dummy1
, Dummy2
in RecordList
:
428 PcdDict
[Arch
, PcdCName
, TokenSpaceGuid
] = (Setting
, Dummy2
)
429 if not (PcdCName
, TokenSpaceGuid
) in PcdSet
:
430 PcdSet
.append((PcdCName
, TokenSpaceGuid
))
432 DefinitionPosition
= {}
433 for PcdCName
, TokenSpaceGuid
in PcdSet
:
435 # limit the ARCH to self._Arch, if no self._Arch found, tdict
436 # will automatically turn to 'common' ARCH and try again
438 Setting
, LineNo
= PcdDict
[self
._Arch
, PcdCName
, TokenSpaceGuid
]
442 DefaultValue
, DatumType
, TokenNumber
= AnalyzePcdData(Setting
)
443 validateranges
, validlists
, expressions
= self
._RawData
.GetValidExpression(TokenSpaceGuid
, PcdCName
)
444 PcdObj
= PcdClassObject(
447 self
._PCD
_TYPE
_STRING
_[Type
],
455 list(validateranges
),
459 DefinitionPosition
[PcdObj
] = (self
.MetaFile
.File
, LineNo
)
460 if "." in TokenSpaceGuid
:
461 StrPcdSet
.append((PcdObj
, LineNo
))
463 Pcds
[PcdCName
, TokenSpaceGuid
, self
._PCD
_TYPE
_STRING
_[Type
]] = PcdObj
465 StructurePcds
= self
.ProcessStructurePcd(StrPcdSet
)
466 for pcd
in StructurePcds
:
467 Pcds
[pcd
.TokenCName
, pcd
.TokenSpaceGuidCName
, self
._PCD
_TYPE
_STRING
_[Type
]] = pcd
468 StructPattern
= compile(r
'[_a-zA-Z][0-9A-Za-z_]*$')
469 for pcd
in Pcds
.values():
470 if pcd
.DatumType
not in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
, TAB_VOID
, "BOOLEAN"]:
471 if not pcd
.IsAggregateDatumType():
472 EdkLogger
.error('build', FORMAT_INVALID
, "DatumType only support BOOLEAN, UINT8, UINT16, UINT32, UINT64, VOID* or a valid struct name.", DefinitionPosition
[pcd
][0], DefinitionPosition
[pcd
][1])
473 elif not pcd
.IsArray() and not pcd
.StructuredPcdIncludeFile
:
474 EdkLogger
.error("build", PCD_STRUCTURE_PCD_ERROR
, "The structure Pcd %s.%s header file is not found in %s line %s \n" % (pcd
.TokenSpaceGuidCName
, pcd
.TokenCName
, pcd
.DefinitionPosition
[0], pcd
.DefinitionPosition
[1] ))
478 def CommonIncludes(self
):
479 if self
._CommonIncludes
is None:
481 return self
._CommonIncludes