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
.String
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
: "FixedAtBuild",
31 MODEL_PCD_PATCHABLE_IN_MODULE
: "PatchableInModule",
32 MODEL_PCD_FEATURE_FLAG
: "FeatureFlag",
33 MODEL_PCD_DYNAMIC
: "Dynamic",
34 MODEL_PCD_DYNAMIC_DEFAULT
: "Dynamic",
35 MODEL_PCD_DYNAMIC_HII
: "DynamicHii",
36 MODEL_PCD_DYNAMIC_VPD
: "DynamicVpd",
37 MODEL_PCD_DYNAMIC_EX
: "DynamicEx",
38 MODEL_PCD_DYNAMIC_EX_DEFAULT
: "DynamicEx",
39 MODEL_PCD_DYNAMIC_EX_HII
: "DynamicExHii",
40 MODEL_PCD_DYNAMIC_EX_VPD
: "DynamicExVpd",
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
='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
103 self
._PrivateProtocols
= None
104 self
._PrivatePpis
= None
105 self
._PrivateGuids
= None
106 self
._PrivateIncludes
= None
108 ## Get current effective macros
109 def _GetMacros(self
):
110 if self
.__Macros
is None:
112 self
.__Macros
.update(GlobalData
.gGlobalDefines
)
121 # Changing the default ARCH to another may affect all other information
122 # because all information in a platform may be ARCH-related. That's
123 # why we need to clear all internal used members, in order to cause all
124 # information to be re-retrieved.
126 # @param Value The value of ARCH
128 def _SetArch(self
, Value
):
129 if self
._Arch
== Value
:
134 ## Retrieve all information in [Defines] section
136 # (Retriving all [Defines] information in one-shot is just to save time.)
138 def _GetHeaderInfo(self
):
139 RecordList
= self
._RawData
[MODEL_META_DATA_HEADER
, self
._Arch
]
140 for Record
in RecordList
:
143 self
[Name
] = Record
[2]
144 self
._Header
= 'DUMMY'
146 ## Retrieve package name
147 def _GetPackageName(self
):
148 if self
._PackageName
is None:
149 if self
._Header
is None:
150 self
._GetHeaderInfo
()
151 if self
._PackageName
is None:
152 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "No PACKAGE_NAME", File
=self
.MetaFile
)
153 return self
._PackageName
155 ## Retrieve file guid
156 def _GetFileGuid(self
):
157 if self
._Guid
is None:
158 if self
._Header
is None:
159 self
._GetHeaderInfo
()
160 if self
._Guid
is None:
161 EdkLogger
.error("build", ATTRIBUTE_NOT_AVAILABLE
, "No PACKAGE_GUID", File
=self
.MetaFile
)
164 ## Retrieve package version
165 def _GetVersion(self
):
166 if self
._Version
is None:
167 if self
._Header
is None:
168 self
._GetHeaderInfo
()
169 if self
._Version
is None:
173 ## Retrieve protocol definitions (name/value pairs)
174 def _GetProtocol(self
):
175 if self
._Protocols
is None:
177 # tdict is a special kind of dict, used for selecting correct
178 # protocol defition for given ARCH
180 ProtocolDict
= tdict(True)
181 PrivateProtocolDict
= tdict(True)
185 # find out all protocol definitions for specific and 'common' arch
186 RecordList
= self
._RawData
[MODEL_EFI_PROTOCOL
, self
._Arch
]
187 for Name
, Guid
, Dummy
, Arch
, PrivateFlag
, ID
, LineNo
in RecordList
:
188 if PrivateFlag
== 'PRIVATE':
189 if Name
not in PrivateNameList
:
190 PrivateNameList
.append(Name
)
191 PrivateProtocolDict
[Arch
, Name
] = Guid
192 if Name
in PublicNameList
:
193 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
)
195 if Name
not in PublicNameList
:
196 PublicNameList
.append(Name
)
197 if Name
in PrivateNameList
:
198 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
)
199 if Name
not in NameList
:
200 NameList
.append(Name
)
201 ProtocolDict
[Arch
, Name
] = Guid
202 # use OrderedDict to keep the order
203 self
._Protocols
= OrderedDict()
204 self
._PrivateProtocols
= OrderedDict()
205 for Name
in NameList
:
207 # limit the ARCH to self._Arch, if no self._Arch found, tdict
208 # will automatically turn to 'common' ARCH for trying
210 self
._Protocols
[Name
] = ProtocolDict
[self
._Arch
, Name
]
211 for Name
in PrivateNameList
:
212 self
._PrivateProtocols
[Name
] = PrivateProtocolDict
[self
._Arch
, Name
]
213 return self
._Protocols
215 ## Retrieve PPI definitions (name/value pairs)
217 if self
._Ppis
is None:
219 # tdict is a special kind of dict, used for selecting correct
220 # PPI defition for given ARCH
222 PpiDict
= tdict(True)
223 PrivatePpiDict
= tdict(True)
227 # find out all PPI definitions for specific arch and 'common' arch
228 RecordList
= self
._RawData
[MODEL_EFI_PPI
, self
._Arch
]
229 for Name
, Guid
, Dummy
, Arch
, PrivateFlag
, ID
, LineNo
in RecordList
:
230 if PrivateFlag
== 'PRIVATE':
231 if Name
not in PrivateNameList
:
232 PrivateNameList
.append(Name
)
233 PrivatePpiDict
[Arch
, Name
] = Guid
234 if Name
in PublicNameList
:
235 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
)
237 if Name
not in PublicNameList
:
238 PublicNameList
.append(Name
)
239 if Name
in PrivateNameList
:
240 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
)
241 if Name
not in NameList
:
242 NameList
.append(Name
)
243 PpiDict
[Arch
, Name
] = Guid
244 # use OrderedDict to keep the order
245 self
._Ppis
= OrderedDict()
246 self
._PrivatePpis
= OrderedDict()
247 for Name
in NameList
:
249 # limit the ARCH to self._Arch, if no self._Arch found, tdict
250 # will automatically turn to 'common' ARCH for trying
252 self
._Ppis
[Name
] = PpiDict
[self
._Arch
, Name
]
253 for Name
in PrivateNameList
:
254 self
._PrivatePpis
[Name
] = PrivatePpiDict
[self
._Arch
, Name
]
257 ## Retrieve GUID definitions (name/value pairs)
259 if self
._Guids
is None:
261 # tdict is a special kind of dict, used for selecting correct
262 # GUID defition for given ARCH
264 GuidDict
= tdict(True)
265 PrivateGuidDict
= tdict(True)
269 # find out all protocol definitions for specific and 'common' arch
270 RecordList
= self
._RawData
[MODEL_EFI_GUID
, self
._Arch
]
271 for Name
, Guid
, Dummy
, Arch
, PrivateFlag
, ID
, LineNo
in RecordList
:
272 if PrivateFlag
== 'PRIVATE':
273 if Name
not in PrivateNameList
:
274 PrivateNameList
.append(Name
)
275 PrivateGuidDict
[Arch
, Name
] = Guid
276 if Name
in PublicNameList
:
277 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
)
279 if Name
not in PublicNameList
:
280 PublicNameList
.append(Name
)
281 if Name
in PrivateNameList
:
282 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
)
283 if Name
not in NameList
:
284 NameList
.append(Name
)
285 GuidDict
[Arch
, Name
] = Guid
286 # use OrderedDict to keep the order
287 self
._Guids
= OrderedDict()
288 self
._PrivateGuids
= OrderedDict()
289 for Name
in NameList
:
291 # limit the ARCH to self._Arch, if no self._Arch found, tdict
292 # will automatically turn to 'common' ARCH for trying
294 self
._Guids
[Name
] = GuidDict
[self
._Arch
, Name
]
295 for Name
in PrivateNameList
:
296 self
._PrivateGuids
[Name
] = PrivateGuidDict
[self
._Arch
, Name
]
299 ## Retrieve public include paths declared in this package
300 def _GetInclude(self
):
301 if self
._Includes
is None or self
._CommonIncludes
is None:
302 self
._CommonIncludes
= []
304 self
._PrivateIncludes
= []
306 RecordList
= self
._RawData
[MODEL_EFI_INCLUDE
, self
._Arch
]
307 Macros
= self
._Macros
308 Macros
["EDK_SOURCE"] = GlobalData
.gEcpSource
309 for Record
in RecordList
:
310 File
= PathClass(NormPath(Record
[0], Macros
), self
._PackageDir
, Arch
=self
._Arch
)
313 ErrorCode
, ErrorInfo
= File
.Validate()
315 EdkLogger
.error('build', ErrorCode
, ExtraData
=ErrorInfo
, File
=self
.MetaFile
, Line
=LineNo
)
317 # avoid duplicate include path
318 if File
not in self
._Includes
:
319 self
._Includes
.append(File
)
320 if Record
[4] == 'PRIVATE':
321 if File
not in self
._PrivateIncludes
:
322 self
._PrivateIncludes
.append(File
)
323 if File
in PublicInclues
:
324 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
)
326 if File
not in PublicInclues
:
327 PublicInclues
.append(File
)
328 if File
in self
._PrivateIncludes
:
329 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
)
330 if Record
[3] == "COMMON":
331 self
._CommonIncludes
.append(File
)
332 return self
._Includes
334 ## Retrieve library class declarations (not used in build at present)
335 def _GetLibraryClass(self
):
336 if self
._LibraryClasses
is None:
338 # tdict is a special kind of dict, used for selecting correct
339 # library class declaration for given ARCH
341 LibraryClassDict
= tdict(True)
342 LibraryClassSet
= set()
343 RecordList
= self
._RawData
[MODEL_EFI_LIBRARY_CLASS
, self
._Arch
]
344 Macros
= self
._Macros
345 for LibraryClass
, File
, Dummy
, Arch
, PrivateFlag
, ID
, LineNo
in RecordList
:
346 File
= PathClass(NormPath(File
, Macros
), self
._PackageDir
, Arch
=self
._Arch
)
347 # check the file validation
348 ErrorCode
, ErrorInfo
= File
.Validate()
350 EdkLogger
.error('build', ErrorCode
, ExtraData
=ErrorInfo
, File
=self
.MetaFile
, Line
=LineNo
)
351 LibraryClassSet
.add(LibraryClass
)
352 LibraryClassDict
[Arch
, LibraryClass
] = File
353 self
._LibraryClasses
= OrderedDict()
354 for LibraryClass
in LibraryClassSet
:
355 self
._LibraryClasses
[LibraryClass
] = LibraryClassDict
[self
._Arch
, LibraryClass
]
356 return self
._LibraryClasses
358 ## Retrieve PCD declarations
360 if self
._Pcds
is None:
361 self
._Pcds
= OrderedDict()
362 self
._Pcds
.update(self
._GetPcd
(MODEL_PCD_FIXED_AT_BUILD
))
363 self
._Pcds
.update(self
._GetPcd
(MODEL_PCD_PATCHABLE_IN_MODULE
))
364 self
._Pcds
.update(self
._GetPcd
(MODEL_PCD_FEATURE_FLAG
))
365 self
._Pcds
.update(self
._GetPcd
(MODEL_PCD_DYNAMIC
))
366 self
._Pcds
.update(self
._GetPcd
(MODEL_PCD_DYNAMIC_EX
))
370 def ProcessStructurePcd(self
, StructurePcdRawDataSet
):
371 s_pcd_set
= OrderedDict()
372 for s_pcd
,LineNo
in StructurePcdRawDataSet
:
373 if s_pcd
.TokenSpaceGuidCName
not in s_pcd_set
:
374 s_pcd_set
[s_pcd
.TokenSpaceGuidCName
] = []
375 s_pcd_set
[s_pcd
.TokenSpaceGuidCName
].append((s_pcd
,LineNo
))
378 for pcdname
in s_pcd_set
:
380 struct_pcd
= StructurePcd()
381 for item
,LineNo
in s_pcd_set
[pcdname
]:
382 if "<HeaderFiles>" in item
.TokenCName
:
383 struct_pcd
.StructuredPcdIncludeFile
.append(item
.DefaultValue
)
384 elif "<Packages>" in item
.TokenCName
:
385 dep_pkgs
.append(item
.DefaultValue
)
386 elif item
.DatumType
== item
.TokenCName
:
387 struct_pcd
.copy(item
)
388 struct_pcd
.TokenValue
= struct_pcd
.TokenValue
.strip("{").strip()
389 struct_pcd
.TokenSpaceGuidCName
, struct_pcd
.TokenCName
= pcdname
.split(".")
390 struct_pcd
.PcdDefineLineNo
= LineNo
391 struct_pcd
.PkgPath
= self
.MetaFile
.File
392 struct_pcd
.SetDecDefaultValue(item
.DefaultValue
)
394 struct_pcd
.AddDefaultValue(item
.TokenCName
, item
.DefaultValue
,self
.MetaFile
.File
,LineNo
)
396 struct_pcd
.PackageDecs
= dep_pkgs
397 str_pcd_set
.append(struct_pcd
)
400 ## Retrieve PCD declarations for given type
401 def _GetPcd(self
, Type
):
404 # tdict is a special kind of dict, used for selecting correct
405 # PCD declaration for given ARCH
407 PcdDict
= tdict(True, 3)
408 # for summarizing PCD
410 # find out all PCDs of the 'type'
413 RecordList
= self
._RawData
[Type
, self
._Arch
]
414 for TokenSpaceGuid
, PcdCName
, Setting
, Arch
, PrivateFlag
, Dummy1
, Dummy2
in RecordList
:
415 PcdDict
[Arch
, PcdCName
, TokenSpaceGuid
] = (Setting
,Dummy2
)
416 if not (PcdCName
, TokenSpaceGuid
) in PcdSet
:
417 PcdSet
.append((PcdCName
, TokenSpaceGuid
))
419 for PcdCName
, TokenSpaceGuid
in PcdSet
:
421 # limit the ARCH to self._Arch, if no self._Arch found, tdict
422 # will automatically turn to 'common' ARCH and try again
424 Setting
,LineNo
= PcdDict
[self
._Arch
, PcdCName
, TokenSpaceGuid
]
428 DefaultValue
, DatumType
, TokenNumber
= AnalyzePcdData(Setting
)
429 validateranges
, validlists
, expressions
= self
._RawData
.GetValidExpression(TokenSpaceGuid
, PcdCName
)
430 PcdObj
= PcdClassObject(
433 self
._PCD
_TYPE
_STRING
_[Type
],
441 list(validateranges
),
445 PcdObj
.DefinitionPosition
= (self
.MetaFile
.File
,LineNo
)
446 if "." in TokenSpaceGuid
:
447 StrPcdSet
.append((PcdObj
,LineNo
))
449 Pcds
[PcdCName
, TokenSpaceGuid
, self
._PCD
_TYPE
_STRING
_[Type
]] = PcdObj
451 StructurePcds
= self
.ProcessStructurePcd(StrPcdSet
)
452 for pcd
in StructurePcds
:
453 Pcds
[pcd
.TokenCName
, pcd
.TokenSpaceGuidCName
, self
._PCD
_TYPE
_STRING
_[Type
]] = pcd
454 StructPattern
= re
.compile(r
'[_a-zA-Z][0-9A-Za-z_]*$')
455 for pcd
in Pcds
.values():
456 if pcd
.DatumType
not in [TAB_UINT8
, TAB_UINT16
, TAB_UINT32
, TAB_UINT64
, TAB_VOID
, "BOOLEAN"]:
457 if StructPattern
.match(pcd
.DatumType
) is None:
458 EdkLogger
.error('build', FORMAT_INVALID
, "DatumType only support BOOLEAN, UINT8, UINT16, UINT32, UINT64, VOID* or a valid struct name.", pcd
.DefinitionPosition
[0],pcd
.DefinitionPosition
[1])
459 for struct_pcd
in Pcds
.values():
460 if isinstance(struct_pcd
,StructurePcd
) and not struct_pcd
.StructuredPcdIncludeFile
:
461 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
,struct_pcd
.DefinitionPosition
[0],struct_pcd
.DefinitionPosition
[1] ))
465 def CommonIncludes(self
):
466 if self
._CommonIncludes
is None:
468 return self
._CommonIncludes
471 _Macros
= property(_GetMacros
)
472 Arch
= property(_GetArch
, _SetArch
)
473 PackageName
= property(_GetPackageName
)
474 Guid
= property(_GetFileGuid
)
475 Version
= property(_GetVersion
)
477 Protocols
= property(_GetProtocol
)
478 Ppis
= property(_GetPpi
)
479 Guids
= property(_GetGuid
)
480 Includes
= property(_GetInclude
)
481 LibraryClasses
= property(_GetLibraryClass
)
482 Pcds
= property(_GetPcds
)