2017-11-24 07:30:11 +01:00
## @file
# This file is used to create a database used by build tool
#
2018-02-02 08:46:08 +01:00
# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
2017-11-24 07:30:11 +01:00
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
from Common . String import *
from Common . DataType import *
from Common . Misc import *
from types import *
2018-02-28 06:59:20 +01:00
from collections import OrderedDict
2017-11-24 07:30:11 +01:00
from Workspace . BuildClassObject import PackageBuildClassObject , StructurePcd , PcdClassObject
## Platform build information from DEC file
#
# This class is used to retrieve information stored in database and convert them
# into PackageBuildClassObject form for easier use for AutoGen.
#
class DecBuildData ( PackageBuildClassObject ) :
# dict used to convert PCD type in database to string used by build tool
_PCD_TYPE_STRING_ = {
2018-04-26 18:57:55 +02:00
MODEL_PCD_FIXED_AT_BUILD : TAB_PCDS_FIXED_AT_BUILD ,
MODEL_PCD_PATCHABLE_IN_MODULE : TAB_PCDS_PATCHABLE_IN_MODULE ,
MODEL_PCD_FEATURE_FLAG : TAB_PCDS_FEATURE_FLAG ,
MODEL_PCD_DYNAMIC : TAB_PCDS_DYNAMIC ,
MODEL_PCD_DYNAMIC_DEFAULT : TAB_PCDS_DYNAMIC ,
MODEL_PCD_DYNAMIC_HII : TAB_PCDS_DYNAMIC_HII ,
MODEL_PCD_DYNAMIC_VPD : TAB_PCDS_DYNAMIC_VPD ,
MODEL_PCD_DYNAMIC_EX : TAB_PCDS_DYNAMIC_EX ,
MODEL_PCD_DYNAMIC_EX_DEFAULT : TAB_PCDS_DYNAMIC_EX ,
MODEL_PCD_DYNAMIC_EX_HII : TAB_PCDS_DYNAMIC_EX_HII ,
MODEL_PCD_DYNAMIC_EX_VPD : TAB_PCDS_DYNAMIC_EX_VPD ,
2017-11-24 07:30:11 +01:00
}
# dict used to convert part of [Defines] to members of DecBuildData directly
_PROPERTY_ = {
#
# Required Fields
#
TAB_DEC_DEFINES_PACKAGE_NAME : " _PackageName " ,
TAB_DEC_DEFINES_PACKAGE_GUID : " _Guid " ,
TAB_DEC_DEFINES_PACKAGE_VERSION : " _Version " ,
TAB_DEC_DEFINES_PKG_UNI_FILE : " _PkgUniFile " ,
}
## Constructor of DecBuildData
#
# Initialize object of DecBuildData
#
# @param FilePath The path of package description file
# @param RawData The raw data of DEC file
# @param BuildDataBase Database used to retrieve module information
# @param Arch The target architecture
# @param Platform (not used for DecBuildData)
# @param Macros Macros used for replacement in DSC file
#
2018-04-16 15:52:13 +02:00
def __init__ ( self , File , RawData , BuildDataBase , Arch = TAB_ARCH_COMMON , Target = None , Toolchain = None ) :
2017-11-24 07:30:11 +01:00
self . MetaFile = File
self . _PackageDir = File . Dir
self . _RawData = RawData
self . _Bdb = BuildDataBase
self . _Arch = Arch
self . _Target = Target
self . _Toolchain = Toolchain
self . _Clear ( )
## XXX[key] = value
def __setitem__ ( self , key , value ) :
self . __dict__ [ self . _PROPERTY_ [ key ] ] = value
## value = XXX[key]
def __getitem__ ( self , key ) :
return self . __dict__ [ self . _PROPERTY_ [ key ] ]
## "in" test support
def __contains__ ( self , key ) :
return key in self . _PROPERTY_
## Set all internal used members of DecBuildData to None
def _Clear ( self ) :
self . _Header = None
self . _PackageName = None
self . _Guid = None
self . _Version = None
self . _PkgUniFile = None
self . _Protocols = None
self . _Ppis = None
self . _Guids = None
self . _Includes = None
2018-02-28 06:59:19 +01:00
self . _CommonIncludes = None
2017-11-24 07:30:11 +01:00
self . _LibraryClasses = None
self . _Pcds = None
self . __Macros = None
self . _PrivateProtocols = None
self . _PrivatePpis = None
self . _PrivateGuids = None
self . _PrivateIncludes = None
## Get current effective macros
def _GetMacros ( self ) :
2018-03-26 22:25:43 +02:00
if self . __Macros is None :
2017-11-24 07:30:11 +01:00
self . __Macros = { }
self . __Macros . update ( GlobalData . gGlobalDefines )
return self . __Macros
## Get architecture
def _GetArch ( self ) :
return self . _Arch
## Set architecture
#
# Changing the default ARCH to another may affect all other information
# because all information in a platform may be ARCH-related. That's
# why we need to clear all internal used members, in order to cause all
# information to be re-retrieved.
#
# @param Value The value of ARCH
#
def _SetArch ( self , Value ) :
if self . _Arch == Value :
return
self . _Arch = Value
self . _Clear ( )
## Retrieve all information in [Defines] section
#
# (Retriving all [Defines] information in one-shot is just to save time.)
#
def _GetHeaderInfo ( self ) :
RecordList = self . _RawData [ MODEL_META_DATA_HEADER , self . _Arch ]
for Record in RecordList :
Name = Record [ 1 ]
if Name in self :
self [ Name ] = Record [ 2 ]
self . _Header = ' DUMMY '
## Retrieve package name
def _GetPackageName ( self ) :
2018-03-26 22:25:43 +02:00
if self . _PackageName is None :
if self . _Header is None :
2017-11-24 07:30:11 +01:00
self . _GetHeaderInfo ( )
2018-03-26 22:25:43 +02:00
if self . _PackageName is None :
2017-11-24 07:30:11 +01:00
EdkLogger . error ( " build " , ATTRIBUTE_NOT_AVAILABLE , " No PACKAGE_NAME " , File = self . MetaFile )
return self . _PackageName
## Retrieve file guid
def _GetFileGuid ( self ) :
2018-03-26 22:25:43 +02:00
if self . _Guid is None :
if self . _Header is None :
2017-11-24 07:30:11 +01:00
self . _GetHeaderInfo ( )
2018-03-26 22:25:43 +02:00
if self . _Guid is None :
2017-11-24 07:30:11 +01:00
EdkLogger . error ( " build " , ATTRIBUTE_NOT_AVAILABLE , " No PACKAGE_GUID " , File = self . MetaFile )
return self . _Guid
## Retrieve package version
def _GetVersion ( self ) :
2018-03-26 22:25:43 +02:00
if self . _Version is None :
if self . _Header is None :
2017-11-24 07:30:11 +01:00
self . _GetHeaderInfo ( )
2018-03-26 22:25:43 +02:00
if self . _Version is None :
2017-11-24 07:30:11 +01:00
self . _Version = ' '
return self . _Version
## Retrieve protocol definitions (name/value pairs)
def _GetProtocol ( self ) :
2018-03-26 22:25:43 +02:00
if self . _Protocols is None :
2017-11-24 07:30:11 +01:00
#
# tdict is a special kind of dict, used for selecting correct
# protocol defition for given ARCH
#
ProtocolDict = tdict ( True )
PrivateProtocolDict = tdict ( True )
NameList = [ ]
PrivateNameList = [ ]
PublicNameList = [ ]
# find out all protocol definitions for specific and 'common' arch
RecordList = self . _RawData [ MODEL_EFI_PROTOCOL , self . _Arch ]
for Name , Guid , Dummy , Arch , PrivateFlag , ID , LineNo in RecordList :
if PrivateFlag == ' PRIVATE ' :
if Name not in PrivateNameList :
PrivateNameList . append ( Name )
PrivateProtocolDict [ Arch , Name ] = Guid
if Name in PublicNameList :
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 )
else :
if Name not in PublicNameList :
PublicNameList . append ( Name )
if Name in PrivateNameList :
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 )
if Name not in NameList :
NameList . append ( Name )
ProtocolDict [ Arch , Name ] = Guid
2018-04-03 23:03:07 +02:00
# use OrderedDict to keep the order
self . _Protocols = OrderedDict ( )
self . _PrivateProtocols = OrderedDict ( )
2017-11-24 07:30:11 +01:00
for Name in NameList :
#
# limit the ARCH to self._Arch, if no self._Arch found, tdict
# will automatically turn to 'common' ARCH for trying
#
self . _Protocols [ Name ] = ProtocolDict [ self . _Arch , Name ]
for Name in PrivateNameList :
self . _PrivateProtocols [ Name ] = PrivateProtocolDict [ self . _Arch , Name ]
return self . _Protocols
## Retrieve PPI definitions (name/value pairs)
def _GetPpi ( self ) :
2018-03-26 22:25:43 +02:00
if self . _Ppis is None :
2017-11-24 07:30:11 +01:00
#
# tdict is a special kind of dict, used for selecting correct
# PPI defition for given ARCH
#
PpiDict = tdict ( True )
PrivatePpiDict = tdict ( True )
NameList = [ ]
PrivateNameList = [ ]
PublicNameList = [ ]
# find out all PPI definitions for specific arch and 'common' arch
RecordList = self . _RawData [ MODEL_EFI_PPI , self . _Arch ]
for Name , Guid , Dummy , Arch , PrivateFlag , ID , LineNo in RecordList :
if PrivateFlag == ' PRIVATE ' :
if Name not in PrivateNameList :
PrivateNameList . append ( Name )
PrivatePpiDict [ Arch , Name ] = Guid
if Name in PublicNameList :
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 )
else :
if Name not in PublicNameList :
PublicNameList . append ( Name )
if Name in PrivateNameList :
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 )
if Name not in NameList :
NameList . append ( Name )
PpiDict [ Arch , Name ] = Guid
2018-04-03 23:03:07 +02:00
# use OrderedDict to keep the order
self . _Ppis = OrderedDict ( )
self . _PrivatePpis = OrderedDict ( )
2017-11-24 07:30:11 +01:00
for Name in NameList :
#
# limit the ARCH to self._Arch, if no self._Arch found, tdict
# will automatically turn to 'common' ARCH for trying
#
self . _Ppis [ Name ] = PpiDict [ self . _Arch , Name ]
for Name in PrivateNameList :
self . _PrivatePpis [ Name ] = PrivatePpiDict [ self . _Arch , Name ]
return self . _Ppis
## Retrieve GUID definitions (name/value pairs)
def _GetGuid ( self ) :
2018-03-26 22:25:43 +02:00
if self . _Guids is None :
2017-11-24 07:30:11 +01:00
#
# tdict is a special kind of dict, used for selecting correct
# GUID defition for given ARCH
#
GuidDict = tdict ( True )
PrivateGuidDict = tdict ( True )
NameList = [ ]
PrivateNameList = [ ]
PublicNameList = [ ]
# find out all protocol definitions for specific and 'common' arch
RecordList = self . _RawData [ MODEL_EFI_GUID , self . _Arch ]
for Name , Guid , Dummy , Arch , PrivateFlag , ID , LineNo in RecordList :
if PrivateFlag == ' PRIVATE ' :
if Name not in PrivateNameList :
PrivateNameList . append ( Name )
PrivateGuidDict [ Arch , Name ] = Guid
if Name in PublicNameList :
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 )
else :
if Name not in PublicNameList :
PublicNameList . append ( Name )
if Name in PrivateNameList :
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 )
if Name not in NameList :
NameList . append ( Name )
GuidDict [ Arch , Name ] = Guid
2018-04-03 23:03:07 +02:00
# use OrderedDict to keep the order
self . _Guids = OrderedDict ( )
self . _PrivateGuids = OrderedDict ( )
2017-11-24 07:30:11 +01:00
for Name in NameList :
#
# limit the ARCH to self._Arch, if no self._Arch found, tdict
# will automatically turn to 'common' ARCH for trying
#
self . _Guids [ Name ] = GuidDict [ self . _Arch , Name ]
for Name in PrivateNameList :
self . _PrivateGuids [ Name ] = PrivateGuidDict [ self . _Arch , Name ]
return self . _Guids
## Retrieve public include paths declared in this package
def _GetInclude ( self ) :
2018-03-26 22:25:43 +02:00
if self . _Includes is None or self . _CommonIncludes is None :
2018-02-28 06:59:19 +01:00
self . _CommonIncludes = [ ]
2017-11-24 07:30:11 +01:00
self . _Includes = [ ]
self . _PrivateIncludes = [ ]
PublicInclues = [ ]
RecordList = self . _RawData [ MODEL_EFI_INCLUDE , self . _Arch ]
Macros = self . _Macros
Macros [ " EDK_SOURCE " ] = GlobalData . gEcpSource
for Record in RecordList :
File = PathClass ( NormPath ( Record [ 0 ] , Macros ) , self . _PackageDir , Arch = self . _Arch )
LineNo = Record [ - 1 ]
# validate the path
ErrorCode , ErrorInfo = File . Validate ( )
if ErrorCode != 0 :
EdkLogger . error ( ' build ' , ErrorCode , ExtraData = ErrorInfo , File = self . MetaFile , Line = LineNo )
# avoid duplicate include path
if File not in self . _Includes :
self . _Includes . append ( File )
if Record [ 4 ] == ' PRIVATE ' :
if File not in self . _PrivateIncludes :
self . _PrivateIncludes . append ( File )
if File in PublicInclues :
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 )
else :
if File not in PublicInclues :
PublicInclues . append ( File )
if File in self . _PrivateIncludes :
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 )
2018-04-16 15:52:13 +02:00
if Record [ 3 ] == TAB_COMMON :
2018-02-28 06:59:19 +01:00
self . _CommonIncludes . append ( File )
2017-11-24 07:30:11 +01:00
return self . _Includes
## Retrieve library class declarations (not used in build at present)
def _GetLibraryClass ( self ) :
2018-03-26 22:25:43 +02:00
if self . _LibraryClasses is None :
2017-11-24 07:30:11 +01:00
#
# tdict is a special kind of dict, used for selecting correct
# library class declaration for given ARCH
#
LibraryClassDict = tdict ( True )
LibraryClassSet = set ( )
RecordList = self . _RawData [ MODEL_EFI_LIBRARY_CLASS , self . _Arch ]
Macros = self . _Macros
for LibraryClass , File , Dummy , Arch , PrivateFlag , ID , LineNo in RecordList :
File = PathClass ( NormPath ( File , Macros ) , self . _PackageDir , Arch = self . _Arch )
# check the file validation
ErrorCode , ErrorInfo = File . Validate ( )
if ErrorCode != 0 :
EdkLogger . error ( ' build ' , ErrorCode , ExtraData = ErrorInfo , File = self . MetaFile , Line = LineNo )
LibraryClassSet . add ( LibraryClass )
LibraryClassDict [ Arch , LibraryClass ] = File
2018-04-03 23:03:07 +02:00
self . _LibraryClasses = OrderedDict ( )
2017-11-24 07:30:11 +01:00
for LibraryClass in LibraryClassSet :
self . _LibraryClasses [ LibraryClass ] = LibraryClassDict [ self . _Arch , LibraryClass ]
return self . _LibraryClasses
## Retrieve PCD declarations
def _GetPcds ( self ) :
2018-03-26 22:25:43 +02:00
if self . _Pcds is None :
2018-04-03 23:03:07 +02:00
self . _Pcds = OrderedDict ( )
2017-11-24 07:30:11 +01:00
self . _Pcds . update ( self . _GetPcd ( MODEL_PCD_FIXED_AT_BUILD ) )
self . _Pcds . update ( self . _GetPcd ( MODEL_PCD_PATCHABLE_IN_MODULE ) )
self . _Pcds . update ( self . _GetPcd ( MODEL_PCD_FEATURE_FLAG ) )
self . _Pcds . update ( self . _GetPcd ( MODEL_PCD_DYNAMIC ) )
self . _Pcds . update ( self . _GetPcd ( MODEL_PCD_DYNAMIC_EX ) )
return self . _Pcds
def ProcessStructurePcd ( self , StructurePcdRawDataSet ) :
2018-02-28 06:59:20 +01:00
s_pcd_set = OrderedDict ( )
2017-11-24 07:30:11 +01:00
for s_pcd , LineNo in StructurePcdRawDataSet :
if s_pcd . TokenSpaceGuidCName not in s_pcd_set :
s_pcd_set [ s_pcd . TokenSpaceGuidCName ] = [ ]
s_pcd_set [ s_pcd . TokenSpaceGuidCName ] . append ( ( s_pcd , LineNo ) )
str_pcd_set = [ ]
for pcdname in s_pcd_set :
dep_pkgs = [ ]
struct_pcd = StructurePcd ( )
for item , LineNo in s_pcd_set [ pcdname ] :
if " <HeaderFiles> " in item . TokenCName :
2018-01-29 07:09:36 +01:00
struct_pcd . StructuredPcdIncludeFile . append ( item . DefaultValue )
2017-11-24 07:30:11 +01:00
elif " <Packages> " in item . TokenCName :
dep_pkgs . append ( item . DefaultValue )
elif item . DatumType == item . TokenCName :
struct_pcd . copy ( item )
struct_pcd . TokenValue = struct_pcd . TokenValue . strip ( " { " ) . strip ( )
struct_pcd . TokenSpaceGuidCName , struct_pcd . TokenCName = pcdname . split ( " . " )
2018-01-23 04:03:05 +01:00
struct_pcd . PcdDefineLineNo = LineNo
struct_pcd . PkgPath = self . MetaFile . File
2018-02-28 06:59:18 +01:00
struct_pcd . SetDecDefaultValue ( item . DefaultValue )
2017-11-24 07:30:11 +01:00
else :
struct_pcd . AddDefaultValue ( item . TokenCName , item . DefaultValue , self . MetaFile . File , LineNo )
struct_pcd . PackageDecs = dep_pkgs
str_pcd_set . append ( struct_pcd )
return str_pcd_set
## Retrieve PCD declarations for given type
def _GetPcd ( self , Type ) :
2018-04-03 23:03:07 +02:00
Pcds = OrderedDict ( )
2017-11-24 07:30:11 +01:00
#
# tdict is a special kind of dict, used for selecting correct
# PCD declaration for given ARCH
#
PcdDict = tdict ( True , 3 )
# for summarizing PCD
2017-12-22 13:07:54 +01:00
PcdSet = [ ]
2017-11-24 07:30:11 +01:00
# find out all PCDs of the 'type'
StrPcdSet = [ ]
RecordList = self . _RawData [ Type , self . _Arch ]
for TokenSpaceGuid , PcdCName , Setting , Arch , PrivateFlag , Dummy1 , Dummy2 in RecordList :
PcdDict [ Arch , PcdCName , TokenSpaceGuid ] = ( Setting , Dummy2 )
2017-12-22 13:07:54 +01:00
if not ( PcdCName , TokenSpaceGuid ) in PcdSet :
PcdSet . append ( ( PcdCName , TokenSpaceGuid ) )
2017-11-24 07:30:11 +01:00
for PcdCName , TokenSpaceGuid in PcdSet :
#
# limit the ARCH to self._Arch, if no self._Arch found, tdict
# will automatically turn to 'common' ARCH and try again
#
Setting , LineNo = PcdDict [ self . _Arch , PcdCName , TokenSpaceGuid ]
2018-03-26 22:25:43 +02:00
if Setting is None :
2017-11-24 07:30:11 +01:00
continue
DefaultValue , DatumType , TokenNumber = AnalyzePcdData ( Setting )
validateranges , validlists , expressions = self . _RawData . GetValidExpression ( TokenSpaceGuid , PcdCName )
PcdObj = PcdClassObject (
PcdCName ,
TokenSpaceGuid ,
self . _PCD_TYPE_STRING_ [ Type ] ,
DatumType ,
DefaultValue ,
TokenNumber ,
' ' ,
{ } ,
False ,
None ,
list ( validateranges ) ,
list ( validlists ) ,
list ( expressions )
)
2018-03-19 05:05:19 +01:00
PcdObj . DefinitionPosition = ( self . MetaFile . File , LineNo )
2017-11-24 07:30:11 +01:00
if " . " in TokenSpaceGuid :
StrPcdSet . append ( ( PcdObj , LineNo ) )
else :
Pcds [ PcdCName , TokenSpaceGuid , self . _PCD_TYPE_STRING_ [ Type ] ] = PcdObj
StructurePcds = self . ProcessStructurePcd ( StrPcdSet )
for pcd in StructurePcds :
Pcds [ pcd . TokenCName , pcd . TokenSpaceGuidCName , self . _PCD_TYPE_STRING_ [ Type ] ] = pcd
2018-03-19 05:05:19 +01:00
StructPattern = re . compile ( r ' [_a-zA-Z][0-9A-Za-z_]*$ ' )
for pcd in Pcds . values ( ) :
if pcd . DatumType not in [ TAB_UINT8 , TAB_UINT16 , TAB_UINT32 , TAB_UINT64 , TAB_VOID , " BOOLEAN " ] :
2018-03-26 22:25:43 +02:00
if StructPattern . match ( pcd . DatumType ) is None :
2018-03-19 05:05:19 +01:00
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 ] )
for struct_pcd in Pcds . values ( ) :
if isinstance ( struct_pcd , StructurePcd ) and not struct_pcd . StructuredPcdIncludeFile :
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 ] ) )
2017-11-24 07:30:11 +01:00
return Pcds
2018-02-28 06:59:19 +01:00
@property
def CommonIncludes ( self ) :
if self . _CommonIncludes is None :
self . Includes
return self . _CommonIncludes
2017-11-24 07:30:11 +01:00
_Macros = property ( _GetMacros )
Arch = property ( _GetArch , _SetArch )
PackageName = property ( _GetPackageName )
Guid = property ( _GetFileGuid )
Version = property ( _GetVersion )
Protocols = property ( _GetProtocol )
Ppis = property ( _GetPpi )
Guids = property ( _GetGuid )
Includes = property ( _GetInclude )
LibraryClasses = property ( _GetLibraryClass )
Pcds = property ( _GetPcds )