## @file | |
# Common routines used by workspace | |
# | |
# Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.<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.Misc import sdict | |
from Common.DataType import SUP_MODULE_USER_DEFINED | |
from BuildClassObject import LibraryClassObject | |
import Common.GlobalData as GlobalData | |
from Workspace.BuildClassObject import StructurePcd | |
## Get all packages from platform for specified arch, target and toolchain | |
# | |
# @param Platform: DscBuildData instance | |
# @param BuildDatabase: The database saves all data for all metafiles | |
# @param Arch: Current arch | |
# @param Target: Current target | |
# @param Toolchain: Current toolchain | |
# @retval: List of packages which are DecBuildData instances | |
# | |
def GetPackageList(Platform, BuildDatabase, Arch, Target, Toolchain): | |
PkgSet = set() | |
for ModuleFile in Platform.Modules: | |
Data = BuildDatabase[ModuleFile, Arch, Target, Toolchain] | |
PkgSet.update(Data.Packages) | |
for Lib in GetLiabraryInstances(Data, Platform, BuildDatabase, Arch, Target, Toolchain): | |
PkgSet.update(Lib.Packages) | |
return list(PkgSet) | |
# def ProcessStructurePcd(StructurePcdRawDataSet): | |
# s_pcd_set = dict() | |
# for s_pcd 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) | |
# | |
# str_pcd_set = [] | |
# for pcdname in s_pcd_set: | |
# dep_pkgs = [] | |
# struct_pcd = StructurePcd() | |
# for item in s_pcd_set[pcdname]: | |
# if "<HeaderFiles>" in item.TokenCName: | |
# struct_pcd.StructuredPcdIncludeFile = item.DefaultValue | |
# elif "<Packages>" in item.TokenCName: | |
# dep_pkgs.append(item.DefaultValue) | |
# elif item.DatumType == item.TokenCName: | |
# struct_pcd.copy(item) | |
# struct_pcd.TokenValue.strip("{").strip() | |
# struct_pcd.TokenSpaceGuidCName, struct_pcd.TokenCName = pcdname.split(".") | |
# else: | |
# struct_pcd.AddDefaultValue(item.TokenCName, item.DefaultValue) | |
# | |
# struct_pcd.PackageDecs = dep_pkgs | |
# | |
# str_pcd_set.append(struct_pcd) | |
# | |
# return str_pcd_set | |
# | |
## Get all declared PCD from platform for specified arch, target and toolchain | |
# | |
# @param Platform: DscBuildData instance | |
# @param BuildDatabase: The database saves all data for all metafiles | |
# @param Arch: Current arch | |
# @param Target: Current target | |
# @param Toolchain: Current toolchain | |
# @retval: A dictionary contains instances of PcdClassObject with key (PcdCName, TokenSpaceGuid) | |
# | |
def GetDeclaredPcd(Platform, BuildDatabase, Arch, Target, Toolchain): | |
PkgList = GetPackageList(Platform, BuildDatabase, Arch, Target, Toolchain) | |
DecPcds = {} | |
# StructurePcdRawData = [] | |
for Pkg in PkgList: | |
for Pcd in Pkg.Pcds: | |
PcdCName = Pcd[0] | |
PcdTokenName = Pcd[1] | |
# if "." in PcdTokenName: | |
# StructurePcdRawData.append(Pkg.Pcds[Pcd]) | |
# continue | |
if GlobalData.MixedPcd: | |
for PcdItem in GlobalData.MixedPcd.keys(): | |
if (PcdCName, PcdTokenName) in GlobalData.MixedPcd[PcdItem]: | |
PcdCName = PcdItem[0] | |
break | |
if (PcdCName, PcdTokenName) not in DecPcds.keys(): | |
DecPcds[PcdCName, PcdTokenName] = Pkg.Pcds[Pcd] | |
# StructurePcds = ProcessStructurePcd(StructurePcdRawData) | |
# for pcd in StructurePcds: | |
# DecPcds[pcd.TokenCName, pcd.TokenSpaceGuidCName] = pcd | |
return DecPcds | |
## Get all dependent libraries for a module | |
# | |
# @param Module: InfBuildData instance | |
# @param Platform: DscBuildData instance | |
# @param BuildDatabase: The database saves all data for all metafiles | |
# @param Arch: Current arch | |
# @param Target: Current target | |
# @param Toolchain: Current toolchain | |
# @retval: List of dependent libraries which are InfBuildData instances | |
# | |
def GetLiabraryInstances(Module, Platform, BuildDatabase, Arch, Target, Toolchain): | |
if Module.AutoGenVersion >= 0x00010005: | |
return _GetModuleLibraryInstances(Module, Platform, BuildDatabase, Arch, Target, Toolchain) | |
else: | |
return _ResolveLibraryReference(Module, Platform) | |
def _GetModuleLibraryInstances(Module, Platform, BuildDatabase, Arch, Target, Toolchain): | |
ModuleType = Module.ModuleType | |
# for overriding library instances with module specific setting | |
PlatformModule = Platform.Modules[str(Module)] | |
# add forced library instances (specified under LibraryClasses sections) | |
# | |
# If a module has a MODULE_TYPE of USER_DEFINED, | |
# do not link in NULL library class instances from the global [LibraryClasses.*] sections. | |
# | |
if Module.ModuleType != SUP_MODULE_USER_DEFINED: | |
for LibraryClass in Platform.LibraryClasses.GetKeys(): | |
if LibraryClass.startswith("NULL") and Platform.LibraryClasses[LibraryClass, Module.ModuleType]: | |
Module.LibraryClasses[LibraryClass] = Platform.LibraryClasses[LibraryClass, Module.ModuleType] | |
# add forced library instances (specified in module overrides) | |
for LibraryClass in PlatformModule.LibraryClasses: | |
if LibraryClass.startswith("NULL"): | |
Module.LibraryClasses[LibraryClass] = PlatformModule.LibraryClasses[LibraryClass] | |
# EdkII module | |
LibraryConsumerList = [Module] | |
Constructor = [] | |
ConsumedByList = sdict() | |
LibraryInstance = sdict() | |
while len(LibraryConsumerList) > 0: | |
M = LibraryConsumerList.pop() | |
for LibraryClassName in M.LibraryClasses: | |
if LibraryClassName not in LibraryInstance: | |
# override library instance for this module | |
if LibraryClassName in PlatformModule.LibraryClasses: | |
LibraryPath = PlatformModule.LibraryClasses[LibraryClassName] | |
else: | |
LibraryPath = Platform.LibraryClasses[LibraryClassName, ModuleType] | |
if LibraryPath == None or LibraryPath == "": | |
LibraryPath = M.LibraryClasses[LibraryClassName] | |
if LibraryPath == None or LibraryPath == "": | |
return [] | |
LibraryModule = BuildDatabase[LibraryPath, Arch, Target, Toolchain] | |
# for those forced library instance (NULL library), add a fake library class | |
if LibraryClassName.startswith("NULL"): | |
LibraryModule.LibraryClass.append(LibraryClassObject(LibraryClassName, [ModuleType])) | |
elif LibraryModule.LibraryClass == None \ | |
or len(LibraryModule.LibraryClass) == 0 \ | |
or (ModuleType != 'USER_DEFINED' | |
and ModuleType not in LibraryModule.LibraryClass[0].SupModList): | |
# only USER_DEFINED can link against any library instance despite of its SupModList | |
return [] | |
LibraryInstance[LibraryClassName] = LibraryModule | |
LibraryConsumerList.append(LibraryModule) | |
else: | |
LibraryModule = LibraryInstance[LibraryClassName] | |
if LibraryModule == None: | |
continue | |
if LibraryModule.ConstructorList != [] and LibraryModule not in Constructor: | |
Constructor.append(LibraryModule) | |
if LibraryModule not in ConsumedByList: | |
ConsumedByList[LibraryModule] = [] | |
# don't add current module itself to consumer list | |
if M != Module: | |
if M in ConsumedByList[LibraryModule]: | |
continue | |
ConsumedByList[LibraryModule].append(M) | |
# | |
# Initialize the sorted output list to the empty set | |
# | |
SortedLibraryList = [] | |
# | |
# Q <- Set of all nodes with no incoming edges | |
# | |
LibraryList = [] #LibraryInstance.values() | |
Q = [] | |
for LibraryClassName in LibraryInstance: | |
M = LibraryInstance[LibraryClassName] | |
LibraryList.append(M) | |
if ConsumedByList[M] == []: | |
Q.append(M) | |
# | |
# start the DAG algorithm | |
# | |
while True: | |
EdgeRemoved = True | |
while Q == [] and EdgeRemoved: | |
EdgeRemoved = False | |
# for each node Item with a Constructor | |
for Item in LibraryList: | |
if Item not in Constructor: | |
continue | |
# for each Node without a constructor with an edge e from Item to Node | |
for Node in ConsumedByList[Item]: | |
if Node in Constructor: | |
continue | |
# remove edge e from the graph if Node has no constructor | |
ConsumedByList[Item].remove(Node) | |
EdgeRemoved = True | |
if ConsumedByList[Item] == []: | |
# insert Item into Q | |
Q.insert(0, Item) | |
break | |
if Q != []: | |
break | |
# DAG is done if there's no more incoming edge for all nodes | |
if Q == []: | |
break | |
# remove node from Q | |
Node = Q.pop() | |
# output Node | |
SortedLibraryList.append(Node) | |
# for each node Item with an edge e from Node to Item do | |
for Item in LibraryList: | |
if Node not in ConsumedByList[Item]: | |
continue | |
# remove edge e from the graph | |
ConsumedByList[Item].remove(Node) | |
if ConsumedByList[Item] != []: | |
continue | |
# insert Item into Q, if Item has no other incoming edges | |
Q.insert(0, Item) | |
# | |
# if any remaining node Item in the graph has a constructor and an incoming edge, then the graph has a cycle | |
# | |
for Item in LibraryList: | |
if ConsumedByList[Item] != [] and Item in Constructor and len(Constructor) > 1: | |
return [] | |
if Item not in SortedLibraryList: | |
SortedLibraryList.append(Item) | |
# | |
# Build the list of constructor and destructir names | |
# The DAG Topo sort produces the destructor order, so the list of constructors must generated in the reverse order | |
# | |
SortedLibraryList.reverse() | |
return SortedLibraryList | |
def _ResolveLibraryReference(Module, Platform): | |
LibraryConsumerList = [Module] | |
# "CompilerStub" is a must for Edk modules | |
if Module.Libraries: | |
Module.Libraries.append("CompilerStub") | |
LibraryList = [] | |
while len(LibraryConsumerList) > 0: | |
M = LibraryConsumerList.pop() | |
for LibraryName in M.Libraries: | |
Library = Platform.LibraryClasses[LibraryName, ':dummy:'] | |
if Library == None: | |
for Key in Platform.LibraryClasses.data.keys(): | |
if LibraryName.upper() == Key.upper(): | |
Library = Platform.LibraryClasses[Key, ':dummy:'] | |
break | |
if Library == None: | |
continue | |
if Library not in LibraryList: | |
LibraryList.append(Library) | |
LibraryConsumerList.append(Library) | |
return LibraryList |