1## @file
2#
3# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
4#
5# SPDX-License-Identifier: BSD-2-Clause-Patent
6
7from plugins.EdkPlugins.basemodel import ini
8from plugins.EdkPlugins.edk2.model import dsc
9from plugins.EdkPlugins.edk2.model import inf
10from plugins.EdkPlugins.edk2.model import dec
11import os
12from plugins.EdkPlugins.basemodel.message import *
13
14class SurfaceObject(object):
15    _objs = {}
16
17    def __new__(cls, *args, **kwargs):
18        """Maintain only a single instance of this object
19        @return: instance of this class
20
21        """
22        obj = object.__new__(cls)
23        if "None" not in cls._objs:
24            cls._objs["None"] = []
25        cls._objs["None"].append(obj)
26
27        return obj
28
29    def __init__(self, parent, workspace):
30        self._parent    = parent
31        self._fileObj   = None
32        self._workspace = workspace
33        self._isModify  = False
34        self._modifiedObjs = []
35
36    def __del__(self):
37        pass
38
39    def Destroy(self):
40        key = self.GetRelativeFilename()
41        self.GetFileObj().Destroy(self)
42        del self._fileObj
43        # dereference self from _objs arrary
44        assert key in self._objs, "when destory, object is not in obj list"
45        assert self in self._objs[key], "when destory, object is not in obj list"
46        self._objs[key].remove(self)
47        if len(self._objs[key]) == 0:
48            del self._objs[key]
49
50    def GetParent(self):
51        return self._parent
52
53    def GetWorkspace(self):
54        return self._workspace
55
56    def GetFileObjectClass(self):
57        return ini.BaseINIFile
58
59    def GetFilename(self):
60        return self.GetFileObj().GetFilename()
61
62    def GetFileObj(self):
63        return self._fileObj
64
65    def GetRelativeFilename(self):
66        fullPath = self.GetFilename()
67        return fullPath[len(self._workspace) + 1:]
68
69    def Load(self, relativePath):
70        # if has been loaded, directly return
71        if self._fileObj is not None: return True
72
73        relativePath = os.path.normpath(relativePath)
74        fullPath = os.path.join(self._workspace, relativePath)
75        fullPath = os.path.normpath(fullPath)
76
77        if not os.path.exists(fullPath):
78            ErrorMsg("file does not exist!", fullPath)
79            return False
80
81        self._fileObj = self.GetFileObjectClass()(fullPath, self)
82
83        if not self._fileObj.Parse():
84            ErrorMsg("Fail to parse file!", fullPath)
85            return False
86
87        # remove self from None list to list with filename as key
88        cls = self.__class__
89        if self not in cls._objs["None"]:
90            ErrorMsg("Sufrace object does not be create into None list")
91        cls._objs["None"].remove(self)
92        if relativePath not in cls._objs:
93            cls._objs[relativePath] = []
94        cls._objs[relativePath].append(self)
95
96        return True
97
98    def Reload(self, force=False):
99        ret = True
100        # whether require must be update
101        if force:
102            ret = self.GetFileObj().Reload(True)
103        else:
104            if self.IsModified():
105                if self.GetFileObj().IsModified():
106                    ret = self.GetFileObj().Reload()
107        return ret
108
109    def Modify(self, modify=True, modifiedObj=None):
110        if modify:
111            #LogMsg("%s is modified, modified object is %s" % (self.GetFilename(), modifiedObj))
112            if issubclass(modifiedObj.__class__, ini.BaseINIFile) and self._isModify:
113                return
114            self._isModify = modify
115            self.GetParent().Modify(modify, self)
116        else:
117            self._isModify = modify
118
119    def IsModified(self):
120        return self._isModify
121
122    def GetModifiedObjs(self):
123        return self._modifiedObjs
124
125    def FilterObjsByArch(self, objs, arch):
126        arr = []
127        for obj in objs:
128            if obj.GetArch().lower() == 'common':
129                arr.append(obj)
130                continue
131            if obj.GetArch().lower() == arch.lower():
132                arr.append(obj)
133                continue
134        return arr
135
136class Platform(SurfaceObject):
137    def __init__(self, parent, workspace):
138        SurfaceObject.__init__(self, parent, workspace)
139        self._modules    = []
140        self._packages   = []
141
142    def Destroy(self):
143        for module in self._modules:
144            module.Destroy()
145        del self._modules[:]
146
147        del self._packages[:]
148        SurfaceObject.Destroy(self)
149
150    def GetName(self):
151        return self.GetFileObj().GetDefine("PLATFORM_NAME")
152
153    def GetFileObjectClass(self):
154        return dsc.DSCFile
155
156    def GetModuleCount(self):
157        if self.GetFileObj() is None:
158            ErrorMsg("Fail to get module count because DSC file has not been load!")
159
160        return len(self.GetFileObj().GetComponents())
161
162    def GetSupportArchs(self):
163        return self.GetFileObj().GetDefine("SUPPORTED_ARCHITECTURES").strip().split('#')[0].split('|')
164
165    def LoadModules(self, precallback=None, postcallback=None):
166        for obj in self.GetFileObj().GetComponents():
167            mFilename = obj.GetFilename()
168            if precallback is not None:
169                precallback(self, mFilename)
170            arch = obj.GetArch()
171            if arch.lower() == 'common':
172                archarr = self.GetSupportArchs()
173            else:
174                archarr = [arch]
175            for arch in archarr:
176                module = Module(self, self.GetWorkspace())
177                if module.Load(mFilename, arch, obj.GetOveridePcds(), obj.GetOverideLibs()):
178                    self._modules.append(module)
179                    if postcallback is not None:
180                        postcallback(self, module)
181                else:
182                    del module
183                    ErrorMsg("Fail to load module %s" % mFilename)
184
185    def GetModules(self):
186        return self._modules
187
188    def GetLibraryPath(self, classname, arch, type):
189        objs = self.GetFileObj().GetSectionObjectsByName("libraryclasses")
190
191        for obj in objs:
192            if classname.lower() != obj.GetClass().lower():
193                continue
194            if obj.GetArch().lower() != 'common' and \
195               obj.GetArch().lower() != arch.lower():
196                continue
197
198            if obj.GetModuleType().lower() != 'common' and \
199               obj.GetModuleType().lower() != type.lower():
200                continue
201
202            return obj.GetInstance()
203
204        ErrorMsg("Fail to get library class %s [%s][%s] from platform %s" % (classname, arch, type, self.GetFilename()))
205        return None
206
207    def GetPackage(self, path):
208        package = self.GetParent().GetPackage(path)
209        if package not in self._packages:
210            self._packages.append(package)
211        return package
212
213    def GetPcdBuildObjs(self, name, arch=None):
214        arr = []
215        objs = self.GetFileObj().GetSectionObjectsByName('pcds')
216        for obj in objs:
217            if obj.GetPcdName().lower() == name.lower():
218                arr.append(obj)
219        if arch is not None:
220            arr = self.FilterObjsByArch(arr, arch)
221        return arr
222
223    def Reload(self, callback=None):
224        # do not care force paramter for platform object
225        isFileChanged = self.GetFileObj().IsModified()
226        ret = SurfaceObject.Reload(self, False)
227        if not ret: return False
228        if isFileChanged:
229            # destroy all modules and reload them again
230            for obj in self._modules:
231                obj.Destroy()
232            del self._modules[:]
233            del self._packages[:]
234            self.LoadModules(callback)
235        else:
236            for obj in self._modules:
237                callback(self, obj.GetFilename())
238                obj.Reload()
239
240        self.Modify(False)
241        return True
242
243    def Modify(self, modify=True, modifiedObj=None):
244        if modify:
245            #LogMsg("%s is modified, modified object is %s" % (self.GetFilename(), modifiedObj))
246            if issubclass(modifiedObj.__class__, ini.BaseINIFile) and self._isModify:
247                return
248            self._isModify = modify
249            self.GetParent().Modify(modify, self)
250        else:
251            if self.GetFileObj().IsModified():
252                return
253            for obj in self._modules:
254                if obj.IsModified():
255                    return
256
257            self._isModify = modify
258            self.GetParent().Modify(modify, self)
259
260    def GetModuleObject(self, relativePath, arch):
261        path = os.path.normpath(relativePath)
262        for obj in self._modules:
263            if obj.GetRelativeFilename() == path:
264                if arch.lower() == 'common':
265                    return obj
266                if obj.GetArch() == arch:
267                    return obj
268        return None
269
270    def GenerateFullReferenceDsc(self):
271        oldDsc = self.GetFileObj()
272        newDsc = dsc.DSCFile()
273        newDsc.CopySectionsByName(oldDsc, 'defines')
274        newDsc.CopySectionsByName(oldDsc, 'SkuIds')
275
276        #
277        # Dynamic common section should also be copied
278        #
279        newDsc.CopySectionsByName(oldDsc, 'PcdsDynamicDefault')
280        newDsc.CopySectionsByName(oldDsc, 'PcdsDynamicHii')
281        newDsc.CopySectionsByName(oldDsc, 'PcdsDynamicVpd')
282        newDsc.CopySectionsByName(oldDsc, 'PcdsDynamicEx')
283
284        sects = oldDsc.GetSectionByName('Components')
285        for oldSect in sects:
286            newSect = newDsc.AddNewSection(oldSect.GetName())
287            for oldComObj in oldSect.GetObjects():
288                module = self.GetModuleObject(oldComObj.GetFilename(), oldSect.GetArch())
289                if module is None: continue
290
291                newComObj = dsc.DSCComponentObject(newSect)
292                newComObj.SetFilename(oldComObj.GetFilename())
293
294                # add all library instance for override section
295                libdict = module.GetLibraries()
296                for libclass in libdict.keys():
297                    if libdict[libclass] is not None:
298                        newComObj.AddOverideLib(libclass, libdict[libclass].GetRelativeFilename().replace('\\', '/'))
299
300                # add all pcds for override section
301                pcddict = module.GetPcds()
302                for pcd in pcddict.values():
303                    buildPcd   = pcd.GetBuildObj()
304                    buildType  = buildPcd.GetPcdType()
305                    buildValue = None
306                    if buildType.lower() == 'pcdsdynamichii' or \
307                       buildType.lower() == 'pcdsdynamicvpd' or \
308                       buildType.lower() == 'pcdsdynamicdefault':
309                        buildType = 'PcdsDynamic'
310                    if buildType != 'PcdsDynamic':
311                        buildValue = buildPcd.GetPcdValue()
312                    newComObj.AddOveridePcd(buildPcd.GetPcdName(),
313                                            buildType,
314                                            buildValue)
315                newSect.AddObject(newComObj)
316        return newDsc
317
318class Module(SurfaceObject):
319    def __init__(self, parent, workspace):
320        SurfaceObject.__init__(self, parent, workspace)
321        self._arch        = 'common'
322        self._parent      = parent
323        self._overidePcds = {}
324        self._overideLibs = {}
325        self._libs        = {}
326        self._pcds        = {}
327        self._ppis        = []
328        self._protocols   = []
329        self._depexs      = []
330        self._guids       = []
331        self._packages    = []
332
333    def Destroy(self):
334        for lib in self._libs.values():
335            if lib is not None:
336                lib.Destroy()
337        self._libs.clear()
338
339        for pcd in self._pcds.values():
340            pcd.Destroy()
341        self._pcds.clear()
342
343        for ppi in self._ppis:
344            ppi.DeRef(self)
345        del self._ppis[:]
346
347        for protocol in self._protocols:
348            if protocol is not None:
349                protocol.DeRef(self)
350        del self._protocols[:]
351
352        for guid in self._guids:
353            if guid is not None:
354                guid.DeRef(self)
355        del self._guids[:]
356
357        del self._packages[:]
358        del self._depexs[:]
359        SurfaceObject.Destroy(self)
360
361    def GetFileObjectClass(self):
362        return inf.INFFile
363
364    def GetLibraries(self):
365        return self._libs
366
367    def Load(self, filename, arch='common', overidePcds=None, overideLibs=None):
368        if not SurfaceObject.Load(self, filename):
369            return False
370
371        self._arch = arch
372        if overidePcds is not None:
373            self._overideLibs = overideLibs
374        if overideLibs is not None:
375            self._overidePcds = overidePcds
376
377        self._SearchLibraries()
378        self._SearchPackage()
379        self._SearchSurfaceItems()
380        return True
381
382    def GetArch(self):
383        return self._arch
384
385    def GetModuleName(self):
386        return self.GetFileObj().GetDefine("BASE_NAME")
387
388    def GetModuleType(self):
389        return self.GetFileObj().GetDefine("MODULE_TYPE")
390
391    def GetPlatform(self):
392        return self.GetParent()
393
394    def GetModuleObj(self):
395        return self
396
397    def GetPcds(self):
398        pcds = self._pcds.copy()
399        for lib in self._libs.values():
400            if lib is None: continue
401            for name in lib._pcds.keys():
402                pcds[name] = lib._pcds[name]
403        return pcds
404
405    def GetPpis(self):
406        ppis = []
407        ppis += self._ppis
408        for lib in self._libs.values():
409            if lib is None: continue
410            ppis += lib._ppis
411        return ppis
412
413    def GetProtocols(self):
414        pros = []
415        pros = self._protocols
416        for lib in self._libs.values():
417            if lib is None: continue
418            pros += lib._protocols
419        return pros
420
421    def GetGuids(self):
422        guids = []
423        guids += self._guids
424        for lib in self._libs.values():
425            if lib is None: continue
426            guids += lib._guids
427        return guids
428
429    def GetDepexs(self):
430        deps = []
431        deps += self._depexs
432        for lib in self._libs.values():
433            if lib is None: continue
434            deps += lib._depexs
435        return deps
436
437    def IsLibrary(self):
438        return self.GetFileObj().GetDefine("LIBRARY_CLASS") is not None
439
440    def GetLibraryInstance(self, classname, arch, type):
441        if classname not in self._libs.keys():
442            # find in overide lib firstly
443            if classname in self._overideLibs.keys():
444                self._libs[classname] = Library(self, self.GetWorkspace())
445                self._libs[classname].Load(self._overideLibs[classname])
446                return self._libs[classname]
447
448            parent = self.GetParent()
449            if issubclass(parent.__class__, Platform):
450                path = parent.GetLibraryPath(classname, arch, type)
451                if path is None:
452                    ErrorMsg('Fail to get library instance for %s' % classname, self.GetFilename())
453                    return None
454                self._libs[classname] = Library(self, self.GetWorkspace())
455                if not self._libs[classname].Load(path, self.GetArch()):
456                    self._libs[classname] = None
457            else:
458                self._libs[classname] = parent.GetLibraryInstance(classname, arch, type)
459        return self._libs[classname]
460
461    def GetSourceObjs(self):
462        return self.GetFileObj().GetSectionObjectsByName('source')
463
464    def _SearchLibraries(self):
465        objs = self.GetFileObj().GetSectionObjectsByName('libraryclasses')
466        arch = self.GetArch()
467        type = self.GetModuleType()
468        for obj in objs:
469            if obj.GetArch().lower() != 'common' and \
470               obj.GetArch().lower() not in self.GetPlatform().GetSupportArchs():
471                continue
472            classname = obj.GetClass()
473            instance = self.GetLibraryInstance(classname, arch, type)
474            if not self.IsLibrary() and instance is not None:
475                instance._isInherit = False
476
477            if classname not in self._libs.keys():
478                self._libs[classname] = instance
479
480    def _SearchSurfaceItems(self):
481        # get surface item from self's inf
482        pcds  = []
483        ppis  = []
484        pros  = []
485        deps  = []
486        guids = []
487        if self.GetFileObj() is not None:
488            pcds = self.FilterObjsByArch(self.GetFileObj().GetSectionObjectsByName('pcd'),
489                                          self.GetArch())
490            for pcd in pcds:
491                if pcd.GetPcdName() not in self._pcds.keys():
492                    pcdItem = PcdItem(pcd.GetPcdName(), self, pcd)
493                    self._pcds[pcd.GetPcdName()] = ModulePcd(self,
494                                                             pcd.GetPcdName(),
495                                                             pcd,
496                                                             pcdItem)
497
498            ppis += self.FilterObjsByArch(self.GetFileObj().GetSectionObjectsByName('ppis'),
499                                          self.GetArch())
500
501            for ppi in ppis:
502                item = PpiItem(ppi.GetName(), self, ppi)
503                if item not in self._ppis:
504                    self._ppis.append(item)
505
506            pros += self.FilterObjsByArch(self.GetFileObj().GetSectionObjectsByName('protocols'),
507                                          self.GetArch())
508
509            for pro in pros:
510                item = ProtocolItem(pro.GetName(), self, pro)
511                if item not in self._protocols:
512                    self._protocols.append(item)
513
514            deps += self.FilterObjsByArch(self.GetFileObj().GetSectionObjectsByName('depex'),
515                                          self.GetArch())
516            for dep in deps:
517                item = DepexItem(self, dep)
518                self._depexs.append(item)
519
520            guids += self.FilterObjsByArch(self.GetFileObj().GetSectionObjectsByName('guids'),
521                                          self.GetArch())
522            for guid in guids:
523                item = GuidItem(guid.GetName(), self, guid)
524                if item not in self._guids:
525                    self._guids.append(item)
526
527    def _SearchPackage(self):
528        objs = self.GetFileObj().GetSectionObjectsByName('packages')
529        for obj in objs:
530            package = self.GetPlatform().GetPackage(obj.GetPath())
531            if package is not None:
532                self._packages.append(package)
533
534    def GetPackages(self):
535        return self._packages
536
537    def GetPcdObjects(self):
538        if self.GetFileObj() is None:
539            return []
540
541        return self.GetFileObj().GetSectionObjectsByName('pcd')
542
543    def GetLibraryClassHeaderFilePath(self):
544        lcname = self.GetFileObj().GetProduceLibraryClass()
545        if lcname is None: return None
546
547        pkgs = self.GetPackages()
548        for package in pkgs:
549            path = package.GetLibraryClassHeaderPathByName(lcname)
550            if path is not None:
551                return os.path.realpath(os.path.join(package.GetFileObj().GetPackageRootPath(), path))
552        return None
553
554    def Reload(self, force=False, callback=None):
555        if callback is not None:
556            callback(self, "Starting reload...")
557
558        ret = SurfaceObject.Reload(self, force)
559        if not ret: return False
560
561        if not force and not self.IsModified():
562            return True
563
564        for lib in self._libs.values():
565            if lib is not None:
566                lib.Destroy()
567        self._libs.clear()
568
569        for pcd in self._pcds.values():
570            pcd.Destroy()
571        self._pcds.clear()
572
573        for ppi in self._ppis:
574            ppi.DeRef(self)
575        del self._ppis[:]
576
577        for protocol in self._protocols:
578            protocol.DeRef(self)
579        del self._protocols[:]
580
581        for guid in self._guids:
582            guid.DeRef(self)
583        del self._guids[:]
584
585        del self._packages[:]
586        del self._depexs[:]
587
588        if callback is not None:
589            callback(self, "Searching libraries...")
590        self._SearchLibraries()
591        if callback is not None:
592            callback(self, "Searching packages...")
593        self._SearchPackage()
594        if callback is not None:
595            callback(self, "Searching surface items...")
596        self._SearchSurfaceItems()
597
598        self.Modify(False)
599        return True
600
601    def Modify(self, modify=True, modifiedObj=None):
602        if modify:
603            #LogMsg("%s is modified, modified object is %s" % (self.GetFilename(), modifiedObj))
604            if issubclass(modifiedObj.__class__, ini.BaseINIFile) and self._isModify:
605                return
606            self._isModify = modify
607            self.GetParent().Modify(modify, self)
608        else:
609            if self.GetFileObj().IsModified():
610                return
611
612            self._isModify = modify
613            self.GetParent().Modify(modify, self)
614
615class Library(Module):
616    def __init__(self, parent, workspace):
617        Module.__init__(self, parent, workspace)
618        self._isInherit = True
619
620    def IsInherit(self):
621        return self._isInherit
622
623    def GetModuleType(self):
624        return self.GetParent().GetModuleType()
625
626    def GetPlatform(self):
627        return self.GetParent().GetParent()
628
629    def GetModuleObj(self):
630        return self.GetParent()
631
632    def GetArch(self):
633        return self.GetParent().GetArch()
634
635    def Destroy(self):
636        self._libs.clear()
637        self._pcds.clear()
638        SurfaceObject.Destroy(self)
639
640class Package(SurfaceObject):
641    def __init__(self, parent, workspace):
642        SurfaceObject.__init__(self, parent, workspace)
643        self._pcds      = {}
644        self._guids     = {}
645        self._protocols = {}
646        self._ppis      = {}
647
648    def GetPcds(self):
649        return self._pcds
650
651    def GetPpis(self):
652        return list(self._ppis.values())
653
654    def GetProtocols(self):
655        return list(self._protocols.values())
656
657    def GetGuids(self):
658        return list(self._guids.values())
659
660    def Destroy(self):
661        for pcd in self._pcds.values():
662            if pcd is not None:
663                pcd.Destroy()
664        for guid in self._guids.values():
665            if guid is not None:
666                guid.Destroy()
667        for protocol in self._protocols.values():
668            if protocol is not None:
669                protocol.Destroy()
670        for ppi in self._ppis.values():
671            if ppi is not None:
672                ppi.Destroy()
673        self._pcds.clear()
674        self._guids.clear()
675        self._protocols.clear()
676        self._ppis.clear()
677        self._pcds.clear()
678        SurfaceObject.Destroy(self)
679
680    def Load(self, relativePath):
681        ret = SurfaceObject.Load(self, relativePath)
682        if not ret: return False
683        pcds = self.GetFileObj().GetSectionObjectsByName('pcds')
684        for pcd in pcds:
685            if pcd.GetPcdName() in self._pcds.keys():
686                if self._pcds[pcd.GetPcdName()] is not None:
687                    self._pcds[pcd.GetPcdName()].AddDecObj(pcd)
688            else:
689                self._pcds[pcd.GetPcdName()] = PcdItem(pcd.GetPcdName(), self, pcd)
690
691        guids = self.GetFileObj().GetSectionObjectsByName('guids')
692        for guid in guids:
693            if guid.GetName() not in self._guids.keys():
694                self._guids[guid.GetName()] = GuidItem(guid.GetName(), self, guid)
695            else:
696                WarnMsg("Duplicate definition for %s" % guid.GetName())
697
698        ppis = self.GetFileObj().GetSectionObjectsByName('ppis')
699        for ppi in ppis:
700            if ppi.GetName() not in self._ppis.keys():
701                self._ppis[ppi.GetName()] = PpiItem(ppi.GetName(), self, ppi)
702            else:
703                WarnMsg("Duplicate definition for %s" % ppi.GetName())
704
705        protocols = self.GetFileObj().GetSectionObjectsByName('protocols')
706        for protocol in protocols:
707            if protocol.GetName() not in self._protocols.keys():
708                self._protocols[protocol.GetName()] = ProtocolItem(protocol.GetName(), self, protocol)
709            else:
710                WarnMsg("Duplicate definition for %s" % protocol.GetName())
711
712        return True
713
714    def GetFileObjectClass(self):
715        return dec.DECFile
716
717    def GetName(self):
718        return self.GetFileObj().GetDefine("PACKAGE_NAME")
719
720    def GetPcdDefineObjs(self, name=None):
721        arr = []
722        objs = self.GetFileObj().GetSectionObjectsByName('pcds')
723        if name is None: return objs
724
725        for obj in objs:
726            if obj.GetPcdName().lower() == name.lower():
727                arr.append(obj)
728        return arr
729
730    def GetLibraryClassObjs(self):
731        return self.GetFileObj().GetSectionObjectsByName('libraryclasses')
732
733    def Modify(self, modify=True, modifiedObj=None):
734        if modify:
735            self._isModify = modify
736            self.GetParent().Modify(modify, self)
737        else:
738            if self.GetFileObj().IsModified():
739                return
740
741            self._isModify = modify
742            self.GetParent().Modify(modify, self)
743
744    def GetLibraryClassHeaderPathByName(self, clsname):
745        objs = self.GetLibraryClassObjs()
746        for obj in objs:
747            if obj.GetClassName() == clsname:
748                return obj.GetHeaderFile()
749        return None
750
751class DepexItem(object):
752    def __init__(self, parent, infObj):
753        self._parent = parent
754        self._infObj = infObj
755
756    def GetDepexString(self):
757        return str(self._infObj)
758
759    def GetInfObject(self):
760        return self._infObj
761
762class ModulePcd(object):
763    _type_mapping = {'FeaturePcd': 'PcdsFeatureFlag',
764                     'FixedPcd': 'PcdsFixedAtBuild',
765                     'PatchPcd': 'PcdsPatchableInModule'}
766
767    def __init__(self, parent, name, infObj, pcdItem):
768        assert issubclass(parent.__class__, Module), "Module's PCD's parent must be module!"
769        assert pcdItem is not None, 'Pcd %s does not in some package!' % name
770
771        self._name          = name
772        self._parent        = parent
773        self._pcdItem       = pcdItem
774        self._infObj        = infObj
775
776    def GetName(self):
777        return self._name
778
779    def GetParent(self):
780        return self._name
781
782    def GetArch(self):
783        return self._parent.GetArch()
784
785    def Destroy(self):
786        self._pcdItem.DeRef(self._parent)
787        self._infObj = None
788
789    def GetBuildObj(self):
790        platformInfos = self._parent.GetPlatform().GetPcdBuildObjs(self._name, self.GetArch())
791        modulePcdType = self._infObj.GetPcdType()
792
793        # if platform do not gives pcd's value, get default value from package
794        if len(platformInfos) == 0:
795            if modulePcdType.lower() == 'pcd':
796                return self._pcdItem.GetDecObject()
797            else:
798                for obj in self._pcdItem.GetDecObjects():
799                    if modulePcdType not in self._type_mapping.keys():
800                        ErrorMsg("Invalid PCD type %s" % modulePcdType)
801                        return None
802
803                    if self._type_mapping[modulePcdType] == obj.GetPcdType():
804                        return obj
805                ErrorMsg ('Module PCD type %s does not in valied range [%s] in package!' % \
806                          (modulePcdType))
807        else:
808            if modulePcdType.lower() == 'pcd':
809                if len(platformInfos) > 1:
810                    WarnMsg("Find more than one value for PCD %s in platform %s" % \
811                            (self._name, self._parent.GetPlatform().GetFilename()))
812                return platformInfos[0]
813            else:
814                for obj in platformInfos:
815                    if modulePcdType not in self._type_mapping.keys():
816                        ErrorMsg("Invalid PCD type %s" % modulePcdType)
817                        return None
818
819                    if self._type_mapping[modulePcdType] == obj.GetPcdType():
820                        return obj
821
822                ErrorMsg('Can not find value for pcd %s in pcd type %s' % \
823                         (self._name, modulePcdType))
824        return None
825
826
827class SurfaceItem(object):
828    _objs = {}
829
830    def __new__(cls, *args, **kwargs):
831        """Maintain only a single instance of this object
832        @return: instance of this class
833
834        """
835        name    = args[0]
836        parent  = args[1]
837        fileObj = args[2]
838        if issubclass(parent.__class__, Package):
839            if name in cls._objs.keys():
840                ErrorMsg("%s item is duplicated defined in packages: %s and %s" %
841                         (name, parent.GetFilename(), cls._objs[name].GetParent().GetFilename()))
842                return None
843            obj = object.__new__(cls)
844            cls._objs[name] = obj
845            return obj
846        elif issubclass(parent.__class__, Module):
847            if name not in cls._objs.keys():
848                ErrorMsg("%s item does not defined in any package! It is used by module %s" % \
849                         (name, parent.GetFilename()))
850                return None
851            return cls._objs[name]
852
853        return None
854
855
856    def __init__(self, name, parent, fileObj):
857        if issubclass(parent.__class__, Package):
858            self._name    = name
859            self._parent  = parent
860            self._decObj  = [fileObj]
861            self._refMods = {}
862        else:
863            self.RefModule(parent, fileObj)
864
865    @classmethod
866    def GetObjectDict(cls):
867        return cls._objs
868
869    def GetParent(self):
870        return self._parent
871
872    def GetReference(self):
873        return self._refMods
874
875    def RefModule(self, mObj, infObj):
876        if mObj in self._refMods.keys():
877            return
878        self._refMods[mObj] = infObj
879
880    def DeRef(self, mObj):
881        if mObj not in self._refMods.keys():
882            WarnMsg("%s is not referenced by module %s" % (self._name, mObj.GetFilename()))
883            return
884        del self._refMods[mObj]
885
886    def Destroy(self):
887        self._refMods.clear()
888        cls = self.__class__
889        del cls._objs[self._name]
890
891    def GetName(self):
892        return self._name
893
894    def GetDecObject(self):
895        return self._decObj[0]
896
897    def GetDecObjects(self):
898        return self._decObj
899
900class PcdItem(SurfaceItem):
901    def AddDecObj(self, fileObj):
902        for decObj in self._decObj:
903            if decObj.GetFilename() != fileObj.GetFilename():
904                ErrorMsg("Pcd %s defined in more than one packages : %s and %s" % \
905                         (self._name, decObj.GetFilename(), fileObj.GetFilename()))
906                return
907            if decObj.GetPcdType() == fileObj.GetPcdType() and \
908               decObj.GetArch().lower() == fileObj.GetArch():
909                ErrorMsg("Pcd %s is duplicated defined in pcd type %s in package %s" % \
910                         (self._name, decObj.GetPcdType(), decObj.GetFilename()))
911                return
912        self._decObj.append(fileObj)
913
914    def GetValidPcdType(self):
915        types = []
916        for obj in self._decObj:
917            if obj.GetPcdType() not in types:
918                types += obj.GetPcdType()
919        return types
920
921class GuidItem(SurfaceItem):
922    pass
923
924class PpiItem(SurfaceItem):
925    pass
926
927class ProtocolItem(SurfaceItem):
928    pass
929