## @file # Common routines used by workspace # # Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.
# 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 ## 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) ## 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 = {} for Pkg in PkgList: for Pcd in Pkg.Pcds: PcdCName = Pcd[0] PcdTokenName = Pcd[1] 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] 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