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
20 from Workspace
.BuildClassObject
import PackageBuildClassObject
, StructurePcd
, PcdClassObject
22 ## Platform build information from DEC file
24 # This class is used to retrieve information stored in database and convert them
25 # into PackageBuildClassObject form for easier use for AutoGen.
27 class DecBuildData(PackageBuildClassObject
):
28 # dict used to convert PCD type in database to string used by build tool
30 MODEL_PCD_FIXED_AT_BUILD
: TAB_PCDS_FIXED_AT_BUILD
,
31 MODEL_PCD_PATCHABLE_IN_MODULE
: TAB_PCDS_PATCHABLE_IN_MODULE
,
32 MODEL_PCD_FEATURE_FLAG
: TAB_PCDS_FEATURE_FLAG
,
33 MODEL_PCD_DYNAMIC
: TAB_PCDS_DYNAMIC
,
34 MODEL_PCD_DYNAMIC_DEFAULT
: TAB_PCDS_DYNAMIC
,
35 MODEL_PCD_DYNAMIC_HII
: TAB_PCDS_DYNAMIC_HII
,
36 MODEL_PCD_DYNAMIC_VPD
: TAB_PCDS_DYNAMIC_VPD
,
37 MODEL_PCD_DYNAMIC_EX
: TAB_PCDS_DYNAMIC_EX
,
38 MODEL_PCD_DYNAMIC_EX_DEFAULT
: TAB_PCDS_DYNAMIC_EX
,
39 MODEL_PCD_DYNAMIC_EX_HII
: TAB_PCDS_DYNAMIC_EX_HII
,
40 MODEL_PCD_DYNAMIC_EX_VPD
: TAB_PCDS_DYNAMIC_EX_VPD
,
43 # dict used to convert part of [Defines] to members of DecBuildData directly
48 TAB_DEC_DEFINES_PACKAGE_NAME
: "_PackageName",
49 TAB_DEC_DEFINES_PACKAGE_GUID
: "_Guid",
50 TAB_DEC_DEFINES_PACKAGE_VERSION
: "_Version",
51 TAB_DEC_DEFINES_PKG_UNI_FILE
: "_PkgUniFile",
55 ## Constructor of DecBuildData
57 # Initialize object of DecBuildData
59 # @param FilePath The path of package description file
60 # @param RawData The raw data of DEC file
61 # @param BuildDataBase Database used to retrieve module information
62 # @param Arch The target architecture
63 # @param Platform (not used for DecBuildData)
64 # @param Macros Macros used for replacement in DSC file
66 def __init__(self
, File
, RawData
, BuildDataBase
, Arch
=TAB_ARCH_COMMON
, Target
=None, Toolchain
=None):
68 self
._PackageDir
= File
.Dir
69 self
._RawData
= RawData
70 self
._Bdb
= BuildDataBase
73 self
._Toolchain
= Toolchain
77 def __setitem__(self
, key
, value
):
78 self
.__dict
__[self
._PROPERTY
_[key
]] = value
81 def __getitem__(self
, key
):
82 return self
.__dict
__[self
._PROPERTY
_[key
]]
85 def __contains__(self
, key
):
86 return key
in self
._PROPERTY
_
88 ## Set all internal used members of DecBuildData to None
91 self
._PackageName
= None
94 self
._PkgUniFile
= None
95 self
._Protocols
= None
99 self
._CommonIncludes
= None
100 self
._LibraryClasses
= None
102 self
._MacroDict
= None
103 self
._PrivateProtocols
= None
104 self
._PrivatePpis
= None
105 self
._PrivateGuids
= None
106 self
._PrivateIncludes
= None
108 ## Get current effective macros
111 if self
._MacroDict
is None:
112 self
._MacroDict
= dict(GlobalData
.gGlobalDefines
)
113 return self
._MacroDict
120 ## Retrieve all information in [Defines] section
122 # (Retriving all [Defines] information in one-shot is just to save time.)
124 def _GetHeaderInfo(self
):
125 RecordList
= self
._RawData
[MODEL_META_DATA_HEADER
, self
._Arch
]
126 for Record
in RecordList
:
129 self
[Name
] = Record
[2]
130 self
._Header
= 'DUMMY'
132 ## Retrieve package name
134 def PackageName(self
):
135 if self
._PackageName
is None:
136 if self
._Header
is None:
137 self
._GetHeaderInfo
()
138 if self
._PackageName
is None:
139 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "No PACKAGE_NAME", File
=self
.MetaFile
)
140 return self
._PackageName
142 ## Retrieve file guid
144 def PackageName(self
):
145 if self
._Guid
is None:
146 if self
._Header
is None:
147 self
._GetHeaderInfo
()
148 if self
._Guid
is None:
149 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "No PACKAGE_GUID", File
=self
.MetaFile
)
152 ## Retrieve package version
155 if self
._Version
is None:
156 if self
._Header
is None:
157 self
._GetHeaderInfo
()
158 if self
._Version
is None:
162 ## Retrieve protocol definitions (name/value pairs)
165 if self
._Protocols
is None:
167 # tdict is a special kind of dict, used for selecting correct
168 # protocol defition for given ARCH
170 ProtocolDict
= tdict(True)
171 PrivateProtocolDict
= tdict(True)
175 # find out all protocol definitions for specific and 'common' arch
176 RecordList
= self
._RawData
[MODEL_EFI_PROTOCOL
, self
._Arch
]
177 for Name
, Guid
, Dummy
, Arch
, PrivateFlag
, ID
, LineNo
in RecordList
:
178 if PrivateFlag
== 'PRIVATE':
179 if Name
not in PrivateNameList
:
180 PrivateNameList
.append(Name
)
181 PrivateProtocolDict
[Arch
, Name
] = Guid
182 if Name
in PublicNameList
:
183 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
)
185 if Name
not in PublicNameList
:
186 PublicNameList
.append(Name
)
187 if Name
in PrivateNameList
:
188 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
)
189 if Name
not in NameList
:
190 NameList
.append(Name
)
191 ProtocolDict
[Arch
, Name
] = Guid
192 # use OrderedDict to keep the order
193 self
._Protocols
= OrderedDict()
194 self
._PrivateProtocols
= OrderedDict()
195 for Name
in NameList
:
197 # limit the ARCH to self._Arch, if no self._Arch found, tdict
198 # will automatically turn to 'common' ARCH for trying
200 self
._Protocols
[Name
] = ProtocolDict
[self
._Arch
, Name
]
201 for Name
in PrivateNameList
:
202 self
._PrivateProtocols
[Name
] = PrivateProtocolDict
[self
._Arch
, Name
]
203 return self
._Protocols
205 ## Retrieve PPI definitions (name/value pairs)
208 if self
._Ppis
is None:
210 # tdict is a special kind of dict, used for selecting correct
211 # PPI defition for given ARCH
213 PpiDict
= tdict(True)
214 PrivatePpiDict
= tdict(True)
218 # find out all PPI definitions for specific arch and 'common' arch
219 RecordList
= self
._RawData
[MODEL_EFI_PPI
, self
._Arch
]
220 for Name
, Guid
, Dummy
, Arch
, PrivateFlag
, ID
, LineNo
in RecordList
:
221 if PrivateFlag
== 'PRIVATE':
222 if Name
not in PrivateNameList
:
223 PrivateNameList
.append(Name
)
224 PrivatePpiDict
[Arch
, Name
] = Guid
225 if Name
in PublicNameList
:
226 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
)
228 if Name
not in PublicNameList
:
229 PublicNameList
.append(Name
)
230 if Name
in PrivateNameList
:
231 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
)
232 if Name
not in NameList
:
233 NameList
.append(Name
)
234 PpiDict
[Arch
, Name
] = Guid
235 # use OrderedDict to keep the order
236 self
._Ppis
= OrderedDict()
237 self
._PrivatePpis
= OrderedDict()
238 for Name
in NameList
:
240 # limit the ARCH to self._Arch, if no self._Arch found, tdict
241 # will automatically turn to 'common' ARCH for trying
243 self
._Ppis
[Name
] = PpiDict
[self
._Arch
, Name
]
244 for Name
in PrivateNameList
:
245 self
._PrivatePpis
[Name
] = PrivatePpiDict
[self
._Arch
, Name
]
248 ## Retrieve GUID definitions (name/value pairs)
251 if self
._Guids
is None:
253 # tdict is a special kind of dict, used for selecting correct
254 # GUID defition for given ARCH
256 GuidDict
= tdict(True)
257 PrivateGuidDict
= tdict(True)
261 # find out all protocol definitions for specific and 'common' arch
262 RecordList
= self
._RawData
[MODEL_EFI_GUID
, self
._Arch
]
263 for Name
, Guid
, Dummy
, Arch
, PrivateFlag
, ID
, LineNo
in RecordList
:
264 if PrivateFlag
== 'PRIVATE':
265 if Name
not in PrivateNameList
:
266 PrivateNameList
.append(Name
)
267 PrivateGuidDict
[Arch
, Name
] = Guid
268 if Name
in PublicNameList
:
269 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
)
271 if Name
not in PublicNameList
:
272 PublicNameList
.append(Name
)
273 if Name
in PrivateNameList
:
274 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
)
275 if Name
not in NameList
:
276 NameList
.append(Name
)
277 GuidDict
[Arch
, Name
] = Guid
278 # use OrderedDict to keep the order
279 self
._Guids
= OrderedDict()
280 self
._PrivateGuids
= OrderedDict()
281 for Name
in NameList
:
283 # limit the ARCH to self._Arch, if no self._Arch found, tdict
284 # will automatically turn to 'common' ARCH for trying
286 self
._Guids
[Name
] = GuidDict
[self
._Arch
, Name
]
287 for Name
in PrivateNameList
:
288 self
._PrivateGuids
[Name
] = PrivateGuidDict
[self
._Arch
, Name
]
291 ## Retrieve public include paths declared in this package
294 if self
._Includes
is None or self
._CommonIncludes
is None:
295 self
._CommonIncludes
= []
297 self
._PrivateIncludes
= []
299 RecordList
= self
._RawData
[MODEL_EFI_INCLUDE
, self
._Arch
]
300 Macros
= self
._Macros
301 Macros
["EDK_SOURCE"] = GlobalData
.gEcpSource
302 for Record
in RecordList
:
303 File
= PathClass(NormPath(Record
[0], Macros
), self
._PackageDir
, Arch
=self
._Arch
)
306 ErrorCode
, ErrorInfo
= File
.Validate()
308 EdkLogger
.error('build', ErrorCode
, ExtraData
=ErrorInfo
, File
=self
.MetaFile
, Line
=LineNo
)
310 # avoid duplicate include path
311 if File
not in self
._Includes
:
312 self
._Includes
.append(File
)
313 if Record
[4] == 'PRIVATE':
314 if File
not in self
._PrivateIncludes
:
315 self
._PrivateIncludes
.append(File
)
316 if File
in PublicInclues
:
317 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
)
319 if File
not in PublicInclues
:
320 PublicInclues
.append(File
)
321 if File
in self
._PrivateIncludes
:
322 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
)
323 if Record
[3] == TAB_COMMON
:
324 self
._CommonIncludes
.append(File
)
325 return self
._Includes
327 ## Retrieve library class declarations (not used in build at present)
329 def LibraryClasses(self
):
330 if self
._LibraryClasses
is None:
332 # tdict is a special kind of dict, used for selecting correct
333 # library class declaration for given ARCH
335 LibraryClassDict
= tdict(True)
336 LibraryClassSet
= set()
337 RecordList
= self
._RawData
[MODEL_EFI_LIBRARY_CLASS
, self
._Arch
]
338 Macros
= self
._Macros
339 for LibraryClass
, File
, Dummy
, Arch
, PrivateFlag
, ID
, LineNo
in RecordList
:
340 File
= PathClass(NormPath(File
, Macros
), self
._PackageDir
, Arch
=self
._Arch
)
341 # check the file validation
342 ErrorCode
, ErrorInfo
= File
.Validate()
344 EdkLogger
.error('build', ErrorCode
, ExtraData
=ErrorInfo
, File
=self
.MetaFile
, Line
=LineNo
)
345 LibraryClassSet
.add(LibraryClass
)
346 LibraryClassDict
[Arch
, LibraryClass
] = File
347 self
._LibraryClasses
= OrderedDict()
348 for LibraryClass
in LibraryClassSet
:
349 self
._LibraryClasses
[LibraryClass
] = LibraryClassDict
[self
._Arch
, LibraryClass
]
350 return self
._LibraryClasses
352 ## Retrieve PCD declarations
355 if self
._Pcds
is None:
356 self
._Pcds
= OrderedDict()
357 self
._Pcds
.update(self
._GetPcd
(MODEL_PCD_FIXED_AT_BUILD
))
358 self
._Pcds
.update(self
._GetPcd
(MODEL_PCD_PATCHABLE_IN_MODULE
))
359 self
._Pcds
.update(self
._GetPcd
(MODEL_PCD_FEATURE_FLAG
))
360 self
._Pcds
.update(self
._GetPcd
(MODEL_PCD_DYNAMIC
))
361 self
._Pcds
.update(self
._GetPcd
(MODEL_PCD_DYNAMIC_EX
))
364 def ProcessStructurePcd(self
, StructurePcdRawDataSet
):
365 s_pcd_set
= OrderedDict()
366 for s_pcd
, LineNo
in StructurePcdRawDataSet
:
367 if s_pcd
.TokenSpaceGuidCName
not in s_pcd_set
:
368 s_pcd_set
[s_pcd
.TokenSpaceGuidCName
] = []
369 s_pcd_set
[s_pcd
.TokenSpaceGuidCName
].append((s_pcd
, LineNo
))
372 for pcdname
in s_pcd_set
:
374 struct_pcd
= StructurePcd()
375 for item
, LineNo
in s_pcd_set
[pcdname
]:
376 if "<HeaderFiles>" in item
.TokenCName
:
377 struct_pcd
.StructuredPcdIncludeFile
.append(item
.DefaultValue
)
378 elif "<Packages>" in item
.TokenCName
:
379 dep_pkgs
.append(item
.DefaultValue
)
380 elif item
.DatumType
== item
.TokenCName
:
381 struct_pcd
.copy(item
)
382 struct_pcd
.TokenValue
= struct_pcd
.TokenValue
.strip("{").strip()
383 struct_pcd
.TokenSpaceGuidCName
, struct_pcd
.TokenCName
= pcdname
.split(".")
384 struct_pcd
.PcdDefineLineNo
= LineNo
385 struct_pcd
.PkgPath
= self
.MetaFile
.File
386 struct_pcd
.SetDecDefaultValue(item
.DefaultValue
)
388 struct_pcd
.AddDefaultValue(item
.TokenCName
, item
.DefaultValue
, self
.MetaFile
.File
, LineNo
)
390 struct_pcd
.PackageDecs
= dep_pkgs
391 str_pcd_set
.append(struct_pcd
)
394 ## Retrieve PCD declarations for given type
395 def _GetPcd(self
, Type
):
398 # tdict is a special kind of dict, used for selecting correct
399 # PCD declaration for given ARCH
401 PcdDict
= tdict(True, 3)
402 # for summarizing PCD
404 # find out all PCDs of the 'type'
407 RecordList
= self
._RawData
[Type
, self
._Arch
]
408 for TokenSpaceGuid
, PcdCName
, Setting
, Arch
, PrivateFlag
, Dummy1
, Dummy2
in RecordList
:
409 PcdDict
[Arch
, PcdCName
, TokenSpaceGuid
] = (Setting
, Dummy2
)
410 if not (PcdCName
, TokenSpaceGuid
) in PcdSet
:
411 PcdSet
.append((PcdCName
, TokenSpaceGuid
))
413 DefinitionPosition
= {}
414 for PcdCName
, TokenSpaceGuid
in PcdSet
:
416 # limit the ARCH to self._Arch, if no self._Arch found, tdict
417 # will automatically turn to 'common' ARCH and try again
419 Setting
, LineNo
= PcdDict
[self
._Arch
, PcdCName
, TokenSpaceGuid
]
423 DefaultValue
, DatumType
, TokenNumber
= AnalyzePcdData(Setting
)
424 validateranges
, validlists
, expressions
= self
._RawData
.GetValidExpression(TokenSpaceGuid
, PcdCName
)
425 PcdObj
= PcdClassObject(
428 self
._PCD
_TYPE
_STRING
_[Type
],
436 list(validateranges
),
440 DefinitionPosition
[PcdObj
] = (self
.MetaFile
.File
, LineNo
)
441 if "." in TokenSpaceGuid
:
442 StrPcdSet
.append((PcdObj
, LineNo
))
444 Pcds
[PcdCName
, TokenSpaceGuid
, self
._PCD
_TYPE
_STRING
_[Type
]] = PcdObj
446 StructurePcds
= self
.ProcessStructurePcd(StrPcdSet
)
447 for pcd
in StructurePcds
:
448 Pcds
[pcd
.TokenCName
, pcd
.TokenSpaceGuidCName
, self
._PCD
_TYPE
_STRING
_[Type
]] = pcd
449 StructPattern
= re
.compile(r
'[_a-zA-Z][0-9A-Za-z_]*$')
450 for pcd
in Pcds
.values():
451 if pcd
.DatumType
not in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
, TAB_VOID
, "BOOLEAN"]:
452 if StructPattern
.match(pcd
.DatumType
) is None:
453 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])
454 for struct_pcd
in Pcds
.values():
455 if isinstance(struct_pcd
, StructurePcd
) and not struct_pcd
.StructuredPcdIncludeFile
:
456 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
, DefinitionPosition
[struct_pcd
][0], DefinitionPosition
[struct_pcd
][1] ))
461 def CommonIncludes(self
):
462 if self
._CommonIncludes
is None:
464 return self
._CommonIncludes